wtorek, 8 października 2019

PIC32MM - biblioteka do obsługi kart SD od Microchipa. Wyświetlanie bitmapy na LCD.

Wszystkim dobrze znana biblioteka FatFs została bardzo ładnie i zgrabnie zaimplementowana dla serii PIC32MM . Kawał dobrej roboty zrobił Microchip ,dzięki czemu nie trzeba się trudzić aby bibliotekę FatFs przysposobić do współpracy z naszym miłym MCU. Co więcej biblioteka jest fajnie konfigurowalna i automatycznie dołączana z poziomu MCC w MPLAB-X IDE. Użytkownik praktycznie zwolniony jest z wszelkiej ingerencji w soft i może skupić się wyłącznie na używaniu biblioteki. W artykule pokażę jak dodać bibliotekę do projektu i jak tego użyć . Naszym celem będzie wyświetlenie obrazka z nagłówka artykułu na LCD i pobranie jego danych z karty SD . Mały Fiat na "małym" wyświetlaczu LCD powinień współgrać idelanie :)

Moja baza sprzętowa to :

- płytka firmy Microchip PIC32MM USB Curiosity Development Board z PIC32MM0256GPM064 na pokładzie.


- wyświetlacz LCD 2.8" lub 2.2" (320x240)  ILI9341 z czytnikiem kart SD.

- karta microSD firmy Kingston o pojemności 8GB z adapterem do formatu czytnika w LCD. Swoją drogą ogromniasty nośnik pamięci do wykorzystania przez MCU.


Dla przypomnienia mikrokontroler 32-bitowy z serii PIC32MM jest w pełni wspierany przez MCC co oznacza bajecznie prostą konfigurację, profesjonalne biblioteki konfiguracyjne peryferiów i wszystko to co najlepsze w świecie MCU :). Trochę czasu ostatnio spędziłem na ARM-ach w szczególności na ATSAM-ach. Wracając do środowiska MPLAB-X poczułem się jak u Mamy w domu, wszystko podane na tacy, komfortowo , prosto i bezpiecznie :) . Co z tego , że wolniej ale swojsko i sielsko :). Microchip serią PIC32MM wstrzelił się idealnie w segment low end w 32-bitach.

Przechodzimy do części artystycznej :) W MPLABX- IDE tworzymy nowy projekt


Wybieramy MCU znajdujące się na płytce Microchipa :


Podpinamy płytkę Microchipa do portu USB w PC aby w okienku wyboru programatora wyskoczyła nam odpowiednia opcja i zaznaczamy ją :


W kolejnym okienku zaznaczamy kompilator XC32 , który musimy mieć doinstalowany :


W ostatnim okienku tworzenia nowego projektu podajemy jego nazwę :


Utworzony projekt w postaci drzewa katalogów zobaczymy po lewej stronie w zakładce Projects ale na razie jest tam pusto i nie ma nawet pliku main.c.

Przechodzimy teraz do konfiguracji naszego MCU i zrobimy to za pomocą przyjaznego narzędzia jakim jest MCC (MPLABX Code Configurator). Za pomocą MCC dołączymy również bibliotekę do obsługi czytnika kart SD. Klikamy jeden raz ikonkę MCC (pamiętamy, że to narzędzie trzeba doinstalować po każdej nowej instalacji MPLABX, zakładka Tools-->Plugins).

Otwiera się okienko z nazwą pliku konfiguracyjnego, nie ma potrzeby jej zmieniać, klikamy Save :


Po uruchomieniu MCC zobaczymy okienko startowe jak poniżej :


W pierwszej kolejności ustawiamy zegar np. tak jak zrobiłem to poniżej  :


