piątek, 25 stycznia 2019

ATSAML21 - rozpoznajemy moduł TC , a podobno szczęśliwi czasu nie liczą.

Kontynuujemy dobrą passę w poznaniu mikrokontrolerów ATSAM. W artykule zajmiemy się rozpoznaniem modułu peryferyjnego  TC (Timer/Counter), jaki został zaimplementowany w   ATSAML21/D21. Jest to jeden z dwóch (nie liczę SysTick-a i RTC) dostępnych modułów czasowych w naszym procku. Drugim jest bardziej rozbudowany TCC (Timer/Counter for Control Applications) ale tym się na razie zajmować nie bedziemy co by nas głowa nie rozbolała. Do ćwiczeń będziemy potrzebować płytki developerskiej, programatora (ja używam J-LINK EDU mini) oraz środowiska SEGGER. Nie używamy ASF (jest to ważna infomacja dlatego powtarzam ją ciągle).


W artykule przyjmę konwencję taką jak w artykule o SPI. Czyli pokażę dokładnie drogę jaką sam przeszedłem aby poznać dane peryferium w ATSAM-ach i uzyskać zamierzony efekt. A zamierzonym efektem niech będzie togglowanie diody LED z użyciem timera zbudowanego w oparciu o moduł peryferyjny TC.
Wiem , że osobom początkującym trudno jest odnaleźć się w gąszczu nowych zagadnień dotyczących poznawanego MCU, nie mają wprawy ,nie mają doświadczenia ale mają chęci. Z reguły dostępne informacje to już gotowe rozwiązania ale jaką drogą do nich dotrzeć tego nikt nie pokazuje. A czasami chcemy wiedzieć jak powstał kotlet schabowy podany na nasz talerz :) tym bardziej, że nam bardzo smakuje. Pisząc ten artykuł sam się uczę.

No dobra koniec pustosłowia bierzemy się za robotę. Na wstępie informacja : w module TC znajdziemy 5 x 16-bitowych Timerów , każdy z nich możemy konfigurować jako 8, 16 lub 32 bitowy. Zaczynam tak jak w przypadku z SPI od schematów blokowych serwowanych przez ATMEL START. Tworzę nowy projekt w tej aplikacji webowej dla MCU ATSAML21G18B. Na tym etapie jeszcze nie przeczytałem rozdziału o TC z datasheet. W zakładce zegara szukam modułu o nazwie TC. Nie znajduję takiego modułu tylko Timer.  Wybieram ten Timer i wyskakuje mi bloczek z podpiętym zegarem RTC ustawionym na 32kHz :

Coś słabo, wolałbym podpiąć ten blok do szybszego zegara , próbuję go zatem podpiąć do Generatora nr 0. I pupa blada nie mogę tego zrobić. Coś mi się wydaje , że ten Timer  nie jest tym czego szukam . Wracam zatem do komponentów i tam znajduję PWM, pobieram ten komponent. Komponent PWM jest podłączony już do Generatora nr 0. Wewnątrz bloczek ma podłączenie opisane jako TC, więc chyba bingo. Zauważmy, że w komponentach brakuje modułu TC co pokazuje jak ten cały ekosystem ASF ukrywa przed użytkownikiem prawdziwą budowę MCU.


No to mamy obrazek z podłączonym PWM , który jak się domyślamy opiera się o moduł TC a upewniamy się o tym jak wejdziemy w zakładkę DASHBOARD i bloczek PWM. Dla mnie kluczową informacją wynikającą ze schematu blokowego zegara jest to , jakich moduł TC potrzebuje zegarów do pracy i gdzie to ewentualnie podpiać. Widzę zatem, że moduł TC muszę podpiąć do Generatora nr 0 (mogę sobie wybrać inny Generator ale tak proponuje na starcie  ATMEL START) i do bloku opisanego jako CPU. Z artykułu o SPI wiemy już, że Generatory znajdują się w module zegarowym GCLK a bloczek CPU to moduł zegara MCLK. Zatem czynności jakich się spodziewamy zgrubnie w ustawieniach zegara to :
  • włączenie kanału zegarowego dla modułu TC
  • podpięcie kanału zegarowego TC do Generatora nr 0 w module GCLK
Teraz pora na zajrzenie do datasheet i zobaczenie co tam jest na temat zegarów dla modułu TC. Wchodzimy do rozdziału o TC i widzimy następujący opis:


Z opisu dowiadujemy się m.in tego, że  TC0 i TC1 oraz TC2 i TC3 są sparowane z punktu widzenia zegara. Co oznacza, że dla każdej z tych par można przyłożyć tylko jeden wspólny zegar. Odnośnie samych zegarów dowiadujemy się , że moduł TC potrzebuje do pracy dwóch zegarów :
  • CLK_TCx_APB - TC bus clock
  • GCLK_TCx - TC generic clock
