Jak zoptymalizować obsługę SPI, aby osiągnąć wysoką przepustowość ADC

| Technika

W przypadku aplikacji Internetu Rzeczy wraz z rozwojem technologii przetwarzania brzegowego danych oraz rozwiązań działających w chmurze rośnie potrzeba realizacji niskoenergetycznej transmisji danych z precyzyjnych czujników. Na rysunku 1 pokazano bezprzewodowy system monitoringu i gromadzenia danych z 24-bitowym przetwornikiem analogowo-cyfrowym. Zapewnia on dużą precyzję pomiaru, ale przy takim formacie danych problemem jest to, czy mikrokontroler obsłuży szybką transmisję szeregową danych z przetwornika podczas pomiarów w trybie ciągłym.

Jak zoptymalizować obsługę SPI, aby osiągnąć wysoką przepustowość ADC

W artykule opisano proces projektowania szybkiego interfejsu SPI działającego między mikrokontrolerem a ADC oraz zaprezentowano sposoby optymalizacji SPI podczas współpracy przetwornika ADC i MCU. Pokazano przykładowy kod obsługi transmisji danych po SPI i z dostępem przez DMA. Na koniec omówiono osiągnięte rezultaty w zakresie przepustowości ADC z tym samym driverem i dwoma różnymi MCU (ADuCM4050, MAX32660).

General SPI Driver

Producenci mikrokontrolerów dostarczają typowe rozwiązanie sterownika SPI/API (General SPI Driver) w postaci przykładowego kodu. Zwykle wystarcza on do obsługi większości typowych aplikacji, ale w niektórych przypadkach, takich jak akwizycja danych z użyciem wysokorozdzielczego ADC, typowy sterownik SPI może nie zapewnić pełnej przepustowości odbierania danych, ponieważ ma on zbyt ogólną funkcjonalność, czyli zaimplementowano w nim zbyt wiele różnych konfiguracji. I te konfiguracje, które nie są do niczego potrzebne w aplikacji, powodują dodatkowe narzuty czasowe i opóźnienie przekładające się na szybkość komunikacji.

Aby odebrać dane pomiarowe z ADC przez SPI, hostem jest MCU ze względu na jego małe zużycie energii i dużą szybkość. Jednak, gdy wymiana danych wykorzystuje driver ADI SPI, prędkość maksymalna może zostać obniżona z powodu zaimplementowania poleceń, które nie są wykorzystywane w połączeniu ADC-MCU. W przypadku mikrokontrolera ADuCM4050 i przetwornika AD7768-1, pomimo maksymalnej wyjściowej szybkości transmisji danych wynoszącej 256 kHz (przy domyślnym filtrze), ADuCM4050 działa z maks. szybkością do 8 kHz. Stąd przyspieszenie musi obejmować usunięcie z kodu zbędnych fragmentów oraz także aktywację kontrolera DMA.

 
Rys. 1. Schemat blokowy systemu pomiarowego z przetwornikiem ADC o dużej precyzji
 
Rys. 2. Konfiguracja API w typowym sterowniku
 
Rys. 3. ODR-y i ich związek z DRDY i SCLK

MCU jako host i ADC jako node

Mikrokontroler ADuCM4050 to jednostka z rdzeniem Arm Cortex-M4F o bardzo małym poborze mocy taktowana zegarem 26 MHz. ADuCM4050 zawiera trzy bloki SPI, a każdy z nich ma dwa kanały DMA na odbiór i nadawanie, które są obsługiwane przez kontroler. Kontroler DMA umożliwia przesyłanie danych między pamięcią a urządzeniami peryferyjnymi bez udziału MCU. Jest to skuteczny sposób na obsługę paczek danych, który uwalnia rdzeń od tego zadania.

AD7768-1 to 24-bitowy przetwornik A/C sigma-delta (Σ-Δ) o małym poborze mocy i dużej wydajności. Jego wyjściową szybkość transmisji danych (ODR) i pobieraną moc można regulować w zależności od wymagań aplikacji. Współczynnik decymacji i tryb poboru mocy razem definiują parametr ODR, jak pokazano w tabeli 1.

Ważną cechą AD7768-1 jest również tryb odczytu ciągłego. Dane wyjściowe ADC są wtedy zapisywane do rejestru 0x6C. Co do zasady, pobieranie danych wymaga wybrania adresu rejestru i następnie wywołania odczytu. Tryb pracy z ciągłą akwizycją umożliwia pobieranie danych z rejestru 0x6C po każdym pojawieniu się sygnału gotowości oznaczającego zakończenie konwersji. Dane wyjściowe ADC to 24-bitowe liczby, które dalej konwertuje się na napięcie, jak pokazano w tabeli 2.

 
Rys. 4. Schemat połączenia pinów interfejsowych dla AD7768-1 i ADuCM4050

