STM32G0 i ADC

Tu możesz pisać o swoich problemach z pisaniem programów w języku C/C++ dla STM.
Awatar użytkownika
Marcin
User
User
Posty: 224
Rejestracja: środa 09 wrz 2015, 19:30

STM32G0 i ADC

Postautor: Marcin » sobota 25 sty 2020, 22:24

Hej wszystkim.

Od pewnego czasu siedzę nad ADC w STM32G0, chciałbym tu odrobinkę przybliżyć jego funkcjonalność i zachęcić początkujących do jego poznania. Swój opis oprę na przetworniku zawartym w układzie STM32G071. Układ ten to jeden z nowszych produktów STMicroelectornics bazujący na rdzeniu Cortex-M0+, pracuje z częstotliwością do 64MHz. Pomimo ciekawych funkcjonalności jakie w nim zaimplementowano jest całkiem tani. Znajdziemy w nim jeden przetwornik ADC z rozdzielczością 12 bitów. W porównaniu z przetwornikami znanymi z wielu z atmeg ten ma znacznie bardziej rozbudowaną funkcjonalność, dla znawców AVRów na pierwszy rzut oka to prawie jak drugi mały i niezależny mikrokontroler w mikrokontrolerze.

Na początek trochę teoretycznego opisu.

Zegar
Na początek przyjrzyjmy się sygnałowi zegarowemu. Datasheet podaje, że ADC w STM32G071 może być taktowany zegarem o częstotliwości 0,14-35MHz. Poniżej schemat układu zegarowego ADC:
RCC.JPG

Do wyboru mamy dwa źródła zegarowe, synchroniczny pochodzący z szyny APB (PCLK) lub asynchroniczny dedykowany dla ADC mogący pochodzić z trzech różnych źródeł - wewnętrzny oscylator (HSE), PLLP lub SYSCLK. Multiplexer wybierający źródło sygnału taktowania ADC i podział sygnału pochodzącego z PCLK a także dzielnik sygnału asynchronicznego jest częścią ADC, multiplexer który wybiera źródło sygnału synchronicznego należy do bloku RCC.
Napięcie odniesienia
Kolejną rzeczą o której warto wspomnieć to źródło napięcia odniesienia (Vref) niezbędne do funkcjonowania przetwornika. Do ADC jest dostarczane ono poprzez pin mikrokontrolera Vref. Na pin ten możemy podać napięcie z naszego zewnętrznego źródła napięcia odniesienia jak i również podłączyć wewnętrzne źródło napięcia odniesienia dostarczane z bloku Power control. Blok ten oferuje nam dwa poziomy napięć, 2.048V oraz 2.5V. Są pewne minimalne wymagania niezbędne do uzyskania z bloku Power Control żądanego napięcia odniesienia. Aby wewnętrznie uzyskać napięcie odniesienia 2.048V mikrokontroler mus być zasilany napięciem minimum 2.4V, dla uzyskania napięcia odniesienia 2.5V musimy zasilić mikrokontroler napięciem minimum 2.8V.

Wybór napięcia odniesienia ma wpływ na pomiar i wartości mierzone przez ADC. Wartość tego napięcia to jednocześnie największa mierzalna przez przetwornik wartość. Im większa wartość Vref tym większa możliwa wartość do zmierzenia przez ADC, im mniejsza wartość Vref tym dokładniejszy pomiar (mniejsza wartość napięcia mierzonego przypadająca na jeden bit wyniku) O tym wspomnę przy przeliczaniu zmierzonej wartości na realną wartość napięcia.

W temacie wyboru napięć odniesienia bardzo ważna uwaga. W obudowach które nie posiadają wyprowadzonego na zewnątrz pinu Vref (np. LQFP32) pin ten wewnętrznie jest na stałe podłączony do pinu zasilania Vdd. W takim przypadku napięcie odniesienia które jest dostarczane do ADC jest równie zapięciu zasilającego mikrokontroler (Vdd) W tym przypadku nie ma możliwości podłączenia własnego źródła napięcia odniesienia czy wyboru któregoś z wewnętrznych dostarczanych przez blok Power control.

