STM32F100-Mikrokontrollerin ohjelmointi

Alunperin julkaistu: 9.10.2019

Viimeksi muokattu: keskiviikko 25.11.2020

ARM mikroprosessori STM32VLDISCOVERY
STM32VLDISCOVERY-kehitysalusta, missä on STM32F100RB-mikroprosessori.

STM32-mikrokontrollerit ovat nykypäivänä todella suosittuja 32-bittisiä Arm Cortex-M prosessorilla varustettuja mikro-ohjaimia. Niitä käytetään monissa eri teollisuuden laitteissa, instrumenteissa, kuluttajalaitteissa ja vähän vaikka missä. STM32-tuoteperheen valikoimista löytyy ohjaimia "yksinkertaisten" ja vähävirtaisten laitteiden älyksi, mutta myös suurempiin ja haastavampiin sovelluksiin ohjaimia voidaan käyttää. Myöskin langaton ohjainpiiri on saatavilla.

Tässä kirjoituksessa ajattelin valottaa ja tuoda esille niitä vaiheita, joita itselläni tarvitsi toteuttaa, että sain ledin vilkkumaan ja vähän muutakin ARM-prosessorin avulla. Lyhyesti vaiheet ovat nämä:

  1. Kehitysalustan hankkiminen
  2. Tarvittavien ohjelmien asentaminen
  3. Projektin luonti
  4. Ensimmäinen ohjelma: Ledin vilkutus
  5. Ohjelmointi kohdelaitteeseen (STM32-mikroprosessori) ja toiminnan toteaminen
  6. Toinen ohjelma: sarjaporttiin tulostus
  7. Kolmas ohjelma: printf/scanf-tuki
  8. Neljäs ohjelma: AD-muunnin DMA:n avulla

Olen tälle mikroprosessorille joskus vuosia sitten (edellisen tietokoneen aikaan) tehnyt koodeja pienen OLED-näytön ohjaamiseksi, mutta en silloin kirjoitellut ylös mitään koodin kommentteja erikoisempaa. Siksi ajattelin nyt kirjoitella siitä, kuinka "hello world" -tapaisen ohjelman saa tällä toteutettua.

HUOM! Tässä on tehty oletuksia, että lukija jo jotain tietääkin aiheen tiimoilta eli kaikkea ei ole selitetty juurta jaksain. Jos mikrokontrollerien ohjelmointi kiinnostaa, mutta kokemusta ei vielä ole niin kannattaa aloittaa helpommista kuten Arduino-oppaasta tai MSP430-oppaasta.

1. Tarvittava elektroniikka l. rauta

Kaapissani on jo vuosia lojunut STM32VLDISCOVERY-niminen kehitysalusta, missä on istutettuna STM32F100RB-mikroprosessori, muutama led ja painonappi sekä headereita oheislaitteiden ja muiden komponenttien liittämiseen.

ARM mikroprosessori STM32VLDISCOVERY
STM32VLDISCOVERY-kehitysalusta.

Kehitysalustan tilasin aikoinaan verkkokaupasta X, minkä nimeä en nyt satu muistamaan, mutta pulitin tästä noin kymmenisen euroa ja parin euron postimaksun.

Vaikka näitä ei nykyään enää taideta myydä, niin esimerkiksi STM32 tuoteperheen uudempia Nucleo-kehitysalustoja löytyy mm. elfan verkkokaupasta: https://www.elfadistrelec.fi/fi/stm32-nucleo-kortti-stm32f411ret6-st-nucleo-f411re/p/30009240. Myöskin Partcolla vaikuttaa olevan jonkin verran valikoimaa näistä tuotteista: https://www.partco.fi/fi/search?controller=search&orderby=position&orderway=desc&search_query=stm32&submit_search=.

Esimerkkien teko ja koodien ohjelmointi onnistuu myös muillakin kehitysalustoilla, joten jos aivan yllä olevan kaltaista kehitysalustaa ei löydy, niin muunlaisetkin alustat kelpaavat. Tämän kirjoituksen kannalta pääasia on se, että mikrokontrolleri voidaan ohjelmoida ST-Link Utility -ohjelmalla (tällöin pitää tietenkin esimerkeissä valita muu kuin STM32F100 kohdelaitteeksi). Uudemmat Nucleo-kehitysalustat ovat suoraan tuettuja STM32CubeIDE-ympäristössä.

