środa, 9 stycznia 2019

ATSAML21 - zaczynamy zabawę z legendarną serią MCU w nowym środowisku SEGGER-a

Moja płytka developerska dla ATSAML21 jest już gotowa do testów i wyszła bardzo fajnie. MCU jaki zastosowałem na niej to ATSAML21G18B. Ale możemy zastosować również modele z serii ATSAMD21. Czekam jeszcze na dostawę wyświetlacza 2.2 " ILI9341 aby uzupełnić płytkę . Nie przeszkadza mi to jednak aby zacząć na tym etapie zabawę z MCU. Nie mam żadnego doświadczenia z tą serią MCU ani ze środowiskiem SEGGERA. Czas to zmienić i rozpocząć nową przygodę. Pierwszą czynnością będzie instalacja środowiska od firmy SEGGER. Ściągamy zatem aktualną wersję ze strony producenta Embedded Studio . Ja wybrałem wersję dla Linuxa 64-bit, instalacja jest bardzo prosta i nie wymaga komentarza.

Po instalacji i uruchomieniu środowiska musimy dodać pakiet z naszym MCU. Otwieramy zakładkę Tools i wybieramy opcję Package Manager. wyskoczy nam poniżej pokazane okienko.


Wyszukujemy rodzinę w której jest nasz MCU czyli SAM-L. Klikamy w kolumnie Status na napis Not Installed w wierszu dla naszej rodziny MCU. Na obrazku jest już zainstalowana paczka ,więc tam jest napis Installed. Klikamy Next na dole okienka , potem ponownie Next w kolejnym okienku i na końcu Finish.
Paczka powinna być już zainstalowana. Aby to sprawdzić wchodzimy jeszcze raz w Tools --> Package Manager, w kolumnie Status powinien być zielony napis Installed tak jak na powyższym zdjęciu.

Teraz tworzymy nowy projekt File --> New Project. Wyskoczy nam okienko w wyborem :


Ja wybieram drugą na dole opcję. Projekt będzie utworzony w istniejącym Solution "SAML21".Wyskoczy nam kolejne okienko w którym wybierzemy zaznaczoną poniżej opcję i wpiszemy na dole nazwę projektu np.Hello World. Możemy również podać ścieżkę dostępu gdzie zapiszemy nasz projekt lub zostawić domyślną.


Klikamy Next i wyskakuje nam kolejne okienko gdzie musimy podać model naszego MCU , w moim przypadku jest to ATSAML21G18B. Widzimy również, że mamy możliwość podania rozmiaru stosu ale to zostawiamy tak jak jest domyślnie. Klikamy Next i pojawi się kolejne okienko gdzie zobaczymy jak będzie wyglądała struktura naszego projektu.


Kolejne kliknięcie Next i już ostatnie okienko gdzie opcja Debug i Release muszą być zaznaczone . Tutaj mała uwaga, ze świata AVR jesteśmy przyzwyczajeni , że opcję Debug musimy wyłączyć  a jedynym wsparciem dla debugowania jest dioda LED. W przypadku ARM jeśli opcję Debug wyłączymy to pozbawiamy się całego kramu możliwości i opcji debugowania sprzętowego. Na koniec pracy z programem kiedy wszystko jest na tip top to wtedy  program kompilujemy  z wybraną opcją Release .Klikamy Finish.


Zwieńczeniem naszego trudu powinno być stworzenie projektu Hello World, który zobaczymy na lewej belce .


Po rozwinięciu katalogów stworzonego projektu widzimy  , że nie mamy  plików nagłówkowych  naszego MCU. A bez nich to raczej pupa blada. Po chwili konsternacji uruchamiam kompilację projektu Build --> Compile.
W procesie pierwszej kompilacji dołączone zostały brakujące pliki, które znajdziemy w katalogu Dependencies i zrobiłem wielkie Uff. Możemy również użyć opcji Build, może nawet lepiej jej użyć na początku.


