Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

phanick 21 Apr 2021 09:54 3429 3
lampy.pl
  • Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Motywacja
    Jeden ze znajomych poprosił mnie, aby taki śmieszny pad na USB (kształtem przypominający dżojstik od konsoli NES)
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB
    przerobić tak, aby dało się go podpiąć właśnie do konsoli NES albo Pegasus. Kontroler ma tez dodatkowy bajer: kilka diod RGB, których kolor świecenia możemy ustawić przełącznikiem na górze (oraz jasność świecenia potencjometrem). Od razu więc nasunął mi się nietuzinkowy pomysł na podrasowanie tego wynalazku, więc... do dzieła.
    PS. Swoją drogą, ciekawe cóż za rakotwórcze substancje zawiera ten joypad:
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Zanim przejdę do właściwego tematu tylko napomknę, że pierwszą rzeczą, która mnie w tym kontrolerze "urzekła" jest to, że podłączając go, system nie wymaga żadnych sterowników. W grze (ja akurat testowałem na emulatorze) wystarczy wywołać okno przypisania klawisza do danej czynności, a następnie wcisnąć przycisk na dżojstiku. System sam przypisze funkcje. To chyba dlatego, że joypad jest zgodny ze standardem USB HID (czyli klasą podstawowych urządzeń USB typu mysz/klawiatura, które nie wymagają sterowników i można ich używać nawet w BIOSie). Może dla niektórych to oczywistość, ja jednak nie grywam w gry na co dzień, a ostatni mój joystick jaki miałem to kontroler podłączany do portu typu Gamepad (w karcie dźwiękowej).
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Podłączenie do konsoli
    Konsole NES/Pegasus/SNES komunikują się z joypadem za pomocą prostego protokołu szeregowego (linie STROBE, CLOCK, DATA), niezgodnego z USB. Nieinwazyjną metodą byłoby stworzenie mini adaptera opartego na mikrokontrolerze z funkcją USB Host, który odpytywałby cyklicznie joypad USB o stany przycisków, a następnie podsuwał te dane podczas żądania odczytu stanu klawiszy pochodzącego z konsoli. Projekt jednak miał być tani i szybki, a popularne Atmegi (których mam całą szufladę) nie obsługują trybu USB Host (popularna biblioteka V-USB obsługuje jedynie zwykły tryb USB). Są co prawda dedykowane Atmegi z literką U na końcu, wzbogacone o sprzętową obsługę USB, jednak ich ceny i mała popularność odstrasza.

    Powstała nawet amatorska biblioteka do programowej obsługi trybu USB Host na mikrokontrolerach bez ich sprzętowego wsparcia, jednak pochłania ona większość czasu działania mikrokontrolera, a do tego tryb USB wymagania niejako "pierwszeństwa", podczas gdy w tym projekcie to żądania obsługi pochodzące z konsoli powinny mieć priorytet (tak naprawdę wszystko powinno dziać się równolegle i niezależnie od siebie, no ale mikrokontroler ma przecież tyko jeden rdzeń)...
    http://people.ece.cornell.edu/land/courses/ec...ct23/blh36_cdl28_dct23/index.html#codelisting

    Kolejną ciekawostką jest fakt, że większość klawiatur/myszek USB posiada wsteczną zgodność z szeregowym trybem PS/2 - wystarczy linie USB D+ i USB D- podciągnąć do zasilania, a wtedy przechodzą one w tryb PS/2 stając się odpowiednio liniami PS2 CLOCK i PS2 DATA. Adapter PS/2 -> NES byłby dużo prostrzy, jednak omawiany joystick takiej funkcji nie powiada.
    https://pinouts.ru/InputCables/usb_ps2_mouse_pinout.shtml

    Ostatecznie więc realizacji uległ pomysł, który od początku zakładałem - zaprojektowanie i umieszczenie we wnętrzu joysticka małej płytki z mikrokontrolerem, która podlutowana byłaby do wszystkich przycisków w joysticku i która to zajmowałaby się obsługą żądań z konsoli. W zasadzie to nic nowego, wielokrotnie robiąc tzw. zestawy naprawcze do różnych joypadów od Pegasus-ów bazowałem właaśnie na tym pomyśle:
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Najpierw musiałem jednak odtworzyć schemat omawianego joysticka USB:
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Biała soldermaska skutecznie wszystko utrudniała, a podglądanie płytki pod światło niewiele pomagało. Szczęśliwie udało się odkryć tajemnice:
    * nad całością czuwa pojedynczy układ scalony (mikrokontroler albo dedykowany układ ASIC - któż to wie bez zaglądania do środka) - glut - tym razem w białym kubraczku, taktowany kwarcem 6 MHz (prawdopodobnie wewnątrz musi być on zwielokrotniony PLLem, bo USB wymaga zdaje się 12 albo 16MHz). Z układu wychodzi 16 ścieżek (oprócz masy, zasilania, linii do przycisków, sygnałów USB D+ i USB D- jest także wyjście +3.6V pochodzące z wbudowanego w glut stabilizatora napięcia +3.6V oraz pin1 podpięty rezystorem 1k do masy, którego funkcji nie badałem.
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB
    * z każdym przyciskiem związany jest punkt testowy (test-pad), do którego można się podlutować, bez konieczności lutowania się do samych pól stykowych; aby uniknąć plątaniny przewodów na przodzie joypada (przezroczysta obudowa wrzystko by ujawniła), przewierciłem każdy test-pad na wylot i podlutowałem się do nich "od spodu".
    * niestety o ile przyciski A, B, Select, Start podłączone są osobnymi liniami, o tyle przyciski przeciwległych kierunków (Lewo/Prawo oraz Dół/Góra) współdzielą po jednej linii: wciśnięcie pierwszego zwiera linię do masy, a drugiego do +5V) Początkowo zastanawiałem się jak to w ogóle działa - czyżby stan napięcia utrzymywany był wewnątrz gluta w połowie (2.5V) i był tam przetwornik DAC? Otóż nie. Glut generuje na tej linii sygnał prostokątny (45 Hz) i bada, czy poziom napięcia zgadza się z generowanym (wtedy nic nie jest wciśnięte) czy jest np. cały czas niski lub wysoki. Trochę zastanawiam się po co taka komplikacja - niby oszczędność dwóch linii, ale czy to aż takie krytyczne? No i ogranicza się możliwość wciśnięcia obu kierunków na raz (co akurat fizycznie nawet w krzyżaku typu D-Pad możliwe nie jest).
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Mógłbym oczywiście rozciąć to połączenie i podlutować się bezpośrednio do każdego z czterech kierunków, ale zależało mi aby jednak joypad nadal mógł też być podłączany pod USB i działać jak do tej pory. Wpadłem więc po prostu na pomysł, że mikrokontroler trzy razy (w odstępie 11 ms) odczyta stan tej linii. Gdy wszystkie trzy odczyty zwrócą taki sam stan to będzie oznaczać, że wciśnięto przycisk (0,0,0 = dół, 1,1,1 = góra). W przeciwnym razie przycisk kierunku wciśnięty nie jest. Działa rewelacyjnie!
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    W ten sposób udało się zrealizować podstawową założoną funkcjonalność. Na marginesie dodam, że pewnym niuansem, odróżniającym konsole PAL NES od Pegasusów (oraz konsoli NTSC NES) jest to, że linie CLOCK i STROBE muszą być wewnątrz joypada podciągnięte rezystorami +5V. Dlaczego? Zapewne celowe "utrudnienie" życia przez firmę Nintendo, aby joysticków NTSC nie dało się podpiąć do konsoli PAL. W konsoli na tych liniach są diody w szeregu. Gdy konsola wystawia stan niski, joypad widzi stan niski. Gdy konsola wystawia stan wysoki, joypad widzi wiszącą linię. Wartość 3.6k jest chyba w pewnym sensie optymalna - większa wartość powoduje zbyt długie narastanie zboczy i "niewyrabianie" się sygnałów (zwłaszcza, że kable w joypadach są długie)
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Dodatkowy bajer - efekt świetlny RGB
    Wybranie jednego z trzech kolorów za pomocą suwaka (nota bene - dość sprytnie połączonego) moim zdaniem zdecydowanie marnuje potencjał siedmiu diod RGB.
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Pomyślałem więc, że skoro już mam płytkę z mikrokontrolerem to przecież może on sterować też PWMem każdą z trzech składowych (R,G,B) diod, robiąc różne ciekawe efekty świetlne (chociażby płynne przejście a'la tęcza). Atmega 8 (wykorzystana w tym projekcie) ma akurat 3 liczniki, które mogą sterować trzema pinami w trybie PWM, więc idealnie. Wystarczy tylko dodać trzy tranzystorowe klucze nasycone (przy rezystorach 470R, siedem diod w sumie pobiera: R=40mA, G/B=22mA i et voila.

    W diodzie RGB, strumienie światła "wydostające" się z trzech różnych struktur, leżących bardzo blisko siebie mieszają się, tworząc wrażenie świecenia jednego koloru o różnych odcieniach (jakość tego efektu zależy tez od samej diody - im struktura diody mniejsza (SMD) a obudowa matowa, tym mieszanie barw jest lepsze. Istota PWMa polega na tym, aby sterować wszystkimi trzema składowymi kolorów NA RAZ, zmieniając poziom wypełnienia:
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Niestety, "oszczędny", bo redukujący liczbę rezystorów, sposób podłączenia diod na tej płytce (katody tych samych kolorów zwarte, wspólne anody podłączone jednym rezystorem do +5V) był kolejną "kłodą pod nogi". Próbując zapalić więcej niż jeden kolor (zwierając katody do masy), na anodzie odłoży się najniższe z napięć. A że różne składowe mają różne napięcia przewodzenia (R=2.2V, G=3.5V, B=3.5V) to w efekcie świecić się będzie tylko czerwona (zielona i niebieska z uwagi na podobne napięcie przewodzenia w mniejszym stopniu podchodzą pod ten efekt, ale i tak nie jest to prawidłowe połączenie dla takiego trybu).
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB
    Dlatego musiałem zmodyfikować sposób sterowania tak, aby cyklicznie przez pewien czas sterował tylko składowa czerwoną, potem zieloną, potem niebieską. Ludzkie oko i tak uśredni to na ten sam sposób, jednak teraz każda składowa świeci się średnio 3 razy krócej, wobec czego maksymalna jasność świecenia spada (może nie trzykrotnie z uwagi na logarytmiczny charakter ludzkiego oka). Aby tego uniknąć, należałoby jednak wymienić wszystkie 7 rezystorów tak, aby prąd diod wzrósł 3 krotnie)
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    W efekcie joystick obsługuje następujące tryby świecenia (zmiany dokonuje się trzymając przycisk START+SELECT+LEWO lub START+SELECT+PRAWO)
    * brak świecenia
    * pojedynczy kolor R
    * pojedynczy kolor G
    * pojedynczy kolor B
    * płynne przechodzenie przez 7 kolorów tęczy

    Dodałem też możliwość ustawiania jasności sterowania (25 poziomów, (START+SELECT+GÓRA zwiększa, START+SELECT+DÓŁ zmniejsza)

    Obie wymienione funkcje wykorzystują PWM (dzięki temu uniknąłem w ogóle konieczności korzystania z przełącznika suwakowego i potencjometru)

    Dodatkowy bajer - dodanie przycisków TURBO
    W joypadzie, podobnie jak w NESowym oryginale brakuje przycisków Turbo A i Turbo B. Chcąc zrekompensować tą stratę postanowiłem, że dodam możliwość ich "symulacji":
    * wciskając przycisk START+SELECT+A przełączamy zachowanie przycisku A między zwykłym, a TURBO
    * wciskając przycisk START+SELECT+B przełączamy zachowanie przycisku B między zwykłym, a TURBO

    Obsługa USB
    Chcąc wciąż zachować możliwość korzystania z joysticka po USB, oprócz 5 przewodów do NESa wyprowadziłem też 4 przewody do USB. Aby jednak uniknąć dwóch wtyczek wychodzących na raz, przylutowałem pojedynczą wtyczkę 9pin (Pegasus) oraz dodałem dwa adaptery: 9pin->NES oraz 9pin->USB. Po podłączeniu do PC po USB joypad oczywiście nadal ma możliwość sterowania kolorami

    Efekt końcowy
    Cały opisywany tu projekt składał się w zasadzie z dwóch części. Pierwszą było zaprojektowanie i wykonanie małej płytki, umieszczanej wewnątrz joypada, rozszerzającą jego funkcjonalność o opisywane zagadnienia. Płytką starałem się zaprojektować możliwie małą (w obudowie jest ograniczona ilość miejsca) oraz jednostronną (aby żadne przelotki, wykonane drutem niczego nie zwierały po przyklejeniu do bazowej białej płytki). Jedyną pomyłką na etapie projektu było podłączenie bazy tranzystora od składowej czerwonej do nogi PB0 zamiast PB3.
    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Drugą częścią było oprogramowanie całości (nigdy wcześniej nie bawiłem się z PWMem na diodach RGB). Program składa się z kilku osobnych funkcjonalnosci, realizowanych na licznikach i przerwaniach.

    Kluczową funkcjonalnością jest oczywiście komunikacja z konsolą. Linie sygnałowe, pochodzące z konsoli (CLOCK, STROBE) podłączone są do dwóch przerwań (odpowiednio: INT0, INT1), reagujących na zbocze opadające. Prosty kod do realizacji tej funkcjonalności, który kiedyś napisałem, po prostu po każdym zboczy wystawiał stan następnego przycisku.

    Code:

    ISR(PEG_STRB_INT) {
       out(PEG_DATA, in(BTN_A));
       clk_cnt = 0;
    }

    ISR(PEG_CLK_INT) {
       switch (clk_cnt) {
       case 0:
          out(PEG_DATA, in(BTN_B));
          break;
       case 1:
          out(PEG_DATA, in(BTN_SELECT));
          break;
       case 2:
          out(PEG_DATA, in(BTN_START));
          break;
       case 3:
          out(PEG_DATA, in(BTN_UP));
          break;
       case 4:
          out(PEG_DATA, in(BTN_DOWN));
          break;
       case 5:
          out(PEG_DATA, in(BTN_LEFT));
          break;
       case 6:
          out(PEG_DATA, in(BTN_RIGHT));
          break;
       default:
          out(PEG_DATA, 1);
       }      
       if (clk_cnt < 8) {
          clk_cnt++;
       }
    }


    Jednak kiedyś zauwazyłem, że istnieje pewna mała liczba gier (np. Tom & Jerry), która nie działa prawidłowo z takim padem. Trochę zastanawiałem się w czym kłopot i okazało się, że powyższa realizacja (mimo taktowania mikrokontrolera wbudowanym generatorem 8 MHz) jest zbyt wolna. Większość gier, która w pętli odpytuje stany kolejnych przycisków działała, jednak pewna pula gier (w tym wspomniany Tom & Jerry) odpytuje o stany przycisków bez pętli i joystick się "nie wyrabia"
    Code:

     07:E27C: A2 01     LDX #$01
     07:E27E: 8E 16 40  STX $4016
     07:E281: CA        DEX
     07:E282: 8E 16 40  STX $4016
    >07:E285: AD 16 40  LDA $4016
     07:E288: 4A        LSR
     07:E289: 26 2B     ROL $002B
     07:E28B: AD 16 40  LDA $4016
     07:E28E: 4A        LSR
     07:E28F: 26 2B     ROL $002B
     07:E291: AD 16 40  LDA $4016
     07:E294: 4A        LSR
     07:E295: 26 2B     ROL $002B
     07:E297: AD 16 40  LDA $4016
     07:E29A: 4A        LSR
     07:E29B: 26 2B     ROL $002B
     07:E29D: AD 16 40  LDA $4016
     07:E2A0: 4A        LSR
     07:E2A1: 26 2B     ROL $002B
     07:E2A3: AD 16 40  LDA $4016
     07:E2A6: 4A        LSR
     07:E2A7: 26 2B     ROL $002B
     07:E2A9: AD 16 40  LDA $4016
     07:E2AC: 4A        LSR
     07:E2AD: 26 2B     ROL $002B
     07:E2AF: AD 16 40  LDA $4016
     07:E2B2: 4A        LSR
     07:E2B3: 26 2B     ROL $002B


    Sprytnym sposobem na przyspieszenie było cykliczne czytanie stanu wszystkich przycisków (poza przerwaniem) i umieszczenie ich w pojedynczym bajcie na kolejnych bitach. W przerwaniu program ogranicza się jedynie do wystawienia stanu najmłodszego bitu i przesunięcia wszystkich bitów w prawo
    Code:

    volatile union {
       struct {
          uint8_t a      : 1;
          uint8_t b      : 1;
          uint8_t select : 1;
          uint8_t start  : 1;
          uint8_t up     : 1;
          uint8_t down   : 1;
          uint8_t left   : 1;
          uint8_t right  : 1;
          } bits;
       uint8_t all;
    } peg_btns, peg_btns_copy;


    ISR(PEG_STRB_INT) {
       peg_btns_copy.all = peg_btns.all;
       out(PEG_DATA, peg_btns_copy.all & 1);
       peg_btns_copy.all >>= 1;

    }

    ISR(PEG_CLK_INT) {
       out(PEG_DATA, peg_btns_copy.all & 1);
       peg_btns_copy.all >>= 1;
    }

    ..

       while (1) {
          peg_btns.bits.down = in(BTN_DOWN);
          peg_btns.bits.left = in(BTN_LEFT);
          peg_btns.bits.right = in(BTN_RIGHT);
          peg_btns.bits.up = in(BTN_UP);
          peg_btns.bits.select = in(BTN_SELECT);
          peg_btns.bits.start = in(BTN_START);
          peg_btns.bits.b = in(BTN_B)
          peg_btns.bits.a = in(BTN_A);

          _delay_ms(7);
       }



    Obsługa PWMa polega na cyklicznym (sterowanym za pomocą licznika 0) odczycie wartości trzech zmiennych 8 bitowych:
    Code:

    volatile uint8_t pwm_red;
    volatile uint8_t pwm_green;
    volatile uint8_t pwm_blue;

    i przepisywaniu ich wartości do rejestrów sterujących pinami od kluczy tranzystorowych trzech barw.

    Przeróbka joysticka USB do konsoli NES/Pegasus + diody RGB

    Cool? Ranking DIY
    Can you write similar article? Send message to me and you will get SD card 64GB.
    About Author
    phanick
    Level 28  
    Offline 
    Has specialization in: energetyk najwyższych napięć
    phanick wrote 2464 posts with rating 2553, helped 57 times. Live in city Warszawa. Been with us since 2007 year.
  • lampy.pl
  • #2
    linuxtorpeda
    Level 26  
    Co do odczytu przycisków pada, ciekawą realizację widziałem w Paged Out #1 w artykule "Build your own controller for Pegasus": https://pagedout.institute/download/PagedOut_001_beta1.pdf

    Pomysł opiera się o wykorzystanie SPI w Atmedze.

    Co do projektu, bardzo interesujący, szczególnie część dotycząca reverse engineeringu pierwotnego pada. Gratuluję chęci i umiejętności ;)
  • lampy.pl
  • #3
    phanick
    Level 28  
    Genialny pomysł z tyn SPI. Parę tygodni temu odkryłem ciekawy gadżet do Pegasusa - Batle Box. To małe "pudełeczko", zawierające 2 pamęci EEPROM (w sumie 512 bajtów), wtykane do portu Joysticka (rozszerzeń). Umożliwiało zapisywanie stanu gier w paru dedykowanych tytułach.
    "Toto" coś wykorzystuje do komunikacji z konsolą pin STROBE oraz dwa piny (D4,D3), uzywane tez przez pistolet. Niestety, użyte tam pamięci są dość trudno dostępne, pomyślałem, że zrobię małą "kopię" tego na mirko atmega 8 (akurat ona ma dokładnie 512 bajtó EEPROMU), i też mi przyszedł wtedy taki pomysł, że może czas wreszcie skorzystac ze sprzętowego SPI w medze ;)
  • #4
    Tommy82
    Level 41  
    @phanick
    Zrób kontroler z predefiniowanym trybem przechodzenia gier ;).
    Taki demo emulator klikania ;P.