środa, 16 maja 2018

PIC32MM - SPI , szybka konfiguracja za pomocą MCC

W MCU PIC32MM mamy do dyspozycji 3 x SPI, które mają trzy wyróżniające cechy : powiązany interfejs I2S co umożliwa np. przesyłanie muzyki z kodowaniem PCM, zmienną szerokość danych 8,16 i 32 bity oraz bufory FIFO niezależne dla RX i TX. Szybkość do 25 Mbps czyli szybko.W celu zapoznania się z konfiguracją SPI posłużymy się wtyczką do MPLABX-IDE - MCC (MPLAB Code Configurator). Microchip może być dumny z tego narzędzia bo jakość i opis generowanego kodu deklasuje podobne rozwiązania stosowane  u innych producentów MCU.

MCC to taka droga na skróty , która w bardzo łatwy sposób umożliwia nam uruchomienie dowolnego peryferium w PIC32MM bez dodatkowych nakładów czasowych na dogłębne zapoznanie się z ustawieniami i konfiguracją rejestrów.

Uważam jednak , że optymalnym kierunkiem jest najpierw zapoznanie się z rejestrami a potem korzystanie z takich narzędzi jak MCC celem przyspieszenia pracy.

Zdarza się jednak , że za chiny ludowe nie kapujemy jakie ustawienia w rejestrze zastosować i ewentualnie jakie rejestry wymagają konfiguracji. W takim układzie MCC nakieruje nas na właściwy tor .

Zerknijmy jak wygląda z grubsza obieg danych podczas nadawania i odbierania za pomocą SPI w PIC32MM, posłużymy się w tym celu obrazkiem z dokumentacji :


SPI w PIC32MM jest bardzo sprytnym peryferium nie dość że jest bardzo szybkie bo 25 Mbps (dla porównania STM-y Cortex M0+ i M0 mają 16 lub 18 Mbps) to jeszcze przepływ danych jest buforowany w 128 bitowych buforach FIFO. Microchip zaimplementował tutaj dwa tryby działania z buforami STANDARD BUFFER MODE i ENHANCED BUFFER MODE i musimy mieć o tym jakieś pojęcie.

Przyjrzyjmy się najprostszej opcji STANDARD BUFFER MODE. Jest to opcja domyślna i nie wymaga ustawiania w rejestrach konfiguracyjnych. W tej opcji nie korzystamy z buforów FIFO.

Rozważmy obieg danych w przypadku odbioru danych.
Dane wchodzą do rejstru/bufora SPIxSR  i tam są przesuwane bit po bicie. Do tego bufora nie mamy dostępu programowo. Kiedy bufor SPIxSR zostanie zapełniony danymi a może to być 8 lub 16 lub 32 bity w zależności od ustawienia, dane zostaną przepisane do bufora pomocniczego SPIxRXB i zostanie ustawiona flaga SPIxRBF. Bufor SPIxRXB jest zmapowany do głównego bufora SPIxBUF i z tego bufora możemy odczytać dane. Po odczytaniu danych z bufora SPIxBUF, flaga SPIxRBF zostanie wyzerowana .

Teraz zobaczmy co się dzieje w przypadku nadawania.
Dane do wysłania umieszczamy w znanym nam buforze SPIxBUF stąd trafiają automatycznie do bufora pomocniczego SPIxTXB, jeśli dane w tym buforze są kompletne ustawiana jest flaga SPIxTBF. W następnej kolejności dane z bufora SPIxTXB są przepisywane do SPIxSR skąd lecą w świat. Po wysłaniu danych i opróżnieniu bufora SPIxSR, zerowana jest sprzętowo flaga SPIxTBF.

O trybie ENHANCED BUFFER MODE doczytamy sobie w manualu SPI link poniżej artykułu.
Mamy tu do dyspozycji dwa oddzielne 128 bitowe bufory FIFO, jeśli przesyłamy dane 8 bitowe to głębokość FIFO wynosi 16 , dla 16 bitów mamy głębokość 8 a dla 32 bitów , 4. Dostęp do elemenów FIFO zapewnia bufor SPIxBUF. Liczba bitów w RXBUFELM <4: 0> w rejestrze SPIxSTAT <28:24> wskazuje liczbę nieprzeczytanych elementów w odbieranym FIFO. Liczba bitów w TXBUFELM <4: 0> w rejestrze SPIxSTAT <20:16> wskazuje na liczbę elementów nieprzesłanych w transmitującym FIFO.

Spróbujmy zatem zobaczyć jak krok po kroku dojść do wygenerowania przez MCC plików konfiguracyjnych do obsługi SPI.

Ogólny schemat podłączeń SPI dla przypomnienia wygląda tak :


Na początku musimy określić na jakich pinach chcemy komunikować się po SPI.
Ja potrzebuję zrobić to na następujących pinach :

RB3 - SDO (od strony Mastera)
RA9 - SDI (od strony Mastera) 
RB8 - SCK

Dlaczego na tych konkretnych ? , tak mam zaprojektowany slot PICbus MB1 na płytce developerskiej PIC32MM a w dalszej kolejności będę go właśnie wykorzystywał wraz z SPI. A na jakich pinach wogóle możemy podpiąć SPI ? to nam w najprostszym  przypadku podpowie MCC.

Tworzymy sobie zatem nowy projekt w MPLABX-IDE (pokazuję kroczek po kroczku) :







Na ostatnim powyżej obrazku mamy wygenerowany nowy projekt ale na razie bez żadnej konkretnej zawartości czyli tabula raza.

