niedziela, 14 października 2018

EFM32TG11B120F128GQ48 ARM Cortex-M0+ od Silicon Labs - ustawienie zegara w środowisku Simplicity Studio 4

Moją standardową procedurą w rozpoznaniu nowego MCU jest poznanie na początku aspektów dotyczących zegara. Na warsztat biorę MCU z nowej serii Tiny Gecko 11 firmy Silicon Labs w obudowie TQFP 48 pin 7x7 mm. Tak jakoś polubiłem ten format obudowy, który zajmuje znacznie mniej miejsca niż obudowa 64 pinowa. MCU Silicona zaciekawiły mnie m.in z racji ciekawych peryferiów , ceny  oraz z uwagi na zarąbiste logo na MCU :).


Za ciekawy produkt firmy Silicon Labs uznałem MCU z nowej serii Tiny Gecko 11 model EFM32TG11B120F128GQ48 z CAN i kryptografią na pokładzie w cenie ok 10 zł. I temu modelowi MCU poświęce chwilę uwagi. Traktuję to jako Cortexowe uzupełnienie mojej przygody z MCU  i ciekawy eksperyment "naukowy".

Podstawowymi dokumentami z jakimi trzeba się zaprzyjaźnić w  przypadku każdego Cortexa to minimum datasheet i manual warto też zerknąć do erraty. Manual w naszym przypadku ma ok 1253 stron ale nie czytamy tego od deski do deski tylko to co nas w danym momencie interesuje lub co rozgryzamy w danej chwili, w innym przypadku odwiozą nas do zakładu psychiatrycznego.

W artykule skupiamy się na zegarze, więc ogólne opcje wyczytujemy sobie w datasheet a manual przybliża nam perspektywę bardziej szczegółowo , łącznie z opisem konkretnych rejestrów. Zaglądamy również do krótkiego dokumentu Clock Managment Unit AN0004. Cała niezbędna dokumentacja w linkach poniżej artykułu.

Na początek dobra informacja. EFM32TG11 startuje deafault-owo z uruchomionym zegarem  RC 19 MHz, czyli defakto jakiś zegar bez ustawiania na starcie mamy. Pamiętajmy jednak , że zegar trzeba podpinać do każdego użytego peryferium oddzielnie np jeśli chcemy użyć jakiegoś pinu do sterowania diodą LED to musimy podpiąć zegar do peryferium GPIO. To jest cecha charakterystyczna w świecie ARM-a i z tego nic nas nie zwolni. Ale do wszystkiego dojdziemy w swoim czasie.

Wewnętrzny zegar RC możemy ustawić na następujące wartości : 4,7,13,16,19,26 MHz. Generalnie EFM32TG11 można rozpędzić na wewnętrznym zegarze do 28MHz ale brakuje takiej opcji w ustawieniach API oraz od strony opisu rejestrów HFRCO Calibration Register (manual sekcja 4.7.14) .Być może to wymaga aktualizacji API i dokumentacji. W artykule pokażę jak zmienić ustawienie zegara RC na inną wartość niż deafault-owa. Drugim wariantem jakim się zajmiemy będzie ustawienie zegara zewnętrznego 48 MHz na zewnętrznym kwarcu.
I to w zasadzie na razie do szczęścia nam wystarczy.

W przypadku PIC32MM Microchipa, zegar mogliśmy sobie w prosty sposób ustawić np.  za pomocą narzędzia MCC, który wygeneruje nam przejrzysty kod konfiguracyjny . W przypadku Cortexów lepiej nie tykać tego typu wspomagaczy m.in dlatego , że generują duży narzut "kociego" i przerośniętego niepotrzebnie kodu . Dlatego ja konfiguratorami  CUBE podobnymi nie będę się posługiwał w świecie ARM-a.