2. Tarvittavien ohjelmien asentaminen

STM32-mikroprosessorien ohjelmointiin on aivan viime kuukausina ilmestynyt ST:n oma ohjelmointi- ja debuggaus-ympäristö nimeltä STM32CubeIDE. Kyseessä on täysiverinen kehitysympäristö, missä esimerkiksi mikroprosessorin pinnit voidaan määritellä graafisesti ja alustuskoodit generoida sen mukaisesti ja alkaa sen jälkeen koodailemaan omaa ohjelmaansa. Tästä lisää myöhemmin.

Ensiksi pitää asentaa siis STM32CubeIDE osoitteesta https://www.st.com/en/development-tools/stm32cubeide.html. Latauslinkin saaminen edellyttää sähköpostin antamista, mutta linkki tulee aika nopeasti sähköpostiin mistä ohjelman voi ladata.

Asennuksen jälkeen tälle STM32VLDISCOVERY-kehitysalustalle tarvitaan ohjelmointi-ohjelma, koska kyseessä on niin vanha kehitysalusta ettei uusinta uutta oleva ohjelma tue sitä ohjelman polton ja debuggauksen merkeissä. Tarvitaan siis ladata ST-Link Utility-ohjelma, minkä avulla mikroprosessorille ohjelma voidaan ladata. Ohjelmalla voidaan käsittääkseni ohjelmoida myös muita mikroprosessoreita.

STM32 ST-LINK Utility ohjelma
STM32 ST-LINK Utility ohjelma

Kun perusteet on kunnossa niin voidaan aloittaa ohjelmaprojektin tekeminen!

3. Projektin luonti

Aloitetaan luomalla uusi projekti STM32CubeIDE:llä, File -> New -> STM32 Project. Ohjelma voi vähän tietokoneesta riippuen odotuttaa ikkunan avaamista, mutta ainakin alla olevan ikkunan pitäisi ruutuun ilmestyä:

STM32 Projektin luonti
Odottele rauhassa...

Kun projekti-ikkuna avautuu, voidaan valita haluttu kohdelaite tai kehitysalusta hakemalla osanumerolla kuvan korostamasta ikkunan paikasta tai valitsemalla MCU/MPU-välilehdeltä haluttu chippi.

Mikrokontrollerin valinta projekti-ikkunassa
Kohdelaitteen valinta

Tämän jälkeen voidaan asettaa projektille nimi ja haluttu sijainti mikäli vakiopaikkaa ei halua käyttää kyseiselle projektille. Muut täpät kannattaa antaa olla tällaisenaan.

Projektin asetukset
Projektin nimi ja valinnat

Next-napilla kannattaa käydä kurkkaamassa vielä pari muuta asetusta, joilla voidaan määrittää kopioidaanko kirjastotiedostot projektikansioon vai käytetäänkö ohjelman asennuksen yhteydessä luotuja kirjastotiedostoja vain referenssinä.

Kirjastotietojen kopiointi
Valitse haluatko kopioida kirjastotiedostot projektiisi

(Yllä olevassa kuvassa on "Target Reference" merkitty eriksi, kuin aiemmin mainittu kehitysalusta. Tämä johtuu siitä, että screenshottia tehdessäni valitsin vain nopeasti jonkun targetin randomisti.)

Jos valitset alimman vaihtoehdon Copy, niin voit ainakin turvallisesti "puukottaa" oletustiedostoja haluamaksesi ilman pelkoa siitä, että koko ohjelmointiympäristön kirjasto halvautuu. Tämä voi joskus olla tarpeellistakin. Valinta Copy kasvattaa projektitiedostojen vaatimaa tilaa kiintolevyltä. Tämän sivun esimerkkien kannalta on ihan sama kuinka tekee, itse valitsin kuitenkin "Add necessary library files as reference in the toolchain project configuration file", jolloin käännöksessä käytettyihin tiedostoihin vain viitataan ja ne ovat ns. "read only" formaatissa.

