[3] Kurs: pierwsze kroki z STM32F0DISCOVERY. Zabawy z USART

Zliczanie czasu i transmisja USART z użyciem DMA

Kolejny program będzie transmitował dane przez USART korzystając z modułu bezpośredniego dostępu do pamięci, czyli bez udziału oprogramowania w transmisji każdego bajtu. Tam razem program będzie pełnił rolę prostego timera, odliczającego czas w sekundach. Naciśnięcie przycisku umieszczonego na płytce będzie powodowało wyzerowanie i restart timera. Co jedną sekundę bieżąca wartość timera będzie transmitowana przez USART – można ją wyświetlić na PC korzystając z programu terminala. Program, powstały przez modyfikację poprzedniego przykładu, jest zawarty w projekcie UART1dma.

 

Oprogramowanie modułu USART i DMA

Moduł USART1 jest inicjowany podobnie jak w poprzednim przykładzie. Wprowadzono jedną istotną zmianę – przed finalnym uaktywnieniem USART w rejestrze CR modułu jest ustawiony bit włączający zgłaszanie żądania DMA przez nadajnik.

Na początku sekwencji inicjującej jest włączany moduł DMA – wymaga to ustawienia odpowiedniego bitu w rejestrze AHBENR modułu RCC.

Sterownik bezpośredniego dostępu do pamięci zrealizowany w STM32F05x dysponuje pięcioma kanałami transmisji. Z nadajnikiem USART1 jest związany kanał 2; programując moduł DMA będziemy używali rejestrów tego kanału, dostępnych w postaci struktury poprzez wskaźnik DMA1_Channel2.

Do jednorazowego zainicjowania modułu DMA potrzebne są dwa zapisy rejestrów adresów. Ponieważ specyfikowanie adresów jako stałych typów numerycznych generuje ostrzeżenie w ANSI C, zapisy te zostały umieszczone w funkcji main. Pełne programowanie modułu DMA do współpracy z nadajnikiem USART1 wymaga łącznie czterech operacji:

  • Ustawienia adresu początkowego bufora w pamięci, z którego będą pobierane dane, w rejestrze CMAR.
  • Ustawienia adresu rejestru danych nadajnika USART w rejestrze CMAR.
  • Ustawienia liczby transmitowanych bajtów w rejestrze CNDTR.
  • Ustawienia trybu transmisji oraz uaktywnienia kanału DMA poprzez zapis do rejestru sterującego kanału CCR bitów: inkrementacji adresu pamięci – MINC, kierunku transmisji – z pamięci do modułu peryferyjnego – DIR oraz aktywacji kanału – EN.

Z powodu wymagań standardu ANSI języka C zapis rejestrów adresowych kanału DMA następuje w funkcji main – umieszczenie go w tablicy inicjowania peryferiali spowodowałoby wygenerowanie przez kompilator ostrzeżeń o użyciu stałych wbrew standardowi.

Moduł DMA po zakończeniu transmisji zachowuje początkowe wartości rejestrów adresowych, ale wymaga zapisu długości bloku danych przed każdą transmisją. Dodatkowo rejestr długości bloku może być zapisany tylko wówczas, gdy kanał jest nieaktywny, a kanał nie deaktywuje się samoczynnie po zakończeniu transmisji bloku. Z tych powodów w procedurze obsługi przrwania timera, w miejscu, gdzie następuje uaktywnienie kanału i rozpoczęcie transmisji znalazła się sekwencja trzech instrukcji:

  • deaktywacji kanału – zapis 0 do CCR,
  • zapisu długości bloku do CNDTR,
  • powtórnej aktywacji kanału – zapis słowa sterującego do CCR.

 

Obsługa przerwania timera

Przerwanie timera generującego przebiegi PWM sterujące diodami jest zgłaszane tak samo, jak we wcześniejszych projektach, z częstotliwością 400 Hz. Jego obsługa obejmuje kilka czynności, wykonywanych z różnymi częstotliwościami:

  • płynną modyfikację wypełnień PWM dla diod – 400 Hz;
  • reakcję na przycisk zerowania timera – 100 Hz;
  • zliczanie czasu w timerze programowym i błyskanie zieloną diodą – 1 Hz.

W celu uniknięcia konwersji wartości timera z postaci binarnej na reprezentację znakową, wartość ta jest przechowywana w postaci znakowej, w tablicy znakowej timer[]. Tablica ta, o długości 8 bajtów, zawiera na pozycjach 0..5 sześć cyfr timera, a na pozycjach 6 i 7 – sekwencję końca wiersza, przesyłaną wraz z wartością timera przez łącze szeregowe.

Blok reakcji na naciśnięcie przycisku jest wywoływany, tak jak poprzednio, w co czwartym przerwaniu. W bloku tym sprawdzany jest stan przycisku oraz inkrementowany jest licznik sdiv, zliczający setne części sekundy. Przy naciśnięciu przycisku zerowany jest timer odliczający sekundy oraz licznik setnych części sekundy. Dodatkowo jest zaświecana niebieska dioda; jej wygaszanie rozpoczyna się po upływie ? sekundy po naciśnięciu przycisku. Po zinkrementowaniu licznika setnych do wartości 100 jest on zerowany oraz następuje inkrementacja timera programowego. Inkrememtacja ta jest wykonywana w prostej pętli for(). Zarówno inkrementacja, jak i wyzerowanie licznika kończy się ustawieniem zmiennej logicznej upd_time, co w dalszej części przerwania timera powoduje zainicjowanie transmisji całego bufora timera programowego przez USART.

 

Grzegorz Mazur

gbm@ii.pw.edu.pl

 

 

Do pobrania

O autorze