Odnośnie bibliotek dla mnie najlepszą drogą jest minimalizm bez zbędnego narzutu abstrakcji na kod. Dlatego tam gdzie będzie to możliwe ,będę starał się posługiwać podstawowymi bibliotekami dla danego Cortexowego MCU dostarczonymi przez producenta. W przypadku rozważanego MCU EFM32TG11 podstawowym plikiem za pomocą , którego "gadamy" z MCU jest plik nagłówkowy efm32tg11b120f128gq48.h Plik ten opisuje nam w przejrzysty sposób większość dostępnych w MCU rejestrów i jest zgodny ze "standardem" ARM-a - CMSIS. Za pomocą tych definicji możemy w wygodny sposób poruszać się po rejestrach. Jest to najbardziej niskopoziomowy sposób programowania bibliotekami. Wymaga jednak grzebania w rejestrach i głębszego zapoznania się z MCU. Ale jest i alternatywa w postaci biblioteki emlib o której napiszę w dalszej części artykułu.

Dla rozjaśnienia obrazu sytuacji w zakresie możliwości zegarowych opisywanego MCU zerknijmy na poniższy rysunek blokowy symbolizujący z grubsza wewnętrzną strukturę sprzętową naszego mikrokontrolera.


Na rysunku widzimy blok zegarowy : Clock Management. Wewnątrz tego blogu są jakieś magiczne skróty , które po rozszyfrowaniu zobrazują nam bliżej zagadnienie.

  • ULFRCO - jest to najwolniejszy wewnętrzny zegar RC w systemie 1kHz, umożliwiający uzyskanie ekstremalnie niskiego poboru energii.
  • AUXHFRCO - Pomocniczy wewnętrzny zegar RC o szerokim zakresie regulacji 1-48 MHz, używany do ADC, LESENSE, Debugera
  • LFRCO - wewnętrzny zegar RC "zegarkowy" 32.768 kHz
  • LFXO - zewnętrzny zegar RC "zegarkowy" 32.768 kHz
  • HFRCO + DPLL - wewnętrzny zegar RC max 28 MHz. DPLL cyfrowa pętla fazowa modelująca zegar.
  • HFXO - zewnętrzny zegar kwarcowy w zakresie 4 - 48 MHz
Fajne jest to , że do zewnętrznych kwarców nie trzeba dawać zewnętrznych kondensatorów niezbędnych m.in do prawidłowego wzbudzania kwarca. Te kondensatory a zasadniczo ich pojemności są zaimplementowane w MCU.
Zawsze to w sumie o cztery elementy mniej na płytce.

Mamy zatem z grubsza pojęcie jakie zegary są w naszym MCU a w zasadzie jakie, źródła zegarowe.

Spróbujmy dojść to tego jak ustawić wewnętrzne źródło taktowania HFRCO na  częstotliwość 26 MHz. A jest to maksymalna częstotliwość jaką w praktyce możemy ustawić na wewnętrznym zegarze bo w teorii jest to wartość 28 MHz.

W manualu w rodziale 10.4 mamy tabelkę z opisem rejestrów. Jest tego trochę ale nie zrażamy się nadmiarem tylko patrzymy na to wybiórczo, szukamy rejestru w którym można włączyć zegar wewnętrzny HFRCO i rejestru w którym możemy ingerować w ustawienia zegara. Nazwy rejestrów w tabelce są na tyle czytelne, że szybko można się w ich funkcjonalności połapać. Zatem rejestry które nas interesują to :

CMU_OSCENCMD - Oscillator Enable/Disable Command Register

CMU_HFRCOCTRL - HFRCO Control Register

Aby włączyć wewnętrzny zegar HFRCO należy w rejestrze CMU_OSCENCMD ustawić bit o czytelnej nazwie HFRCO Enable. Ponieważ jednak po starcie HFRCO jest włączony ,więc nic nie musimy tutaj  ustawiać.





Drugim pożądanym ustawieniem , który trzeba dokonać to prędkość zegara. Dokonamy tego w rejestrze CMU_HFRCOCTRL zmieniając wartość w polu bitowym FREQRANGE. Pole ma 5 bitów.