No to się cieszymy , że tylko dwóch :) Pierwszego zegara szukam w module zegarowym core czyli MCLK. Wchodzę do tabelki z rejestrami tego modułu i szukam czegoś co by przypominało  CLK_TC0_APB. Do ćwiczeń wykorzystam TC0, w sumie mamy dostępnych 5 timerów w module TC.


W tabelce znajdujemy rejestr  APBCMASK a w nim pole bitowe TC0. Wchodzimy do opisu tego rejestru :


Widzimy , że aby włączyć zegar na szynie APB Bridge C dla TC0 trzeba tam ustawić wartość 1 . Taka wartość jest na starcie w tym polu, więc nic nie musimy robić tutaj.

Zajmujemy się zatem drugim zegarem czyli GCLK_TCx - TC generic clock
Tu wiemy, że musimy włączyć kanał sparowany z TC0 i podpiać go do Generatora nr 0.
Wchodzimy do spisu rejestrów modułu GCLK, rejestry GENCTRLn nas tam nie interesują bo Generator nr 0 do którego podpięty jest nasz TC jest na starcie uruchomiony i skonfigurowany. Interesuja nas rejestry PCHCTRLn Tutaj musimy ustalić do jakego kanału jest sparowany moduł TC0. Wchodzimy do opisu dowolnego rejestru PCHCTRLn i znajdujemy tam tabelkę opisaną jako Table 17-9. PCHCTRLm Mapping:


Z tabelki odczytujemy, że TC0 sparowane jest z kanałem nr. 27. Zatem nasz docelowy rejestr w module zegarowym GCLK w którym musimy coś zmienić jest PCHCTRLn27. Wchodzimy do opisu tego rejestru :


Interesują nas tylko pola bitowe CHEN i GEN . Pierwsze pole włącza kanał dystrybucji zegara a drugie ustala do którego Generatora kanał będzie podpięty.
My musimy podpiąć się do Generatora nr 0 czyli wartosć zero w polu GEN
Widzimy, że taka wartość jest domyślna dla tego pola. Czyli nie musimy nic wpisywać. Jedynym wpisem będzie 1 w polu CHEN czyli włączenie kanału.
Zapis symboliczny jaki musimy zrobić to :

PCHCTRL27 --> CHEN --> 1   

I to w zasadzie wszystko jeśli chodzi o uruchomienie zegara dla naszego TC0. Proste jak świński ogon. Na początku w obcowaniu z ATSAM-ami może trochę przerażać to kombinowanie z ustawieniami zegara, cały ten kram Generatorów , kanałów etc. Zapewniam jednak, że jak raz się zatrybi tę specyfikę konfiguracji zegara w ATSAM to potem to już tylko rutyna i nic więcej. I nie ma czym się zrażać bo nie warto.
Zegar mamy teraz to już powinno być z górki. Spodziewamy sie ogólnie następujących czynności , które musimy zrobić :
  • jakaś lekka konfiguracja timera , trybu pracu , preskalera etc.
  • ustalenie wartości Compare (chcemy uzyskać "tykanie" co 10 ms)
  • włączenie Timera
  • włączenie przerwań
Wertujemy sobie rozdział o TC w datasheet a na koniec wchodzimy do spisu rejestrów. Tam widzimy podział na trzy tabelki w zależności od trybu : 8 ,16, lub 32 bit Mode. My sobie wybieramy tabelkę z rejestrami dla 16-bit Mode, wydaje mi się , że taki tryb powinien być ustawiony po starcie MCU.


Wchodzimy sobie kolejno do rejestrów modułu TC w trybie 16-bit Mode i patrzymy co może nam się przydać.
Ja wybrałem takie rejestry i pola bitowe w których być może coś trzeba będzie pogrzebać :

CTRLA pole :
PRESCALER - dzielimy zegar wejściowy przez dostępną wartość
MODE - wybieramy tryb 8 lub 16 lub 32 bit timera. Jak słusznie podejrzewałem na starcie mamy  16-bit Mode i przy takim pozostajemy
ENABLE - jak sama nazwa wskazuje robimy tutaj ON/OFF naszego timera.

INTENSET pole :
MCx - włącza przerwanie od porównania wartości licznika z wartością compare ustawioną w polu CCx

COUNT pole :
COUNT - aktualna wartość licznika, przed startem timera w trybie compare warto wyzerować.

CCx pole : (x = 0,1 bo mamy dwa kanały do dyspozycji w jednym TC)
CC - tu wpisujemy wartość do porównania z tykającym licznikiem , jeśli zachodzi równość to generowane jest przerwanie. 