Zegar Core i Peryferiów skonfigurowany mamy na 24MHz. I to już wszystko jeśli chodzi o konfigurację zegara, zapominamy o temacie. Teraz zajmiemy się dołączeniem do projektu biblioteki  FatFs. W zasadzie musimy dołączyć dwie biblioteki FatFs i SD Card . W tym celu odnajdujemy w spisie bibliotek w lewym dolnym okienku MCC w/w dwóch bibliotek. Wybrane biblioteki trzeba doinstalować , w tym celu rozwijamy nazwy bibliotek FatFs i SD Card i zaznaczam opis wersji bibliotek , po zaznaczeniu  klikamy przycisk Load Selected Libraries. Pokazuje to obrazek poniżej :



Po chwili otrzymamy dwa kolejne komunikaty o zainstalowaniu wybranych bibliotek. Na razie zostały one tylko ściągnięte do MCC ale jeszcze nie dołączone do naszego projektu. W środkowym okienku po lewej stronie MCC , opisanym jako Device Resources, przewijamy treść okienka na koniec, gdzie znajdujemy zakładkę Libraries i tam gotowe w lukach startowych nasze dwie biblioteki FatFs i SD Card. Za pomocą zielonych plusików dołączamy je do naszego projektu.



Efekt dołączenia bibliotek zobaczymy w okienku Project Recources :


Teraz pora na konfigurację bibliotek choć to nazbyt szumne słowo dla tej czynności nie mniej jakieś działania trzeba wykonać. W środkowym okienku MCC pojawi nam się okienko zatytułowane SD Card (SPI). W okienku tym odznaczamy dwie ostatnie opcje, efekt na poniższym zdjęciu :


W tym momencie warto zwrócić uwagę na warningi jakie mamy w dolnym okienku w zakładce Notifications (MCC). W sumie mamy trzy , jeden informuje nas , że biblioteka FatFs nie ma wybranego drivera, drugi komunikat informuje, że biblioteka SD Card wymaga wybrania pinu, domyślnie wiemy, że dla CS. Trzeci warning dotyczy niestandardowego zegara USB. Ponieważ nie używamy w projekcie USB nie interesuje nas ten temat. Najpierw zajmiemy się warningiem dotyczącym biblioteki FatFs, klikamy zatem w nazwę biblioteki w okienku Project Resources. Wyświetli nam się kienko z informacją o tej bibliotece , w okienku tym przełączamy się na zakładkę Configuration, efekt jak poniżej :


W okienku konfiguracyjnym biblioteki FatFs klikamy przycisk opisany jako +Insert Driver. Dołączy nam się driver w postaci biblioteki SD Card do biblioteki FatFs. Jednocześnie zniknie nam na dole warning dotyczący biblioteki FatFs. Efekt poniżej :


Jeśli przewiniemy w dół okienko konfiguracyjne biblioteki FatFs , zobaczymy tam mnóstwo różnych opcji konfiguracyjnej dotyczących m.in obsługi specyficznych funkcjonalności samej biblioteki ale nic tam nie zmieniamy zostawiamy wszystko tak jak zastaliśmy.
Teraz kolej na zlikwidowanie warninga dotyczącego wybrania pinu , którego domaga się biblioteka SD Card. Na razie udajemy, że nie wiemy o co chodzi. 
Przełączamy się na widok z pinami , w tym celu klikamy zakładkę Pin Manager Grid View i tam szukamy o co chodzi. Znajdujemy w kolumnie Module pozycję  SD Card(SPI) i widzimy, że żaden pin nie jest dla tego modułu aktywny. Domyślamy się , że warning jest powiązany z tym stanem rzeczy. Wybieramy sobie pin np. RA10 i zapinamy na nim kłódeczkę. Ten pin podłączymy do pinu CS w czytniku kart SD. Efekt poniżej :


Przełączamy się w dolnym oknie na zakładkę Notifications (MCC) i widzimy , że warning od SD Card(SPI) zniknął.

To już w zasadzie wszystkie czynności jakie trzeba zrobić aby dołączyć bibliotekę do obsługi kart SD  w MCC. Bajecznie prosto. Warto nadmienić, że przy dołączaniu biblioteki automatycznie został skonfigurowany moduł SPI. Przełączmy się na widok Pin Module aby podejrzeć na jakich pinach będzie chodzić nam SPI, widok jak poniżej :