Wejścia przetwornika ADC
W STM32G071 jest tylko jeden przetwornik ADC który posiada do 19 multipleksowanych kanałów. 16 kanałów to analogowe wejścia przeznaczone do pomiaru sygnałów zewnętrznych oznaczone jako ADC_INxx, gdzie xx oznacza numer kanału. Kanały te są połączone z dedykowanymi pinami IO mikrokontrolera. W grupie tej nie ma kanałów od 12 do 14, te 3 kanały są zarezerwowane dla sygnałów: wewnętrzny czujnik temperatury, wewnętrzne napięcie odniesienia oraz zewnętrzny pin Vbat do monitorowania napięcia baterii. Najlepiej pokazuje to reference manual:
Inputs.JPG

Mniejsze obudowy mogą nie posiadać wyprowadzonych wszystkich zewnętrznych kanałów analogowych, dla przykładu mikrokontroler STM32G071KBT6 który jest w obudowie LQFP32 posiada analogowe wejściowe kanały od numeru 0 do 10, nie posiada analogowych kanałów o numerach 11, 15, 16, 17 oraz 18.

Bardzo istotna rzecz przy wyborze kanału który będzie użyty do pomiaru, pin odpowiadający używanemu kanałowi powinien być skonfigurowany jako wejście / wyjście analogowe.

Zmianę konfiguracji kanałów nie możemy dokonać podczas konwersji (pomiaru) przez przetowrnik, każda zmiana konfiguracji wybranych kanałów wymaga zatrzymania aktualnej konwersji. Gotowość nowej konfiguracji sygnalizowana jest ustawieniem flagi Channel Configuration Ready flag (CCRDY) znajdującej się w rejestrze ADC interrupt and status register (ADC_ISR)

Źródła wyzwalania konwersji i tryby pracy przetwornika ADC
Przed rozpoczęciem opisu trybów pracy warto wspomnieć o źródłach wyzwalania pomiarów. Konwersja może być zainicjowana jawnie programowo przez programistę poprzez ustawienie bitu ADSTART. Konwersja może być również wyzwolona czysto sprzętowo jednym z siedmiu trigerów. Trigerami takimi są liczniki TIM1, 2, 3, 6, 15. Niektóre zdarzenia generowane przez te liczniki mogą wyzwalać konwersję ADC. Trigerem wyzwalającym konwersję jest również EXTI line 11. Rozpoczętą konwersję można programowo zatrzymać, i tu uwaga, nie kasując bit ADSTART, do zatrzymania wymagane jest ustawienie bitu ADSTP. Zatrzymanie konwersji sygnalizowane jest wyzerowaniem bitu ADSTART.

Przejdźmy do trybów pracy. Przetwornik ADC w naszym układzie oferuje ich kilka. Tryby pomiaru możemy podzielić na:

Single mode – pomiar pojedynczego kanału, w tym trybie po wyzwoleniu przetwornik mierzy wartości napięcia tylko na jednym wybranym kanale.

Scan mode – sekwencja pomiarów z wielu kanałów uprzednio zdefiniowanych.

Tryb Scan mode możemy ze względu na organizację kolejności pomiarów podzielić na dwa dodatkowe tryby:

Sequencer not fully configurable – gdzie nie określamy jawnie sekwencji skanowania kanałów, kolejność skanowania kanałów określona jest przez numerację skanowanych kanałów, w trybie tym możemy określić kierunek skanowania kanałów, od najniższego do najwyższego lub odwrotnie.

Sequencer fully configurable – gdzie jawnie określamy kolejność skanowanych kanałów. Możemy w tej grupie zdefiniować własną kolejność niezależną od numeracji kanałów. Grupa ta może zawierać maksymalnie 8 mierzonych kanałów. Do grupy tej możemy dodać tylko kanały o numerach od 0 do 14.

Pod względem ciągłości pomiarów wyróżniamy dwa tryby:

Single-shot – w którym po uruchomieniu przetwornik dokonuje jednokrotnego pomiaru pojedynczego kanału lub sekwencji wybranych kanałów.