Po otwarciu katalogu Dependencies zobaczymy całą masę plików nagłówkowych , za pomocą których będziemy próbować programować naszego procka. Jak widzimy w projekcie nie ma bibliotek typu HAL , więc działamy jak najbliżej rejestrów czyli nazwijmy to umownie "programowaniem natywnym" (na poziomie języka C). W sumie "programowanie natywne" ma dwie zalety , nie jesteśmy narażeni na zmiany związane z aktualizacją bibliotek czy w ogóle nowych trendów w bibliotekach (patrz StdPerph/ HAL). Druga zaleta to będąc bliżej rejestrów poznajemy dobrze naszego procka a ta wiedza umożliwi nam rozwój . Programując w abstrakcjach typu HAL oddalamy się od poznania hardware a skupiamy się na poznawaniu software, który dziś jest taki a za rok może być całkiem inny.


Standardowo IDE SEGGERA jest zminimalizowane jeśli chodzi o ikonki na belkach narzędziowych a praktycznie nie mamy żadnych ikonek na panelu. Należy je ręcznie uwidocznić. Ja uaktywniłem widok dwóch belek View --> Toolbars --> Standard i Build.

Teraz dochodzimy do momentu w którym mamy gotowe narzędzia. Więc czas na zapoznanie się z dokumentacją. Naszym celem jest zapalenie diody LED , która znajduje się na pinie PB11 na mojej płytce developerskiej. Cel nie jest ambitny wcale, ale ja mam zamiar tutaj głównie przetestować komunikację z płytką developerską i poprawność programowania. Czyli czy w ogóle coś tutaj działa.

Aby sobie troszeczkę dopomóc w poznaniu zerkam na narzędzie webowe Atmel Start. Podglądam tam jak jest m.in ustawiony zegar po resecie i jaka jest struktura blokowa zegara oczywiście wszystko to wyczytamy w datasheet  :


Ze zdjęcia widzimy , że zegar po resecie tyka na 4 MHz. Na razie taka informacja mi wystarczy. Ściągam datasheet . Biorę pod lupę plik nagłówkowy port.h gdzie są definicje dostępu do GPIO. W datasheet zerkam na rozdziały dotyczące zegara i GPIO.  Generalnie potrzebujemy informacji jak ustawić zegar dla modułu GPIO  , jak ustawić pin PB11 na wyjście cyfrowe i jak ustawić na tym pinie stan wysoki. W SAM-ach moduł odpowiedzialny za interakcję z pinami to moduł PORT.

Najpierw spróbujemy ogarnąć temat włączenia zegara dla modułu PORT. Na stronie 451 datasheet czytamy :


Z powyższego tekstu dowiadujemy się, że zegar dla modułu PORT przyporządkowany jest do szyny AHB/APB a jego ustawienia dokonamy w module MCLK. W sekcji Peripheral Clock Masking dla modułu MCLK dowiemy się jakie są ustawienia startowe. Przechodzimy zatem na stronę 152 i 153 datasheet. Gdzie z tabelki dowiadujemy się , że zegar dla modułu PORT jest na starcie włączony !!!!!!!. CLK_PORT_APB  - enabled



Unikalne w świecie MCU z rdzeniem ARM aby na starcie był kros PORT z zegarem. Jeszcze jedna unikalność dotycząca dokumentacji . W SAM-ach manual i datasheet jest jednym dokumentem a nie dwoma oddzielnymi jak robią to wszyscy producenci .

No dobrze zatem jedna operacja mniej czyli nie musimy podpinać zegara do GPIO (PORT). Idziemy zatem dalej czyli konfiguracja portu i pinu.

Podpieram się tutaj rysunkami z datasheet czyli staram się zgłębiać tajemnice od ogółu do szczegółu :


