niedziela, 10 grudnia 2017

SPI + DMA czyli Struś pędziwiatr w akcji.

W mikrokontrolerze PIC24HJ128GP502 brakuje do pełni szczęścia jeśli chodzi o SPI , sprzętowych buforów FIFO. Ma to znaczenie kiedy wymagane są duże prędkości przesyłu danych.i wtedy rejestr przyjmujący dane na klatę czyli SPIxBUF zacznie się nie wyrabiać z przyjmowaniem danych i w efekcie  zaczniemy je gubić. Przykra sprawa.
Jeśli będą to dane np od Żony z listą zakupów na święta to sami widzicie , że kicha. Z pomocą przychodzi tutaj "Struś pędziwiatr" w postaci kanałów DMA.

Z DMA mieliśmy już randkę przy okazji tego artykułu : DMA - pokochać nieznane . Wiemy zatem z grubsza co to za zwierz i gdzie można go zastosować. Nie zdziwi nas zatem fakt, że wykorzystamy tę technologię do współpracy z SPI . Taki zabieg umożliwia  podrasowanie wydajności w komunikacji w szczególności tam gdzie wysyłane są duże ilości danych. Przyda się to również tam gdzie SPI nie ma buforów FIFO czyli w moim ulubionym 16-bitowym  PIC24HJ128GP502 w którym mamy do dyspozycji  8 kanałów DMA (DMA0...DMA7) . Aby obsłużyć komunikację dwustronną czyli odbiór i nadawanie potrzebujemy dwóch kanałów DMA.
Na przykład za pomocą kanału DMA0 zrealizujemy nadawanie czyli TX SPI, a za pomocą kanału DMA1 odbiór czyli RX SPI.

W dużym skrócie czynności jakie trzeba wykonać aby zrealizować transmisję SPI z wykorzystaniem kanałów DMA w naszym MCU to :

- utworzenie dwóch buforów, nadawczy BuforTX i odbiorczy BuforRX w wydzielonym obszarze pamięci DMA.
- konfiguracja kanałów DMA i przyporządkowanie ich do wymiany danych z SPI, DMA0 do transmisji a DMA1 do odbioru.
- konfiguracja SPI (tu nic się nie zmienia czy z DMA czy bez)
- inicjacja transmisji.

Bardzo ważnym zagadnieniem bez , którego nie wyjdzie nam transfer DMA  po SPI jest właściwa inicjacja transmisji są tu pewne niuanse.
Poniżej esencja inicjacji transferu DMA po SPI dla różnych trybów pracy:


Nas będzie interesować wariant Rx and TX in Master mode. Niuansem tutaj jest to , że aby transfer DMA odpalił to musi najpierw zaistnieć odbiór danych w rejestrze SPIxBUF. No a odbiór nie nastąpi dopóki coś Master nie wyśle :) no i masz babo placek. Musimy zatem ręcznie odpalić transmisję DMA lub wpisać coś po prostu w rejestr SPIxBUF poza percepcją DMA.

Sam proces działania z kanałami DMA jest już bardzo prosty. Dane pakujemy w BuforTX , owieramy wcześniej skonfigurowane kanały DMA i wyzwalamy ręcznie obsługę transmisji w wygodnym dla nas momencie. Po zakończonej transmisji z BuforTX co dzieje się w tle, otrzymujemy dane od Slave, które znajdziemy w BuforRX. O przyjściu danych do BuforRX poinformuje nas ładnie przerwanie od DMA1 ustawionego jako kanał do odbioru danych od SPI.

Podczas testów przesyłu danych za pomocą DMA nie udało mi się szybciej popędzić zegar SPI niż 1,250 MHz być może Slave , który chodzi bez DMA  nie wyrabiał z odsyłaniem danych do Mastera . Samo SPI bez DMA pędziłem 5 MHz i nie było tutaj problemów. Na pewno jest jakaś przyczyna tego stanu rzeczy ale zostawiam to do wyjaśnienia w przyszłości.
Drugim ciekawym zjawiskiem jest struktura odebranych danych w BuforRX, dane nadane to "ALAMAKOTA" mało ambitnie wiem :) dane odebrane to jak widzimy na obrazku poniżej : "AALAMAKOTA". Pojawia się jakieś widmo w postaci nadmiarowej pierwszej literki A , generalnie na pierwszej pozycji w BuforRX jest kopiowana ostatnia pozycja z BuforTX . Nie wiem na tym etapie czy to wynika ze specyfiki inicjacji transferu DMA po SPI czyli konieczności odebrania od Slave jednego transferu aby DMA odpaliło ? czy jest to inna kwestia. Nie mniej nie jest to szczególnie upierdliwe zjawisko i można się łatwo z nim rozprawić programowo za pomocą takiej konstrukcji w sekcji wyświetlania :
WyswietlLCD(BuforRX+1); 




Od strony sprzętowej posłużyłem się dokładnie identyczną konfiguracją jak w artykule o SPI nie będę wiec powielał schematu.

Co robi program ?

Master :
- w buforze nadawczym BuforTX umieszczamy statyczną treść "ALAMAKOTA"
Co ok 1 s
- inicjuje manualnie transfer (kanały po raz pierwszy są otwarte przy wywołaniu funkcji konfiguracyjnej)
- czeka aż transfer zostanie zakończony (tutaj kanały DMA zostaną automatycznie zamknięte)
- otwiera kanały DMA1 (skonfigurowany na odbiór danych przesyłanych po SPI od SLAVE) i DMA0 (skonfigurowany do przesyłania danych do SLAVE) oba kanały pracują w trybie OneShot.
- w tle dane z BuforTX są wysyłane do Slave  i jednocześnie wypełnia nam się bufor odbiorczy BuforRX danymi przychodzącymi od Slave
- w przerwaniu od kanału DMA1 czyli odbiorczym wyświetlamy zawartość bufora odbiorczego  BuforRX
i na końcu czyścimy zawartość bufora odbiorczego aby nie było wątpliwości jak za sekundę przyjdą te same dane.

Tu drobna uwaga , w docelowych aplikacjach staramy się unikać wyświetlania danych w przerwaniu nawet jak mamy szybki wyświetlacz.a do takich DOGM204EA się zalicza.

Slave :
Tutaj program się za dużo nie narobi. W Slave nie korzystamy z DMA.  W przerwaniu SPI sprawdzamy czy coś przyszło do rejestru SPIxBUF, jeśli tak to odsyłamy to z powrotem do Mastera.

Generalnie DMA jest fajną technologią , konfiguracja jest względnie prosta a możliwości mamy naprawdę spore, na początku możemy nie dostrzegać tego potencjału ale w miarę nabywania wiedzy na ten temat odkryjemy naprawdę fajny świat. . Jeśli nasz MCU jest wyposażony w kontroler DMA  to korzystać z tego bo warto.

Poniżej mamy link do kodu projektu na GitHubi-ie. Dwa katalogi z projektem dla MASTERA i SLAVE. Wystarczy dodać do MPLAB-X IDE, wygodniej już się chyba nie da.

Tutaj mamy kod projektu


Pozdrawiam
picmajster.blog@gmail.com

Linki :
PIC24HJ - DMA 



1 komentarz:

  1. fajnie, ale do prawdziwego SPI brakuje tu sterowania linią NCS lub SS jak kto woli, i tu się sprawa komplikuje. W autorskim rozwiązaniu cos tam przyjdzie bo druga strona wie co ma odebrać. ale już typowy sensor SPI dla którego linia NCS jest ważna nie. Trzeb aby to robić przerwaniem od SPI.

    OdpowiedzUsuń