Finish-napilla kuitataan muutokset ja projektin automaattinen generointi alkaa. Ohjelma kysyy (ainakin jos jokin kehitysalusta oli valittu) vielä asetetaanko oheislaitteet (eli AD-muuntimet, UART, DMA, mitä kohdelaitteessa ikinä onkaan saatavilla) oletusmoodiin. Lisäksi ohjelma kysyy avataanko CubeMX-perspektiivi, eli näkymä mistä voidaan pinnejä konfiguroida käsin. Molempiin voidaan vastata kyllä. Tämän jälkeen ohjelma alkaa lataamaan tarvittavia tietoja kehitysalustasta/MCU:sta koneelle.

Oletusasetukset
Oletusmoodien asetus
Perspektiivi
Perspektiivinäkymän avauskysymys
Ohjelmatiedostojen lataaminen
Tarvittavien tiedostojen lataaminen palvelimelta

Näiden vaiheiden jälkeen päästään konfiguroimaan käytettyä MCU:ta ja sen oheislaitteita graafisessa käyttöliittymässä:

Pinnit voidaan konfiguroida visuaalisesti hiirellä klikkailemalla
Pinnit voidaan konfiguroida visuaalisesti hiirellä klikkailemalla

Jos graafinen konfigurointi-ikkuna ei näy, niin tuplaklikkaamalla .ioc -päätteistä tiedostoa voidaan konfigurointinäkymä avata.

Riippuen mitä olet valinnut projektin nimeksi ja mikä on mikroprosessorisi, niin projektin perusrungon näkymä on aikalailla alla olevan kuvan kaltainen.

Ohjelmakoodien rakenne
Project Explorer-ikkunassa näkyvä koodirunko

Lisätään vielä projektin asetuksiin täpät ohjelmointitiedostojen luontiin. Näiden asetusten avulla voidaan ST-Link-Utilitylla ohjelmoida mikroprosessori sitten kun sen aika on. Alla olevan kuvan asetukset löytyvät valikosta: Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -välilehti ja MCU Post build output -valikko.

Ohjelmakoodien generointiin tarvittavat asetusruksit
Ohjelmakoodien generointiin tarvittavat asetusruksit

4. Ensimmäinen ohjelma: Ledin vilkutus

STM32CubeIDE mahdollistaa STM32-mikroprosessorien helpon ohjelmoinnin standardikirjaston HAL avulla. HAL tulee sanoista Hardware Abstraction Layer, mikä yksinkertaisesti tarkoittaa sitä, että mikrokontrolleria ei tarvitse rekisteritasolla komentaa, esimerkiksi:

GPIOA->regs->BSRR = 0b0011000000000100;

Toisin sanottuna, mikroprosessorin pinnejä ja oheislaitteita voidaan ohjata helpoilla C-kirjaston komennoilla esimerkiksi tähän tapaan:

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_9);

Yllä oleva koodi on sama kuin mitä on alla olevassa kuvakaappauksessa led-vilkutuksen lähdekoodissa käytetty. Kuten voinee huomata, niin koodi on aika itsensä selittävää. Olennainen asia, joka kannattaa muistaa kun koodia kirjoittaa on se, että koodi kirjoitetaan kommenttilohkojen "USER CODE BEGIN" ja "USER CODE END" väliin. Tiedoston nimi on main.c eli pääohjelman lähdekoodi.

STM32F100 LED vilkutus
Ledin vilkutuksen koodi

Koodi buildataan Project -> Build Project -valikosta tai CTRL + B näppäinyhdistelmällä. Jos koodi on virheetön niin Console-ikkunaan alhaalle tulee aikaleima ja "Build Finished" -teksti. Virheiden ja varoitusten määrä pitäisi olla 0 tässä vaiheessa.

5. Ohjelmointi kohdelaitteeseen (STM32-mikroprosessori) ja toiminnan toteaminen

Koodin lataus tehdään siis ST-Link Utility ohjelmalla niin, että kytketään STM32VLDISCOVERY-kitti tietokoneeseen ja avataan ko. ohjelma. Sitten valitaan Target -> Program... ja valitaan haluttu binääri/hex -tiedosto joka MCU:lle ladataan. Tässä vaiheessa onkin olennaista, että Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -välilehti ja MCU Post build output -valikosta on valittu koodien generointiruksit aktiiviseksi (kts. kohta 3:n kuva).

STM32 ohjelman lataus ST-Linkillä
Ohjelman lataus ST-Link Utility työkalun avulla