Z rysunku powyższego wynika , że muszę ustawić DIR (kierunek) na 1 i sprawdzić czy INEN jest na zero ale już powiem , że jest . Co ciekawe jest jak widać dostępna opcja gdzie mamy jednocześnie włączone wyjście i wejście !!!
Kolejny rysunek przedstawia blokową budowę modułu PORT


A poniżej rysunek obrazujący multiplexing z użyciem modułu PORT, tu też trzeba pochylić nad tym głowę i przejrzeć rejestry z tym związane na wszelki wypadek.


Multiplexing jest bardzo ważnym zagadnieniem bo to tutaj zachodzi cała magia podłączenia do danego pinu różnych funkcjonalności ale o tym doczytamy na stronie 32 datasheet. Dowiemy się tam, że na starcie moduł PORT jest skrosowany fizycznie do pinów. A jeśli chcemy zmienić ten stan rzeczy to musimy działać na rejestrach PINCFGn.PMUXEN, n = 0..31 i PMUXn.PMUXE/O


Dobra powoli się rozjaśnia. Przejdźmy zatem do konkretów. Ustawmy kierunek pinu PB11 na wyjście. Szukamy w rejestrach czegoś stosownego do takiego ustawienia. W spisie rejestrów modułu PORT widzimy rejestr DIR, który odpowiada za ustawienie kierunku na danym pinie (Output = 1 / Input = 0).
Piny są zgrupowane po 32 sztuki na jednym porcie , czyli na Porcie A mamy do dyspozycji maksymalnie 32 piny na porcie  B też tyle samo . Ile fizycznie pinów na danym porcie jest dostępnych a to jest zależne od ilości nóżek naszego MCU. Wiemy zatem , że musimy ustawić w DIR bit 11 . Dla trybu Output bit ten musimy ustawić na 1. Zerknijmy jak wygląda nasz rejestr DIR :


Jak widzimy nic strasznego, 32 bity , które reprezentują poszczególne piny na Porcie. Oprócz rejestru DIR mamy też rejestry DIRSET , DIRCLR, DIRTGL, do tych rejestrów mamy możliwość dostępu atomowego. I wygląda na to, że łatwiej nam będzie operować na tych "atomowych" rejestrach niż robić wpisy do  rejestru DIR. Zatem do ustawiania kierunku posłużę się w dalszych rozważaniach rejestrem DIRSET.

Teraz przyszła pora na zajrzenie do plików nagłówkowych skojarzonych z modułem PORT. W zakamarkach naszego projekty Hello World znajdujemy plik nagłówkowy port.h i tam szukamy jak producent proponuje nam dokonać fizycznie zapisu do rejestru DIRSET. Przyda się również wiedza o definicjach w pliku nagłówkowym saml21e18b.h. Oba pliki znajdziemy w ścieżce CMSIS Files -- > system_saml21.c --> Dependencies
 
Mając na uwadze definicje w plikach nagłówkowych port.h i saml21e18b.h oraz idąc za podpowiedziami z IDE dochodzę metody zapisu do rejestru DIRSET (ustawiam kierunek pinu PB11):

PORT->Group[1].DIRSET.reg = PORT_PB11; //PORT_PB11 jest definicją zapisu 1<<11

