Dingoo A320 + Arduino, часть вторая

Пришла пора выкладывать схему и прошивку, сопрягающую Dingoo A320 и  SNES-джойстик… О proof-of-concept мы писали вот тут.

Вместо предисловия — все началось с того момента, когда ко мне в руки попала «убитая» A320  неизвестного происхождения (зеленая плата, HK-версия). К сожалению, в процессе сборки-разборки у нее был сломан выключатель питания, замену ему найти не удалось и было решено сделать что-то не пуская Dingoo A320 «на органы» — а тут как раз подоспела партия китайских SNES-джойстиков, один из которых был пущен на PixelKit, еще один подарен, 3 остались лежать «про запас». Dingoo довольно быстро была восстановлена одним из анбрикеров (тупо перебором как анбрикеров, так и загрузчиков для разных LCD). Еще через несколько «граблей» был установлен Dingux с помощью альтернативного hwInit.

Как вы уже читали, нам удалось после некоторых усилий скоммутировать Dingoo A320 и Arduino, не убив при этом ни того, ни другого. Но в гипотетический Arcade Cabinet совершенно не хотелось ставить цельную плату Arduino, поэтому было принято решение решительно собрать минимальный клон ардуино-подобной платы, да и в очередной раз потренироваться в разводке-травлении-пайке. За основу был выбран вот этот вариант. Не будем грузить вас подробностями про бутлоадеры, задержки и так далее — сразу к делу.

Вот схема (клик по картинке увеличивает изображение):

Некоторые комментарии к схеме.

  • Кнопки сброса, включения питания и hold можно было вывести напрямую с платы Dingoo A320 без заведения в Atmega. Но это не спортивно, да и хотелось экзотики 🙂
  • На эти кнопки можно (и нужно ?) параллельно подпаять блокировочные конденсаторы — это частично уберет эффект дребезга.
  • Есть один лишний контакт, помеченный как «FREE» на схеме. Он не используется, но управляется как и все остальные. Когда замкнут — на пине выставляется логический «0». Джампер JP1 отключает защитный диод — если понадобится не только притягивать пин к земле, но и выставлять в 5 вольт
  • Питание и ресет выведены, как джамперы. Это просто «быстро и удобно»
  • Светодиод индицирует не совсем питание, а старт прошивки и использовался в отладочных целях

Плата для ЛУТ в разрешении 600 dpi

Ну и монтажная схема — нужно соединить еще несколько проводников — они отмечены красным

Уже скомпилированная прошивка в формате HEX. Fuse-биты использованы от загрузчика Arduino, а именно :

  • low_fuses=0xe4
  • high_fuses=0xc2

Не хотелось рассчитывать заново, да и для этой прошивки их достаточно — она занимает далеко не все место в атмеге и работает корректно.

Исходник прошивки в формате Arduino Sketch (для работы требуется библиотека NESPad)

#include <SNESpad.h>

#define DS   11
#define SHCP 12
#define STCP 8

#define RESET_PIN 5
#define POWER_PIN 6
#define HOLD_PIN 7
#define FREE_PIN 9

//"Near" 7hc595 is one connected directly to Arduino. The "Far" one is 
//"cascaded" to it.

//The signals are like this:
// Q7-Q1,Q15 are from high bit to lowest. (128-64-32-16-4-2-1)
// firstly "far" 7hc595 is stuffed, then the near one
// see "send2out"

//state definitions for out1 - "near" 7hc595

#define SELECT 0b01111111
#define START  0b10111111
#define A      0b11011111
#define B      0b11101111
#define X      0b11110111
#define Y      0b11111011
#define LSHIFT 0b11111101
#define RSHIFT 0b11111110

//state definitions for out0 - "far" 7hc595

#define UP     0b01111111
#define DOWN   0b10111111
#define LEFT   0b11011111
#define RIGHT  0b11101111
#define RESET  0b11110111
#define POWER  0b11111011
#define HOLD   0b11111101
#define UNUSED 0b11111110

