Gamepad da Sega Mega Drive e Raspberry Pi Parte 2 (seis botões finais)



Continue, o mais fácil acabou! E agora para o mais difícil e interessante. Se você estiver com preguiça de ler, abaixo (mais perto do final do artigo), haverá um link para o vídeo, com o resultado e a explicação de tudo, incluindo o que está descrito na primeira parte. Se você estiver interessado, siga a seguir.

No modo de 6 botões, a leitura ocorre em 4 ciclos ou fases (se expresso no idioma do emulador). Ou seja, a cada 16 ms, há uma alteração cíclica (4 ciclos) no estado da saída Select, e a cada quarto ciclo na saída do controlador aparece o estado dos botões adicionais. Abaixo está um gráfico de leitura, para maior clareza, que deve ser repetido:



É bom que eu tenha um analisador lógico, com a ajuda do qual peguei um bug, que se manifestou no fato de que o ciclo não saiu da quarta fase.

Eu não vou dar a volta, vou dar imediatamente uma lista desta função:

static u32 read_pad_6btn(int i, u32 out_bits) { u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU int phase = Pico.m.padTHPhase[i]; u32 value = 0; if (i == 0 && phase == 0 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 0 && !(out_bits & 0x40)) // TH { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 1 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 1 && !(out_bits & 0x40)) // TH { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 2 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 2 && !(out_bits & 0x40)) { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 3 && (out_bits & 0x40)) { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read Z button value ^= digitalRead(Data1) << 1; //read Y button value ^= digitalRead(Data2) << 2; //read X button value ^= digitalRead(Data3) << 3; //read MODE button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 3 && !(out_bits & 0x40)) { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); value |= 0x0f; } if (i == 1 && phase == 0 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 0 && !(out_bits & 0x40)) // TH { value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU } if (i == 1 && phase == 1 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 1 && !(out_bits & 0x40)) // TH { value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU } if (i == 1 && phase == 2 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 2 && !(out_bits & 0x40)) { value = (pad & 0xc0) >> 2; // ?0SA 0000 } if(i == 1 && phase == 3 && (out_bits & 0x40)) { return (pad & 0x30) | ((pad >> 8) & 0xf); // ?1CB MXYZ } if(i == 1 && phase == 3 && !(out_bits & 0x40)) { return ((pad & 0xc0) >> 2) | 0x0f; // ?0SA 1111 } return value; } 

Vamos analisar qualquer uma das condições, por exemplo:

 if (i == 0 && phase == 1 && !(out_bits & 0x40)) // TH 

Aqui, verifica-se que estamos lendo do primeiro gamepad (i == 0) , da segunda fase de leitura (fase == 1) e da saída Select deve ser definida como 0 ! (Out_bits & 0x40) . Para entender como isso funciona no emulador, compilei o código no Xubuntu e o Visual Studio Code, definindo vários pontos de interrupção, executou o código no modo de depuração. O resultado é uma imagem tão bonita:



Na verdade, o resultado do trabalho é:


Aqui devo dizer algumas palavras sobre o próprio emulador. Ou não descobri ou isso é um bug, mas o emulador é carregado inicialmente no modo de 3 botões, mesmo que o oposto seja indicado nas configurações globais. Para 99% dos jogos, isso é suficiente. Para entrar no modo de operação com um gamepad de 6 botões, você precisa entrar nas configurações e voltar ao jogo sem alterar nada.
Mas há um jogo que está fora desse contexto: Lost Vikings, os botões X, Z, MODE funcionam bem nele, sem dança.

PS

Mas você pode fazer isso ainda mais fácil, uma pessoa amável já escreveu um driver para trabalhar com um gamepad e em um nível muito baixo. Eu ainda estou longe disso.

Obrigado pela atenção!

Source: https://habr.com/ru/post/pt435094/


All Articles