Trochę wygląda to masochistycznie ale zapewniam , że na takich zapisach nasz mózg będzie pracował efektywniej ,jeśli wcześniej nas nie zabiorą do domu wariatów :)
Przetłumaczmy z Chińskiego na Polski. Pierwszy człon PORT odwołuje się ogólnie do modułu sprzętowego o tej samej nazwie, jest to człon struktury , którego elementem jest Group[1] a jest to tablica o typie strukturalnym. Strzałeczka ->, oznacza , że odwołujemy się do elementu struktury za pomocą wskaźnika. Group[0] to odwołanie do PORT(A) a Group[1] reprezentuje odwołanie do PORT(B). Group[1] jest typem strukturalnym zatem odwołujemy się do elementu tej struktury czyli DIRSET. Z kolei DIRSET ma dwa elementy bit i reg. Odwołując się do reg powodujemy , że zapis będzie dokonywany do całego rejestru DIRSET. Konsekwencją tego jest to , że jak wpiszemy wartość 11 to nie ustawimy tym zapisem bitu 11 (czyli naszego PB11) ale wpiszemy wartość 11 do rejestru. Aby zapisać wartość 1 do bitu nr 11 musimy posłużyć się zapisem 1<<11 i tutaj mamy dostępną definicję tego zapisu PORT_PB11. Wybierając opcję bit musimy wybrać również element w niej zawarty czyli DIRSET, ale nie widzę tutaj istotnej różnicy w tym wyborze w stosunku do reg.
Wiem wygląda to zawile ale trochę obycia z ARM-ami i nie będzie to robić na nas wrażenia.

Warto tutaj wspomnieć, że nie ma w SAM-ach pierdyliona podopcji dotyczącej rodzaju I/O, tak jak to bywa u innych producentów MCU z rdzeniem ARM. Jest to kolejny dowód na to, że SAM-y są unikalne i wyjątkowe. Jeszcze nie wiem czy je pokocham tak jak PIC-e ale na razie nie jest źle.

No dobrze wiemy jak fizycznie ustawić rejestr DIRSET czyli kierunek na pinie teraz kolejną czynnością będzie ustawienie pinu PB11 w stan wysoki. Zaglądamy zatem do stosownego rejestru czyli OUTSET. Jeśli chcemy ustawić 0 to posłużymy się rejestrem OUTCLR, jeśli chcemy togglować pin to rejestr OUTTGL. Oczywiście można posługiwać się gołym rejestrem DIR i OUT ale w  przypadku ustawienia  0 na wybranym pinie zapis nam się minimalnie skomplikuje. Spis rejestrów dla modułu PORT znajdziemy na stronie 459 datasheet. Jeszcze raz tutaj przypomnę , że w rodzinie SAM nie ma oddzielnie datasheet i manuala , mamy jeden spójny dokument co jest bardzo wygodne. Rzut okiem jak wygląda nasz rejestr OUTSET :

Widzimy, że nic strasznego. Zapis jakim się posłużymy do ustawienia bitu nr 11 na 1 będzie wyglądał analogicznie jak w przypadku DIRSET.

PORT->Group[1].OUTSET.reg = PORT_PB11; //PORT_PB11 jest definicją zapisu 1<<11

Jeśli chcemy w ten sposób potraktować kilka pinów to dodajemy za pomocą sumy kolejny pin.

Podam na wszelki wypadek sposób zapisu 0 i 1 do rejestru OUT bez atomowych sztuczek :

PORT->Group[1].OUT.reg |= PORT_PB11; //PORT_PB11 jest definicją zapisu 
1<<11. Ustaw PB11 na 1

 PORT->Group[1].OUT.reg &= ~PORT_PB11; //PORT_PB11 jest definicją zapisu 
1<<11 Ustaw PB11 na 0

Tutaj bardzo ważna uwaga !!!! i to trzeba sobie dobrze wbić do głowy bo inaczej będą błędy w działaniu programu . W przypadku dokonywania wpisów atomowych z wykorzystaniem rejestrów OUTSET, OUTCLR etc nie używamy symbolu sumy przed nawiasem !!!!!!! W przypadku zapisu nie atomowego czyli wpis do rejestru OUT , IN znak sumy przed nawiasem w przypadku ustawienie 1 musi być . Poniżej pokazuję o co chodzi :

PORT->Group[1].OUTSET.reg = PORT_PB11 //atomowy wpis do rejestru OUT, ustaw wartość 1 na PB11 , tu nie stawiamy znaku sumy | przed nawiasem.

PORT->Group[1].OUT.reg |= PORT_PB11 // nie atomowy wpis do rejestru OUT, ustaw wartość 1 na PB11, tu znak sumy | przed nawiasem musi być.