Teraz musimy sobie powyliczać wartości jakich użyjemy w preskalerze i w CC.
Zegar na wejściu mamy 4MHz. Czas po którym zostanie wygenerowane przerwanie w trybie compare przyjmujemy 10 ms. Wiemy że CC, mamy 16-bitowe czyli maksymalnie zapiszemy tam wartość  65535. Policzmy sobie trochę :

10ms = 0,01 s = 1/100 = 100 Hz i to nazwijmy Ftimer

A teraz fajny wzorek :

CCvalue = (Fclk / Prescale) / Ftimer)

Fclk = GCLK_TC = 4MHz (tak mamy ustawione po starcie MCU) 

Ftimer - częstotliwość z jaką generowane będzie przerwanie, my chcemy aby to było co 10ms czyli 100 Hz.

Zatem wartość jaką trzeba wpisać w rejestr CCx zakładając prescaler = 1 to (4000000 / 1)/100 = 40000

Zatem zapis do rejestru CCx powinien wyglądać tak : 

CC0 --> CC --> 40000

Pozostałe wpisy , które będą potrzebne do pracy naszego modułu TC to :

CTRLA --> ENABLE --> 1 / włącz moduł TC
INTENSET --> MC0 --> 1 / włącz przerwanie od Compare
COUNT --> COUNT --> 0 / zeruj licznik

Podsumujmy zatem wszystkie wpisy , które zastosujemy w programie  aby uruchomić moduł TC , który będzie nam zgłaszał przerwanie co 10 ms. Kolejność nie jest przypadkowa.

PCHCTRL27 --> CHEN --> 1 / włącz kanał dystrybucji zegara dla TC0
CC0 --> CC --> 40000 / ustaw wyliczoną wartość dla 10ms
COUNT --> COUNT --> 0 / zeruj licznik
INTENSET --> MC0 --> 1 / włącz przerwanie od Compare
CTRLA --> ENABLE --> / włącz moduł TC

Zbliżamy się do końca. Potrzebujemy jeszcze uruchomić przerwanie od modułu TC w module przerwań rdzenia NVIC. Przerwania w Cortexach to prosta sprawa . Funkcje obsługujące przerwania znajdują się w pliku nagłówkowym core_cm0plus.h. Ale nawet i tam nie musimy zaglądać wystarczy wpisać w polu edycyjnym programu NVIC a środowisko SEGGER rozwinie nam opcje z dostępnymi funkcjami. Zobaczymy tam m.in taką funkcję jak np NVIC_EnableIRQ() poniżej obrazek :


tylko skąd wziąć argument dla funkcji  NVIC_EnableIRQ() ? Otwieramy plik nagłówkowy saml21g18b.h i tam znajdujemy te argumenty :


Zwracam uwagę , że mamy dwa pliki saml21g18b.h o tej samej nazwie , wydawać by się mogło , że to jakś babol ale nic z tych rzeczy nazwy te same ale zawartość różna w jednym  znich znajdziemy obrazek jak powyżej .
Zatem aby włączyć przerwanie od peryferium TC użyjemy takiego zapisu :

NVIC_EnableIRQ(TC0_IRQn);

Jest jeszcze jedna droga pozyskania informacji o postaci argumentu dla funkcji NVIC mianowicie datasheet na stronie 53,54 w rozdziale Processor and Architecture. Ostatnia rzecz jaka nam została do ustalenia, to jaką nazwę będzie miała funkcja przerwania . Tutaj mają zastosowanie tzw funkcje "uchwyty" od peryferium . Nazwy tych funkcji  znalazłem w prawym okienku środowiska CPU Support --> ATMEL SAM-L CPU Support Package --> System Files --> ATSAML21G18B Vector Table



W naszym przypadku nazwa funkcji przerwania będzie wyglądać tak :

void TC0_IRQHandler(void);

Jest jeszcze jeden aspekt związany z uchwytami i przerwaniami . Mianowicie w środku funkcji "uchwytu" dobrą praktyką jest sprawdzenie co było przyczyną wywołania funkcji przerwania, bo przyczyny mogą być różne. My musimy sprawdzić czy w czasie wywołania funkcji TC0_IRQHandler() ustawiona została flaga MC0 w rejestrze INTFLAG modułu TC. Jeśli tak to znaczy , że przerwanie wyzwolił moduł TC pracujący w trybie compare i nastąpiła równość licznika z wartością wpisaną do CCx. Po odczytaniu flagi należy ją skasować czyszcząc najlepiej cały rejestr INTFLAG. W funkcji obsługującej przerwanie musimy również wyzerować licznik w rejestrze COUNT. Znalazłem też opcję automatycznego kasowania licznika po zaistnieniu "compare" mianowicie zrobi to następujący wpis w konfiguracji modułu TC :