Konia z rzędem kto odgadnie jaka wartość jest przyporządkowana do jakiej częstotliwości. Widzimy, że zabrakło w opisie pola bitowego tej kluczowej informacji. Pogrzebałem trochę w dokumentacji i znalazłem  ciekawe informacji odnośnie ustawień rejestru CMU_HFRCOCTRL. Po pierwsze wszystkie pola bitowe w rejestrze muszą być wpisane równocześnie, nie możemy wybiórczo dokonać wpisu np. w polu FREQRANGE a to oznacza, zapis typu CMU_HFRCOCTRL = 0x1DF5647A..... (liczba pi  :)) , nie wygląda to wcale ładnie i czytelnie więc nie tędy droga. Ale skąd w ogóle mamy wiedzieć co wpisać w poszczególne pola bitowe ? no trochę musiałem się podrapać w głowę i powertować dokumentację. W pamięci flash MCU jest specjalny zakątek gdzie producent zaszył informację konfiguracyjne i kalibracyjne dla dostępnych wartości częstotliwości zegara RC. Informacje są pogrupowane w rejestry o nazwie HFRCOCALn(n=0,3,6,7,8,10,11,12,13) - HFRCO Calibration Register (manual od 4.7.14) . I teraz taki myk mamy, aby ustawić rejestr CMU_HFRCOCTRL należy najpierw dla danej częstotliwości odczytać zawartość przyporządkowanego rejestru HFRCOCALn a następnie odczytane wartości  przepisać do CMU_HFRCOCTRL Ale spokojnie nie będziemy takiego hardcoru uprawiać. Jest na to o wiele bardziej sympatyczniejszy sposób.

No dobrze, wiemy zatem z grubsza w jakich rejestrach ustawiamy wewnętrzny zegar HFRCO . Teraz pytanie jak to zrobić fizycznie . I tu dochodzimy do odwiecznych dylematów w świecie MCU z rdzeniem ARM-a, czyli jaką drogą pójść jeśli chodzi o programowanie. Czy iść w wyższą formę abstrakcji taką jak znane ze świata STM-a np. HAL(STM), czy może StdPeriph (STM), który jest już nie trendy. Współczuję ludziom, którzy zabrali się właśnie w świecie STM-ów za StdPeriph bo był to kompletnie ślepy zaułek. STM zaleca obecnie bibliotekę HAL ale nie ma gwarancji czy za jakiś czas to też już nie będzie trendy i trzeba będzie znowu się uczyć kolejnej biblioteki tego producenta. W przypadku Silicona wybór jest w miarę prosty i za tę prostotę można Silicona pochwalić.Tu od początku nie było takich potknięć z bibliotekami jak w STM. Albo uczymy się biblioteki emlib, która jest znacznie efektywniej napisana niż HAL STM-a i bardziej przyjazna w użytkowaniu, albo programujemy jak najbliżej rejestrów wspomagając się plikami konfiguracyjnymi mikrokontrolera. Intuicyjnie powinniśmy wybrać  tę drugą drogę, na początku  trudniejszą ale  ona oprócz tego, że jest najbardziej efektywna z punktu widzenia operacji maszynowych to nie jest obarczona problemami związanymi ze zmianą czy aktualizacją biblioteki przez producenta. Po za tym wybór bibliotek typu HAL oddala nas znacznie od poznania mikrokontrolera i jego życia wewnętrznego. Musimy jednak też mieć na uwadze, że dla początkujących walka z rejestrami jest znacznie trudniejsza niż poruszanie się po gotowcach z biblioteki typu HAL i łatwo się wtedy zniechęcić. Dlatego ja  przyjmę pewien kompromis , aby nie stracić kompletnie kontaktu z rejestrami będę posługiwał się tam gdzie uznam to za słuszne zapisami jak najbliżej rejestrów ale jednocześnie wspomagał się biblioteką emlib aby ułatwić sobie drogę np. w uruchomieniu jakiegoś peryferium .Choć pewnie skończy się tym, że ostatecznie będę używał tylko biblioteki emlib :) bo lenistwo to druga natura człowieka.