Schemat połączenia przetwornika i mikrokontrolera pokazano na rysunku 4. Sygnał resetu dla tych chipów jest wysyłany z GPIO28 MCU, który trafia do ADC RST_1, a sygnał gotowości danych dostępny na ADC DRDY_1 trafia do GPIO27 MCU. Pozostałe piny są połączone w typowy dla SPI sposób, gdzie MCU jest hostem, a ADC jest węzłem. SDI_1 odbiera polecenia odczytu/zapisu rejestru ADC z MCU, a DOUT_1 wysyła dane wyjściowe do MCU.

Realizacja transmisji danych

 
Rys. 5. Obsługa przetwornika pracującego w trybie ciągłym musi się zmieścić między dwoma kolejnymi przerwaniami DMA w trybie basic

Aby zrealizować ciągły proces odczytu danych, używany jest GPIO27 (podłączony do DRDY) jako wejście przerwania. Kiedy ADC wystawi sygnał gotowości danych na GPIO27, MCU uruchamia procedurę odczytu. Jak pokazano na rysunku 5, akwizycja danych musi zostać obsłużona w czasie między kolejnymi przerwaniami A i B.

Jak wspomniano, z użyciem SPI można łatwo zrealizować odczyt danych z ADC, jednak ODR jest wówczas ograniczony do 8 kHz z powodu nadmiarowego kodu drivera zapewniającego mu uniwersalność. Aby przyspieszyć odczyt proces, w takiej sytuacji ogranicza się długość słowa danych (przycina kody), ale można też użyć DMA: w trybie podstawowym (basic) i ping-pong.

 
Rys. 6. Kod obsługi transferu DMA w trybie basic

Przed każdą operacją z użyciem DMA wymagane jest dokonanie ustawień rejestrów (patrz przykładowy kod na rys. 6). Konfigurację SPI ustawia się w SPI_CTL (0x280f początkowo), a SPI_CNT determinuje liczbę bajtów do przesyłania. Ponieważ każda operacja na DMA może skutkować przesłaniem 16 bitów, SPI_CNT musi być wielokrotnością 2. W omawianym przypadku wybrano SPI_CNT=4, aby pokryć 24-bitowe słowo danych ADC. Rejestr SPI_DMA włącza DMA, tj. SPI_DMA=0x5 włącza odbieranie żądania DMA; pADI_DMA0 -> EN_SET=(1<<5) włącza DMA piątego kanału DMA – SPI0 RX.

Każdy kanał DMA ma przypisany rejestr struktury DMA jak w tabeli 3. Należy zauważyć, że adres końca danych źródłowych (SPI0 Rx) nie wymaga inkrementowania przy użyciu DMA, ponieważ Rx FIFO automatycznie wysyła dane z rejestru. Z drugiej strony wskaźnik adresu końca miejsca docelowego jest obliczany jako adres docelowy + SPI_CNT -2. Bieżący adres tutaj jest wskaźnikiem wewnętrznej tablicy. Konfiguracja danych kontrolnych DMA obejmuje ustawienia rozmiaru danych źródłowych, skoku adresów źródłowego i docelowego, liczby pozostałych transferów oraz trybu DMA. Wartość 0x4D000011 ustawia konfigurację zgodnie z opisem w tabeli 4.

Za pomocą pustego polecenia odczytu SPI_SPI0 –> RX rozpoczyna się taktowanie SCLK, a dane wyjściowe są przesyłane z ADC do MCU przez linię MISO. Po zapełnieniu bufora FIFO Rx generowane jest żądanie DMA, aktywujące kontroler DMA w celu przesłania danych ze źródła (to znaczy SPI0 Rx FIFO) do miejsca docelowego DMA (czyli wewnętrznego bufora w formie tabeli). Warto zauważyć, że żądanie Tc jest generowane przy SPI_DMA=0x3. W końcu adres docelowy dla następnej 4-bajtowej transmisji jest zapamiętywany przez dodanie 4 do bieżącego adresu docelowego.

Należy również pamiętać, że zarówno pADI_DMA0->DSTADDR_CLR, jak i pADI_DMA0- >RMSK_CLR dla kanału SPI0 DMA musi zostać ustawiony w funkcji main przed wystąpieniem pierwszego przerwania. Rejestr DMA Channel Destination Address Decrement Enable Clear ustawia przesunięcie adresu docelowego po każdym transferze DMA w trybie inkrementacji, a DMA Channel Request Mask Clear kasuje flagę żądania dostępu DMA dla kanału.

Wykres czasowy dla transferu DMA w trybie basic przedstawiono na rysunku 7a. Sloty czasowe reprezentują odpowiednio sygnał DRDY, ustawienia SPI/ DMA i transfer danych DMA. W czasie gdy kontroler DMA realizuje przesyłanie danych, warto przypisać jakieś inne zadania procesorowi, np. obróbkę poprzednich wyników.

 
Rys. 7. Wykres czasowy dla (a) podstawowego trybu DMA i (b) trybu ping-pong

DMA w trybie ping-pong

