Emulator konsoli NES w systemie Linux na komputerze SoMLabs VisonSOM
Kontroler zbudowany z wykorzystaniem układu MCP23S08
Jeżeli nie dysponujemy żadnym kontrolerem, wówczas idealnym rozwiązaniem (choćby ze względu na walor edukacyjny) jest konstrukcja własnego prostego urządzenia. Oryginalny kontroler konsoli NES posiada 8 przycisków: cztery do kontroli kierunku, dwa przyciski akcji (oznaczone jako A i B) oraz przyciski START i SELECT. Aby uniknąć problemów z wyborem i konfiguracją multipleksacji wyprowadzeń GPIO (co nawet przy dużej liczbie wyprowadzeń I/O dostępnych na złączach komputerów jednopłytkowych nie zawsze jest proste), do sprzętowej budowy kontrolera wykorzystamy moduł KAmodEXP1, będący adresowalnym ekspanderem GPIO z układem MCP23S08. Układ ten może pracować zarówno na magistrali SPI jak i I2C oraz posiada dokładnie osiem konfigurowalnych linii GPIO, a więc idealnie wpisuje się w realizowany projekt. Prosty schemat połączeń przedstawiono na rysunku 4 (układ MCP23S08 podłączony w konfiguracji SPI).
Rys. 4. Schemat połączeń dla modułu KAmodEXP1 i płyty bazowej VisionCB-STD
Aby uniknąć programowej implementacji obsługi układu MCP23S08 w przestrzeni użytkownika, wykorzystamy gotowy sterownik dostępny w jądrze systemu. Konfigurację jądra rozpoczynamy od włączenia sprzętowego kontrolera magistrali SPI dla układów i.MX:
Device Drivers ---> [*] SPI support ---> <*> Freescale i.MX SPI controllers
Następnie włączamy docelowy sterownik układu MCP23S08:
Device Drivers ---> -*- GPIO Support ---> SPI GPIO expanders ---> <*> Microchip MCP23xxx I/O expander
Włączenie sterownika układu MCP23S08 oraz przygotowanie dla niego opisu Device Tree (co przedstawiono poniżej), spowoduje pojawienie się w systemie nowego kontrolera GPIO dostępnego w przestrzeni użytkownika poprzez interfejs /sys/class/gpio. Aby maksymalnie uprościć obsługę projektowanego urządzenia, linie kontrolera GPIO wykorzystamy w sterowniku klawiatury Polled GPIO buttons [więcej informacji – patrz ramka]:
Device Drivers ---> Input device support ---> <*> Event interface [*] Keyboards ---> < > GPIO Buttons <*> Polled GPIO buttons
Konfigurację jądra należy uzupełnić opisem Device Tree wymaganym przez włączone powyżej sterowniki. Edycję pliku somlabs-visionsom-6ull.dts rozpoczynamy od dodania opisów dla kontrolera SPI oraz układu MCP23S08 – listing 1.
&ecspi3 { fsl,spi-num-chipselects = <1>; cs-gpios = <&gpio1 20 0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi3>; status = "okay"; gpiom1: gpio@0 { compatible = "microchip,mcp23s08"; gpio-controller; #gpio-cells = <2>; microchip,spi-present-mask = <0x01>; reg = <0>; spi-max-frequency = <10000000>; }; };
List. 1. Opis Device Tree dla kontrolera SPI3 oraz układu MCP23S08
Do komunikacji z układem MCP23S08 wykorzystamy kontroler SPI3 (ecspi3) w konfiguracji z jedną linią CS (wartość określona poprzez pole fsl,spi-num-chipselects), sterowaną poprzez wyprowadzenie GPIO1_20 (definicja linii w polu cs-gpios). W opisie kontrolera wskazujemy również odwołanie do multipleksacji wyprowadzeń I/O (pinctrl-0=<&pinctrl_ecspi3>). Następnie umieszczamy opis nowego kontrolera gpiom1, którego funkcję pełni układ MCP23S08. Opis rozpoczynamy od wskazania typu układu (układ ekspandera występuje również w wersji z 16. liniami GPIO), jak i sposobu jego podłączenia (SPI lub I2C):
- compatible = „microchip,mcp23s08” – dla wersji SPI z 8. liniami GPIO
- compatible = „microchip,mcp23s17” – dla wersji SPI z 16. liniami GPIO
- compatible = „microchip,mcp23008” – dla wersji I2C z 8. liniami GPIO
- compatible = „microchip,mcp23017” – dla wersji I2C z 16. liniami GPIO
Wpisem gpio-controller oznaczamy urządzenie jako pełniące rolę kontrolera GPIO. Pole microchip,spi-present-mask jest istotne wyłącznie gdy jedna linia CS jest dzielona przez większą liczbę adresowalnych układów. Pole reg – dla konfiguracji MCP23S08 jako układu SPI – określa numer porządkowy wyprowadzenia linii CS.
Zaimplementowany w jądrze systemu Linux sterownik układu MCP23S08 nie wspiera aktualnie funkcji przerwań dla konfiguracji SPI (opcja te jest wspierana wyłącznie przez układy pracujące na magistrali I2C). Z tego powodu, na kolejnym etapie konfiguracji jądra wykorzystano sterownik „Polled GPIO buttons” z aktywnym odpytywaniem. Dla układów pracujących na magistrali I2C bardziej optymalnym rozwiązaniem będzie wybór sterownika „GPIO Buttons” oraz konfiguracja kontrolera GPIO jako „interrupt-controller”. Przykładowy opis Device Tree dla układu MCP23S08 pracującego na magistrali I2C może wyglądać następująco:
gpiom1: gpio@20 { compatible = "microchip,mcp23017"; gpio-controller; #gpio-cells = <2>; reg = <0x20>; interrupt-parent = <&gpio1>; interrupts = <17 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells=<2>; microchip,irq-mirror; };
W powyżej przedstawionym opisie, pole reg definiuje sprzętowy adres układu MCP23S08 na magistrali I2C.
Wpisem spi-max-frequency określamy maksymalną dopuszczalną częstotliwość pracy układu na magistrali (tutaj 10MHz). Tak przygotowany opis kontrolera SPI oraz układu MCP23S08 należy uzupełnić o opis konfiguracji multipleksacji wyprowadzeń I/O – listing 2.
&iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog_1>; imx6ul-evk { /* … */ pinctrl_ecspi3: ecspi3grp { fsl,pins = < MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x1b0b1 MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x1b0b1 MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x1b0b1 MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x1b0b0 >; }; }; };
List. 2. Konfiguracja wyprowadzeń I/O dla kontrolera SPI3
Wyprowadzenia, którym na listingu 2 przypisano role linii SCLK oraz CS, w domyślnym opisie Device Tree dostarczanym przez producenta płytki VisionSOM pełnią rolę linii RX oraz TX kontrolera UART2. Aby uniknąć konfliktu, należy wyłączyć kontroler UART2, poprzez wykomentowanie linii statusu, jak przedstawiono to na listingu 3.
&uart2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart2>; fsl,uart-has-rtscts; //status = "okay"; };
List. 3. Wyłączenie kontrolera UART2 w opisie Device Tree
Ostatnim etapem przygotowania opisu Device Tree jest zdefiniowanie ośmiu przycisków w ramach sterownika gpio-keys-polled. Ponieważ sterownik pracuje w trybie odpytywania, niezbędne jest określenie interwału czasowego poprzez pole poll-interval (wartość wyrażona w milisekundach). Następnie dokonano opisu ośmiu przycisków definiując ich etykiety (pole label), odwołania do kontrolera GPIO (do kolejnych linii I/O kontrolera gpiom1/układu MCP23S08) oraz przypisując im wybrane kod, zdefiniowane przez podsystem wejścia. Fragment opisu Device Tree przedstawiono na listingu 4.
gpio-keys { compatible = "gpio-keys-polled"; poll-interval = <100>; btn0 { label = "btn0"; gpios = <&gpiom1 0 GPIO_ACTIVE_HIGH>; linux,code = <103>; /* <KEY_UP> */ }; btn1 { label = "btn1"; gpios = <&gpiom1 1 GPIO_ACTIVE_HIGH>; linux,code = <108>; /* <KEY_DOWN> */ }; btn2 { label = "btn2"; gpios = <&gpiom1 2 GPIO_ACTIVE_HIGH>; linux,code = <105>; /* <KEY_LEFT> */ }; /* … */ };
List. 4. Opis Device Tree dla sterownika gpio-keys-polled
Po skompilowaniu nowego obrazu jądra oraz opisu Device Tree z wykorzystaniem poleceń:
make ARCH=arm zImage make ARCH=arm somlabs-visionsom-6ull.dtb
pliki wynikowe (tj. zImage oraz somlabs-visionsom-6ull.dtb) należy skopiować do katalog /boot na karcie SD. Po ponownym uruchomieniu systemu, w buforze komunikatów jądra zostaną wyświetlone komunikaty informujące o poprawnej konfiguracji sterownika:
root@somlabs:~# dmesg | grep gpio-keys input: gpio-keys as /devices/platform/gpio-keys/input/input0
Poprawność działania kontrolera oraz podłączonych przycisków może zostać przetestowana za pomocą narzędzia evtest:
root@somlabs:~# apt-get install evtest root@somlabs:~# evtest --grab /dev/input/event0 Input driver version is 1.0.1 Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100 Input device name: "gpio-keys" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 103 (KEY_UP) Event code 105 (KEY_LEFT) …. Properties: Testing ... (interrupt to exit) Event: time 1519407395.872567, type 1 (EV_KEY), code 108 (KEY_DOWN), value 0 Event: time 1519407395.872567, -------------- SYN_REPORT ------------
Ostatecznej konfiguracji przycisków należy dokonać z wykorzystaniem opcji Gamepad Config w emulatorze Fceux.
Fot. 5. Moduł VisionSOM z uruchomionym emulator konsoli Famicon/NES
Łukasz Skalski