byte GetAddedState()
{
  byte bRes=0xff;
  if ( digitalRead(RESET_PIN) != HIGH )
    bRes = bRes & RESET;

  if ( digitalRead(POWER_PIN) != HIGH )
    bRes = bRes & POWER;

  if ( digitalRead(HOLD_PIN) != HIGH )
    bRes = bRes & HOLD;

  if ( digitalRead(FREE_PIN) != HIGH )
    bRes = bRes & UNUSED;

    return bRes;

}

byte decodeNear(int state)
{
  byte res=0b11111111;
  if ( state & SNES_SELECT )
    res = res & SELECT;

  if ( state & SNES_START )
    res = res & START;

  if ( state & SNES_A )
    res = res & A;

  if ( state & SNES_B )
    res = res & B;

  if ( state & SNES_X )
    res = res & X;

  if ( state & SNES_Y )
    res = res & Y;

  if ( state & SNES_L )
    res = res & LSHIFT;

  if ( state & SNES_R )
    res = res & RSHIFT;

  return res;

}

byte decodeFar(int state)
{
  byte res=0xff;
  if ( state & SNES_UP )
    res = res & UP;

  if ( state & SNES_DOWN )
    res = res & DOWN;

  if ( state & SNES_LEFT )
    res = res & LEFT;

  if ( state & SNES_RIGHT )
    res = res & RIGHT;                                       

  // the rest shoud be processed in other place - because snes have only 12 buttons  
  return res;
}

void send2out(byte out0, byte out1)
{

  shiftOut(DS,SHCP,MSBFIRST,out0); //far one
  shiftOut(DS,SHCP,MSBFIRST,out1); //near one
  digitalWrite(STCP,HIGH);
  delay(1);
  digitalWrite(STCP,LOW);

}

// setting up arduino pins for connection - as in snespad example
//strobe/clock/data
SNESpad nintendo = SNESpad(2,3,4);

int state = 0x0;
int currentstate = 0x0;
byte nAddedState=0x0;
byte nCurrentAddedState = 0x0; 
byte out0 = 0xff;
byte out1 = 0xff;
void setup() {
  pinMode(13, OUTPUT);

  pinMode(DS,OUTPUT);
  pinMode(SHCP,OUTPUT);
  pinMode(STCP,OUTPUT);

  pinMode(RESET_PIN, INPUT);
  pinMode(POWER_PIN, INPUT);
  pinMode(HOLD_PIN, INPUT);
  pinMode(FREE_PIN, INPUT);

  digitalWrite(SHCP,LOW);  
  digitalWrite(STCP,LOW);  
  digitalWrite(13,HIGH);

  send2out(0xff,0xff); //pull all high
  state=nintendo.buttons();
  nAddedState = GetAddedState();

}

void loop() {

  currentstate = nintendo.buttons();
  nCurrentAddedState = GetAddedState();

  if((state != currentstate) || (nAddedState != nCurrentAddedState))
  {

    out0=decodeFar(currentstate);   
    out1=decodeNear(currentstate);
    //all buttons pressed - means there is no controller
    if (  currentstate == 0xffffffff )
         {
           out0 = 0xFF;
           out1 = 0xFF;
         }
    out0=out0 & nCurrentAddedState;
    send2out(out0,out1);

  }
  state = currentstate;
  nAddedState = nCurrentAddedState;

}

Скачать  .pde (Arduino sketch)

Ну а дальше все просто — собираем плату, прошиваем Атмегу, на плате Dingoo  ищем нужные контакты, не забываем соединить плату общими «землями» c Dingoo A320 — ваша Dingoo  теперь будет управляться джойтика от SNES. Кнопок как раз хватит.

Откроем секрет — наш «нано-кабинет» почти готов. По крайней мере вся «электронная» часть работает, но внешний вид пока не тот, который задумывался — покажем, как только закончим. И питается он от того самого альтернативного источника.

К сожалению, фоток плат нет — они уже внутри. Будут в следующий раз.

 



Добавить комментарий

Комментарии доступны через Intensedebate. Включите JavaScript.