Teraz pokażę gdzie w katalogach projektu znajdziemy pliki do programowania "niskopoziomowego". Gdzie je zatem znaleźć ?? Zerknijmy na strukturę katalogów projektu :


Skoro szukamy plików nagłówkowych to katalog Include będzie właściwy do przeszukania. Otwieramy zatem ten katalog i w sumie dostajemy oczopląsu :




Żeby nie przedłużać wątku poniżej zawartość fragmentu katalogu , który nas interesuje :



W katalogu tym znajdziemy wszystko co nam na początek jest potrzebne do programowania MCU. Znajdziemy tutaj plik nagłówkowy mikrokontrolera efm32tg11b120f128gq48.h i pliki dedykowane poszczególnym modułom naszego MCU, przy czym te dodatkowe pliki są już dołączone w pliku nagłówkowym mikrokontrolera . W sumie nie wygląda to groźnie. Teraz musimy sobie postawić pytanie jak tego używać czyli innymi słowy jak za pomocą pośrednictwa plików nagłówkowych dokonywać modyfikacji rejestrów. Ale o tym dowiemy się w artykule dotyczącym mruganiem LED, tutaj tylko zasygnalizowałem temat. Póki co wracam do głównego wątku artykułu czyli jak ustawić zegar bez zbędnego stresu związanego z poznaniem rozbudowanych rejestrów . Od tego momentu będzie już prosto i z górki ponieważ do akcji wkracza biblioteka emlib, czyli przyjazne API do programowania mikrokontrolerów EFM32 filrmy Silicon Labs. Wyczerpujący opis biblioteki znajdziemy tutaj : emlib 
Warto zauważyć, że opis biblioteki emblib jest w formie interaktywnej co bardzo umila poznanie jej. Dla przykładu opis biblioteki HAL w świecie STM-a to opasły plik (1166 stron) pdf. który trzeba wertować manulanie.

Odpalamy środowisko Simplicity Studio 4, po odpaleniu podpinamy programator J-Link EDU mini . Obrazek jaki powinniśmy ujrzeć poniżej :



Jeśli środowisko po uruchomieniu będzie chciało się zaktualizować to trzeba to zrobić.
Teraz przyporządkujemy model MCU do programatora. W tym celu rozwijamy prawym klawiszem myszki menu na numerze seryjnym programatora (lewy górny róg okienka) lub wybieramy ikonkę ze skrzyżowanymi narzędziami Device Configuration i wchodzimy w zakładkę Device hardware. W opcji wyboru Target part wyszukujemy nasz MCU a konkretnie EFM32TG11B120F128GQ48 i zatwierdzamy ten wybór. Przy okazji na dole w opcji Target Interface zaznaczamy opcję SWD lub JTAG w/g uznania.



Teraz utwórzmy nowy projekt. W tym celu w Launcherze klikamy  ikonkę klucza Tools (górny lewy róg). Wyskoczy nam menu z którego wybieramy opcję Simplicity IDE




Otwiera się główne okno Simplicity IDE. Jeśli chcemy z powrotem wrócić do Launchera to klikamy adekwatną ikonkę w górnym prawym rogu.
Wybieramy z górnej belki File -> New -> Project

W wyskakującym okienku wybieramy  opcję Silicon Labs MCU Project i Next.


W kolejnym okienku tylko Next. I dochodzimy do okienka wyboru jak poniżej :


I tu trzeba się skupić i zrobić dokładnie jak opisuję. Wybieramy opcję Simplicity Configurator Program, mając na uwadze ,że z konfiguratora nie będziemy korzystać w ARM nigdy. Ja wiem kuszą ładne obrazki potencjalna łatwość automatycznej konfiguracji i miód malina. Moja osobista opinia jest krótka nie tykać tego gada w ARM-ach. W PIC-ach inna bajka tam można śmiało tego używać bo jest to zrobione dobrze i generuje czytelny i uporządkowany kod bez użycia HAL-o podobnych bibliotek. Inna sprawa , że Silicon nie przywiązuje dużej uwagi do kreatora konfiguracji co widać po jego szacie i opcjach. i nie udaje tak jak  STM , że jest to dobre narzędzie.

