Gamepad da Sega Mega Drive e Raspberry Pi Parte 1 (preparatório e com três botões)

Chegou o outono , o repolho floresceu , é quase meio do inverno e acabei de mexer nele. Ainda assim, chegou o momento em que você deseja reproduzir algo antigo, ao som de uma tempestade de neve do lado de fora da janela, por exemplo, o Sonic ou o verme de Jim. No final do artigo, há um vídeo com resultados preliminares.



Se você jogou jogos SMD no emulador, provavelmente percebeu que o game pad mais conveniente para esses jogos é o gamepad nativo do SMD. Para a maioria dos outros consoles, ao jogar no emulador, é bem possível conviver com o mesmo gamepad Xbox ou Logitech, o padrão foi formado no final dos anos 90. Mas até o final dos anos 90, todo mundo se esforçava ao máximo.

Não é difícil comprar um gamepad da SMD e, como regra, você pode comprá-lo onde os clones dos próprios consoles são vendidos, a um preço bastante acessível, cerca de 300 rublos.

Como antes, organizei a conexão com o Raspberry pi usando um cabo USB do gabinete descomissionado e o conector DB-9 do pai. E o GPIO tirou as conclusões do programa. O gamepad funciona muito bem a partir de 3,3 Volts.



Como sempre, surgiu a pergunta sobre a escolha de um emulador, e a melhor opção foi o emulador - Picodrive, ele é otimizado para ARM, bem estruturado e, pelo que entendi, faz parte da montagem RetroPi. Mas com a montagem tive que mexer um pouco. O código fonte está localizado no serviço Github, neste endereço .

Para construir, precisamos de 3 componentes de sucesso do repositório do autor do emulador:

  1. Próprio emulador Picodrive;
  2. Emulador de CPU - cyclone68000;
  3. e FrontEnd - Libpicofe.

Agora tudo isso precisa ser montado corretamente. Descompacte ou não descompacte o Picodrive , dependendo de como você o baixou. Agora abra o diretório com cyclone68000 , seu conteúdo deve ser copiado para o diretório:

/ /picodrive-master/cpu/cyclone 

Você também precisa lidar com o conteúdo do diretório Libpicofe , seu conteúdo é copiado para o diretório:

 / /picodrive-master/platform/libpicofe 

Agora você precisa se preparar para a montagem:
fazer configuração

 sudo ./configure 

Após a conclusão da configuração, um arquivo será criado - config.mak , nele você precisará encontrar e alterar algumas linhas. Abaixo está o resultado final:

 AS = arm-linux-as LDLIBS += -L/usr/lib/arm-linux-gnueabihf -lSDL -lasound -lpng -lm -lz -lwiringPi ARCH = arm PLATFORM = rpi1 

Em seguida, você precisa editar o arquivo - config.h . Está localizado no diretório:

 / /picodrive-master/cpu/cyclone 

Nele, você precisa colocar os nas variáveis:

 #define HAVE_ARMv6 1 #define CYCLONE_FOR_GENESIS 1 

E agora a parte do software

Como sempre, foi necessário encontrar um local onde as informações sobre os botões pressionados sejam processadas, entender e perdoar o código e substituí-lo.

Sem capturar suspense, direi imediatamente que os arquivos que você está procurando estão localizados no diretório:

 / /picodrive-master/pico/ 

Aqui estamos interessados ​​em 3 arquivos - pico.c , memory.c , memory.h . Provavelmente você pode fazer com um número menor e juntar tudo em um, mas me pareceu mais fácil.
E assim, no arquivo pico.c, inicializo a biblioteca e configuro inicialmente os pinos do GPIO.

Imediatamente darei parte do cabeçalho do arquivo:

 #include "pico_int.h" #include "sound/ym2612.h" #include <wiringPi.h> #define Data0 3 #define Data1 4 #define Data2 5 #define Data3 12 #define Data4 13 #define Data5 10 #define Select 6 struct Pico Pico; struct PicoMem PicoMem; PicoInterface PicoIn; 

Como você pode ver, o cabeçalho da biblioteca WiringPi é definido e as definições são anunciadas, que aparecerão um pouco mais baixas. Bem, por exemplo, agora na função void PicoInit (void) :

 void PicoInit(void) { ... ... PicoDraw2Init(); wiringPiSetup (); pinMode (Select, OUTPUT); pinMode (Data0, INPUT); pinMode (Data1, INPUT); pinMode (Data2, INPUT); pinMode (Data3, INPUT); pinMode (Data4, INPUT); pinMode (Data5, INPUT); digitalWrite (Select, HIGH); } 

Esta é uma função de inicialização da memória do emulador (mais ou menos). E foi aqui que inseri todas as configurações dos pinos GPIO. Aqui está a pinagem do conector DB-9 .

Aqui devo dizer que o gamepad possui 6 contatos de informação (Dados0 ... Dados5), um controlador (Selest) e energia.

Em seguida, temos as mesmas definições - defina, precisamos repeti-las novamente. Isso pode ser feito tanto na memória.he na memória.c . Eu escolhi a primeira opção. Não faz sentido listar isso.

Então chegamos ao mais interessante - o arquivo memory.c . Possui 2 funções com nomes eloquentes:

 static u32 read_pad_3btn(int i, u32 out_bits) static u32 read_pad_6btn(int i, u32 out_bits) 

Os nomes parecem sugerir discretamente a leitura do status dos gamepads de 3 e 6 botões.

Aqui, deve ser esclarecido que qualquer gamepad de 6 botões pode funcionar como um de 3 botões. E a parte do leão dos jogos funciona exatamente com este modo do gamepad. Nesse modo, uma vez a cada 16 milissegundos, o status da saída Selecionar muda. Quando Selecionar = 0, os valores dos botões são lidos - UP, DOWN, A, Start. Quando Selecionar = 1, o estado dos botões é lido - ACIMA, ABAIXO, ESQUERDA, DIREITA, B, C. Abaixo está um exemplo de como esse modo funciona.



Imediatamente darei uma lista dessa função com as alterações:

 static u32 read_pad_3btn(int i, u32 out_bits) { u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU u32 value = 0; if (i == 0 && (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 && !(out_bits & 0x40)) { digitalWrite (Select, LOW); delayMicroseconds (20); 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 } if (i == 1 && (out_bits & 0x40))// TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && !(out_bits & 0x40)) { value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU } return value; } 

Aqui i é o número do gamepad e a expressão if (out_bits & 0x40) // TH é apenas responsável pelo status da saída Select. Vale ressaltar que no emulador o estado dos botões é fornecido da mesma forma que no console. Botão pressionado = 0.

Aqui está o resultado do trabalho:


Continua na próxima série, Pip-Pip-Pip

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


All Articles