https://obrazki.elektroda.pl/5502422400_1590145798_thumb.jpg Witajcie moi drodzy Chciałbym zaprezentować tutaj drugą wersję mojego Arduino VGA Shield (nakładki na Arduino UNO generującej jednokolorowy obraz VGA i czarno-biały PAL/NTSC) - tym razem wykonaną za pomocą elementów SMD, i z dodatkowymi układami na pokładzie (expander portów MCP23016 oraz dwie kości EEPROM AT24CM02). Opis pierwszej wersji tego shielda znajdziecie tutaj: https://www.elektroda.pl/rtvforum/viewtopic.php?p=18496229#18496229 Co to za Arduino Shield? W dużym skrócie mój shield jest nakładką na Arduino UNO która pozwala bardzo łatwo generować jednokolorowy obraz na monitor VGA oraz obsługiwać klawiaturę PS/2. Opcjonalnie też dostępne jest wyjście sygnału PAL/NTSC dla telewizorów. Shield korzysta z biblioteki 'ASCII Video Terminal' dla PIC32MX250F128B autorstwa geoffg. Arduino UNO komunikuje się z tym shieldem poprzez UART na wybranych przez nas za pomocą lutowanej zworki pinach. Dodatkowo na pokładzie (nowość w tej wersji!) znajduje się: - expander portów MCP23016, dzięki czemu zyskujemy aż 16 dodatkowych IO! - dwie kości EEPROM AT24CM02, dzięki którym zyskujemy aż 512KB pamięci nieulotnej do własnych projektów! Obie nowości znajdują się na magistrali I2C od Arduino. Poniżej szczegółowo opiszę cały projekt, umieszczę proste przykłady użycia nowości na płytce a na koniec dam bardziej zaawansowane demka korzystające z poszczególnych funkcjonalności shielda. Projekt Arduino VGA Shield SMD Niniejszy projekt jest zasadniczo aktualizacją jego poprzedniej wersji która była wykonana w THT (montaż przewlekany): https://obrazki.elektroda.pl/2294289300_1588796118_thumb.jpg W obecnej wersji większość elementów jest w obudowach SMD, dodatkowo dzięki zaoszczędzonemu miejscu udało mi się na płytkę dodać: - złącze USB od PIC32 (do aktualizacji softu poprzez bootloader; może to dać też w przyszłości możliwość łatwego użycia tego shielda bez Arduino, ale na razie brakuje na PCB w tym celu regulatora 3.3V) - dwie kości pamięci EEPROM AT24CM02 na magistralę I2C od Arduino (standardowo piny 4 i 5) - 16-bitowy expander portów MCP23016 na magistralę I2C od Arduino (jak wyżej; piny 4 i 5) - rezystory pull-up na piny 4 i 5 (jak wyżej; magistrala I2C Arduino) W ten sposób obecna wersja wyszła tak: https://obrazki.elektroda.pl/8546300900_1588796382_thumb.jpg Całość open hardware i do pobrania poniżej. Schemat płytki w PDF: 1030456 Schemat płytki w PNG: 1030457 Pełny projekt płytki w Eagle (.sch + .brd): 1030455 Pliki Gerber które wyeksportowałem z Eagle (te same, których użyłem przy zleceniu wykonania gołego PCB płytkarni): 1030453 Tym razem obyło się bez żadnych błędów na płytce. Płytki standardowo zamówiłem w Chinach (10 sztuk - ktoś chętny na kilka?) a jak przybyły to wziąłem się do lutowania. Lutowanie Arduino VGA Shield w wersji SMD Opiszę tutaj szczegółowo jak zlutowałem tę płytkę w warunkach domowych. Na początek przygotowałem wszystkie elementy: https://obrazki.elektroda.pl/8220448100_1588804224_thumb.jpg https://obrazki.elektroda.pl/6139364300_1588804228_thumb.jpg I tym razem nawet nie używałem złącza VGA (DSUB25) z starej płyty głównej od komputera, tylko miałem zakupione przez internet. Do lutowania użyłem mojej wiernej najtańszej lutownicy kolbowej i na tę okazję zmieniłem jej grot na grot ścięty (choć pewnie lepszy byłby grot ścięty typu minifala, ten z wyżłobionym 'zbiorniczkiem' na cynę): https://obrazki.elektroda.pl/4748971600_1588804324_thumb.jpg Zacząłem lutowanie od najmniejszych elementów: https://obrazki.elektroda.pl/3753769700_1588804437_thumb.jpg Dałem też wtedy cynową zworkę na sygnał "B" (Blue) koło złącza VGA, czyli wybrałem niebieski kolor czcionki. Szybko przyszła pora na złącza: https://obrazki.elektroda.pl/8356330500_1588804501_thumb.jpg https://obrazki.elektroda.pl/6638436500_1588804722_thumb.jpg Złącze DSUB25 czyli VGA oraz MDC6 (aka 'mini din') czyli PS/2: https://obrazki.elektroda.pl/6815685300_1588804785_thumb.jpg Na zdjęciu można zobaczyć, że wciąż nie przylutowałem EEPROMów - to dlatego, że dopiero czekałem na paczkę z nimi. Jak przyszły to uzupełniłem ubytek: https://obrazki.elektroda.pl/3204394600_1588804882_thumb.jpg https://obrazki.elektroda.pl/1382751400_1588804914_thumb.jpg Potem jeszcze uzupełniłem ubytek złącza RCA (od sygnału PALNTSC); nie miałem takiego na składzie więc wylutowałem z jakiegoś fragmentu urządzenia elektronicznego, to chyba był odtwarzacz kaset VHS: https://obrazki.elektroda.pl/7021071000_1588805047_thumb.jpg https://obrazki.elektroda.pl/9088830900_1588805043_thumb.jpg https://obrazki.elektroda.pl/5706716800_1588805051_thumb.jpg Złącze RCA: https://obrazki.elektroda.pl/4076050200_1588805209_thumb.jpg I oto końcowy efekt (już po wyczyszczeniu z nadmiaru topnika): https://obrazki.elektroda.pl/1416338600_1588846009_thumb.jpg https://obrazki.elektroda.pl/6408921300_1588846191_thumb.jpg Warto jeszcze pamiętać, że przed użyciem należy zrobić ze spoiwa lutowniczego następujące zworki: - zworka pinu RX shielda z Arduino - zworka pinu TX shielda z Arduino - zworka pinu RESET z Shielda (łączy RESET od PIC32 z RESET od Arduino) - zworka wyboru koloru VGA z Shielda - dwie zworki na magistrali I2C dla EEPROMów Przed użyciem shielda trzeba oczywiście też wgrać mu firmware na PIC32MX250F128B za pomocą PICKIT3 (lub innego programatora) poprzez złącze ICSP dostępne na płytce. Test generowanego sygnału VGA z różnymi monitorami i telewizorem W temacie dotyczącym poprzedniej wersji mojego shielda (tutaj: https://www.elektroda.pl/rtvforum/viewtopic.php?p=18496229#18496229 ) pojawiła się uwaga, że nie działa on z częścią monitorów. Postanowiłem to zweryfikować. Użyłem do tego: - telewizora LG42LE4500 - monitora DELL 1703FP - monitora ASUS VH196S - monitora HP L1706 - monitora SyncMaster 740N Zapraszam do obejrzenia zdjęć z testów. Test 1 - monitor DELL 1703FP: https://obrazki.elektroda.pl/9890789800_1588852185_thumb.jpg https://obrazki.elektroda.pl/5803001300_1588852224_thumb.jpg Tabliczka znamionowa użytego monitora: https://obrazki.elektroda.pl/2073302500_1588783980_thumb.jpg Test 2 - telewizor LG42LE4500: https://obrazki.elektroda.pl/5747425500_1588852640_thumb.jpg https://obrazki.elektroda.pl/7081934500_1588852638_thumb.jpg Tabliczka znamionowa użytego telewizora: https://obrazki.elektroda.pl/7031910900_1588783997_thumb.jpg Test 3 - monitor ASUS VH196S: https://obrazki.elektroda.pl/2275459400_1588854942_thumb.jpg https://obrazki.elektroda.pl/3360872300_1588854987_thumb.jpg Tabliczka znamionowa użytego monitora: https://obrazki.elektroda.pl/5879373100_1588854839_thumb.jpg Test 4 - HP L1706. https://obrazki.elektroda.pl/7060437300_1588855274_thumb.jpg https://obrazki.elektroda.pl/2953685300_1588855274_thumb.jpg Tabliczka znamionowa użytego monitora: https://obrazki.elektroda.pl/6106436200_1588855202_thumb.jpg Test 5 - SyncMaster 740N. Ten monitor naprawiałem tutaj: https://www.elektroda.pl/rtvforum/topic3688191.html , wymieniłem w nim kondensatory elektrolityczne. Dzięki temu może dalej działać i brać udział w testach mojego shielda: https://obrazki.elektroda.pl/4246636900_1588855412_thumb.jpg https://obrazki.elektroda.pl/2066575900_1588855446_thumb.jpg Tabliczka znamionowa użytego monitora: https://obrazki.elektroda.pl/1258439900_1588855496_thumb.jpg Podsumowując, shield VGA przetestowałem z czterema monitorami i jednym telewizorem i w każdym przypadku obraz był poprawnie wyświetlany. Sygnał widziany jest przez wszystkie urządzenia jako 640x480, mimo iż w dokumentacje użytej biblioteki jest podana nieco inna rozdzielczość. Po prostu shield w sprytny sposób sobie z tym radzi zostawiając puste marginesy wokół obrazu (co zresztą widać na większości zdjęć z jego działania). Nie znalazłem ani jednego urządzenia przez którego sygnał VGA z mojego shielda nie był wspierany, a jego timingi (31.5kHz i 60Hz) są zgodne z tym, co jest w kodzie: https://obrazki.elektroda.pl/8567581200_1590314726_thumb.jpg Test generowanego sygnału PAL Generowanie czarno-białego obrazu PAL (oraz NTSC - też jest wspierany) może się przydać gdy chcemy obsłużyć jakiś starszy telewizor, pewnie jeszcze CRT, który nie posiada złącza VGA. Może to być podyktowane chociażby sentymentem - niektórzy lubią korzystać ze starszego sprzętu nawet dla samej satysfakcji korzystania z niego. Z tego powodu przetestowałem też jak shield radzi sobie z generowaniem sygnału PAL. Sygnał PAL ze shielda podłącza się za pomocą przewodu RCA: https://obrazki.elektroda.pl/9451123200_1590143186_thumb.jpg Wystarczy pojedynczy sygnał video, audio nie jest oferowane przez ten shield. Test PAL 1 - telewizor LG42LE4500: Podłączenie: https://obrazki.elektroda.pl/2258585600_1590146184_thumb.jpg https://obrazki.elektroda.pl/9368920000_1590146199_thumb.jpg https://obrazki.elektroda.pl/3942760900_1590146205_thumb.jpg Obraz na ekranie: https://obrazki.elektroda.pl/9427440500_1590146322_thumb.jpg Obraz generowany przez shield jest tutaj rzecz jasna czarno-biały; zworka od koloru (wybór R/G/B) jest tylko dla VGA. Test PAL 2 - stary telewizor CRT TX-21AT1P: Ten pierwszy test PAL z nowym, płaskim telewizorem LG42LE4500 poniekąd mija się z celem, bo użyty tam telewizor ma złącze VGA (i to nie jedno!) więc nic nie stoi na przeszkodzie, by go podłączyć normalnie. Z tego powodu też przetestowałem tryb PAL z telewizorem który jest o wiele bardziej z tym trybem związanym - ze starym, ciężkim telewizorem kineskopowym, dokładniej 'Panasonic Colour TV' model TX-21AT1P: https://obrazki.elektroda.pl/8911258000_1590161461_thumb.jpg Tabliczka znamionowa tego telewizora: https://obrazki.elektroda.pl/8935412200_1590161531_thumb.jpg https://obrazki.elektroda.pl/7483420000_1590161541_thumb.jpg Sygnał PAL podłączyłem z przodu telewizora do złącz RCA: https://obrazki.elektroda.pl/9148315700_1590161702_thumb.jpg Warto tu wspomnieć, że nawet jeśli telewizor nie ma złącz RCA to sygnał PAL można też podać poprzez SCART - w przewodzie SCART jest jeden pin odpowiedzialny za wejście 'composite video'. Sygnał PAL oczywiście tutaj nie jest modulowany i odbieramy go w trybie AV: https://obrazki.elektroda.pl/6474478000_1590161796_thumb.jpg (Aczkolwiek jakby się postarać i użyć np. modulatora ze starego odtwarzacza VHS to można by prosto odbierać sygnał ze shielda poprzez złącze antenowe; choć wtedy jest ryzyko, że będziemy 'siać' sygnał po okolicy; do tej pory pamiętam jak kilkanaście lub więcej lat temu odbierałem przez przypadek na telewizorze obraz z konsoli do gier sąsiada). Na telewizorze uruchomiłem demko, które opisane jest nieco niżej w tekście. Rezultat: https://obrazki.elektroda.pl/3756502800_1590162046_thumb.jpg Uwaga - co jeśli monitor pokazuje 'nieobsługiwany format VGA'? Chciałbym tu tylko jeszcze przypomnieć, że shield w celu obsługi zarówno standardu PAL jak i VGA musi w sprytny sposób między nimi przełączać. Nie generuje dwóch sygnałów naraz. Shield przy starcie (po sygnale RESET lub podaniu zasilania) sam określa, czy monitor VGA jest podłączony i jeśli nie, to przechodzi w tryb PAL. Określa to poprzez badanie stanu na pinie RA4. Więc jeśli podłączymy monitor VGA w trakcie do shielda to powinniśmy wcisnąć przycisk RESET na Arduino lub wyłączyć i włączyć zasilanie - w przeciwnym razie shield będzie już 'nastawiony na PAL' i monitor VGA nic nie wyświetli. RESET z Arduino jest połączony z RESET (aka MCLR) z PIC32 z płytki shielda, ale należy pamiętać by na płytce shielda dać tam zworkę by oba układy resetowały się razem. (O tym, że mam wspomnieć o tym problemie przypomniał mi Bartek, który odkupił ode mnie jedno PCB poprzedniej wersji shielda - za przetestowanie układu i zwrócenie uwagi tu dziękuję) Test magistrali I2C - skan dostępnych urządzeń Na samym początku na mojej płytce uruchomiłem prosty program całkowicie niezwiązany z VGA - skaner I2C. Program ten pochodzi z oficjalnej strony Arduino: https://playground.arduino.cc/Main/I2cScanner/ i po prostu wykrywa wszystkie urządzenia podłączone na magistralę I2C, czyli w przypadku użytego przeze mnie Arduino UNO na jego piny 4 i 5. Program drukuje adresy I2C znalezionych urządzeń na port szeregowy/terminal Arduino. #include <Wire.h> //include Wire.h library void setup() { Wire.begin(); // Wire communication begin Serial.begin(9600); // The baudrate of Serial monitor is set in 9600 while (!Serial); // Waiting for Serial Monitor Serial.println("\nI2C Scanner"); } void loop() { byte error, address; //variable for error and I2C address int nDevices; Serial.println("Scanning..."); nDevices = 0; for (address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address < 16) Serial.print("0"); Serial.print(address, HEX); Serial.println(" !"); nDevices++; } else if (error == 4) { Serial.print("Unknown error at address 0x"); if (address < 16) Serial.print("0"); Serial.println(address, HEX); } } if (nDevices == 0) Serial.println("No I2C devices found\n"); else Serial.println("done\n"); delay(5000); // wait 5 seconds for the next I2C scan } Program skompilowałem i wgrałem na Arduino z założonym moim shieldem. Rezultat sketchu: https://obrazki.elektroda.pl/8259841700_1588789861_thumb.jpg Widzimy, że skan I2C znalazł aż 9 urządzeń! Ale czy na pewno? Na powyższym zrzucie ekranu: - adres 0x20 to port expander MCP23016 - adresy 0x50, 0x51, 0x52, 0x53 to pierwszy AT24CM02 (przypominam: w adresie urządzenia AT24CM02 dwa bity odpowiadają za jego 'wewnętrzny adres' pamięci; dwa bity dają nam 4 możliwe adresy) - adresy 0x54, 0x55, 0x56, 0x57 to drugi AT24CM02 Czyli wszystko jest okej - dwie pamięci EEPROM i jeden expander portów. Poniżej zaprezentuję już jak można ich użyć. Lutowanie przejściówki do expandera portów (dla płytki stykowej) Na płytce znajduje się 16-pinowe złącze 2.54mm (2 rzędy po 8 pinów) od MCP23016: https://obrazki.elektroda.pl/3189098400_1588846402_thumb.jpg Oferuje ono dodatkowe 16 pinów IO którymi możemy sterować przez I2C. Polecam używać go w połączeniu z takim przewodem (najlepiej też zakupić odpowiednie gniazdo pod ten przewód by nie dało się go wsadzić odwrotnie, ale ja takiego pod ręką nie miałem): https://obrazki.elektroda.pl/1013751400_1588799286_thumb.jpg https://obrazki.elektroda.pl/6126385500_1588799285_thumb.jpg Do tego sugeruję zlutować sobie przejściówkę z tego przewodu do płytki stykowej/prototypowej. Płytka stykowa ma rozstaw pól 2.54mm pasujący do goldpinów, za wyjątkiem środkowego przedziałka płytki który ma akurat 5.08mm, czyli tyle ile wąski rozstaw pinów z obudowy DIP. Aż prosi się to wykorzystać. Opiszę tutaj jak - na początek trzeba przygotować goldpiny 1x8 (dwie sztuki) i 2x8 (jedna sztuka) oraz płytkę wierconą: https://obrazki.elektroda.pl/8689529400_1588799587_thumb.jpg https://obrazki.elektroda.pl/3694746900_1588799587_thumb.jpg Następnie warto dodać topnik na płytkę, by się lepiej lutowało: https://obrazki.elektroda.pl/4560970200_1588799647_thumb.jpg Dalej umieścić na naszej płytce pierwszy rząd goldpinów (on będzie wchodzić w płytkę stykową), ale odwrotnie niż zazwyczaj: https://obrazki.elektroda.pl/3611174500_1588799703_thumb.jpg Teraz trzeba ją przylutować - najwygodniej bardzo cienką końcówką. Przy lutowaniu pilnować, by goldpiny były prostopadle do płytki: https://obrazki.elektroda.pl/8970239000_1588799870_thumb.jpg Pierwszy lut gotowy: https://obrazki.elektroda.pl/5596099700_1588799906_thumb.jpg Następnie trzeba dokończyć wszystkie luty i można od drugiej strony płytki dać złącze 2x8 2.54mm goldpin i zacząć łączyć odpowiednie piny: https://obrazki.elektroda.pl/1829572700_1588799984_thumb.jpg Dalej polecam delikatnie przylutować drugi pojedynczy rząd goldpinów który wejdzie w płytkę stykową: https://obrazki.elektroda.pl/6292228500_1588800085_thumb.jpg https://obrazki.elektroda.pl/3709848100_1588800087_thumb.jpg Następnie wystarczy zmostkować odpowiednie piny za pomocą lutownicy. Jeszcze tylko trzeba odciąć zbędny fragment PCB: https://obrazki.elektroda.pl/8851617300_1588800172_thumb.jpg Przejściówka gotowa: https://obrazki.elektroda.pl/5095248300_1588800212_thumb.jpg Idealnie pasuje do wybranego przeze mnie przewodu (choć ponownie tu Wam polecam użyć nie zwykłych goldpinów 2x8, lecz złącza pod ten konkretny kabelek; wtedy unikniecie ryzyka podłączenia go odwrotnie): https://obrazki.elektroda.pl/1732464200_1588800500_thumb.jpg Przejściówka expandera portów gotowa. Tak wygląda razem z Shieldem i Arduino: https://obrazki.elektroda.pl/3922228300_1588800544_thumb.jpg Następne cztery akapity przedstawią testy MCP23016 w oparciu o te połączenie. Test expandera portu - MCP23016 - użyta biblioteka Na początku do obsługi expandera portów MCP23016 sterowanego poprzez I2C próbowałem użyć tej biblioteki od Adafruit (mimo iż jest ona dla MCP23017 - liczyłem na podobieństwo układów): https://obrazki.elektroda.pl/9380545400_1588790023_thumb.jpg Ale nie zadziałała, więc ostatecznie użyłem biblioteki CyMCP23016 autorstwa Chris Brunner aka cyrusbuilt, stąd: https://github.com/cyrusbuilt/CyMCP23016 Kopia zapasowa repozytorium (na czas pisania tematu): 1030477 Bibliotekę dodałem do Arduino poprzez Sketch->Include Library->Add .ZIP Library. Test expandera portu - MCP23016 - układ testowy Do przygotowania układu testowego MCP23016 użyłem płytki stykowej i wcześniej opisanej przejściówki i kabelka, do tego kilka rezystorów: https://obrazki.elektroda.pl/7024523100_1588802931_thumb.jpg https://obrazki.elektroda.pl/2680579400_1588802952_thumb.jpg Do tego oczywiście trzeba osobno podpiąć masę (i zasilanie, jeśli go potrzebujemy) https://obrazki.elektroda.pl/4391025300_1588803055_thumb.jpg Test expandera portu - MCP23016 - blink LED Pierwszym przykładem użycia MCP23016 jaki przygotowałem jest proste miganie jedną diodą poprzez ten expander portów, poprzez I2C. Wybrałem pin GP0.0, w tej bibliotece oznaczany MCP23016_PIN_GPIO0_0. Kod prawie w całości pochodzi z przykładu biblioteki z Githuba: /** * Basic input/output test for MCP23016 expander. */ #include <Arduino.h> #include "CyMCP23016.h" CyMCP23016 mcp; void setup() { Serial.begin(9600); Serial.println(("start")); // Init MCP23016 at the default address. This assumes we are running on // an ATmel AVR-based arduino, like the Arduino Uno. mcp.begin(); Serial.println(("begin")); // Set Pin 0 on Port 0 as an output. mcp.pinMode(MCP23016_PIN_GPIO0_0, OUTPUT); Serial.println(("pm")); } void loop() { delay(1000); // Set the pin HIGH and read back the state. mcp.digitalWrite(MCP23016_PIN_GPIO0_0, HIGH); uint8_t val = mcp.digitalRead(MCP23016_PIN_GPIO0_0); Serial.print(F("Pin 0.0 is ")); Serial.println(val == HIGH ? "HIGH" : "LOW"); delay(1000); // Set the pin LOW and read back the state. mcp.digitalWrite(MCP23016_PIN_GPIO0_0, LOW); val = mcp.digitalRead(MCP23016_PIN_GPIO0_0); Serial.print(F("Pin 0.0 is ")); Serial.println(val == HIGH ? "HIGH" : "LOW"); } Kod tylko przełącza stan na pierwszym pinie expandera i dodatkowo wysyła jego stan na UART. Rezultat w Serial Monitor: https://obrazki.elektroda.pl/7086169000_1588791010_thumb.jpg Rezultat na filmie: https://filmy.elektroda.pl/92_1588794181.mp4 W taki sam sposób możemy sterować wszystkimi 16 pinami od MCP23016. Test expandera portu - MCP23016 - prosty licznik binarny Drugim, bardziej zaawansowanym przykładem użycia MCP23016 jaki tu zaprezentuję jest prosty licznik binarny zrealizowany na 8 diodach LED (czyli 8-bitowy). Do tego użyłem całego portu GP0: https://obrazki.elektroda.pl/6748085500_1588798418_thumb.jpg Odpowiednio zmodyfikowałem też kod przykładu. Do ustawienia odpowiednich diod LED użyłem pętli for oraz operatorów bitowych, całość sketchu jest do wglądu poniżej: /** * Basic input/output test for MCP23016 expander. */ #include <Arduino.h> #include "CyMCP23016.h" CyMCP23016 mcp; int counter = 0; void setup() { Serial.begin(9600); Serial.println(("start")); mcp.begin(); Serial.println(("begin")); // Set Pin 0 on Port 0 as an output. for(int i = 0; i < 8; i++) { mcp.pinMode(i, OUTPUT); mcp.digitalWrite(i, LOW); } delay(1000); Serial.println(("pm")); } void loop() { delay(250); for(int i = 0; i < 8; i++) { mcp.digitalWrite(i, counter & (1<<(i))); } counter++; } Powyższy kod powinien być zrozumiały nawet dla początkujących z Arduino, jedyną z pozoru trudną rzeczą w nim jest 'wyłuskanie' bitu za pomocą counter & (1<<(i)). Ta linijka po prostu sprawdza, czy i-ty bit zmiennej counter jest zapalony. Rezultat na filmie: https://filmy.elektroda.pl/15_1588793680.mp4 Wszystko działa poprawnie. Można by jeszcze sprawdzić czy wszystko jest okej z drugim portem od MCP23016, ale uznałem, że to już jest zbędne. Test pamięci EEPROM - AT24CM02 - użyta biblioteka Do obsługi pamięci EEPROM a dokładniej dwóch kości AT24CM02 użyłem biblioteki autorstwa Rushikesh Patel aka luffykesh z Githuba, tej: https://github.com/luffykesh/AT24Cx Kopia zapasowa/snapshot repo na czas pisania artykułu: 1030460 Bibliotekę dodałem do Arduino poprzez Sketch->Include Library->Add .ZIP Library. Test pamięci EEPROM - AT24CM02 - test zapisu i odczytu Na początek sprawdziłem czy w ogóle komunikacja z AT24CM02 działa poprawnie. W tym celu użyłem przykładowego kodu z wybranej biblioteki, jedynie tylko zmodyfikowałem go by korzystał z konkretnie AT24CM02 (z pierwszego na PCB, o adresie 0x50): /* * * Read and write demo of the AT24CX library * Written by Christian Paul, 2014-11-24 * * */ // include libraries #include <Wire.h> #include <AT24CX.h> // EEPROM object AT24CM02 mem; // setup void setup() { // serial init Serial.begin(9600); Serial.println("AT24CX read/write demo"); Serial.println("----------------------"); } // main loop void loop() { // read and write byte Serial.println("Write 42 to address 12"); mem.write(12, 42); Serial.println("Read byte from address 12 ..."); byte b = mem.read(12); Serial.print("... read: "); Serial.println(b, DEC); Serial.println(); // read and write integer Serial.println("Write 65000 to address 15"); mem.writeInt(15, 65000); Serial.println("Read integer from address 15 ..."); unsigned int i = mem.readInt(15); Serial.print("... read: "); Serial.println(i, DEC); Serial.println(); // read and write long Serial.println("Write 3293732729 to address 20"); mem.writeLong(20, 3293732729UL); Serial.println("Read long from address 20 ..."); unsigned long l = mem.readLong(20); Serial.print("... read: "); Serial.println(l, DEC); Serial.println(); // read and write long Serial.println("Write 1111111111 to address 31"); mem.writeLong(31, 1111111111); Serial.println("Read long from address 31 ..."); unsigned long l2 = mem.readLong(31); Serial.print("... read: "); Serial.println(l2, DEC); Serial.println(); // read and write float Serial.println("Write 3.14 to address 40"); mem.writeFloat(40, 3.14); Serial.println("Read float from address 40 ..."); float f = mem.readFloat(40); Serial.print("... read: "); Serial.println(f, DEC); Serial.println(); // read and write double Serial.println("Write 3.14159265359 to address 50"); mem.writeDouble(50, 3.14159265359); Serial.println("Read double from address 50 ..."); double d = mem.readDouble(50); Serial.print("... read: "); Serial.println(d, DEC); Serial.println(); // read and write char Serial.print("Write chars: '"); char msg = "This is a message"; Serial.print(msg); Serial.println("' to address 200"); mem.writeChars(200, msg, sizeof(msg)); Serial.println("Read chars from address 200 ..."); char msg2; mem.readChars(200, msg2, sizeof(msg2)); Serial.print("... read: '"); Serial.print(msg2); Serial.println("'"); Serial.println(); // write array of bytes Serial.println("Write array of 80 bytes at address 1000"); byte xy = {0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9, // 10 x 3 = 30 10,11,12,13,14,15,16,17,18,19, // 10 120,121,122,123,124,125,126,127,128,129, // 10 130,131,132,133,134,135,136,137,138,139, // 10 200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219}; // 20 mem.write(1000, (byte*)xy, sizeof(xy)); // read bytes with multiple steps Serial.println("Read 80 single bytes starting at address 1000"); for (int i=0; i<sizeof(xy); i++) { byte sb = mem.read(1000+i); Serial.print(" = "); Serial.println(sb); } Serial.println(); // read bytes with one step Serial.println("Read 80 bytes with one operation at address 1000"); byte z; memset(&z, 32, sizeof(z)); mem.read(1000, z, sizeof(z)); for (int i=0; i<sizeof(z); i++) { Serial.print(" = "); Serial.println(z); } // stop while (1==1) {delay(1000);} } https://obrazki.elektroda.pl/7951808100_1588847183_thumb.jpg Następnie zmodyfikowałem ten kod tak, by przetestować użycie dwóch EEPROM jednocześnie. W celu weryfikacji czy na pewno kod korzysta z dwóch różnych kości postanowiłem zapisać na ten sam adres różne wartości (dla pierwszej kości: 42, dla drugiej: 15) i potem je odczytać i sprawdzić czy są zachowywane. /* * * Read and write demo of the AT24CX library * Written by Christian Paul, 2014-11-24 * * */ // include libraries #include <Wire.h> #include <AT24CX.h> // EEPROM object AT24CM02 mem0(0); AT24CM02 mem1(1); // setup void setup() { // serial init Serial.begin(9600); Serial.println("AT24CX read/write demo"); Serial.println("----------------------"); } // main loop void loop() { // read and write byte Serial.println(" Write 42 to address 12"); mem0.write(12, 42); Serial.println(" Write 15 to address 12"); mem1.write(12, 15); Serial.println(" Read byte from address 12 ..."); byte b0 = mem0.read(12); Serial.print(" ... read: "); Serial.println(b0, DEC); Serial.println(" Read byte from address 12 ..."); byte b1 = mem1.read(12); Serial.print(" ... read: "); Serial.println(b1, DEC); // stop while (1==1) {delay(1000);} } Rezultat sketchu: https://obrazki.elektroda.pl/9200007400_1588847521_thumb.jpg Jak widać obie pamięci EEPROM działają poprawnie. W ten sposób zyskujemy całe dodatkowe 512KB (dwie kości po 256KB) pamięci! Małe demko - drukowanie kodów klawiszy na ekranie Teraz przedstawię proste demko już bezpośrednio związane z głównymi atutami mojej nakładki, czyli generowaniem obrazu VGA i obsługą klawiatury PS/2. Poniższe demko odbiera klawisze wciśnięte na klawiaturze i wyświetla ich kody na ekranie - za wyjątkiem strzałek, które są kodowane jako kilka kolejnych wartości i trzeba je w specjalny sposób wykrywać. Każda wciśnięcie jednej ze strzałek daje na UART następujące kody: * Up Arrow - 27 91 65 * Down Arrow - 27 91 66 * Right Arrow 27 91 67 * Left Arrow 27 91 68 Strzałki w poniższym demku są wykrywane poprawne i informacje o ich wciśnięciu są wyświetlane jako tekst. UWAGA: Poniższe demko poprawnie obsługuje Caps Lock i wpisywanie znaków z Shift, ale tego nie ma w kodzie na Arduino, gdyż dzieje się to w samym shieldzie i na klawiaturze. Pełny kod demka: /* * Up Arrow - 27 91 65 * Down Arrow - 27 91 66 * Right Arrow 27 91 67 * Left Arrow 27 91 68 * */ #if 0 #define USE_ARDUINO_RXTX #endif #ifdef USE_ARDUINO_RXTX #define vgaSerial Serial #else #include <SoftwareSerial.h> SoftwareSerial mySerial(2, 3); // RX, TX #define vgaSerial mySerial #endif void SCR_Reset() { vgaSerial.print((char)27); vgaSerial.print("c"); } void SCR_PrintLn(const char *s) { vgaSerial.println(s); } void SCR_Print(const char *s) { vgaSerial.print(s); } void SCR_ClearScreen() { vgaSerial.print((char)27); vgaSerial.print("[2J"); } void SCR_SetPos(int x, int y) { vgaSerial.print((char)27); vgaSerial.print("["); vgaSerial.print(x); vgaSerial.print(";"); vgaSerial.print(y); vgaSerial.print("H"); } void setup() { // Open serial communications and wait for port to open: Serial.begin(57600); while (!Serial) { ; // wait for serial port to connect. Needed for Native USB only } Serial.println("started vga"); #ifndef USE_ARDUINO_RXTX //mySerial.begin(1200); // mySerial.begin(57600); // mySerial.begin(38400); mySerial.begin(19200); //mySerial.begin(115200); mySerial.listen(); #endif delay(10); SCR_Reset(); SCR_ClearScreen(); // put your setup code here, to run once: SCR_PrintLn("Arduino VGA Shield Key Code Tester"); //SCR_SetPos(5,5); //SCR_Print("A"); } char buffer ; //whatever void OnPress_ArrowDown() { sprintf (buffer, "Pressed DOWN ARROW"); SCR_PrintLn(buffer); } void OnPress_ArrowRight() { sprintf (buffer, "Pressed RIGHT ARROW"); SCR_PrintLn(buffer); } void OnPress_ArrowLeft() { sprintf (buffer, "Pressed LEFT ARROW"); SCR_PrintLn(buffer); } void OnPress_ArrowUp() { sprintf (buffer, "Pressed UP ARROW"); SCR_PrintLn(buffer); } void OnPress_Key(char inByte) { sprintf (buffer, "Pressed code %i (visual %c)", (int)inByte, inByte); SCR_PrintLn(buffer); } void loop() { // put your main code here, to run repeatedly: while (vgaSerial.available() > 0) { char inByte = vgaSerial.read(); if(inByte == 27) { while (vgaSerial.available() == 0) { } vgaSerial.read(); while (vgaSerial.available() == 0) { } char inByte2 = vgaSerial.read(); if(inByte2 == 65) { OnPress_ArrowUp(); } if(inByte2 == 66) { OnPress_ArrowDown(); } if(inByte2 == 68) { OnPress_ArrowLeft(); } if(inByte2 == 67) { OnPress_ArrowRight(); } } else { OnPress_Key(inByte); } } } Rezultat działania: https://obrazki.elektroda.pl/9093480600_1589293381_thumb.jpg Shift i Caps-Lock są poprawnie obsługiwane, a same klawisze są bezbłędnie odbierane (za wyjątkiem pewnej sytuacji - ale o tym w następnym akapicie). Dlaczego lepiej korzystać z baud 19200 a nie np. z 1200? Tutaj chciałbym zwrócić uwagę na to jak duże znaczenie ma świadomy wybór odpowiedniego baud komunikacji UART ze shieldem. Nie można wybrać zbyt dużego baud, bo ogranicza nas zdolność SoftwareSerial z Arduino. Przy około 38400 mogą się zacząć problemy. To raczej wiadomo, podobne informacje powtarzają się na forum Arduino: https://forum.arduino.cc/index.php?topic=528912.0 Ale nie można też wybrać zbyt małego baud, bo wtedy będziemy gubić znaki lub co gorsza otrzymywać błędne dane. Łatwo to pokazać uruchamiając demo 'test klawiszy' i wciskając (trzymając cały czas) klawisz strzałki, który wysyłany jest przez UART jako trzy znaki. Zdjęcie demka 'odbiór klawiszy' przy baud 1200: https://obrazki.elektroda.pl/9787153500_1589293837_thumb.jpg Zdjęcie demka 'odbiór klawiszy' przy baud 19200: https://obrazki.elektroda.pl/2876768200_1589293876_thumb.jpg Widzicie różnicę? Wniosek: nieodpowiednio dobrany baud może naprawdę namieszać, również gdy wybierzemy jego zbyt małą wartość. Na zdjęciu widać, że raz nawet wysłała się wartość '109' która odpowiada klawiszowi 'm', co z pewnością mogłoby mieć niepożądany skutek jeśli byśmy w naszym programie korzystali zarówno ze strzałek jak i z tego klawisza. Zaawansowane edytor tekstu Teraz zaprezentuję nieco bardziej zaawansowane demko oparte o mojego shielda, a mianowicie prosty edytor tekstu. Edytor tekstu będzie oferować: - obsługa klawisza Shift - obsługa klawisza Caps Lock - obsługa klawisza Delete (usuwanie znaku po kursorze) - obsługa klawisza Backspace (usuwanie znaku przed kursorem) - obsługa klawisza Enter (dodawanie nowej linii) Część tej funkcjonalności jest po stronie Arduino, a część na shieldzie. Rzeczy takie jak poruszanie kursorem, obsługa bufora tekstu, dodawanie znaków, usuwanie ich itp. są po stronie Arduino. Zdjęcia z działania dema-edytora tekstu na monitorze VGA i klawiaturze PS2: https://obrazki.elektroda.pl/5248090800_1589747497_thumb.jpg https://obrazki.elektroda.pl/5745421400_1589747497_thumb.jpg https://obrazki.elektroda.pl/5153392700_1589747496_thumb.jpg https://obrazki.elektroda.pl/5951234900_1589747502_thumb.jpg https://obrazki.elektroda.pl/5538928900_1589747504_thumb.jpg Edytor tekstu można by znacznie ulepszyć, ograniczyć bardziej zbędne odświeżanie pełnego ekranu lub po prostu przenieść w większej części na PICa. Skecz Arduino do pobrania: 1030452 Test edytora tekstu na starym telewizorze CRT TX-21AT1P W ramach uzupełnienia poprzedniego akapitu przedstawiam tu filmik z działania edytora tekstu w trybie PAL na telewizorze kineskopowym: https://filmy.elektroda.pl/13_1590143145.mp4 Zbędne 'pełne odświeżenie' ekranu w trakcie dodawania nowej linii do tekstu można by usunąć w kodzie programu, ale nie to było celem tego demka. Zaawansowane demko - system plików na EEPROM Przedstawione tutaj demko opracowałem w celu dokładniejszego przetestowania obu pamięci EEPROM znajdujących się na płytce (te pamięci pozwalają nam zapisać dane które nie utracą się nawet po całkowitym odłączeniu zasilania od Arduino). Demko to stanowi podstawową wersję systemu plików, który wspiera podstawowe operacje na plikach i katalogach (tworzenie ich, usuwanie, dodawanie danych, przeglądanie, czyszczenie), pozwala też zagnieżdżać katalogi/pliki w innych katalogach tworząc strukturę drzewa. System oczywiście też jest na różne sposoby ograniczony - brakuje dynamicznej alokacji pamięci dla danych pliku, choć jest ona dostępna dla samych katalogów i plików (używane są ponownie zwolnione sloty). Demko obsługuje się poprzez Serial Monitor od Arduino który pełni dla niego funkcję linii komend i wspiera następujące polecenia: - dirls - wyświetla zawartość bieżącego katalogu - mkdir - tworzy katalog o danej nazwie - rmdir - usuwa katalog z zawartością - resetfs - resetuje EEPROMy do pustego systemu plików - resetfile - resetuje plik do stanu pustego (tj. ustawia jego długość na zero) - rmfile - usuwa plik - cd - przechodzi do danego folderu - mkfile - tworzy pusty plik o danej nazwie - append - dodaje do danego pliku dany ciąg znaków - show - pokazuje dany plik w konsoli Poniżej umieszczam zrzuty ekranu z testów powyższego systemu plików; myślę, że ich zawartość nie wymaga komentarza. Testy komend mkdir, ls, mkfile, append, ls: https://obrazki.elektroda.pl/9208051700_1589744617_thumb.jpg Testy komend: cd, mkdir, mkfile: https://obrazki.elektroda.pl/5551405800_1589744899_thumb.jpg Testy komend: rmdir, rmfile, resetfs: https://obrazki.elektroda.pl/7737634500_1589744985_thumb.jpg Testy komend: show, mkfile, append: https://obrazki.elektroda.pl/9026338300_1589745050_thumb.jpg Demko do pobrania: 1030449 Kompilacja wsadu z kodu źródłowego Jeśli tylko chcecie złożyć i używać tego shielda z Arduino to nie musicie samodzielnie kompilować kodu na PICa, potrzebny dla niego .hex załączam tutaj: 1030451 Ale jeśli ktoś chce zmodyfikować samo działanie shielda, to kod można łatwo skompilować w środowisku MPLAB X IDE v5.20: https://obrazki.elektroda.pl/1438991700_1590314916_thumb.jpg Przy użyciu kompilatora XC32 (v2.20): https://obrazki.elektroda.pl/6079210300_1590315087_thumb.jpg Dodatkowo do kompilacji wymagana jest biblioteka PIC32 Peripheral Library (słynne plib.h wraz z innymi nagłówkami), którą ściąga się osobno ze strony Microchipa: https://www.microchip.com/SWLibraryWeb/product.aspx?product=PIC32%20Peripheral%20Library Gdy już ją zainstalujemy, to wszystko poprawnie się kompiluje: https://obrazki.elektroda.pl/2965134100_1590410028_thumb.jpg Kompilować wsad można w dwóch trybach: - tryb dla bootloadera (do wgrania wsadu przez USB za pomocą PIC32UBL.exe) - wtedy w projekcie załączamy 32MX250F128B.ld - tryb bez bootloadera (do wgrania wsadu przez ICSP) - wtedy w projekcie wykluczamy plik 32MX250F128B.ld Więcej informacji na ten temat znajdziecie w oryginalnej paczce z kodem źródłowym: 1030459 Dalszy rozwój projektu - dalsza minimalizacja? Obecna wersja pozostawia jeszcze pole do popisu i możliwość ulepszenia, m.in. dlatego że np. użyty PIC32 jest w wersji PIC32MX250F128B-50I/SO, czyli obudowa SOIC: https://obrazki.elektroda.pl/7523413500_1588796498_thumb.jpg A ten sam mikrokontroler jest jeszcze dostępny w obudowach SSOP (PIC32MX250F128B-50I/SS): https://obrazki.elektroda.pl/9127079900_1588796563_thumb.jpg ... oraz w QFN (PIC32MX250F128B-50I/ML): https://obrazki.elektroda.pl/2453157800_1588796599_thumb.jpg Wszystkie obudowy naszego PICa (kolejno: QFN, SSOP, SOIC i SPDIP) umieściłem na obrazku poniżej: https://obrazki.elektroda.pl/2428852500_1588857711_thumb.jpg Dalszy rozwój projektu - co można by lepiej zrobić? Projekt (i też jego wykonanie - luty) nie jest idealny i dużo można by jeszcze ulepszyć. - można by dać slot na kartę microSD na płytce (podłączony do SPI od Arduino) - można by (jak wspomniałem wyżej) użyć mniejszych obudów elementów i zyskać w ten sposób miejsce na coś więcej na płytce - można by zastąpić MCP23016 (wymagający zewnętrznego rezystora i kondensatora na pinie CLK) poprzez nieco lepszy MCP23017 (który nie wymaga tych dwóch elementów) - można by też dać tam mocniejszego PICa i/lub iść w stronę kolorowego VGA - umieszczone tu przykłady możny by ulepszyć i zoptymalizować, lecz nie to było ich celem (to tylko demonstracja możliwości shielda, nie miała być wydajna) Możliwe zatem, że za jakiś czas zrobię trzecią wersję shielda. Tabela załączników Dla wygody czytelników umieszczam tutaj raz jeszcze odnośniki do załączników które pojawiły się w temacie: NazwaOpisZałącznik Źródła Eagle projektuPliki .sch i .brd które można edytować w Eagle. Użyjcie tego, jeśli chcecie zrobić własną, zmodyfikowaną wersję tego shielda. 1030455 Pliki Gerber projektuTe pliki wysyłamy płytkarni jeśli chcemy by nam wyprodukowali PCB pod ten projekt. Nie polecam ich edytować. 1030453 Arduino skecz - demo edytora tekstuPełny kod edytora tekstu zrealizowanego na tym shieldzie dla Arduino w formacie .ino. Wymaga podłączonej klawiatury i monitora/telewizora do działania. 1030452 Arduino skecz - demo klawiszyPełny kod testera klawiszy PS/2 z obsługą strzałek zrealizowanego na tym shieldzie dla Arduino w formacie .ino. Wymaga podłączonej klawiatury i monitora/telewizora do działania. 1030450 Arduino skecz - demo system plików na EEPROMPełny kod prostego systemu plików na dwóch kościach EEPROM na magistrali I2C Arduino wraz z linią komend na UART. Ten projekt nie korzysta wcale z VGA i nie korzysta z klawiatury PS/2. Kod w formacie .ino 1030449 Skompilowane firmware dla PICa z ShieldaNiezbędny wsad do jednorazowego wgrania na PIC32MX250F128B znajdującego się na pokładzie shielda. Można go wgrać np. za pomocą PICKIT3. 1030451 Kod źródłowy shieldaKod C firmware shielda na PIC32MX250F128B dla MPLAB. Projekt autorstwa geoffg. 1030459 Datasheet AT24CM02Dla dociekliwych - nota katalogowa użytej kości pamięci 1030458 Datasheet MCP23016Dla dociekliwych - nota katalogowa użytego expandera portów 1030454 Biblioteka AT24CXBiblioteka AT24CX z Githuba - kopia zapasowa, wersja ta którą przetestowałem i wykorzystałem do tego projektu. Tę paczkę .ZIP można łatwo dodać do Arduino poprzez 'Add .ZIP Library...'. 1030460 Biblioteka CyMCP23016Biblioteka CyMCP23016 z Githuba - kopia zapasowa, wersja ta którą przetestowałem i wykorzystałem do tego projektu. Tę paczkę .ZIP można łatwo dodać do Arduino poprzez 'Add .ZIP Library...'. 1030477 Podsumowanie Jestem bardzo zadowolony z drugiej wersji mojego shielda. Przejście z montażu przewlekanego na powierzchniowy pozwoliło mi zmieścić na nim nieco więcej niż w pierwszej wersji. Dzięki oparciu o Arduino UNO całość jest wygodna i prosta w użyciu nawet dla początkujących. Umieszczone dodatkowo na płytce układy (MCP23016 i AT24CM02) też posiadają gotowe biblioteki dla Arduino dostępne w sieci, co sprawia, że obsługa mojego shielda sprowadza się do składania programów niemalże jak z klocków, a użycie klawiatury PS/2 oraz możliwość wyświetlania jednokolorowego obrazu VGA oraz czarno-białego obrazu PAL/NTSC nadaje całości nieco 'oldschoolowy' klimat.
ICSP for PICKIT3 etc
ICSP
3.3V
MCLR
3.3V
GND
PGD
PGC
1
2
3
4
5
6
7
10k
VGA_RX
RX_IN
R3
6
4
2
5
3
1
PGC
BSEL_B
BSEL_A
BAUD
GND
GND
10x1F-H8.5
AD5/SCL 10
SCL
AD4/SDA 9
SDA
AREF
GND
8
7
6
5
4
3
2
1
SCK
N$4
MOSI
SS
SS
IO9
IO8
VGA_RX
1 IO0
2
1 IO1
2
1 IO3
2
1 IO5
1 IO6
2
PE
1 IO4
GND
R9
220
470
470
GND
HSYNC
3.3V
1
2
3
4
GND
1 IO6
2
GND
3.3V
3.3V
3.3V
3.3V
3.3V
5V
5V
5V
100nF
100nF
100nF
100nF
100nF
100nF
100nF
100nF
C12
C2
C4
C5
C6
C7
C10
C11
GND
GND
GND
GND
GND
GND
GND
GND
GND
1 IO7
SJ1
5V
5V
IC1
AT24CM02-SSHD-T
5V
1
2
3
4
M_SCL
10k
1 IO9
NC_1
NC_2
A2
GND
VCC
WP
SCL
SDA
8
7
6 M_SCL
5 M_SDA
1
2
3
4
IC3
AT24CM02-SSHD-T
NC_1
NC_2
A2
GND
M_SDA
GND
PE
M_SCL 2
1
VCC
WP
SCL
SDA
8
7
6 M_SCL
5 M_SDA
1
SJ20
IC4
JP3
GP0.7
GP0.6
GP0.5
GP0.4
GP0.3
GP0.2
GP0.1
GP0.0
1
3
5
7
9
11
13
15
2
4
6
8
10
12
14
16
2
3
4
5
7
11
12
13
AD5/SCL_2
M_SCL 14
M_SDA15
AD4/SDA_2
16
17
18
SJ9
M_SDA 2
PS2_DATA
R7
1 IO5
R11
MTN1
MTN3
LED2
COMPOSITE
22p
SJ18
1 IO8
SJ2
150
C9
22p
PS2_CLK
3
2 1
GND
SJ16
SJ19
2
GND
SJ14
1 IO7
2
COMPOSITE
6
4.7k
JP4
C8
SJ12
SJ17
2
Q3
OSC2
8MHz
1 IO3
2
SJ15
2
1 IO2
2
SJ13
2
VID_COM
OSC1
SJ10
1 IO4
8
5
5V
20
GND
GP1.0
GP1.1
GP1.2
GP1.3
GP1.4
GP1.5
GP1.6
GP1.7
SCL
SDA
A0
A1
A2
VDD
GP0.0
GP0.1
GP0.2
GP0.3
GP0.4
GP0.5
GP0.6
GP0.7
CLK
TP
INT#
VSS
VSS
VSS
MCP23016SO
21
22
23
24
25
26
27
28
GP0.0
GP0.1
GP0.2
GP0.3
GP0.4
GP0.5
GP0.6
GP0.7
5V
9
10
3k9
2
R6
X2
R5
SJ4
SJ11
4.7k
GND
HSYNC
VSYNC
TOBU3
1 IO1
2
SJ7
2
X3
1 IO0
SJ3
1 IO2
1
5V
GND
1
C1
9
10
11
12
13
14
15
R10
2
7
6
5
4
3
2
1
0
SJ5
SJ6
1
2
3
4
5
6
7
8
B
R4
SJ8
2
X1
1
2
JP1
HSYNC
VSYNC
3.3V
HSYNC
DIS ON
D+
VCAP
TWO PINS
GND
HSYNC
PS2_CLK
PS2_DATA
VBUS
10uF
R
2
3.3V
GND
VCAP
1
G
IOL
10k
GND
2
GND
LED/BOOT
8
7
6
5
4
3
2
1
VGA_TX
2
28
27
26
25
24
23
22
21
20
19
18
17
16
15
AVDD
AVSS
AN9/C3INA/RPB15/SCK2/CTED6/PMCS1/RB15
CVREFOUT/AN10/C3INB/RPB14/VBUSON/SCK1/CTED5/RB14
AN11/RPB13/CTPLS/PMRD/RB13
VUSB3V3
PGEC2/RPB11/D-/RB11
PGED2/RPB10/D+/CTED11/RB10
VCAP
VSS_2
TDO/RPB9/SDA1/CTED4/PMD3/RB9
TCK/RPB8/SCL1/CTED10/PMD4/RB8
TDI/RPB7/CTED3/PMD5/INT0/RB7
VBUS
VGA_VID (RA4) is also used to detect
is VGA monitor connector
(if not, PAL mode is started)
VGA_VID
AD
8x1F-H8.5
IO7
IO6
IO5
IO4
IO3
IO2
IO1 TX
IO0 RX
DD+
2
1
BOOT
6
5
4
3
2
1
R12
VBUS
DD+
ID
GND
MTN4
MTN2
USB
GND
MCLR
PGED3/VREF+/CVREF+/AN0/C3INC/RPA0/CTED1/PMD7/RA0
PGEC3/VREF-/CVREF-/AN1/RPA1/CTED2/PMD6/RA1
PGED1/AN2/C1IND/C2INB/C3IND/RPB0/PMD0/RB0
PGEC1/AN3/C1INC/C2INA/RPB1/CTED12/PMD1/RB1
AN4/C1INB/C2IND/RPB2/SDA2/CTED13/PMD2/RB2
AN5/C1INA/C2INC/RTCC/RPB3/SCL2/PMWR/RB3
VSS_1
OSC1/CLKI/RPA2/RA2
OSC2/CLKO/RPA3/PMA0/RA3
SOSCI/RPB4/RB4
SOSCO/RPA4/T1CK/CTED9/PMA1/RA4
VDD
TMS/RPB5/USBID/RB5
IOH
6x1F-H8.5
AD5/SCL_2
AD4/SDA_2
AD3
AD2
AD1
AD0
VBUS
LED/BOOT
13
12
11
10
9
8
IC2
PIC32MX250F128B-I_SO
1
MCLR
2
PGD
3
PGC
VGA_TX 4
5
RX_IN
VID_COM 6
BSEL_B 7
8
GND
OSC1 9
OSC2 10
BSEL_A 11
VGA_VID 12
3.3V 13
14
LED/BOOT
R8
3.3V
5V
1
2
3
4
5
10k
JMP_RST
R1
1
R2
JP2
MCLR 2
100k
3.3V
33pF
6
C3
1
8
19
GND
GND
GND
GNDGND