Podsumujmy w tym momencie "pinologię" jaką przyłożymy do naszego czytnika SD :

RC13 - SCK
RD0 - MOSI (SDO)
RD4 - MISO (SDI)
RA10 - CS

Teraz rzecz o której nagminnie zapominam, musimy zmienić piny dla programatora dla naszej płytki Curiosity z PIC32MM . Standardowo ustawione są na RB0 i RB1 czyli PGD1 i PGC1. Musimy to zmienić na PGD2 i PGC2 co jest tożsame z przełączeniem się na piny RA0 i RA1. W tym celu wystarczy dla modułu ICD w okienku Pin Manager Grid View kliknąć w pin RA0 i wtedy z automatu pin RA01 zostanie dołączony do funkcjonalności dla programatora. Efekt poniżej :



Kończymy na razie działalność w MCC , klikamy Generate w okienku Project Resources i wychodzimy z MCC klikając jeden raz w ikonkę MCC. Po zamknięciu MCC przełączamy się na zakładkę Projects. Możemy teraz skompilować program ikonką młoteczka. Jeśli wszystko będzie oki otrzymamy widok jak poniżej. Ja otworzyłem dodatkowo plik main.c , który został wygenerowany przez MCC. Od tego momentu mamy skonfigurowany MCU i możemy korzystać z  biblioteki FatFS.

Teraz dołączam do projektu pliki biblioteczne dla wyświetlacza ILI9341 i delay.
Prawym klawiszem  myszki traktuję Header Files i wybieram opcję Add Existing Item wyszukuje stosownych plików do obsługi wyświetlacza i delay. Ja to mam na dysku lokalnie a publiczność znajdzie to na moim  GitHub .

Przy okazji dodawania plików do projektu istotna uwaga , w okienku w którym podajemy ścieżkę do plików , które chcemy dołączyć zaznaczyć koniecznie opcję Store Path as : Absolute i zaptaszkować Copy. Widać to na poniższym obrazku :



Dodałem do projektu pliki ili9341.h i .c oraz delay.h i .c i font.h. W pliku main.c "inkluduje" te pliki.



Otwieram zawartość pliku ili9341.h i patrzę na "pinologię" czyli jakie piny należy podłączyć do wyświetlacza . Od razu rzuca się w oczy zong, pin RD0 wykorzystuje biblioteka wyświetlacza i karty SD. Ponadto pin RB11 na płytce Microchipa jest niedostępny i podłączony do USB. Musimy to zmienić w MCC.

Signal LCD ---> MCU PIC32MM
  
CS     (Chip Select)              --> Ground
RESET                                 --> RB11 (do zmiany)
DC/RS  (Command / Data)  --> RC3
MOSI   (Serial Data)           --> RD0 (do zmiany)
SCK    (Serial Clock)           --> RB8


Uruchamiamy zatem MCC ponownie klikając jeden raz w ikonkę MCC. Po uruchomieniu MCC patrzymy, że biblioteka karty SD zajmuje nam SPI1. Zatem nasz wyświetlacz musi rozmawiać na innym numerku SPI, mamy w rezerwie SPI2 i SPI3. Wybieramy do sterowania wyświetlaczem SPI2. W tym celu po uruchomieniu MCC w okienku Device Recources dodajemy plusikiem moduł SPI2 do naszego projektu. Efekt jak poniżej :



Ustawienia SPI2 zostawiamy tak jak są , zapinamy tylko kłódeczki na wybranych pinach. Potrzebujemy dla wyświetlacza ILI9341 pinów dla MOSI, SCK, DC/RS i RESET. Najpierw na poziomie modułu SPI2 zapinamy kłódeczki w wierszu SCK2OUT i SDO2, odpowiednio piny RB8 i RB9.


Potem na poziomie Pin Module, GPIO, Output zapinamy dla RESET RC2 i dla DC/RS RC3. Wszystkie zmiany na pinach można monitorować w okienku Pin Module. Efekt poniżej :