Continus mode – w którym przetwornik dokonuje ciągłej konwersji z wybranego kanału lub grupy kanałów.

Discontinuous mode – tryb przypominający tryb krokowy. Przetwornik po wyzwoleniu w trybie scan mode wykonuje pomiar tylko jednego kanału i zatrzymuje się. Każde następne wyzwolenie programowe czy sprzętowe rozpoczyna pomiar następnego kolejnego zdefiniowanego w trybie scan mode kanału.

Wynik każdego pomiaru zapisywany jest do rejestru ADC data register (ADC_DR), po zakończeniu konwersji wybranego kanału i zapisaniu jego wyniku do ADC_DR ustawiana jest flaga End of conversion flag (EOC) Flagę tą można programowo skasować poprzez wpisanie do niej 1. Kasowanie flagi dokonywane jest również w momencie odczytu wartości zapisanej w ADC_DR. Zakończenie całej sekwencji konwersji grupy kanałów zdefiniowanej w trybie scan mode jest sygnalizowane ustawieniem flagi End of sequence flag (EOS) Skasowanie jej następuje również jak w przypadku poprzednim poprzez zapisanie do niej jedynki. Flagi EOS i EOC znajdziemy w rejestrze ADC interrupt and status register (ADC_ISR)

W czasie pracy ADC może dojść do sytuacji, w której program nie zdążył jeszcze odczytać danych z ADC a przetwornik już chce wrzucić do ADC_DR nowe dane nadpisując nimi nieodczytane poprzednie wartości. Taka sytuacja będzie sygnalizowana flagą overrun flag (OVR) Możliwe jest zablokowanie nadpisania dotychczasowej wartości w ADC_DR jeśli nie została jeszcze odczytana, w takim przypadku nowa wartość zostanie utracona bez zapisu. Można również zezwolić na nadpisanie ADC_DR pomimo braku odczytu dotychczasowej wartości, w takim przypadku dotychczasowa nieodczytana wartość jest tracona i zastąpiona nową z aktualnej konwersji.

Powyższe dwie sytuacje mogą prowadzić do utraty jeszcze nieodczytanych danych czy też porzucania nowych bez zapisu. W tej sytuacji pomocny może okazać się tryb Wait mode conversion, który zapobiega rozpoczęciu nowej konwersji do czasu wyzerowania flagi End of conversion flag (EOC) a więc i odczytania dotychczasowych danych z rejestru ADC_DR (jak wyżej wspomniałem flaga ta jest automatycznie zerowana podczas odczytu z ADC_DR)

Zdarzenia opisane wyżej mogą również generować przerwania, aby było to możliwe należy włączyć poszczególne źródła przerwań w ADC interrupt enable register (ADC_IER)

Zdarzenia mogą również generować żądania do DMA, myślę że na temat DMA warto poświęcić oddzielny wątek.

Spójrzmy teraz na sam wynik konwersji. Przetwornik ma rozdzielczość do 12 bitów, w przypadku kiedy tak duża rozdzielczość nie jest wymagana możemy zmniejszyć jego rozdzielczość. Do wyboru mamy rozdzielczość 12, 10, 8 i 6 bitów. Im mniejsza rozdzielczość tym szybszy czas konwersji. Wynik w 16-bitowym rejestrze ADC_DR może być wyrównany do prawej lub lewej strony.

Odczyt i przeliczanie zmierzonej wartości
Aby odczytać wartość napięcia mierzonego przez ADC należy posłużyć się wzorem:
calc.JPG

n - rozdzielczość