Kolejnym krokiem będzie uruchomienie wtyczki MCC aby skonfigurować zegar , wybrane SPI i inne duperele. Zaczynamy zawsze od skonfigurowania zegara.

Klikamy zatem w niebieską ikonkę MCC znajdującą się dokładnie po środku górnej belki narzędziowej (jeśli ikonki nie mamy to znaczy, że nie zainstalowaliśmy wtyczki MCC)

Pierwsze okienko jakie nas przywita po chwili od uruchomienia MCC to okienko z zapisem pliku konfiguracyjnego, klikamy save i jedziemy dalej :


poniżej obrazek jaki zobaczymy po pełnym uruchomieniu się MCC :


Ustawiamy zegar na 24 MHz (wewnętrzny RC), opcję Clock Output Pin Configuration na OSCO pin operates as a normal pin oraz odznaczamy "ptaszka" w opcji Use Secondary Oscillator efekt końcowy ustawień na obrazku poniżej :


i to tyle działań w okienku konfiguracyjnym zegara w MCC, jeszcze tylko jedno drobne ustawienie , klikamy zakładkę Registers w okienku System Module i sprawdzamy czy opcja JTAGEN jest disabled i tak ma być  :


kliknijmy sobie ikonkę dwóch dyskietek aby zapisać nasze dzieło epokowe .
Gdybyśmy na tym skończyli i wygenerowali pliki MCC do naszego projektu i wgrali wsad do MCU to na pewno serce procka zaczęło by bić z tętnem 24 MHz.

Teraz kolej na ustawienie  SPI.
Pierwszą czynnością będzie w tym przypadku wybranie w okienku Device Resource opcji SPI, rozwijamy tę opcję i ukazuje nam się jej struktura wewnętrzna  :


widzimy dla każdego SPI (SPI1 ... SPI3) jakieś dwie podopcje. Nas interesuje  ta opisana jako SPIx [PIC24/ds33/PIC32MM MCU ...]

Teraz przyjrzyjmy się możliwości przyporządkowania SPI do wybranych pinów naszego MCU. I tu od razu mówię, że prawie dowolne przyporządkowanie pinów jest możliwe tylko w przypadku SPI2. Dla SPI1 i SPI3 piny są na stałe przypisane.
Poniżej rozkład pinów jakie możemy użyć z SPI1, SPI2 i SP3 w MCU PIC32MM0256GPM048


 
Dla przypomnienia potrzebujemy ustawić taki układ :

RB3 - SDO (od strony Mastera)
RA9 - SDI (od strony Mastera)
RB8 - SCK

Klikamy zatem na opcje SPI2 [PIC24/ds33/PIC32MM MCU ...] w SPI2 i otrzymujemy taki obrazek :


Kolejnym krokiem jest działanie (klikanie) na kłódeczkach czyli musimy przyporządkować nasze piny do poszczególnych funkcjonalności SPI2, po ustawieniu otrzymamy poniższy układ :


zapięte kłódeczki w kolorze zielonym symbolizują aktywacje danego pinu w MCU a na grafice MCU po prawej stronie widać tekstowy opis funkcjonalności danego pinu.
Jeśli okienko do ustawienia SPI nas nie zadowala bo jest zbyt proste :) to możemy przełączyć się na widok rejestrów (klikamy w zakładkę Registers w okienku SPI2) i tutaj mamy wszystkie rejestry niezbędne do działania z SPI2, łącznie z aktywacją przerwań stąd możemy czerpać garściami wiedzę jak i co ustawiać w rejestrach.




Zapisujemy ustawienia i klikamy opcję Generate w okienku Project Resources
MCC wygereneruje nam pliki i dołączy je do naszego projektu.
Przełączmy się zakładką Projects na widok drzewa projektu i odszukajmy plik spi2.c i spi2.h W plikach tych mamy całą esencję ustawień dla SPI2 oraz funkcje zaserwowane przez Microchipa do działania z SPI2. Możemy sobie  podpatrzeć jak wygląda inicjalizacja i funkcje do wysyłania i odbierania danych oraz próbować to zrozumieć :)
Oczywiście nikt nas nie zmusza do korzystania z wygenerowanych przez MCC funkcji do obsługi SPI od Microchipa ale warto sobie podpatrzeć np w celach dydaktycznych jak to jest zrobione. Warto nadmienić , że Microchip dostarcza również przykłady jak się posługiwać funkcjami w praktyce, przykłady znajdziemy zakomentowane w pliku spi2.h

W sumie mamy wszystko podane jak na tacy wystarczy tylko to próbować zrozumieć i używać :). Jeśli nie rozumiemy jak działa jakaś wygenerowana funkcja to się nie przejmować , przyjdzie czas , że kiedyś wraz z rozwojem naszej wiedzy i umiejętności otworzy się klapka w mózgu i wszystko będzie jasne jak słońce.


Funkcje , które nam się przydadzą i skorzystamy z nich przy następnym projekcie to niewątpliwie :

/*inicjalizacja SPI2*/
void SPI2_Initialize (void)

/*wyślij i pobierz jeden bajt data*/
uint8_t SPI2_Exchange8bit( uint8_t data )

/*wyślij i pobierz bajty w ilości byteCount, dane wysyłamy z bufora dataTransmitted odbieramy w dataReceived*/
uint16_t SPI2_Exchange8bitBuffer(uint8_t *dataTransmitted, uint16_t byteCount, uint8_t *dataReceived)




Pozdrawiam
picmajster.blog@gmail.com



Linki :


Brak komentarzy:

Prześlij komentarz