Klikamy Next  i w wyskakującym okienku podajemy nazwę projektu i Next :


Kolejne okienko ustawiamy tak ja na obrazku i Finish :


Uruchamia się okienko konfiguratora :



 ,które zamykamy i zapominamy o istnieniu tego. W prawym górnym rogu usuwamy zakładkę dla Konfiguratora. Otrzymujemy w efekcie taki obrazek :



Struktura naszego projektu powinna wyglądać jak poniżej, plik main.c w katalogu src jest tworzony automatycznie.


Z pliku main.c usuwamy wpis #include "em_device.h" i #include "hal-config.h" Po czym klikamy w ikonkę młoteczka i kompilujemy program. efekt końcowy powinien wyglądać tak :



I to już koniec z przygotowaniem projektu do działania czyli do pisania programów.

Teraz czeka nas najfajnieszy etap spotkania z Siliconami czyli radosna twórczość z biblioteką emlib
Ja widzimy interaktywna biblioteka jest skatalogowana w/g modułów naszego MCU.


Wszelkie sprawy dotyczące zegara znajdziemy w module CMU (Clock management unit). Wchodzimy zatem w ten moduł i wyszukujemy funkcji do zmiany prędkości zegara RC.


Funkcja nazywa się CMU_HFRCOBandSet(), tylko jak są zdefiniowane argumenty dla tej funkcji ??? i tutaj wchodzi do akcji magia interaktywności biblioteki emlib. Klikamy w nazwę argumentu funkcji czyli w CMU_HFRCOFreq_TypeDef i naszym oczom ukazuje się ładna tabelka z nazwami argumentów, których możemy użyć w funkcji.


Jak zatem za pomocą biblioteki emlib ustawić zegar na 26 MHz ?? ano tak :

CMU_HFRCOBandSet(cmuHFRCOFreq_26MHz);

i się samo ustawi :). Spoczywamy w takim razie na laurach z poczuciem dobrze spełnionego obowiązku ale zauważmy, że nie przybliżyło nas to kompletnie to poznania mikrokontrolera i jego życia wewnętrznego. Zrobiliśmy tylko jak małpy przełożenie banana z jednego wiaderka do drugiego. Witaj w świecie ARM-a :) i jego bibliotek typu HAL. Nadmienię ,że producent taki jak STM zaleca taką drogę. Jak zaleca Silicon, pewnie też tak bo w dokumentacji więcej widać emliba. Czyli producenci MCU z rdzeniem ARM-a chcą wychować pokolenie małp :) Jak do tego dojdzie zmiana biblioteki , nazwy funkcji, struktury etc to małpa się pogubi i zamiast do wiadra to w końcu tego banana za okno wyrzuci lub zje. Jaki wniosek możemy z tego wysnuć ?? W sumie to każdy musi swój wniosek wysnuć i wydaje mi się, że nie ma w tej materii jednego właściwego. Z jednej strony grzebanie w mocno rozbudowanych i coraz bardziej skomplikowanych rejestrach ARM-a ale z jakąś gwarancją niezmienności nabytej wiedzy i łatwości implementowanie jej w innych modelach MCU a z drugiej pełny luz i komfort związany z wysokopoziomową biblioteką lub inaczej API i z zagrożeniem, że nauczona biblioteka będzie do kosza za jakiś czas a praktyka pokazuje , że to się zdarza.

Zwrócę jeszcze uwagę, że biblioteka emlib opiera się na funkcjach i bardziej to wygląda jak rasowe API. Dla porównania HAL firmy STM jest oparte o struktury i tu musimy poruszać się po nich. Moim zdaniem emlib jest zdecydowanie przyjemniejszy w użyciu niż HAL a szczególnie to powinni odczuć początkujący. Przy okazji artykułu z mruganiem LED przyjrzymy się jak to wygląda w obu przypadkach.