Wiemy zatem jak ustawić nasz pin PB11 czas naszą wiedzę zweryfikować. Teraz wypadałoby wgrać nasze wypociny do MCU. Mój programator to J-Link EDU Mini , czyli najtańszy model J-Linka. Na wszelki wypadek wgrywam soft SEGGERA dla J-Linka , J-Link Sotware and Documentation pack Prawdopodobnie jest to zbędna czynność w przypadku korzystania ze środowiska SEGGERA ale zrobiłem to i tyle. Aby programator był wykryty przez środowisko musi być koniecznie podłączony do docelowej płytki z naszym MCU a płytka musi być zasilana. Inaczej otrzymamy komunikat typu Error No idcode detected. Aby środowisko wykryło nasz programator wybieramy Target --> Connect J-Link, po wykryciu programatora na dole z prawej strony pojawi się napis CORTEX M0 on J-Link. MCU SAM programujemy w trybie SWD ale to domyślny tryb środowiska dla tych procków.



Aby wgrać nasz program wybieramy Target --> Download  Nazwa naszego projektu lub ikonka wykrzyknika ! na belce narzędziowej. W ułamku sekundy nasz program znajdzie się w we FLASH-u MCU. Jeśli chcemy zobaczyć jak działa Debugger to wybieramy Debug --> Go.



Debugger działa doskonale i bardzo szybko.

Poniżej daję przepis jak togglować diodą LED na pinie PB11 bez użycia delaya a z wykorzystaniem SysTicka.


Trzeba przyznać ,że IDE SEGGERA jest najszybszym środowiskiem z jakim miałem do czynienia. Samo otwarcie środowiska zajmuje 3 sekundy. Nie sądzę aby to było napisane w Javie ale jeśli tak to pisali to programiści z najwyższej półki. Moim  zdaniem jest to obecnie najlepsze środowisko na rynku działające pod LINUXEM do programowania MCU z rdzeniem ARM i RISC-V. No właśnie, pojawia się wątek RISC-V, jak widać firma SEGGER poważnie podchodzi do postępu i nie zamyka się tylko na jedyny obecnie słuszny nurt. Dziś ARM  a jutro RISC-V. Warto tu przypomnieć , że firma Microchip aktywnie wspiera architekturę RISC-V poprzez swoja spółkę zależną Microsemi.

W zasadzie to co chciałem osiągnąć na tym etapie zrealizowałem z powodzeniem. Uruchomiłem moją płytkę developerską , zapoznałem się ze środowiskiem, zaprogramowałem MCU używając plików nagłówkowych producenta dołączanych automatycznie po pierwszej kompilacji projektu w środowisku SEGGER-a. Żadnych pałętających się bibliotek typu HAL, żadnych szemranych wspomagaczy do  konfigurowania MCU etc. Wszystko poszło jak na razie gładko. W sumie jedynym dokumentem , którym się wspierałem był datasheet i to wystarczyło. Inna dokumentacja na stronie producenta jest oparta głównie o ASF a ja tym się nie chcę posługiwać .
Generalnie ludzie jak widzę do zabaw z ATSAM-ami używają kobyły ATMEL Studio i Frameworku ASF. Ograniczeniem jak dla mnie  jest to, że to ociężałe środowisko nie jest dostępne pod LINUX-em . Inna sprawa, że Microchip będzie prawdopodobnie wygaszał to środowisko i przenosił dziedzictwo byłej firmy ATMEL do MPLABX-IDE co już generalnie się dzieje.

Wadą ekosystemu ATSAM są stosunkowo drogie płytki developerskie co moim zdaniem skutecznie blokuje propagację tych fajnych procków w świecie hobbystycznym. Choć może to się wkrótce zmienić bo organizacja ARDUINO wybrała ATSAM-y jako lidera do swoich nowych wyrobów. Żeby nie być gołosłownym pierwszy lepszy przykład jednego z nowych modułów na oficjalnej stronie Arduino MKR WiFi 1010 lub też ARDUINO M0. Jak widzimy nowe moduły Arduino oparto o rodzinę ATSAMD21, która jest w pełni kompatybilna z moim wyborem tj. ATSAML21.

