Projekty mikrokontrolerowe często potrzebują dokonywać pomiarów sygnałów analogowych. Niestety same rozumieją tylko ciągi cyfrowe, które mogą przybrać tylko dwa stany. Najczęściej jest to poziom masy oraz zasilania. Aby zmierzyć wartość analogową należy użyć przetwornika analogowo cyfrowego – w skrócie ADC. Praktycznie każdy współczesny mikrokontroler jest w taki przetwornik wyposażony. STM32 oczywiście też.
ADC w STM32
Układ przetwornika analogowo cyfrowego w mikrokontrolerach STM32 jest dosyć rozbudowany. Niektóre z MCU mają nawet dwa, a nawet więcej takich przetworników. Do głównych cech wbudowanych ADC należą:
- Konfigurowalna rozdzielczość do 12 bitów
- Mnogość przerwań np. od zakończenia konwersji zwykłej, wstrzykiwanej lub od analogowego watchdoga
- Tryb konwersji pojedynczy, lub ciągły
- Automatyczne skanowanie kanałów
- Programowalny czas próbkowania
- Generowanie żądania odczytu przez DMA
To tylko najważniejsze rzeczy, które wybrałem z dokumentacji. Ok, ale jak działa taki przetwornik?
Próbkowanie
Sygnał analogowy może przybierać różne wartości napięcia. Do tego jest on ciągły w czasie. Próbkowanie polega na wyznaczeniu momentów pomiarowych sygnału analogowego, który podawany jest na wejście ADC. W efekcie próbkowania dostajemy pojedyncze punkty, które należą do wykresu ciągłego.
Bardzo ważne jest tutaj twierdzenie o próbkowaniu (Kotielnikowa-Shannona). Mówi ono o tym, że aby w zadowalający sposób móc odtworzyć ze spróbkowanego sygnału cyfrowego oryginalny sygnał analogowy, należy próbkować z częstotliwością co najmniej dwukrotnie większą od najwyższej częstotliwości składowej sygnału.
Krótko mówiąc – próbkując sygnał sinusoidalny 1 kHz, powinieneś robić to, co najmniej z częstotliwością 2 kHz. Przykład bliższy życiu – podstawowe próbkowanie dźwięku wykonuje się z częstotliwością 44,1 kHz, ponieważ przyjmuje się, że sygnał mowy ma najwyższą częstotliwość składową około 20 kHz.
Kwantowanie
Jest to tzw. cyfrowy pomiar. Próbkowana wielkość przedstawiana jest w postaci najbliższej wartości cyfrowej. Kwantowanie jest silnie uzależnione od rozdzielczości przetwornika. Mierzona wartość wyrażona jest bowiem w liczbie kwantów, czyli liczbie najmniejszych części, na które można podzielić pełny zakres napięciowy przetwornika.
Mając 12-bitowy przetwornik, jego rozdzielczość wynosi 4096 i tyle mamy tych kwantów. Dajmy na to, że napięcie referencyjne, czyli to, wobec którego porównujemy nasz sygnał wynosi 3,3 V. Zmierzona wartość 4095 odpowiada temu napięciu. Podając 1 V na wejście ADC, próbka będzie miała wartość 1/3,3 * 4095 = 1240,909. Jak widzisz wartość ta nie wypada idealnie na równym kwancie, więc przetwornik przyporządkuje ją do 1241. Na tym polega kwantyzacja 🙂
Metoda, jakiej używa przetwornik jest nieco inna niż takie mnożenie napięć. Przetwornik nie zna wartości napięcia odniesienia. Może na przykład porównywać sygnał analogowy z narastającym sygnałem schodkowym w zakresie napięcia odniesienia, a następnie zapamiętanie liczby tych schodków. Pamiętaj, że po tym etapie dostajemy liczbę kwantów, a nie wartość napięcia.
Kodowanie
Ostatni etap to dostosowanie zmierzonej liczby kwantów do kodowania użytego w aplikacji. W mikrokontrolerach najczęściej jest to jednak zapis binarny liczby kwantów. W ustawieniach ADC można na przykład wyrównać tę wartość do lewej lub prawej w 16-bitowym rejestrze wyjściowym ADC.
Odczyt sygnału joysticka na STM32
Skoro już wiesz z grubsza jak działa ADC, możemy przejść do jego użycia. Joystick taki to nic innego jak dwa potencjometry działające na zasadzie dzielnika rezystancyjnego. Dwie skrajne nóżki potencjometrów są podłączone do + i – zasilania. Środkowa nóżka wyprowadzona jest na zewnątrz i napięcie na niej odwzorowuje pozycję drążka.
Jako że mamy dwie osie to takie potencjometry są dwa. Jak możesz się domyślić, będziemy mierzyć dwa niezależne sygnały. Jeden dla pozycji w osi X, drugi w osi Y.
Dzisiaj działam na Nucleo F411RE razem z STM32CubeIDE oraz bibliotekami HAL F4 w wersji 1.24.1.
Schemat
Joystick podłączyłem pod kanały 6 i 7 przetwornika analogowo cyfrowego.
Kod odczytu ADC – Polling
W pierwszej kolejności pokażę Ci najprostszy sposób na odczyt z ADC, czyli “ręczne” zlecanie konwersji ADC oraz odczyt wartości.
Przejdźmy do Cube’a. Utwórz projekt dla płytki Nucleo F411RE. Zaakceptuj domyślną konfigurację peryferiów na płytce. Przyśpiesza to nieco konfigurację – UART jest już z bańki i HCLK jest ustawione na dosyć wysoką wartość 84 MHz.
Napisałem, że podłączyłem się do kanałów IN6 i IN7, dlatego zaznacz je w konfiguracji ADC1.
Zauważysz, że piny na modelu obok się podświetlą. Teraz można przejść do ustawień ADC. Możesz ustawić preskaler zegara jak Ci się podoba. Ja mam ustawione na dzielenie przez 4. Upewnij się, że masz 12-bitową rozdzielczość, choć oczywiście z mniejszą również będzie działać poprawnie. Reszta domyślna tak jak na poniższym screenie.
I to tyle z konfiguracji. Można wygenerować kod i przejść do edytora.
Polling jak wspominałem wcześniej jest to “ręczne” odpytywanie ADC. W takim wypadku trzeba:
- Jeżeli trzeba włączy ADC
- Zlecić konwersję, czyli pobranie próbki, kwantyzację oraz kodowania
- Poczekać na zakończenie konwersji
- Odczytać zmierzoną wartość
Pierwszy i drugi punkt robi funkcja
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc)
Trzeci punkt zrealizujesz za pomocą
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout)
Ostatni to już tylko odczytanie z rejestru. Jest na to oczywiście funkcja
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc)
W celu pobrania kolejnej próbki czynność powtórzyć. Dobra, dobra! Nie wiem, czy wiesz, ale ADC może konwertować tylko jeden kanał na raz. Oznacza to, że musi mieć gdzieś wskazane, którym ma się zająć. Domyślnie jest to pierwszy zaznaczony, czyli w naszym wypadku IN6. Dla oczytu innych kanałów przed zleceniem konwersji należy wskazać, z którego kanału ma skorzystać.
Napisałem to tego prostą funkcję opierając się na kodzie inicjalizującym ADC który wygenerował Cube.
void ADC_SetActiveChannel(ADC_HandleTypeDef *hadc, uint32_t AdcChannel) { ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = AdcChannel; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; if (HAL_ADC_ConfigChannel(hadc, &sConfig) != HAL_OK) { Error_Handler(); } }
Kod standardowo jest w czwartej sekcji użytkownika.
Ostatecznie odczytanie dwóch kanałów i przesłanie ich na UART2 wygląda tak:
/* USER CODE BEGIN 2 */ HAL_ADC_Start(&hadc1); // You have to start ADC /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) { Joystick[0] = HAL_ADC_GetValue(&hadc1); // Get X value ADC_SetActiveChannel(&hadc1, ADC_CHANNEL_7); HAL_ADC_Start(&hadc1); } if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) { Joystick[1] = HAL_ADC_GetValue(&hadc1); // Get Y value ADC_SetActiveChannel(&hadc1, ADC_CHANNEL_6); HAL_ADC_Start(&hadc1); } sprintf((char*)UartMessage, "X: %d, Y: %d\n\r", Joystick[0], Joystick[1]); UART2_Print(UartMessage); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ }
Wynikiem tego są wartości ADC na terminalu. Bez ingerencji w gałkę joysticka, znajduje się ona w centralnym położeniu. Połowa z 12-bitowej rozdzielczości to 2048, czyli około tego wyniku powinniśmy się spodziewać.
Jak widać bywa różnie, ale zawsze gdzieś wokół 2048. Niestety pomiar ADC potrafi mocno pływać. Ma na to wpływ mnóstwo czynników, ale to nie jest dzisiejszy temat. Można na przykład zebrać 10 próbek i uśrednić je. Na pewno będzie wtedy mniej pływania.
Myślę, że czasu konwersji nie ma co badać. Wymienię tylko, że na jego długość mają takie czynniki jak:
- Czas próbkowania
- Taktowanie ADC
- Rozdzielczość
Przetworniki mogą być bardzo szybkie. W STM32 niektóre sięgają maksymalnemu samplingowi na poziomie na przykład 5 MSPS(Megasamples per Second) w STM32F303. Zewnętrzne układy potrafią być jeszcze szybsze.
Kod z pollingiem znajdziesz tutaj.
Kod odczytu ADC – Continuous reading DMA
Nie mogło zabraknąć DMA 🙂 Mało tego! Możes uruchomić ADC raz i zapomnieć o nim całkowicie. Umożliwia to Continuous Conversion Mode. Polega on na tym, że ADC zaraz po zakończonym pomiarze startuje kolejny bez naszej ingerencji.
Dodatkowo, gdy chcesz mierzyć więcej niż jeden kanał przyda się Scan Conversion Mode. Dzięki niemu ADC będzie sam przełączał kolejne kanały. Fajnie, co nie?
Do tego dorzućmy DMA, które samodzielnie odczyta pomiary i wpisze je w odpowiednie miejsce w pamięci. Koniec z ręcznym odpytywaniem i czytaniem pomiarów!
Do dzieła. Skonfigurujmy tę magię. Poprawmy też delikatnie wahania odczytów. Tak się prezentuje konfiguracja.
Lećmy od góry. Zwiększyłem preskaler ADC. Będzie działał trochę dłużej, ale powinno poprawić to stabilność odczytu(dłuższy sampling).
Włączyłem Scan Conversion Mode i Continuous Conversion Mode z wiadomych względów.
Włączyłem DMA Continuous Requests. Pozwólmy, aby ADC sam szturchał DMA, że ma już gotowe dane do odczytu.
Upewnij się, że End of Conversion Selection masz ustawione na zakończenie konwersji pojedynczego kanału.
Teraz w sekcji ADC_Regular_ConversionMode ustaw ilość konwersji na 2. Chcemy, aby ADC automatycznie skanowało dwa kanały.
Tutaj jeszcze ustawiłem sampling każdego z kanałów na wartość maksymalna 480 cykli zegara. Wpłynie to na stabilność odczytów.
W zakładce DMA Settings musisz jeszcze ustawić, aby zapis DMA do bufora był cykliczny.
Tak przygotowaną konfigurację możesz wygenerować i przejść do kodu.
Narobiliśmy się, ale co wpisać w kodzie. Otóż cały kod, który będzie nam konwertował sygnał analogowy i pisał do przygotowanych wcześniej zmiennych to, uwaga:
/* USER CODE BEGIN 2 */ HAL_ADC_Start_DMA(&hadc1, Joystick, 2); // You have to start ADC with DMA /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { sprintf((char*)UartMessage, "X: %d, Y: %d\n\r", (int)Joystick[0], (int)Joystick[1]); UART2_Print(UartMessage); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */
Tak! Wystarczy uruchomić ADC w trybie DMA i już odczyty z obu kanałów lecą do wybranej tablicy (u mnie uint16_t Joystick[2]). Warto tutaj wspomnieć, że lecą one z maksymalną możliwą prędkością.
Jak szybko w tej konfiguracji? Sprawdźmy poprzez zmianę stanu pinu testowego podczas każdego zakończonego transferu DMA.
Obydwa kanały odczytywane są co 92 µs, czyli wychodzi jakieś 10,8 kHz. Nie ma szału, ale pamiętaj, że w tej chwili mamy bardzo długi czas samplowania.
Kod z odczytem ciągłym znajdziesz tutaj.
No dobra, ale jeśli chciałbym uzyskać 44,1 kHz to po prostu skracam sampling i próbuję tym sposobem wcelować w 44,1 kHz? Zmniejszyć czas samplowania tak, ale czy celować na ślepo tak, aby to była pełna prędkość ADC? Niekoniecznie. Jest lepsza metoda!
Kod odczytu ADC – Timer triggering conversion
Możesz zaprzęgnąć któryś z Timerów, aby w równych odstępach czasu zlecał konwersję sygnału analogowego. Dzięki temu ustawiając Timer na 44,1 kHz będziemy pewni, że kolejne próbki będą pobierane w odpowiednim czasie. Let’s do this!
Ja zostawię czas konwersji tak jak był. Spróbujmy wycelować Timerem w 200 Hz regularnego samplingu. To będzie wystarczające dla działania z joystickiem. Takie urządzenie nie wymaga częstego czytania. Przejdźmy do Cube’a. Najpierw ADC.
Jak widzisz wyłączyłem Continuous Conversion Mode. Tym razem to nie ADC będzie decydowało o tym, kiedy wystartować konwersję.
W sekcji ADC_Regular_ConversionMode jest takie ustawienie jak External Trogger Conversion Source. Do wyboru masz kilka Timerów oraz rodzaj triggera. Albo jest to Capture Compare Event albo Out Event. Ustaw Timer 2 Trigger Out Event. Będzie on występował po przepełnieniu licznika TIM2.
Teraz przejdź do ustawień TIM2.
Clock Source ustaw na Internal Clock. Taktowanie dostarczone, teraz konfiguracja przepełnienia.
Chcemy uzyskać 200 Hz, czyli każde przepełnienie powinno wystąpić dokładnie co 5 ms. W pierwszej kolejności ustawmy Preskaler. Częstotliwość “główna” to 84 MHz. Dzieląc przez 84, uzyskasz tick na poziomie 1 µs. Dzielny dalej. Podział na 8400 da już 0,1 ms. Może być, co? Wpisz 8400-1 lub 8399.
Teraz ustaw okres zliczania na 49, aby uzyskać 5 ms na przepełnieniu licznika.
Ważne, abyś ustawił TRGO, które jest wyzwalaczem dla ADC. Trigger Event Selection ustaw na Update Event, aby przekazywać odpowiednie zdarzenie dla ADC. Teraz przejdźmy do kodu.
Kod jest bardzo podobny do tego, który obsługuje ADC + DMA w trybie ciągłym.
/* USER CODE BEGIN 2 */ HAL_TIM_Base_Start(&htim2); HAL_ADC_Start_DMA(&hadc1, (uint32_t*)Joystick, 2); // You have to start ADC with DMA /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { sprintf((char*)UartMessage, "X: %d, Y: %d\n\r", (int)Joystick[0], (int)Joystick[1]); UART2_Print(UartMessage); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
Jedyną różnicą jest wystartowanie Timera przed uruchomieniem ADC. Teraz samplowanie powinno odbywać się co 5 ms.
Wyszło 4,93 ms, czyli około 202,8 Hz, więc bardzo blisko. Można by się zastanowić, dlaczego nierówne 5. Ustawiając przepełnienie na 50 uzyskałem według analizatora 5,03 ms, a więc trochę lepiej. Pytanie jak bardzo dokładny mam analizator. Podejrzewam, że nie jest to sprzęt wysokiej klasy 🙂
Spróbuj uzyskać samplowanie Audio, czyli 44,1 kHz. Kod z triggerowaniem timerem znajdziesz tutaj.
Podsumowanie
Jak widzisz wbudowane w STM32 przetworniki analogowo cyfrowe mają ogromne możliwości. Ich konfiguracja jest naprawdę rozbudowana, a jednocześnie prosta mając Cube’a. Przy dobrym skonfigurowaniu, użycie ADC może sprowadzić się jedynie do jego wystartowania, co jest mega udogodnieniem. W Arduino tego nie ma 😉
Co myślisz o ADC w STM32? Podziel się swoją opinią w komentarzu.
Pełny projekt wraz z biblioteką znajdziesz jak zwykle na moim GitHubie: link
Jeśli zauważyłeś jakiś błąd, nie zgadzasz się z czymś, chciałbyś coś dodać istotnego lub po prostu uważasz, że chciałbyś podyskutować na ten temat, napisz komentarz. Pamiętaj, że dyskusja ma być kulturalna i zgodna z zasadami języka polskiego.
23 komentarze
Avery · 28/04/2023 o 02:13
Nie do końca rozumiem dlaczego opcja DMA Continuous Requests musi być włączona kiedy wyzwalamy konwersję z TRGO (Tak sprawdzałem, że bez tego nie działa), ale czy ADC sam nie powinien wyzwalać DMA po każdej zakończonej konwersji?
Nowy · 23/04/2023 o 21:32
Witaj Jestem tu nowy ale mam pytanie. Napisałeś w artykule
“Jak szybko w tej konfiguracji? Sprawdźmy poprzez zmianę stanu pinu testowego podczas każdego zakończonego transferu DMA.”
Rozumiem że zmieniamy stan pinu na przeciwny po zakończonym transferze, ale jak odczytać kiedy kończy się transfer DMA.
Pozdrfawiam. Życzę miłego dnia.
Mateusz Salamon · 24/04/2023 o 10:46
Najlepiej w przerwaniu od zakończenia transferu 🙂 Mamy tam callback od HALa.
Nowy · 24/04/2023 o 18:31
Dziękuję za odpowiedź ale przejrzałem dokumentację HAL i nie znalazłem żadnego callback-a jest jedynie funkcja HAL_DMA_PollForTransfer() oraz można zarejestrować Callbacka funkcją HAL_DMA_RegisterCallback() ale z tym sobie jeszcze nie poradzę bo nie bardzo wiem co wpisać jako parametry zwłaszcza drugi. Może napiszesz coś więcej (jakiś przykład użycia) . Było by miło. Pozdrawiam.
Avery · 28/04/2023 o 02:05
Przynajmniej w przypadku G0, Cube (z tego co zrozumiałem) podpina callbacki od zakończonych transferów DMA do callbacków od peryferiów, np. HAL_ADC_ConvCplt_Callback. Nawet przy wyłączonych przerwaniach od ADC(przerwania od DMA włączone) callback się odzywa. Dlatego nie można Callbacków od DMA domyślnie znaleźć w kodzie jako _weak + domyślnie włączony jest CallbackRegister(pozwala zarejestrować własne callbacki) dla DMA gdzie w Cube nawet nie da sie go wyłączyć. Popraw jeśli się mylę.
Michał · 06/05/2021 o 01:17
Cześć, czy pojawi się jakiś materiał na temat przetworników DAC? A może używałeś jakiegoś przetwornika DAC niewbudowanego w STM32. Mam problem z konfiguracją i obsługą przetwornika MCP4725. Niestety wszystkie tutoriale na yt czy w internecie, są opisane tylko dla Arduino. Byłbym bardzo wdzięczny, gdybyś mógł doradzić mi, za co się zabrać na początku, bo kompletnie nie wiem co zrobić Z góry dzięki za odpowiedź.
Mateusz Salamon · 17/05/2021 o 13:21
Nie planowałem póki co DACa. Musisz zrozumieć jak on działa to po pierwsze. W sensie co na niego wysyłać itp. mam nadzieję, że nie kopiujesz bezmyślnie projektów 😉
Jakub Szymański · 01/04/2021 o 16:56
Mam nadzieję, że ktoś odczyta, bo napotkałem bardzo dziwny problem związany z Joystkickiem. Otóż przy odczytywaniu wartości – używam DMA – gdy nie dotykam joysticka, wartości jakie dostaje są w granicach od 8 do 11. Dopiero po przechyleniu wartości zwiększają się. Kod już sprawdzałem trzy razy, tak samo jak i połączenia, sprawdziłem również joystkick na Arduino i tam wartości są w okolicy połowy zakresu, czyli 512. Co może powodować, że mam tak niskie wartości w STM?
Korzystam z STM3F429IDISC1. Dzięki wielkie za pomoc!
Mateusz Salamon · 02/04/2021 o 09:29
Jasne, że ktoś czasem tu zagląda 😉 Zobacz czy na tym pinie w Disco nie masz czegoś innego, co Ci ściąga pin do masy. Akurat DISCO-F429 ma zdecydowaną większość swoich pinów użytych do TFT i zewnętrznego SDRAM. Musisz znaleźć kanał ADC, który nie jest użyty w zesatwie.
Jakub Szymański · 03/04/2021 o 11:09
Faktycznie wcześniej o tym nie pomyślałem. Teraz zajrzałem do dokumentacji i Piny do których podłączyłem Joystick – PA1 i PA2 są oznaczone w dokumentacji jako INT1 i INT2 w funkcji I3G4250D, czyli z tego co widzę jest to żyroskop. Dzięki za odpowiedź i pomoc!
andrzej · 17/05/2020 o 16:58
Fajnie. Ale ja chciałbym aby timerem były wyzwalane 2ADC w tym samym momencie. Na razie działa mi na jednym timerze, gdy jest ustawione HAL_ADC_Start_IT(&hadc1) i HAL_ADC_Start_IT(&hadc2) to program wisi. HAL_ADC_Start_IT(&hadc1) i HAL_ADC_Start(&hadc2) to działa pierwszy co wybrany timerem czas a drugi ciągle. Pomożesz? Global interrupt od ADC1 i ADC2 ustawione.
Andrzej · 17/05/2020 o 17:38
Chyba rozwiązałem. Przez pomyłkę miałem włączone w ADC2 Continous Conv. Mode. Jak wyłączyłem oraz ADC1 ma Start_IT a ADC2 Start zmiana następuje po zadanym okresie czasu.
Mateusz Salamon · 18/05/2020 o 13:53
No i git, że znalazłeś błąd 🙂
Tomek · 26/04/2020 o 18:36
A co w sytuacji gdy Dma i Twój program w tym samym momencie chce uzyskać dostęp do zmiennej ?
Mateusz Salamon · 26/04/2020 o 18:54
To jest ciekawy przypadek. Masz takie coś? W nocie do F303 można przeczytać coś takiego:
“The DMA controller performs direct memory transfer by sharing the system bus with the Cortex-M4 ® F core. The DMA request may stop the CPU access to the system bus for some bus cycles, when the CPU and DMA are targeting the same destination (memory or peripheral).” Taki konflikt nie powinien mieć znaczenia tak naprawdę 🙂
Bartosz · 30/01/2021 o 22:44
Oczywiście że taki konflikt ma znaczenie… W tej chwili może dochodzić to sytuacji, gdy na UARTa zostanie wysłana wartość jednego kanału z nowego pomiaru, a drugiego jeszcze z poprzedniego. W tak trywialnym przykładzie nic to nie zmienia, ale w wielu przypadkach przetwarzanie takich danych będzie skutkować błędnymi wynikami. Dochodzi do tzw. zjawiska wyścigów. Właśnie dlatego zwykle w DMA używa się przerwań.
Fonak · 18/10/2019 o 19:09
Witam,
Faktycznie STM32 ma dość rozbudowany moduł ADC i jego poznanie wymaga sporo zaangażowania i czasu którego zawsze brakuje :). Może wiec fajnym pomysłem byłoby podzielenie artykułu na części (nie koniecznie po sobie następujące) i opisane tych bardziej zaawansowanych trybów w następnych odcinkach o ADC. Do napisania komentarza o zaawansowanych trybach ADC skłoniła mnie wręcz szczątkowa ilość tutoriali na innych stronach o tematyce związanej z STM32, nawet forum producenta ma niewiele wątków w tym temacie.
Co do samego artykułu to bardzo dobry.
Fonak · 17/10/2019 o 17:44
Witam,
Dobry artykuł lecz uważam że do pełni szczęścia powinny zostać opisane jeszcze takie tryby pracy jak:
– “dual reguar simultaneous mode” bardzo przydatne gdy zachodzi konieczność pomiaru prądu i napięcia jednocześnie, mocy (pomiar kąta) czy impedancji (mostek LCR)
– “dual fast interleaved mode” przydatne w przypadku konieczności podwojenia maksymalnej częstotliwości próbkowania
– wszystkie tryby z “injected”
– tryb z przerwaniami “IT”
– tryb DMA z użyciem dwóch naprzemiennie wykorzystywanych buforów – przydatne w sytuacji gdy procesor obrabia dane w pierwszym buforze natomiast przetwornik zapisuje do drugiego, następnie role sie zamieniają.
– przydałby się dokładniejszy opis odnośnie taktowania ADC w odniesieni do czasu konwersji
PS. Tak wiem że STM32F411 nie ma dwóch modułów ADC lecz nawet wiekowy STM32F103 je ma (popularny chiński bluepill lub klon maple).
Mateusz Salamon · 17/10/2019 o 19:35
Hej, dzięki za spory komentarz. Zgadam się z tym, że mój artykuł to dopiero początek. ADC w STMach jest na prawdę bardzo rozbudowany. Do tego dochodzą tak jak zauważyłeś różnice między rodzinami w ilości przetworników czy nawet ficzerów w nich zawartych. Niestety gdybym miał to wszystko opisać w jednym wpisie to wyszła by mała książka, a tego raczej unikam tworząc artykuły. Na pewno pojawią się z czasem również te bardziej zaawansowane tryby i zastosowania ADC.
Lukasz · 17/10/2019 o 11:53
Fajny artykuł. Ja korzystam z płytki stm32f072rb i przy pomocy ADC i DMA muszę odczytać pomiar z dwóch kanałów – temp wew procesora oraz stężenie gazu w otoczeniu z czujnika mq5. W CubeMX dla mojej płytki nie ma jednak opcji Number of Conversions. I teraz się zastanawiam czy ma to duże znaczenie?
Mateusz Salamon · 17/10/2019 o 12:16
Hmm chyba domyślnie skanuje wszystkie wybrane kanały bo F0 chyba nie na możliwości pomiaru w trybie injected. Spróbuj 🙂
Marcin · 16/10/2019 o 20:51
Dobry materiał, polecam. II część używam, I zacznę
Mateusz Salamon · 16/10/2019 o 21:46
Dzięki 🙂 Warto zawsze zastanowić się która metoda przypasuje do projektu. Nie ma jednej, najlepszej 😀