Kun yllä oleva ledin vilkutuskoodi on ladattu mikroprosessorille niin ohjelma alkaa automaattisesti suorittamaan itseään ja keltainen LED vilkkuu 0,1 sekunnin aikavälein. Alla olevassa kuvassa on näytetty STM32VLDISCOVERY-kitti koekytkentäalustaan kiinnitettunä. Kuvassa näkyy myös eräs MSP430-FRAM kehitysalusta, mutta siihen ei tässä vaiheessa kannata takertua, se toimii tässä tapauksessa vain sarjaporttimuuntimena PC:lle päin.

STM32VLDISCOVERY ja Launchpad
Kehityskitit

Pelkästä ledin vilkutuksesta ei nyt tässä kohtaa sen suurempia kommentteja ole kirjoittaa, koska aihe on melko yksinkertainen. Siirrytäänkin sitten seuraavaan esimerkkiin ja tehdään sarjaporttiin printtaus! (Tämän takia siis tuo punainen häkkyrä yllä olevassa kuvassa)

6. Toinen ohjelma: sarjaporttiin tulostus

Sarjaporttiin tiedon tulostaminen on hyvä tapa saada tietoa ohjelman eri tilasta ja toki sulautetun laitteen komentamiseksikin sarjaporttia voi käyttää. Jos sarjaportti ei ole tuttu, niin lukaise tämä sivu tässä välissä: https://www.hutasu.net/elektroniikka/sulautettu-elektroniikka/sarjaliikenne-ja-sarjaportti/.

Esimerkiksi suurin osa modeemeista ja muista langattomista lähetin-vastaanotin piireistä tottelee sarjaportista tulevia AT-komentoja. Mutta ei mennä AT-komentoihin nyt vaan keskitytään printtaamaan tekstiä sarjaporttiin nopeudella 115200 (8N1).

Ennen kuin varsinaista koodia kirjoitetaan, konfiguroidaan CubeMX-näkymästä (eli graafisesta pinninäkymästä) käyttöön USART3 (klikkaa suuremmaksi tarvittaessa):

CubeMX valinnat USART3:n aktivoimiseksi

Ensimmäiseksi valitaan (1) Connectivity-alasvetovalikosta haluttu kommunikointitapa, tässä tapauksessa siis USART3. Sen jälkeen valitaan (2) Mode-valikosta Asynchronous. Pinnien määritykset luttiaisen kylkeen tulevat näkyviin automaattisesti (3). Seuraavaksi Parameter Settings -ikkunasta valitaan baudinopeudeksi 115200, datan pituudeksi 8, pariteettia ei ja yksi stop-bitti. Muut asetukset voivat olla oletuksena kuten ovat.

Sarjaportin asetukset STM32CubeIDEssä
Sarjaportin asetukset

Nyt koodi voidaan generoida, jolloin sarjaportin alustukset ilmestyvät itsestään koodirunkoon. Koodin generointi suoritetaan pikanapista (alla olevassa kuvassa) tai valikosta Project -> Generate Code.

CubeMX koodin generointi
Koodin generointi

Nyt alustuskoodeihin pitäisi ilmestyä GPIO:n alustuksen jälkeen rivi MX_USART3_UART_Init();.

Seuraavaksi kokeillaan sarjaportin toimintaa ja kirjoitetaan yksinkertainen lähetys HAL-kirjaston UART_Transmit-funktion avulla, kuten alla:

Datan lähetys
UART-lähetys

Kun kytketään sarjaporttimuunnin (tässä tapauksessa käytetty toista kehitysalustaa muuntimena, mutta käytössä voi olla mikä tahansa +3.3V logiikalla toimiva muunnin) pinniin PB10, saadaan ulos koodattua dataa:

STM32 USART3 lähetys
STM32F100 lähettää tietokoneelle viestejä

Fyysinen yhteys PC:lle siis toimii, joten voidaan kehittää esimerkkiohjelmaa hieman lisää. Lisätään printf-tuki tulostusta helpottamaan.

7. Kolmas ohjelma: printf/scanf-tuki

Printf on C-kielen standardi tulostusfunktio, minkä avulla on helppo tulostaa ruudulle (tai mihin vain, kuten tässä tapauksessa sarjaporttiin) tekstin ja kirjainten lisäksi erilaisia numeerisia arvoja, ovatpa ne heksadesimaalisia, liukulukuja, kokonaislukuja tai oktaalilukuja. Scanf toimii päinvastoin kuin printf ja sen avulla voidaan lukuja, merkkejä ja merkkijonoja "skannata" halutusta paikasta.