Plik ili9341.h wymaga drobnej korekty z racji zmiany pinu dla RESET na RC2,  zmianę naniosłem i podświetliłem ją a stare ustawienie zakomentowałem powyżej zmiany. Chodzi o definicję dla pinu RC2 (stare ustawienie to RB11).



Nasze podłączenie do wyświetlacza ILI9341 wygląda ostatecznie jak poniżej :

Signal LCD ---> MCU PIC32MM

CS     (Chip Select)              --> Ground
RESET                                 --> RC2
DC/RS  (Command / Data)  --> RC3
MOSI   (Serial Data)           --> RB9
SCK    (Serial Clock)           --> RB8
 
Podłączenie do karty SD , która znajduje się na płytce wyświetlacza LCD poniżej :

Signal SD  ---> MCU PIC32MM

SCK               -> RC13
MOSI (SDO)  -> RD0
MISO (SDI)   -> RD4
CS                 -> RA10

Musimy upewnić się czy biblioteka obsługująca wyświetlacz ILI9341 po zmianie numerku SPI na SPI2  będzie poprawnie działać. Wchodzimy do pliku ili9341.h i lustrujemy deklaracje funkcji . Pierwsza deklaracja funkcji to sendCmd(). Wchodzę w definicję tej funkcji w pliku ili9341.c i widzę zong, ciało tej funkcji używa funkcji wysyłającej SPI1_Send() a my wybraliśmy w MCC SPI2 do współpracy .


Ponieważ SPI1_Send() nie jest funkcją wygenerowaną przez MCC ale wystruganą przeze mnie. Musimy to skorygować. W tym celu wszystkie odwołania do funkcji SPI1_Send() w pliku ili9341.c zamieniamy na SPI2_Send(). Aby to zrobić szybko i bezboleśnie w menu Edit wybieramy Replace. Wyskoczy okienko w którym wpisujemy dwie dane , tekst źródłowy i tekst na jaki chcemy to zamienić.




Na dole pojawi się małe okienko z informacją ile zostało wyszukanych tekstów źródłowych (SPI1), będzie tego dokładnie 4 sztuki. Pod tym małym okienkiem klikamy Replace i od tej chwili wszystkie funkcje z przedrostkiem SPI1 zamienią się na SPI2. No tak, to była żonglerka z samą nazwą ale teraz trzeba tę funkcję utworzyć . Ciało tej funkcji podaję poniżej :


/*only send, not used receive data*/
void SPI2_Send(uint8_t data)
{
 
    SPI2BUF = data; 
   
    while(SPI2STATbits.SPIBUSY == 1) //SPI peripheral is currently busy with some transactions
    {
    }
  
}


Powyższą definicję dodajemy do pliku spi2.c wygenerowanego przez MCC.


a deklarację do pliku spi2.h :



Konfiguracja warstwy sprzętowej mielibyśmy za sobą. Teraz trzeba by było spiąć kabelkami płytkę Microchipa z wyświetlaczem ILI9341 I na początek spróbować uruchomić wyświetlacz. W pliku main.c inicjalizuję wyświetlacz i wyświetlam tekst "Test ILI9341". Jeśli nic nie poknociłem to powyższy tekst powinniśmy zobaczyć na LCD. Plik main.c ostatecznie wygląda jak poniżej :




Zwracam uwagę , że w "includach" się trochę pozmieniało. Piszę artykuł i wszystko wykonuje na żywym organizmie stąd pewne drobne korekty w locie. Na końcu artykułu i tak dojdziemy do pełnej i ostatecznej wersji programu, który załączę na GitHub. Z ciekawością wgrywam program do MCU na płytce Curiosity i po chwili widzę .... że działa, huraaa :) 

Skoro LCD nam działa możemy zabrać się za użycie biblioteki FatFs. Wiedzy o bibliotece FatFs a w szczególności o jej funkcjach możemy nabyć z tej strony.
Biblioteka Microchipa jest "wariacją" biblioteki FatFs i od strony kodu jest znacznie lepiej napisana niż pierwowzór . Dostępne funkcje w bibliotece Microchipa znajdziemy w pliku ff.h