Wave --> WAVEGEN --> 0x1 / set Match frequency TOP = CC0

a wynika to z tej tabelki :

W rozdziale o TC są rysunki obrazujące o co biega z tym WAVEGEN 

W załączonym do artykułu programie zostanie wszystko pokazane jak na widelcu i może bardziej opadnie mgła niezrozumienia :)

Podsumowując muszę powiedzieć, że poznawanie ATSAML21 idzie mi coraz sprawniej. Poruszanie się po rejestrach daje  ogromną wiedzę o życiu wewnętrznym tego MCU i to jest bardzo dobra droga do poznania MCU. Takiej wiedzy nie pozyskałbym gdybym oparł się o biblioteki typu HAL a w przypadku ATSAM o ASF. Środowisko SEGGERA jest bardzo pomocne na każdym kroku w poznawaniu ATSAM-a. Mam jeszcze tylko lekki problem z  przyzwyczajeniem się do organizacji projektu w/g koncepcji Solution.

Mając jednak do porównania skalę trudności w poznaniu PIC32MM i ATSAML21 to zdecydowanie najmniej się zasapałem przy okazji poznawania PIC32MM. Dlatego PIC32MM polecam osobom , które niezbyt mocno czują się w aspekcie sprzętu bo to lightowy MCU, a PIC-e są naprawdę proste w ogarnięciu i to jest ich ogromna zaleta. ATSAM-y natomiast poleciłbym dla osób już z jakimś doświadczeniem i nie bojących się wyzwań :)

A tak jako ciekawostkę napiszę , że w/g opinii jednego z największych dystrybutorów w naszym kraju - "rynek polski nie jest gotowy jeszcze na konstrukcje 32-bitowe". Ciekawa opinia zważywszy na szał złotych jaj jaki się u nas kreuje wokół MCU 32 bit. A co ciekawe przemysł jedzie cały czas głównie na MCU 8-bitowych :) No ale inne jest spojrzenie/wrażenie hobbysty niż spojrzenie osoby zawodowo poruszającej się wśród dużych korporacyjnych klientów branży przemysłowej , AGD etc. bo to są jak widać dwa różne światy.

Jeszcze informacja gdzie można tanio i szybko pozyskać ATSAM-y. Zaznaczę przy tym, że nie jestem skory na moim blogu do reklamowania czegokolwiek, bo prowadzę blog całkowicie za free bez wpływu żadnego dostawcy na moje opinie i na moje wybory. Ale zrobię tutaj mały wyjątek dla dobra ogółu. Sprawdzonym i bardzo dobrze zaopatrzonym źródłem m.in w  ATSAM-y jest Mouser. Jeśli dokonamy zakupu za 200 zł to dostawa jest darmowa. Czas dostawy do PL to 2-3 dni.
I tu chciałbym zwrócić uwagę, że np seria ATSAMD21G18 jest sporo tańsza niż ATSAML21G18 . Na moją płytkę developerską bez żadnych problemów można zaaplikować ATSAMD21.

Kolejna ciekawostka to z tego co widzę u Microchipa  serie związane z Cortex M3 są pomijane całkowitym milczeniem choć w sprzedaży jeszcze są dostępne. Wiele osób rzuciło się ogólnie u wszystkich producentów na te wydanie Cortexa ale jak widać to się nie za bardzo przyjęło na rynku. Microchip dostrzegł tendencję na rynku jako pierwszy i nie proponuje już klientom tej serii, podczas gdy np STM nadal próbuje to wciskać. Stąd można wysnuć prosty wniosek, że STM nastawiony jest na szybki zysk a Microchip na długoterminowe relacje z klientami , które w dłuższym czasie dadzą stabilny zysk, tak to z moich obserwacji rynku odbieram. Z resztą warto tu przy okazji zauważyć, że sam rynek finansowy zdecydowanie preferuje Microchipa, pokazywałem już wykresy z giełdy i wspominałem o tym jakiś czas temu. Kiedy leje się krew na spółkach technologicznych, Microchip spada o połowę mniej niż STM a to o czymś świadczy.

Projekt z GitHuba ściągamy lokalnie na dysk za pomocą komendy (Linux w konsoli): 

git clone https://github.com/PICmajster/ATSAML21_TC.git

i dodajemy w środowisku SEGGER za pomocą opcji File --> Open Solution

Pozdrawiam
picmajster.blog@gmail.com


Linki :

ATSAML21G18B - strona producenta
ATMEL START - przydaje się do zerkania na bloczek zegara
Projekt na GitHub dla IDE SEGGER
Artykuł o ATSAML21


Brak komentarzy:

Prześlij komentarz