Po wykonaniu za pomocą pustego polecenia odczytu kontroler DMA rozpoczyna transfer danych bez angażowania MCU. Oznacza to, że procesor i kontroler DMA mogą działać jednocześnie, realizując równoległą obsługę zadań. Takie działanie umożliwia tryb pracy ping-pong. Obejmuje on podstawową i alternatywną strukturę DMA i kontroler automatycznie przełącza się między nimi przy każdym żądaniu dostępu; p= 0 wybiera strukturę pierwotną, p=1 alternatywną. Dla p = 0, transfer danych rozpoczyna się od pustego polecenia odczytu, a dla p=1 nastąpi to automatycznie przy kolejnym przerwaniu oraz dla p=1 struktury zamieniają się miejscami po każdej operacji. Z tego powodu korzystanie z trybu ping-pong umożliwia procesorowi dostęp i zapis danych w alternatywnej strukturze DMA, podczas gdy podstawowa jest odczytywana przez kontroler DMA i odwrotnie. Jak pokazano na rysunku 7b, transfer danych DMA może zostać przeprowadzony wkrótce po przesłaniu sygnału DRDY z ADC do MCU, ponieważ konfi- guracja struktury DMA jest wykonywana w ostatnim cyklu. Procesor i DMA działają teraz jednocześnie. Taka właściwość umożliwia "dostrojenie" parametru ODR dla ADC, ponieważ całkowity czas operacji przesyłania danych został znacznie skrócony.

Optymalizacja procedur obsługi przerwań

 
Rys. 8. Kontroler przerwań NVIC

Okres między wystawieniem sygnału gotowości danych obejmuje nie tylko czas niezbędny do wykonywania poleceń funkcji callback, ale niezbędny do obsłużenia przerwania z linii GPIO.

 
Rys. 9. Δt dla (a) trybu podstawowego DMA, (b) trybu ping-pong i (c) trybu ping-pong ze zoptymalizowaną obsługą przerwań

Podczas aktywacji MCU uruchamia plik startowy (startup.s), w którym są zdefiniowane procedury obsługi zdarzeń, w tym obsługa przerwań zgłaszanych przez GPIO. Gdy takie zdarzenie się pojawi, wykonywana jest funkcja GPIO_A_ INT_HANDLER i odpowiednio GPIO_ -B_INT_HANDLER w driverze). Procesor odpytuje wszystkie piny GPIO, aby ustalić, które jest źródłem przerwania, kasuje flagę statusu i uruchamia zarejestrowaną funkcję callback. W omawianym przykładzie ADC-MCU DRDY jest jedynym źródłem przerwania, stąd można wyciąć z procedury callbacku niepotrzebny kod. Możliwe rozwiązania obejmują (1) retargetowanie w pliku startowym i (2) modyfikację oryginalnego programu obsługi przerwań. Retargetowanie oznacza samodzielne zdefiniowanie procedury obsługi przerwań i zastąpienie oryginalnego kodu w pliku startowym.

Z drugiej strony modyfikacja wymaga użycia samodzielnie zdefiniowanego sterownika GPIO. Wybieramy tę drugą opcję i modyfikujemy funkcję jak na Rys. 10. Parametr ODR dla MAX32660 bez DMA rysunku 8, gdzie kasuje ona tylko flagę przerwania dla pinu podłączonego do DRDY i przechodzi bezpośrednio do callbacka. Należy pamiętać, że oryginalny sterownik GPIO musi zostać zablokowany w czasie kompilacji.

 
Rys. 10. Parametr ODR dla MAX32660 bez DMA

Poprawa szybkości

Załóżmy, że odczytujmy 200 24-bitowych danych z ADC, a szybkość taktowania SPI jest ustawiona na 13 MHz. Podłączamy pin z sygnałem DRDY i SCLK do oscyloskopu i dzięki temu z okresu między sygnałem DRDY a rozpoczęciem transferu danych SPI (również DMA) możemy ocenić poprawę prędkości. Dla wygody okres od DRDY do SCLK określamy jako Δt. Dla taktowania SPI 13 MHz zmierzone Δt wynoszą:

  1. Tryb podstawowy DMA Δt = 3,754 μs
  2. Tryb ping-pong DMA Δt = 2,8433 μs
  3. DMA w trybie ping-pong ze zoptymalizowaną obsługą przerwań Δt = 1,694 μs

Podejścia (a) i (b) wystarczą dla ODR 64 kHz, a (c) do 128 kHz, bo mały Δt umożliwia wcześniejsze zakończenie SCLK. W porównaniu z ODR równym 8 kHz sterownika ADI SPI można to postrzegać jako ogromny postęp.

MAX32660 z AD7768-1

Dla układu mikrokontrolera MAX- 32660 taktowanego zegarem 96 MHz dzięki optymalizacji obsługi przerwań można uzyskać wyjściową szybkość transmisji danych 256 kHz bez DMA. Patrz rysunek 10.

Dzięki optymalizacji pracy SPI i użyciu DMA można osiągnąć dużą szybkość akwizycji danych z użyciem wysokorozdzielczego przetwornika ADC i zapewnić niezależne działanie procesora podczas transferu. Najlepszy wynik to ODR = 128 kSPs przy przepływności SPI 13 MHz (tab. 5).

 

Denny Wang, Sally Tseng, ADI


Arrow Electronics Poland
tel. 22 558 82 66
www.arrow.com