W sumie warto nadmienić , że do biblioteki Microchipa FatFs dodany jest przykładowy program ale ja go dezaktywowałem w MCC w ustawieniach biblioteki.

Przechodzimy do działań na bibliotece FatFs. Pierwszą czynnością będzie dodanie w main.c stosownych plików nagłówkowych w tym ff.h i diskio.h. Następnie powołamy do życia zmienne potrzebne do interakcji pomiędzy biblioteką a naszym programem. No i w końcu pierwsza funkcja , która "zamontuje" nam czytnik kart SD. Wszystko powyższe przedstawia zdjęcie poniżej :


W procesie "montowania" czytnika kart SD nie istotne jest czy będzie w nim karta czy nie. Porządany komunikat po poprawnym "zamontowaniu" to "f.mount OK.!" i taki napis powinniśmy zobaczyć na naszym LCD. W przypadku niepowodzenia operacji ,otrzymamy komunikat "f_mount error!". Czytnik nie zamontuje się jeśli np. zabraknie nam jakiegoś połączenia ,przykładowo kabelek nam nie będzie stykał. 

Drugą czynnością będzie inicjalizacja karty. Na tym etapie karta musi być włożona do czytnika SD. Zakładam, że kartę mamy sformatowaną. Funkcja inicjalizacji karty może wyglądać jak poniżej :


Jeśli wszystko z kartą jest w porządku zobaczymy na LCD zielony komunikat "disk init OK.!" . Jeśli coś pójdzie nie tak zobaczymy komunikat "disk init error" i numer błędu. Swoją drogą takie kolorowe komunikaty na LCD fajnie ożywiają i wprowadzają dodatkową dramaturgię, niedostępną na monochromatycznych LCD. Na razie wszystko idzie podejrzanie zbyt łatwo. Artykuł piszę na żywca czyli piszę i jednocześnie wykonuję czynności opisywane  :)

Czas na przygotowanie danych do pobierania z karty SD. Na początku bawiłem się w zamianę obrazka na tablicę danych w postaci 16-bitowych słów. Używając do tego programu np. LCD Image Convert  .Ale szybko doszedłem do wniosku , że jest to nieefektywny sposób przechowywania danych o obrazku na karcie SD. Wielkość pliku była na poziomie 600 kB, pojawiły się tutaj jakieś problemy z formatowaniem danych, więc poszukałem innego rozwiązania i znalazłem. Pliki na karcie będziemy przechowywać w formacie bitmapy z rozszerzeniem .BMP. Dane dla naszego pliku w tym formacie to "zaledwie" 150 kB. Zaletą tego formatu jest prostota w odczycie strumienia danych i implementacji dekodera za pomocą języka C. Ponieważ nasz obrazek z nagłówka artykułu jest w formacie JPG dlatego musimy go przekonwertować . Drugim aspektem oprócz samej konwersji jest zapis koloru w trybie RGB565 bo w takim trybie jest ustawiony nasz LCD. Ale spokojnie wszystkie te czynności zrobi za nas automatycznie jeden z najpopularniejszych programów graficznych w świecie Linuxa - GIMP. Odpalamy zatem GIMP-a i wczytujemy nasz obrazek w formacie .JPG . Następnie wybieramy opcję Plik --> Wyeksportuju jako...
Podajemy nazwę pliku fiat.bmp i wybieramy rozszerzenie .bmp.


Następnie "klikamy" Weksportuj. Otworzy się okienko w którym rozwijamy Ustawienia Zaawansowane i tam zaznaczamy R5 G6 B5 


"Klikamy" Wyeksportuj i zapisuje nam się plik fiat.bmp w którym mamy zakodowane kolory w formacie RGB565 .Teraz pozostaje to tylko wyświetlić.