Póki co, dzięki niewielkiemu wysiłkowi udało mi się stworzyć tanią płytkę developerską i pokazać tą drogą , że można przy odrobinie chęci zrobić coś fajnego własnym sumptem a nie zdawać się na wygodę i kupować gotowy produkt. Zapewniam, że radość z efektów własnej pracy jest niewspółmiernie większa niż z zakupu gotowego produktu.

Seria ATSAML21 jest kompatybilna z serią ATSAMD21, więc na mojej płytce można i  z tej serii procki aplikować, kompatybilność jest również na poziomie peryferiów. Zwracam uwagę na ciekawą serię MCU ATSAML10 i ATSAML11 opartych na nowym CORTEX M23 z technologią Trust Zone, są one nawet bardziej energooszczędne niż seria ATSAML21 i chyba najbardziej energooszczędne obecnie na rynku (w trybie aktywnym 25uA/MHz.) STM32 mogą pomarzyć o takich parametrach. ATSAML11 ma ciekawą właściwość szyfrowania całej pamięci Flash, dzięki czemu nasz soft nawet jak ktoś skopiuje z urządzenia to i tak nie będzie w stanie go wykorzystać. Być może i do tej serii wystrugam płytkę developerską. Środowisko SEGGERA wspiera tę nową serię również.

Pozdrawiam
picmajster.blog@gmail.com


Linki :
ATSAML21G18B - strona produktu
Embedded Studio - IDE firmy SEGGER
Portfolio MCU 32 bit 
Artykuł o ATSAML21


6 komentarzy:

  1. Na razie brak w TME SAML21 https://www.tme.eu/pl/katalog/#cleanParameters=1&parameter_boxes=17&search=atsaml21&page=1&s_field=accuracy&s_order=DESC

    OdpowiedzUsuń
  2. Ciekawe są takie maleństwa SAMD09C13A-SSUT po niecałe 4zł w TME

    OdpowiedzUsuń
  3. TME dopiero chyba zaczyna być oficjalnym dystrybutorem Microchipa, i nie mają obsadzonej pełnej oferty jeszcze. Ale w firmie Mouser dostaniesz wszystkie produkty Microchipa to oficjalny dystrybutor na Europę.Powyżej 200 zeta dostawa za darmo.Zwracam uwagę na nowe procki ATSAML10 i ATSAML11 na Cortex M23.Być może do nich też wystrugam płytkę. We wtorek będe na seminarium TME i Microchipa i o tych prockach będzie m.in.

    OdpowiedzUsuń
  4. ATSAML21G18B w Mouser https://pl.mouser.com/ProductDetail/Microchip-Technology/ATSAML21G18B-AUT?qs=sGAEpiMZZMuoKKEcg8mMKMiM3NDCObf08cu790tRA42DzJvBClE5JQ%3d%3d

    OdpowiedzUsuń
  5. W TME masz dostępne obecnie 4 modele ATSAMD21 w obudowie TQFP48 , zastosujesz je do mojej płytki są komatybilne z serią ATSAML21. Korzystny cenowo jest model
    ATSAMD21G16B-AU | Mikrokontroler ARM Cortex M0; SRAM:8kB; Flash:64kB; 48MHz za 10 zł brutto a jak chcesz większe zasoby pamięci to masz
    ATSAMD21G18A-AU | Mikrokontroler ARM Cortex M0; SRAM:32kB; Flash:256kB; 48MHz za 15 zł

    OdpowiedzUsuń
  6. dzięki za podpowiedź , o mauzerze nie wiedziałem w ogóle

    OdpowiedzUsuń