LABORATORIUM 4 DIRECT MEMORY ACCESS KRAKÓW, 2016
1. Direct Memory Access (DMA) Direct Memory Access (DMA) jest to moduł sprzętowy występujący zarówno w komputerach PC jak i systemach wbudowanych opartych na mikrokontrolerach, FPGA, itd. Głównym zadaniem DMA jest umożliwienie transferu danych (zarówno odczyty jak i zapisu) bez udziału procesora. Może się to odbywać po to, aby odciążyć aktualnie działający procesor lub nie wybudzać go ze stanu uśpienia w celu oszczędności energii. Schemat blokowy modułu DMA używanego podczas ćwiczenia został przedstawiony na Rysunku 1. Rysunek 1. Schemat blokowy modułu DMA Moduł DMA posiada 8 kanałów (channels) do transferu danych (numerowane 0-7) pomiędzy: a) RAM/Flash Peryferia b) Flash RAM c) Peryferia RAM Każdy kanał DMA może zostać skonfigurowany poprzez tzw. Channel descriptors oraz posiada odpowiedni priorytet ważności (kanał 0 najwyższy priorytet). Dostępne są dwie struktury konfiguracyjne dla każdego kanału: główna (primary) i alternatywna (alternate). Możliwe jest również podzielenie kanałów na dwie grupy priorytetowe, co pozwala na lepsze zarządzenie transferami DMA. DIRECT MEMORY ACCESS 2/7
Aktywacji kanałów DMA mogą dokonać zarówno peryferia takie jak USART, LEUART, TIMER, ADC, DAC; jak i kod programu, poprzez Request lines. Po wykonaniu ustalonej ilości transferów danych, moduł DMA może wybudzić procesor ze stanu uśpienia poprzez przerwanie. Dostępne są 4 tryby transferu danych przez kanały: a) Basic po aktywacji kanału wykonywany jest transfer danych. Jeżeli inny kanał o wyższym priorytecie zażąda aktywacji, DMA obsłuży jego zgłoszenie. Po wykonaniu ustalonej ilości takich transferów wykonywana jest przypisana funkcja do obsługi danych (po wybudzeniu procesora). b) Auto-request po aktywacji kanału wykonywana jest ustalona ilość transferów danych. Po wykonaniu ustalonej ilości takich transferów wykonywana jest przypisana funkcja do obsługi danych (po wybudzeniu procesora).jeżeli inny kanał o wyższym priorytecie zażąda aktywacji, DMA nie obsłuży jego zgłoszenia. Tryb ten używany jest do ograniczenia opóźnień transferu spowodowanych zgłoszeniami o wyższych priorytetach. c) Ping-pong po aktywacji kanału wykonany jest jeden cykl transferu DMA zdefiniowany przez konfigurację znajdującą się z strukturze primary, następny cykl transferu DMA jest zgodny z konfiguracją w strukturze alternate i rozpoczyna się od razu po zakończeniu pierwszego, bez potrzeby rekonfiguracji przez CPU. I tak na przemian. Rysunek 2 obrazuje ten tryb pracy. d) Scatter-gather po aktywacji kanału wykonywane są cztery transfery danych zdefiniowane przez konfigurację znajdującą się z strukturze primary, następnie za pomocą tych danych aktualizowana jest konfiguracją w strukturze alternate i rozpoczyna się transfer używając struktury alternate. Rysunek 2. Schemat działania modułu DMA w trybach: Basic, Auto, Ping-pong Dla lepszego zrozumienia analizowanego na laboratorium kodu, proszę zapoznać się z dokumentacją struktur oraz funkcji: 1. struct DMA_Init_TypeDef; 2. struct DMA_CB_TypeDef; 3. struct DMA_CfgChannel_TypeDef; 4. struct DMA_CfgDescr_TypeDef; 5. 6. void DMA_Init ( DMA_Init_TypeDef * init ); 7. 8. void DMA_CfgChannel ( unsigned int channel, DIRECT MEMORY ACCESS 3/7
9. DMA_CfgChannel_TypeDef * cfg 10. ); 11. 12. void DMA_CfgDescr ( unsigned int channel, 13. bool primary, 14. DMA_CfgDescr_TypeDef * cfg 15. ); 16. 17. void DMA_ActivateBasic ( unsigned int channel, 18. bool primary, 19. bool useburst, 20. void * dst, 21. void * src, 22. unsigned int nminus1 23. ); 2. Opis ćwiczenia Ćwiczenie ma na celu zaznajomienie z funkcjonalnością modułu DMA w mikrokontrolerze EFM32 oraz możliwościami oszczędzania energii w aplikacji poprzez użycie DMA do pewnych zadań. Platformą sprzętową do testów jest płytka STK3700 z mikrokontrolerem EFM32 GG na pokładzie. Mikrokontroler posiada kontroler µdma licencjonowany od ARM. Z pomocą zintegrowanego środowiska programistycznego IDE tworzone oraz wgrywane będą poszczególne aplikacje do mikrokontrolera. Środowisko pozwala na debugowanie krok po kroku działania programów. Dodatkowo, użyte zostanie oprogramowanie Energy Profiler do rejestracji oraz analizy zużycia energii przez mikrokontroler oraz peryferia w trakcie wykonywania wgranej aplikacji. Krokowanie programu w powiązaniu z obserwacją zużycia energii w czasie rzeczywistym umożliwia tzw. debugowanie energetyczne bardzo ważne podczas projektowania urządzeń o niskim poborze energii, w szczególności urządzeń zasilanych bateryjnie. Rysunek 3. Cykl tworzenia oprogramowania niskoenergetycznego systemu wbudowanego DIRECT MEMORY ACCESS 4/7
3. Analiza trybów transferu DMA W tej części ćwiczenia będziemy obserwować i analizować działanie oraz pobór energii w aplikacjach używających różnych trybów modułu DMA. Należy podłączyć płytkę STK3700 do komputera, włączyć zintegrowane środowisko programistyczne IDE i aplikację Profiler, otworzyć odpowiedni przykład i wgrać go do mikrokontrolera. a) Flash transfer (Auto-request) W ćwiczeniu użyto modułu DMA do transferu bloku danych z pamięci Flash do pamięci RAM. Po ukończonym przesyłaniu następuje wykonanie funkcji obsługi. Tryb Auto-request gwarantuje nie przerywanie transferu w przypadku, kiedy zgłoszona została chęć aktywacji kanału DMA o wyższym priorytecie. Proszę zaobserwować i przeanalizować pobór energii w poszczególnych momentach pracy programu. b) ADC transfer (Basic) W ćwiczeniu użyto modułu DMA do transferu danych z przetwornika ADC do pamięci RAM. Gdy w buforze ADC znajduje się wartość przetworzonej próbki, dana ta jest przesyłana przez kanał DMA do pamięci RAM. Po ukończonym przesyłaniu ustalonej liczby próbek następuje wykonanie funkcji obsługi. W przykładzie, przetwornik ADC wyzwalany jest synchronicznie przez licznik TIMER. Proszę zaobserwować i przeanalizować pobór energii w poszczególnych momentach pracy programu. c) ADC transfer (Ping-pong) W ćwiczeniu użyto modułu DMA do transferu danych z przetwornika ADC do pamięci RAM w trybie Ping-pong w celu maksymalizacji częstotliwości próbkowania przetwornika ADC. Gdy kończy się główny cykl DMA, procesor jest wybudzany w celu przetworzenia danych przeniesionych do pamięci RAM, a DMA bez żadnych opóźnień działa nadal, zgodnie z konfiguracją alternatywną. Dzięki takiej konfiguracji modułu można zachować stałą, dużą częstotliwość próbkowania. Proszę zaobserwować i przeanalizować pobór energii w poszczególnych momentach pracy programu. d) Scatter-gather transfer W ćwiczeniu użyto modułu DMA do trzech sekwencyjnych transferów danych. Główna konfiguracja transferuje nową konfigurację do struktury alternatywnej, na podstawie której dokonywane są kolejne transfery. Gdy kończy się główny trzy-sekwencyjny cykl DMA, procesor jest wybudzany w celu przetworzenia danych, a następnie wchodzi w pętlę while(1). Proszę zaobserwować i przeanalizować pobór energii w poszczególnych momentach pracy programu. DIRECT MEMORY ACCESS 5/7
4. Analiza konfiguracji i działania kanału DMA oszczędzanie energii W ćwiczeniu nauczymy się konfigurować moduł DMA, aby jak najwięcej operacji dokonywało się bez użycia procesora, w celu oszczędności energii w aplikacji. Jako przykład weźmy sytuację w której mamy obliczać ile znaków x zawiera sekwencja 10 znaków przychodząca przez UART (9600 baud). Pierwsza wersja kodu takiego rozwiązania jest poprawna funkcjonalnie, jednak zużywa bardzo dużo energii. Proszę zaobserwować i przeanalizować pobór energii w poszczególnych momentach pracy programu. W drugiej wersji użyjemy niskoenergetycznego modułu LEUART, trybów uśpienia oraz modułu DMA do transferu danych. Dopiero po 10 otrzymanych znakach, procesor zostanie wybudzony w celu obliczenia ilości występowania znaku x. a) Podstawowa konfiguracja Proszę przeanalizować kod konfiguracyjny w pliku źródłowym. b) Konfiguracja z użycie modułu DMA Kod należy napisać tak, aby mikroprocesor był w możliwie jak najniższym trybie uśpienia (jednocześnie aplikacja musi zachować swoją funkcjonalność). Moduł DMA można zainicjalizować w następujący sposób: 1. /**************************************************************************//** 2. * @Inicjalizacja DMA 3. *****************************************************************************/ 4. void dmaexampleinit(void){ 5. /* Ustawianie parametrów DMA */ 6. dmainit.hprot = 0; // 7. dmainit.controlblock = dmacontrolblock; 8. /* Inicjalizacja DMA */ 9. DMA_Init(&dmaInit); 10. /* Inicjalizacja kanału */ 11. DMACh0_Init(); 12. } Wystarczy aktywować tylko jeden kanał DMA do przesyłania danych odebranych przez LEUART do pamięci RAM: 1. /**************************************************************************//** 2. * @brief Inicjalizacja kanalu 0 3. *****************************************************************************/ 4. void DMACh0_Init(void) 5. { 6. DMA_CfgChannel_TypeDef chnlcfg; 7. DMA_CfgDescr_TypeDef descrcfg; 8. LEUART_TypeDef *leuart = LEUART_USED; 9. 10. /* Ustawienie funcji obsługi po zakończeniu cyklu DMA */ 11. cb[dma_channel_leuart_rx].cbfunc = Ch0_TransferComplete; 12. cb[dma_channel_leuart_rx].userptr = NULL; 13. 14. /* Ustawianie parametrów kanału 0 */ 15. chnlcfg.highpri = false; 16. chnlcfg.enableint = true; 17. chnlcfg.select = DMAREQ_LEUART0_RXDATAV; 18. chnlcfg.cb = &(cb[dma_channel_leuart_rx]); 19. DMA_CfgChannel(DMA_CHANNEL_LEUART_RX, &chnlcfg); DIRECT MEMORY ACCESS 6/7
20. 21. /* Konfiguracja kanału 0 */ 22. descrcfg.dstinc = dmadatainc1; // inkrementacja adresu docelowego 23. descrcfg.srcinc = dmadataincnone; // inkrementacja adresu źródłowego 24. descrcfg.size = dmadatasize1; // rozmiar danej do transferu 25. descrcfg.arbrate = dmaarbitrate1; // co ile ma się odbywac arbitraż 26. descrcfg.hprot = 0; 27. DMA_CfgDescr(DMA_CHANNEL_LEUART_RX, true, &descrcfg); 28. 29. /* Aktywacja kanału 0 DMA */ 30. DMA_ActivateBasic(DMA_CHANNEL_LEUART_RX, 31. true, 32. false, 33. (void *)&bufor, // adres docelowy 34. (void *)&(leuart->rxdata), // adres źródłowy 35. 9); // ile danych ma byc przesłanych w 1 cyklu (n-1) 36. } Po odebraniu 10 znaków wybudzany jest procesor i realizowana jest funkcja obliczająca ilość znaków x w otrzymanej 10 znakowej sekwencji, a następnie wyświetlana jest na wyświetlaczu LCD: 1. /**************************************************************************//** 2. * @brief Funcja obsługi po zakończeniu cyklu DMA 3. *****************************************************************************/ 4. void Ch0_TransferComplete (unsigned int channel, bool primary, void *user) 5. { 6. /* Obliczenie i wywietlenie iloci znaków 'x' na 10 znaków które przyszły */ 7. uint8_t counter=0, i; 8. for(i=0;i<10;i++) 9. { 10. if(bufor[i]=='x') 11. counter++; 12. } 13. SegmentLCD_Number(counter); 14. /* Reinicjalizacja DMA */ 15. Ch0_Reset(); 16. } 17. 18. /**************************************************************************//** 19. * @brief Reinicjalizacja DMA 20. *****************************************************************************/ 21. void Ch0_Reset(void) 22. { 23. LEUART_TypeDef *leuart = LEUART_USED; 24. 25. DMA_ActivateBasic(DMA_CHANNEL_LEUART_RX, 26. true, 27. false, 28. (void *)&bufor, // adres docelowy 29. (void *)&(leuart->rxdata), // adres źródłowy 30. 9); // ile danych ma byc przesłanych w 1 cyklu (n-1) 31. } Proszę uzupełnić oraz skompilować kod, wgrać go do mikrokontrolera, uruchomić i zrobić bilans zaoszczędzonej energii w stosunku do podstawowego kodu. DIRECT MEMORY ACCESS 7/7