Nagrywamy nasz plik z danymi na kartę SD (ja mam sformatowaną w FAT32). Nazwa pliku to fiat.bmp , należy mieć na uwadze, że maksymalna długość znaków w nazwie to 8 plus 3 znaki w rozszerzeniu. Zakładam , że mamy plik nagrany na karcie SD.

Tak w ramach dygresji powiem, że jak na razie operowanie na bibliotece Microchipa FatFs jest bardzo przyjemne i bezstresowe. Polecam korzystać z tego dobrodziejstwa tym bardziej , że za darmo.

Małymi kroczkami zbliżamy się do finału czyli wyświetlenia obrazka na naszym LCD ,gdzie dane odczytamy z karty SD. Ale najpierw musimy zrobić pewną rzecz. Ponieważ w konfiguracji biblioteki FatFs w MCC nie zwróciłem uwagi, że część funkcji bibliotecznych  jest wyłączona m.in funkcja l_seek() i podczas użycia takiej wyłączonej funkcji otrzymamy błąd przy kompilacji undefined reference. Dlatego musimy włączyć te dezaktywowane funkcje i zapomnieć o temacie. W tym celu uruchamiam MCC i wchodzę w konfigurację biblioteki FatFs. Na samym początku widać okno wyboru z opisem 3:f_lseek() function is removed musimy to zmienić na opcję 0: Basic function are fully enable


I generujemy projekt w MCC na tej zmianie.

Przechodzimy fo finału czyli funkcji "dekodującej" format bitmapy .BMP i wyświetlającej obrazek na naszym LCD. Funkcja będzie w miarę prosta ale aby cokolwiek ją zrozumieć należy rozszerzyć swoją wiedzę o budowie pi razy drzwi formatu danych binarnych w pliku bitmapy. Najszybciej tę wiedzę uzupełnimy w Wikipedii
Dla nas najważniejsze informacje to wielkość całego pliku i offset  wskazujący na początek tablicy z danymi o pikselach.   Dane te obrazowo przestawia tabelka z Wikipedii  :


W naszej funkcji musimy w pierwszej kolejności odczytać te dwie dane . Każda z tych danych jak wynika z powyższej tabelki zakodowana jest na 4 bajtach. Dodatkową informację stanowi dla nas to, że każdy piksel jest opisany na 16 bitach ponieważ zapisaliśmy plik bitmapy w formacie RGB565. W sumie mając powyższe informacje możemy przystąpić do zaprezentowania funkcji - dekodera.


Na niebiesko zaznaczyłem naszą funkcję realizującą odczyt danych z pliku bitmapy i wyświetlającą obrazek na LCD ILI9341 320x240. A poniżej kod z wywołaniem funkcji i inicjalizacją


Obrazek wyświetliłem bez problemu na LCD o wymiarze 2.2 i 2.8. Obraz wyświetlany jest w odbiciu lustrzanym w poziomie. Na razie nie udało mi się temu zaradzić ustawieniami wyświetlacza ale nie jest to żaden problem. Możemy przy zapisie obrazka najpierw go odbić w poziomie i wtedy na LCD zobaczymy prawidłową orientację. Ale z drugiej strony takie odbicie jest też ciekawe,
bo to samo zdjęcie widzimy z innej perspektywy dotychczas nieznanej. Przez to stare zdjęcia np rodzinne nabierają innego wymiaru :)

Czekamy na zdjęcie LCD z obrazkiem ...... i na zamieszczenie kodu na GitHub-ie
Ja już po rodzinie mam zamówienia na  interaktywną ramkę ze zdjęciam na LCD, no i się tym artykułem wkopałem w dodatkową robotę :)

W linkach poniżej znajduje się projekt , który wgrałem na GitHub. Sciągamy go do MPLABX-IDE za pomocą Team --> Remote --> Clone lub w konsoli Linuxa :

git clone https://github.com/PICmajster/PIC32MM_FATFS_ILI9341.git



Pozdrawiam
picmajster.blog@gmail.com



Brak komentarzy:

Prześlij komentarz