Ensiksi, jotta kirjastofunktioita voidaan ylipäänsä käyttää, pitää lisätä kirjasto stdio.h koodin alkuun (älä välitä muista includeista tässä):

stdio.h lisäys
stdio.h sisältää printf:n ja muut tarvittavat funktiot

Tavallisesti printf yrittää tulostaa C-kirjaston standardisyötteeseen, joka tyypillisesti on ruutu (console) tietokoneella. Mutta koska käytössämme ei varsinaisesti ole ruutua, niin tuloste täytyy saada ohjattua laitteen sarjaporttiin. Tämän jälkeen printf tulostaa sarjaporttiin tietoa ihan samalla tavalla kuin ruudullekin jos tehtäisiin PC-koodia.

Varsinaisen pääohjelman alle (main.c) eli main() -funktion alle lisätään alla olevat rivit. Printf/scanf-funktiot käyttävät oletuksena standardikirjaston toteutuksia, joten tässä koodissa ikäänkuin ylikirjoitetaan aiempi toiminnallisuus ja ohjataan printtaukset ja luvut oikeaan osoitteeseen, eli sarjaporttiin:

printf/scanf tuen toteutus mikroprosessorille
printf/scanf tuen toteutus

Kun nyt koodiin kirjoitetaan printf-funktio, voidaan sarjaporttiin tulostaa lukuja, kirjaimia ja tekstiä samoten kuin niitä voidaan myös lukeakin:

8. Neljäs ohjelma: AD-muunnin DMA:n avulla

Neljännen ohjelman avulla on hyvä demonstroida AD-muuntimen toimintaa yhdessä edellä tehdyn printf:n kanssa.

Konfiguroidaan ensiksi AD-muunnin käyttöön niin, että DMA-hoitaa muuntimelta saatujen tietojen siirron RAM-muistiin. Näin CPU:n ei tarvitse osallistua muunnostyöhön juuri ollenkaan.

Valitaan graafisesta konfiguraattorista Analog-valikko ja ADC1. Asetetaan aktiiviseksi kanavat "Temperature Sensor Channel" ja IN1:

ADC1 peruskonfigurointi
ADC1 DMA konfigurointi

Määritetään AD-muuntimen asetukset "Parameter Settings" ikkunasta. Huomaa, että "Number Of Conversion" asetuksen pitää vastata valittujen kanavien määrää, joka on tässä tapauksessa 2. Rank <numero> kohdassa määritetään haluttu kanava ja muunnosaika. Tässä on säädetty 239,5 kellojaksoa muunnosajaksi. Ensimmäinen kanava joka muunnetaan on sisäinen lämpötila-anturi ja toinen kanava on pinnissä PA1.

ADC1 konfigurointiasetukset
AD-muuntimen asetukset

Seuraavaksi asetetaan DMA-hoitamaan AD-muuntimen tuloksen muistiin. Valitaan välilehti "DMA Settings" ja klikataan Add-näppäintä. Ilmestyvästä alasvetovalikosta valitaan ADC1. "DMA Request Settings" -ikkunassa Mode-asetus Circular ja Data Width asetus Word.

ADC1 DMA konfigurointi
DMA:n asetukset muunnosten lukemiseksi

Nyt voidaan generoida muutettu koodi ja huomataan, että alustuskomentoihin on ilmestynyt lisää tavaraa MX_DMA_Init() ja MX_ADC1_Init().

Pääohjelman alkuun määritetään integer-tyyppiä oleva taulukko, missä on 10:n mittaustuloksen "varasto" vaikkakaan ei käytetä kuin kahta ensimmäistä mittaustulosta:
int adcData[10] = {};

Alla oleva koodi käynnistää muunnoksen ja printtaa mitatut raaka-arvot sarjaporttiin.

STM32F100 mikroprosessorin AD-muunnin on 12-bittinen, eli maksimiarvo mitä muunnin voi lukea on 212-1 = 4095.


Tässäpä lyhyesti STM32-mikroprosessorin ohjelmointia ilmaisilla työkaluilla joita on kirjoitushetkellä (10/2019) tarjolla. Jos heräsi kysyttävää tai haluat antaa palautetta esitetyistä asioista, käytä info-sivun lomaketta, kiitos!