Wracamy do tematu. Wiemy zatem jakiego wpisu powinniśmy dokonać w programie aby zmienić zegar. Aby użyć naszej funkcji z emlib-a, musimy dołączyć do programu plik modułu CMU o postaci em_cmu.h. Plik ten znajdziemy w katalogu .......emlib/inc. Widać to na rysunku poniżej :



Powyższy rysunek wieńczy nasze dzieło i co już zegar zmieniony ??? No tak.
Biblioteka emlib posiada funkcję do odczytu stanu i wartości zegara ale to już możemy w ramach pracy domowej sami sobie znaleźć np tutaj : emlib

Na koniec wypadałoby pokazać jak taki "rozbudowany" program wgrać do MCU za pomocą np.programatora J-Link Edu mini.

Podłączamy nasz programator i klikamy ikonkę Flash Programmer, ostatnia po prawej w belce ikonek.


Musimy teraz pogrzebać w katalogach projektu na dysku i znaleźć plik Zegar.hex  Moja ścieżka dostępu jest widoczna na obrazku poniżej :


Po wybraniu pliku Zegar.hex klikamy ikonkę Program w oknie Flash Programmer i po krótkim momencie program zostanie przepisany do pamięci Flash naszego MCU.

Widzimy zatem, że ustawienie zegara w Siliconie przy użyciu biblioteki emlib jest proste a nawet można by rzec, że prostackie :)

Teraz podam prosty i sprytny sposób na zweryfikowanie czy zegar tyka tak jak go ustawiliśmy. Do tego celu wykorzystam 24 bitowy "tykacz" rdzenia czyli SysTick i jego przerwanie. Najpierw kod :



Po wgraniu kodu do naszego MCU, do pinu PC9 podłączamy analizator stanów logicznych, ja mam taki najtańszy za 60 zł ale robi swoje :). W efekcie otrzymamy obrazek jak poniżej :


Widać na nim , że otrzymaliśmy okres przebiegu o wypełnieniu 50% ,1Hz. Co oznacza , że nasze ustawienia zegara za pomocą funkcji z biblioteki emlib były skuteczne i zegar ustawił się na 26MHz. A jak ten okres 1 Hz powstał ?? otóż spowodowaliśmy, że przerwanie SysTick napędzane przez zegar systemowy w naszym przypadku 26MHz generuje się co 0.5 s czyli po zliczeniu 13 mln tyknieć zegara otrzymamy przerwanie od SysTicka. Pamietajmy, że SysTick jest 24 bitowy czyli wpiszemy do niego maksymalnie 16777215 ticków dlatego dla zegara 48MHz takim sposobem nie podziałamy.

Kurcze zapomniałem, że jeszcze zegar zewnętrzny mieliśmy ustawić. W tym celu wracamy poszperać w dokumentacji biblioteki emlib Szukamy czegoś do włączenia zegara HFXO. W dokumentacji emlib-a znajdujemy funkcję : CMU_OscillatorEnable() i opis jej argumentów : CMU_Osc_TypeDef



Zakładam, że nasz oscylator zewnętrzny ma 48MHz, ja taki nabyłem bez problemu. Zatem do programu musimy zrobić następujący wpis :

CMU_OscillatorEnable(cmuOsc_HFXO , 1 ,0);

Funkcja działa poprawnie, sprawdziłem. Kwarc zewnętrzny 48MHz działa.

Podsumowując ustawienie zegara w MCU Silicon Labs  za pomocą biblioteki emlib jest naprawdę łatwym zadaniem. Za pomocą tej biblioteki w bajecznie prosty sposób skonfigurujemy i uruchomimy takie peryferia jak np. CAN. A nasz MCU posiada CAN na pokładzie. 

Jak na razie poznanie Cortexa M0+ w wydaniu firmy Silicon Labs jest przyjemnym doznaniem. Jeśli poznamy ten MCU bliżej , żaden przedstawiciel rdzenia ARM nie będzie dla nas problemem.


Pozdrawiam
picmajster.blog@gmail.com



Brak komentarzy:

Prześlij komentarz