Przypuśćmy, że wynik zmierzony przez ADC wynosi 1, czyli najmniejsza możliwa do zaprezentowania przez przetwornik wartość, rozdzielczość 12 bitów a napięcie referencyjne 2.5V, podstawiając do wzoru Vin = 1*2,5/4096 daje nam w przybliżeniu 0,00061035V, a więc ok 610uV, jest to w tej konfiguracji najmniejsza możliwa wartość jaką przetwornik może na znmierzyć. Zmniejszając wartość napięcia referencyjnego zmniejszy się wartość napięcia przypadającego na 1 bit wyniku. Jeżeli napięcie wejściowe jest równe napięciu referencyjnemu otrzymamy wynik 0xFFF czyli maksimum jakie możemy zapisać w 12-bitowej liczbie. Jeżeli podamy na wejście napięcie większe niż napięcie referencyjne, wynik nie przekroczy nam maksymalnej rozdzielczości, będzie zawsze równy 0xFFF.
Uruchomienie przetwornika ADC
Na zakończenie teoretycznego opisu chciałbym wspomnieć o przygotowaniu przetwornika do pracy. Do jego poprawnej pracy musimy włączyć wewnętrzny regulator napięcia, dokonywane jest to poprzez ustawienie bitu ADVREGEN w rejestrze ADC control register (ADC_CR) Po jego włączeniu musimy odczekać krótką chwilę, do czasu aż wewnętrzny regulator napięcia zacznie stabilnie pracować. Czas ten jest podany w dokumentacji mikrokontrolera (tADCVREG_SETUP)

Przetwornik przed pierwszym użyciem warto skalibrować, pozwoli nam to skorygować błąd (Offset) przesunięcia, który może być różny w każdym egzemplarzu i wynika on z procesu technologicznego. Dla przykładu mój mikrokontroler na starcie podawał wartość około 0x20. Po kalibracji każdy wynik pomiaru jest korygowany o tą wartość. Kalibrację możemy dokonać tylko kiedy wewnętrzny regulator napięcia jest włączony i ustabilizowany (ADVREGEN=1) przetwornik jest wyłączony (ADEN=0) oraz DMA (DMAEN=0) w ADC wyłączone. Kalibrację uruchamiamy ustawiając bit ADCAL w DC control register (ADC_CR), dopóki kalibracja nie będzie ukończona bit ADCAL pozostaje ustawiony. Ukończenie kalibracji zgłaszane jest wyzerowaniem bitu ADCAL (oraz ustawieniem flagi EOCAL) a do rejestru ADC_DR zapisywany jest wynik offsetu. Wynik kalibracji dostępny jest również w rejestrze ADC_CALFACT.

Po włączeniu i ustabilizowaniu wewnętrznego regulatora napięcia i kalibracji możemy włączyć nasz przetwornik ustawiając bit ADEN, przetwornik swoją gotowość zgłosi ustawiając flagę ADRDY w rejestrze ADC_ISR.

Wyłączenia przetwornika nie dokonujemy poprzez kasowanie bitu AREN, procedura wyłączenia przetwornika wymaga ustawienia bitu ADDIS znajdującego się w ADC_CR. Zakończenie procedury wyłączenia przetwornika ADC sygnalizowane jest sprzętowym wyzerowaniem bitów ADEN oraz ADDIS.

Praktyczny przykład użycia przetwornika ADC
Po części teoretycznej przyszedł czas na praktyczny projekt. A więc tworzymy prosty przykład wyzwalania i konwersji danych za pomocą ADC. W następnej części wrzucę przykładowy program w którym użyjemy naszego przetwornika. Nie opisałem jeszcze w części teoretycznej zagadnienia analogowego watchdoga oraz nadpróbkowania, myślę że i to warto będzie na końcu dodać jako dodatkowe możliwości ADC.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Zealota
Posty: 1
Rejestracja: środa 08 maja 2019, 08:49

Re: STM32G0 i ADC

Postautor: Zealota » poniedziałek 27 sty 2020, 08:46

Dzięki za poradnik, dla mnie jak znalazł :)
"Zdarzenia mogą również generować żądania do DMA, myślę że na temat DMA warto poświęcić oddzielny wątek."
Popieram i wnioskuję o przybliżenie tego aspektu.
Po pobieżnej lekturze RM widzę, że samo DMA jednak trochę, różni się od starszych rodzin jak F1 czy F4, zatem z chęcią przeczytam dalszą część artykułu.


Wróć do „Programowanie STM w C/C++”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość