Nucleo STM32F411: mały „skok w bok” (pierwsze wrażenia)

Nie tylko Arduino i ESP8266: świat mikrokontrolerów jest znacznie bardziej zróżnicowany. Zafascynowany kursem STM32 opublikowanym na forbot.pl, postanowiłem spróbować czegoś innego.

W tej chwili na forbot.pl rozpoczyna się druga część kursu. Niestety nie na Nucleo, ale płytce Discovery. Płytka Discovery to taka bardziej edukacyjna wersja Nucleo. Zawiera dodatkowe peryferia, jak np. akcelerometr czy kompas (których nie ma na płytce Nucleo).

Kilka szybkich klików i już za chwilę nowiutkie Nucleo STM32F411 leżało na biurku – za wcale nie wygórowanę ceną ok. 60 złotych. Wygląda… inaczej niż Arduino… trochę:)

nucleo_00Poniżej znajdziecie wrażenia z pierwszego kontaktu z tą płytką. Serio: pierwszego, bo z Nucleo nigdy wcześniej nic nie robiłem:)


Sprzęt do testów dostarczył: electropark.pl
electropark_logo


…bo to w ogóle nie jest Arduino. Nucleo to całkiem inna klasa urządzeń, ba – inna filozofia. 32-bitowy procesor w architekturze ARM to obietnica wydajności. Cortex-M4, który napędza Nucleo F411, to jeden z mocniejszych przedstawicieli rodziny 'M' przeznaczonej do zastosowań jako  kontrolery. Jego starsi bracia – z rodziny 'A' – napędzają takie maszynki jak Raspberry Pi (Cortex-A7 w modelu Pi2 czy A53 w Pi 3).

Co ciekawe, płytka jest podzielona na 2 części: programatora (ST-LINK) oraz kontrolera (MCU). Programator? No właśnie – tutaj nie jest tak prosto jak w przypadku Arduino:) Proces programowania tego typu kontrolerów jest bardziej skomplikowany i wymaga specjalnego programatora. Ale nie martwcie się – w domyślnej konfiguracji ST-LINK załatwia za Was (prawie) wszystkie niuanse. Co więcej – tu programator umożliwia  też debuggowanie kodu – funkcjonalność, która bardzo ułatwia pisanie programów (o tym poniżej).

nucleo_02Na pewno zauważyliście, że płytka programatora i kontrolera są tak trochę oddzielone. W teorii możecie płytkę rozłamać na pół i używać  ten sam programator do innych MCU. Oczywiście po tej operacji będziecie musieli łączyć programator z płytką za pomocą kabelków. W postaci jaka jest w sprzedaży – wystarczy podłączyć kabel USB.

Nucleo vs Arduino UNO

Nie jestem pewien, czy ma sens porównywanie Nucleo z UNO – 32-bitowca z 8 bitowcem… Chociaż Nucleo wyposażono w złącze pozwalające na wykorzystanie rozszerzeń z UNO – więc trochę kusi:

Arduino UNO Nucleo STM32F411 Uwagi
Kontroler Atmel AtMega328p Cortex M4/F411RET6
Zegar 16Mhz 100Mhz (maksymalnie)
 Pamięć kodu 32kB 512kB
Pamięć Operacyjna 2kB 128kB
Logika 5V 3.3V  UWAGA!
Wyprowadzenia pinów „Standard” Arduino „Standard” Arduino + ST Morpho  ST Morpho : wyprowadzenia nóżek z procesora)
Ilość portów cyfrowych 13 50
Ilość portów analogowych 6 16
Przetwornik AC/DC 10 bitowy; może mierzyć 0-5V z rozdzielczością co 5mV 12 bitów; może mierzyć 0-3.3V z rozdzielczością co 0.8 mV
SPI 1 5 Piny mają po kilka funkcji, więc nie można mieć jednocześnie 5 SPI i 3 USART
 UART 1 3 (USART)
 timery 3 8 (5×16, 2×32, 1×16-PWM)
i2c 1 3
RTC (real-time clock) nie tak Brak podtrzymania zasilania na płytce
SDIO (interfejs do czytników kart SD) nie tak

32 bity?

8-bitowe komputery (jak np. mikrokontrolery Atmela AVR AtMega) w pojedynczym ogólnym rejestrze mogą trzymać 8 bitów, tzn. dla liczby bez znaku – z zakresu od 0 do 255 (2^8=256). Oznacza to, że „na raz”, w jednym cyklu, taki procesor może np. odczytać liczbę o wartości do 255 – i użyć ją do operacji arytmetycznej lub do adresowania pamięci. Operacje na większych liczbach będą wymagają złożenia kilku rejestrów – stąd będą  dłużej wykonywane. Na tej samej zasadzie ograniczenie to dotyczy również portów wejścia/wyjścia czy zegarów.

Teraz: wyobraźcie sobie, że tych bitów w pojedynczym rejestrze jest 32, czyli zmieści się tam 2^{32} =4294967296 różnych liczb! W ten sposób w jednym kroku będziecie mogli przetwarzać znacznie więcej danych (a więc szybszy procesor) i adresować duże dalsze obszary pamięci (a więc więcej dostępnej pamięci).

Morpho vs piny Arduino

Płytka wyposażona jest w 2 rodzaje złączy: Morpho i Arduino.

nucleo_03Morpho to złącze specyficzne dla STM. Na poszczególnych pinach wyprowadzone są wszystkie nóżki procesora. Znajduje się przy zewnętrznych krawędziach płytki.

Złącza STM32 (pobrano z instrukcji
Złącza STM32 (pobrano z instrukcji

Złącze „Arduino” wbudowano, żeby zapewnić Nucleo kompatybilność z shieldami Arduino. Złącze to jest zorganizowane w identyczny sposób jak to, które znajdziecie na UNO. W tym samym miejscu są piny zasilania i masy – ale również uniwersalnych portów wejścia/wyjścia. Identyczny jest również rozstaw i grupowanie pinów (CN5, CN6, CN8, CN9).

Mapowanie:

Pin Arduino Pin Nucleo 5V? 5V? Pin Nucleo Pin Arduino
 NIE  PA5 D13
 TAK  PA6  D12
 TAK  PA7  D11
 TAK  PB6  D10
 TAK  PC7  D9
 TAK PA9  D8
 TAK  PA8  D7
 TAK  PB10  D6
 A0  PA0  NIE  TAK  PB4  D5
 A1  PA1  TAK  NIE  PB5  D4
 A2  PA4  NIE  TAK  PB3  D3
 A3  PB0  TAK  TAK  PA10  D2
 A4  PC1  TAK  TAK  PA2  D1
 A5  PC0  TAK  TAK  PA3  D0

Jest jednak haczyk.

outputs_1Rozkład pinów jest może taki sam, ale STM32 posługuje się logiką 3.3V. Oznacza to, że stany logiczne pinów będą przyjmowały poziom maksymalnie 3.3V (zazwyczaj trochę mniej) – a nie jak 5V w przypadku Arduino.

Załóżmy sytuację, że rozszerzenie działa na 5V. Takie napięcie pobierze z pinu 5V i z takim będzie działać wewnętrznie. Wyobraźmy sobie, że STM32 chce przesłać logiczną „1” do tego rozszerzenia. Nie ma problemu, ponieważ „logiczna 1” to nie konkretne napięcie (np. 3.3 lub 5v) – a raczej pewien przedział. I na szczęście napięcia te się zazębiają – układ 5v (TTL) zrozumie „1” z układu 3.3v (CMOS).

ALE: w druga stronę może być gorzej!

Porty Nucleo, posługując się logiką 3,3v. Gdy 5v układ TTL zechce wysłać swoją „1”, na wejściu Nucleo pojawi się napięcie wyższe niż nominalne dla pinów… W przypadku Raspberry Pi, może to doprowadzić do jej zniszczenia (słynne przykłady z miernikami odległości HC-SR04).

Konstruktorzy z ST pomyśleli jednak i o tym. Większość pinów STM32 jest typu „FT” – czyli „5V tolerant” – co oznacza, że 5V przychodzące z rozszerzenia nie wyrządzi im krzywdy i będą rozumieć, co dostają. ALE: nie wszystkie piny Nucleo tolerują 5V. Niestety, do tej grupy należą również te … podłączone do pinów złącza Arduino!

Z tego co znalazłem w instrukcji do czipu (tabela 8), 5V nie lubią porty I/O (dyskusja tutaj):

  • PA0 (ADC1_0),podłaczony do złącza Arduino A0,
  • PA4 (ADC1_4), podłaczony do złącza Arduino A2,
  • PA5 (ADC1_5), podłaczony do złącza Arduino D13,
  • PB5, podłaczony do złącza Arduino D4,

Dodatkowo, 5V nie lubią: Vss, Vdd, Vbat, Vssa, Vdda, Vref+, Vref-, BYPASS_REG, Vcap1/2, Boot0.

Kiedy może pojawić się problem? Ano wtedy, gdy D13/D4  ustawicie jako wejście i wprowadzicie na nie sygnał 5v. Albo za pomocą A0/A2 spróbujecie zmierzyć sygnał 5v. Pamiętajcie o tym!

Samo Morpho…

Podoba mi się. W większości przypadków, gdy na Arduino nałożycie jakiegoś shielda, przesłania on wszystkie porty – nawet, jeżeli nie wszystkie wykorzystuje. Wyprowadzenia Morpho są nie tylko po bokach złącza Arduino, ale i pod spodem płytki.

nucleo_01Nie jest wiec problemem, żeby podpiąć się pod nie analizatorem czy oscyloskopem. W ten sposób można łatwo podglądnąć, co się dzieje z podłączonym rozszerzeniem.

Uwaga na przykładowy kod z innych Nucleo

Kolejne układy z rodziny STM32 różnią się między sobą dość znacząco. Spójrzcie na organizację czipa F103RBT6 użytego w kursie na forbot.pl  i tego, który kupiłem: F411RET6.

F103 ma GPIO podłączone do szyny APB2:

GPIO w F103 podłączone są do szyny APB2 (pobrane z instrukcji
GPIO w F103 podłączone są do szyny APB2 (pobrane z instrukcji)

Stąd inicjacja portów PA w przykładzie z forbot.pl, wygląda tak:


#include "stm32f10x.h"

int main(void)
{
  //F103: GPIOs are connected to APB2
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
  //..
}

Natomiast dla F411, GPIO A ( i inne) podłączono do szyny AHB1:

GPIO w F411 podłączone są do szyny AHB1 (pobrane z instrukcji)
GPIO w F411 podłączone są do szyny AHB1 (pobrane z instrukcji)

Stąd dla mojej płytki napiszę raczej:


#include "stm32f41x.h"

int main(void)
{
  //F411: GPIOs are connected to AHB1
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 
  //..
}

Oznacza to ni mniej ni więcej – że kod (czy biblioteki) które działają na jednym typie płytki Nucleo – wcale nie muszą działać na innym. Świat STM32 jest znacznie bardziej rozbudowany i niejednorodny (wystarczy spojrzeć na magiczne oznaczenie płytki:)).

Rodzina Nucleo (pobrane z st.com)
Rodzina Nucleo (pobrane z st.com)

Jak to-to zasilić?

W przypadku Arduino możliwości było kilka:

  • Przez USB z komputera/huba/ładowarki USB,
  • 5V przez pin 5V,
  • Przez jacka DC,
  • Przez pin Vin (najmniej zalecane).

Jak to wygląda z Nucleo?

Przez USB

Płytkę Nucleo wyposażono we wtyk mini-USB (konektor CN1 lub VBUS). Tak dokładniej, to zasila ona programator z którego z kolei zasilana jest płytka MCU. Jeżeli zasilacie płytkę przez USB, zworka JP5 (pod czarnym przyciskiem RESET) musi być ustawiona w pozycji U5V. Wtedy Nucleo i nałożone na niego rozszerzenie nie mogą zużyć więcej niż 300mA. Jeżeli komputer, do którego podłączona jest płytka, nie jest w stanie dostarczyć 300mA – MCU nie zostanie uruchomiony (dioda LD3 nie zapali się).

Dodatkowo, możecie ograniczyć prąd za pomocą zworki JP1 (przy wtyku USB):

  • Zwarta: pobór prądu ograniczony do 100mA
  • Rozwarta: do 300mA.

Jeżeli potrzebujecie więcej prądu, musicie zasilić płytkę zewnętrznie.

A teraz uwaga: ST-LINK kontroluje MCU; zasili go dopiero, gdy ST-LINK zostanie zidentyfikowany jako urządzenie USB. Jeżeli podłączycie Nucleo przez port USB do ładowarki USB – nic takiego się nie stanie. W tym wypadku instrukcja zaleca zwarcie pinu JP1 (tego koło gniazda USB).

Zasianie zewnętrzne

Zworkę JP5 przestawcie w położenie E5V i rozewrzyjcie JP1. Teraz:

  • VIN: ze złącza CN6 Arduino lub 24-tego pinu lewego Morpho (CN7, sąsiadujący z VIN): podłączcie zasilanie 7-12V, do 800mA przy 7v ale tylko 250mA dla 9-12v,
  • E5V: lewe złącze Morpho – CN7, pin 6, oznaczony E5V, podłączcie zasilanie 4.75-5.25v, do 500mA,
  • +3V3: pin 4 CN6 (złącza Arduino), piny 4 lub 12 CN7; 3-3.6V i max. 500mA prądu (ograniczenie stabilizatora U4) – niestety w tej opcji programator ST-LINK nie będzie zasilony (nie ma możliwości programowania)

Maksymalne napięcie na pinie VIN Nucleo wynosi 12v.

Główna zasada:

  • Najpierw podłączacie zewnętrzne zasilanie,
  • Potem podłączacie USB do programowania.
VIN

Gdy zasilacie Arduino przez gniazdo DC, prąd idzie najpierw na diodę zabezpieczającą przed odwrotną polaryzacją, a potem na stabilizator 5V. Dioda (a dokładniej spadek napięcia na niej, ok. 0.7v) i stabilizator (znowu spadek napięcia, tzw. voltage drop) sprawiają, że minimalne napięcie zasilające przez gniazdo DC to 7v.

Pin VIN podłączony jest bezpośrednio do stabilizatora za diodą. Zasilając Arduino przez niego pomijacie diodę.

Z drugiej strony, pin VIN stanowi również wyjście zasilające w momencie gdy zasilacie Arduino przez gniazdo DC. Korzysta z tego wiele rozszerzeń, które czerpią prąd właśnie z VIN.

Podobnie działa to w przypadku Nucleo.

Jeżeli zasilicie Arduino przez USB, napięcie pojawi się również na pinie VIN. Powodem tego jest… dioda D1 zabezpieczająca stabilizator 1117 przed tzw. back-feed (pobrano z instrukcji do NCP1117) :

back_feed_ams1117Dioda ta zadziała, gdy na wejściu do stabilizatora nie będzie napięcia – a pojawi się ono na wyjściu – czyli gdy Arduino zasilicie przez USB a nie przez VIN.

Taka konfiguracja nie działa w przypadku Nucelo. Gdy zasilicie je przez USB, nie będziecie mieli napięcia na VIN.

Jak to-to zaprogramować?!

I tu się zaczynają schody. Bo programuje się w czystym „C”. Bo trzeba się martwić o wiele aspektów, które Arduino IDE załatwia „po dywanem” i początkujący nie muszą się o nie martwić. Bo dostępne biblioteki (StdPeriph czy HAL), które „ułatwiają” programowanie – nie mają nic wspólnego z ułatwieniami w stylu Arduino. Tu trzeba wiedzieć co się robi i rozumieć jak STM32 jest zbudowany (patrz powyżej – przykład ze sposobem podpięcia pinów do szyn danych). Oczywiście nagrodą jest znakomicie większa wydajność i elastyczność – ale nagrodę tą (na początku) okupicie krwią, potem i łzami:)

Tak jak w kursie forbot.pl, użyłem „System Workbench for STM32”.

Środowisko do programowania zainstalowałem zgodnie z instrukcjami na stronie openSTM32. Wszystko jest darmowe,  wymagane jest tylko stworzenia konta. Ja najpierw zainstalowałem eclipse a potem uzupełniłem go o dodatki wymagane do programowania Nucleo.

mars

openSTM32 najlepiej instalować z najnowszymi wersjami eclipse. Niestety często w repozytoriach dystrybucji znajdziecie tylko  starsze wersje (instalowane przez apt-get lub Waszego menadżera pakietów). W używanym przeze mnie MINT, dostępna była jedynie wersja 3.8 – a zainstalowany przeze mnie Mars to 4.5.1. Najlepiej więc zainstalować go ręcznie, ze strony eclipse.org.

Dalej wystarczy stworzyć projekt i zabrać się za kodowanie… Proste prawda? Tak sobie. Ci, którzy nie pracowali wcześniej z eclipse, mogą mieć pewne problemy z opanowaniem go.

mars_01Eclipse to profesjonalne środowisko, bardzo rozbudowane oferujące mnóstwo opcji – przeznaczone dla trochę innego segmentu użytkowników niż Arduino IDE. Na początku trudno się w nim odnaleźć (perspektywy, konfiguracje startowe). Ale gdy się do niego przyzwyczaicie – zobaczycie jak jest potężne.

W Eclipse możecie pisać pod Javą, C, C++  -i dziesiątkami różnych języków czy platform. To profesjonalne narzędzie, które używa wielu programistów.

No to pierwszy program, oczywiście migający diodą. Płytka Nucleo ma na sobie zieloną diodę LD2, podłączoną do pinu D13 złącza Arduino – lub portu PA5.

#include "stm32f4xx.h"

//Based on forbot.pl examples; modified for F411
//Delay function
void delay(int time){
    for (int i = 0; i < time * 4000; i++);
}
//Main function
int main(void)
{
  //Enable clock on AHB1
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  //GPIO object
  GPIO_InitTypeDef gpio;
  //Init with defaults
  GPIO_StructInit(&gpio);
  //Set PA5 to output - there is LED connected there
  gpio.GPIO_Pin = GPIO_Pin_5;
  gpio.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_Init(GPIOA, &gpio);
  //Blink!
  for(;;){
    //Set port A5 HIGH 
    GPIO_SetBits(GPIOA, GPIO_Pin_5);
    delay(1000);
    //Set port A5 LOW
    GPIO_ResetBits(GPIOA, GPIO_Pin_5);
    delay(200);
  }
}

Cóż… Blink dla Arduino zajmuje tylko kilka linijek…

Debuggowanie

Gdy tylko zaczniecie bawić się z eclipse, od razu zauważycie opcję, której w Arduino IDE było nieosiągalna! Chodzi mi o debuggowanie kodu. Co to oznacza?

mars_03Dzięki programatorowi ST-LINK, możecie przejść przez Wasz program krok-po-kroku i dokładnie zobaczyć, co się dzieje ze zmiennymi, rejestrami procesora itp. Żegnaj Serial.println() i konsolo szeregowa, witaj XXI wieku!

mars_02Debuggowanie to naprawdę potężne narzędzie i wiele problemów w Waszym kodzie znajdziecie w pierwszym przebiegu.

Co dalej?!

Płytka spodobała mi się na tyle, że na pewno będę kontynuował doświadczenia z nią.

Zdecydowanie, jest to wyzwanie. Świat Nucleo jest tak inny od Arduino, że aż… nie mogę się doczekać  jak się do niej dobiorę na serio:) Co pójdzie na pierwszy ogień? Może spróbuję zacząć od niedawno testowanego ostatnio rozszerzenia GSM? Jego producent obiecuje, że płytka działa również z Nucleo – sprawdzenie tego jest więc bardzo nęcące:)

nucleo_05

Źródła

Zakupy

Płytki Nucleo dostępne są w Electropark.pl.

Jedna myśl w temacie “Nucleo STM32F411: mały „skok w bok” (pierwsze wrażenia)”

Dodaj komentarz