Kako podesiti pametne telefone i računare. Informativni portal
  • Dom
  • U kontaktu sa
  • Povezivanje standardne periferne biblioteke na bilo koju STM32 familiju.

Povezivanje standardne periferne biblioteke na bilo koju STM32 familiju.

Kada kreirate svoju prvu aplikaciju na STM32 mikrokontroleru, postoji nekoliko načina. Prvi, klasični, uzimamo tačan opis kontrolera na web stranici www.st.com, koji se pojavljuje pod nazivom "Referentni priručnik" i čitamo opis perifernih registara. Zatim pokušavamo da ih zapišemo i vidimo kako periferne jedinice rade. Čitanje ovog dokumenta je vrlo korisno, ali u prvoj fazi savladavanja mikrokontrolera, možete to odbiti, čudno. STMicroelectronics inženjeri su napisali biblioteku standardnih drajvera za periferiju. Štaviše, napisali su mnoge primjere korištenja ovih drajvera, koji mogu svesti programiranje vaše aplikacije na pritiskanje tipki Ctrl + C i Ctrl + V, nakon čega slijedi mala izmjena primjera korištenja drajvera prema vašim potrebama. Dakle, povezivanje biblioteke perifernih drajvera na vaš projekat je drugi način izgradnje aplikacije. Osim brzine pisanja, postoje i druge prednosti ove metode: univerzalnost koda i korištenje drugih vlasničkih biblioteka kao što su USB, Ethernet, kontrola pogona, itd., koje su date u izvornom kodu i koriste standardni drajver periferije. Postoje i nedostaci ove metode: Tamo gdje možete proći s jednom linijom koda, standardni drajver za periferiju STM32 će napisati 10. Sama biblioteka periferije također je dostupna u obliku izvornih datoteka, tako da možete pratiti koji dio registrirati promjene određene funkcije. Ako želite, možete prijeći od drugog načina pisanja programa na prvi tako što ćete komentirati dio koda koji samostalno koristi standardnu ​​biblioteku, koja direktno kontrolira periferni registar. Kao rezultat ove akcije, dobit ćete u brzini kontrole, količini RAM-a i ROM-a i izgubiti u univerzalnosti koda. U svakom slučaju, inženjeri kompanije Promelectronica preporučuju korištenje biblioteke standardnih perifernih uređaja barem u prvoj fazi.

Najveće poteškoće očekuju programera prilikom povezivanja biblioteke sa svojim projektom. Ako ne znate kako to učiniti, možete potrošiti dosta vremena na ovaj događaj, što je u suprotnosti sa samom idejom korištenja gotovog drajvera. Materijal je posvećen povezivanju standardne biblioteke sa bilo kojom porodicom STM32.

Svaka STM32 porodica ima svoju standardnu ​​perifernu biblioteku. To je zbog činjenice da je sama periferija drugačija. Na primjer, periferija STM32L kontrolera ima funkciju uštede energije kao jedan od zadataka, što podrazumijeva dodavanje kontrolnih funkcija. Klasični primjer može se smatrati ADC, koji u STM32L ima mogućnost isključivanja hardvera, u nedostatku naredbe za konverziju duže vrijeme - jedna od posljedica zadatka uštede energije. ADC kontroleri porodice STM32F nemaju ovu funkciju. U stvari, zbog hardverske razlike na periferiji, imamo različite biblioteke drajvera. Pored očigledne razlike u funkcijama kontrolera, postoji poboljšanje na periferiji. Dakle, periferni uređaji kontrolora porodica koji su kasnije objavljeni mogu biti promišljeniji i praktičniji. Na primjer, periferni uređaji STM32F1 i STM32F2 kontrolera imaju razlike u kontroli. Po mišljenju autora, upravljanje periferijama STM32F2 je praktičnije. I ovo je razumljivo zašto: porodica STM32F2 je objavljena kasnije i to je omogućilo programerima da uzmu u obzir neke nijanse. Shodno tome, za ove porodice - individualne periferne kontrolne biblioteke. Ideja iza gore navedenog je jednostavna: na stranici mikrokontrolera koji ćete koristiti postoji odgovarajuća periferna biblioteka za njega.

Uprkos razlikama u periferiji u porodicama, vozači kriju 90% razlika u sebi. Na primjer, funkcija podešavanja ADC-a koja je gore spomenuta izgleda isto za sve porodice:

void ADC_Init (ADC_Nom, ADC_Param),

gdje je ADC_Nom ADC broj u obliku ADC1, ADC2, ADC3, itd.

ADC_Param - pokazivač na strukturu podataka, kako ADC treba biti konfiguriran (od čega početi, koliko kanala digitalizirati, da li to izvoditi ciklično, itd.)

10% razlika između porodica, u ovom primjeru, koje će se morati ispraviti pri prelasku iz jedne STM32 porodice u drugu, skriveno je u ADC_Param strukturi. Broj polja u ovoj strukturi može varirati u zavisnosti od porodice. Opšti dio ima istu sintaksu. Dakle, prevod aplikacije za jednu STM32 familiju, napisanu na osnovu standardnih perifernih biblioteka u drugu, je prilično jednostavan. U smislu univerzalizacije rješenja na mikrokontrolerima, STMicroelectronics je neodoljiv!

Dakle, preuzeli smo biblioteku za korišteni STM32. Šta je sledeće? Zatim moramo kreirati projekat i povezati potrebne datoteke s njim. Razmotrimo kreiranje projekta koristeći IAR Embedded Workbench razvojno okruženje kao primjer. Pokrećemo razvojno okruženje i idemo na karticu "Projekt", odabiremo stavku "Kreiraj projekat" za kreiranje projekta:

U novom projektu koji se pojavi, unesite postavke tako što ćete preći kursorom preko naziva projekta, pritisnuti desnu tipku miša i odabrati "Opcije" u padajućem izborniku:

RAM i ROM memorijska područja:

Kada kliknete na dugme “Sačuvaj”, okruženje će ponuditi da upiše novu datoteku opisa kontrolera u fasciklu projekta. Autor preporučuje kreiranje individualne * .icp datoteke za svaki projekat i pohranjivanje u direktorij projekta.

Ako ćete otklanjati greške u svom projektu u krugu, što je preporučljivo, tada unosimo tip debuggera koji će se koristiti:

Na kartici odabranog debuggera označavamo sučelje za povezivanje debuggera (u našem slučaju je odabran ST-Link) na kontroler:



Od sada je naš projekat bez biblioteka spreman za kompajliranje i učitavanje u kontroler. U drugim okruženjima kao što su Keil uVision4, Resonance Ride7, itd., morat ćete učiniti isto.

Ako upišete red u datoteku main.c:

#include "stm32f10x.h" ili

#include "stm32f2xx.h" ili

#include "stm32f4xx.h" ili

#include "stm32l15x.h" ili

#include "stm32l10x.h" ili

#include "stm32f05x.h"

određujući lokaciju ove datoteke, ili kopirajući ovu datoteku u fasciklu projekta, tada će neke memorijske oblasti biti povezane sa perifernim registrima odgovarajuće porodice. Sama datoteka se nalazi u fascikli standardne periferne biblioteke u odjeljku: \ CMSIS \ CM3 \ DeviceSupport \ ST \ STM32F10x (ili sličan naziv za druge porodice). Od sada, adresu perifernog registra kao broj zamjenjujete njenim imenom. Čak i ako ne namjeravate koristiti funkcije standardne biblioteke, preporučuje se da napravite takvu vezu.

Ako ćete koristiti prekide u svom projektu, preporučljivo je da povežete datoteku za pokretanje s ekstenzijom * .s, koja se nalazi duž putanje \ CMSIS \ CM3 \ DeviceSupport \ ST \ STM32F10x \ startup \ iar, ili slično za druge porodice. Važno je napomenuti da je datoteka različita za svako okruženje. Shodno tome, ako koristimo IAR EWB, onda moramo uzeti datoteku iz IAR foldera. To je zbog malo drugačije sintakse okruženja. Stoga, kako bi projekat odmah započeo, STMicroelectronics inženjeri su napisali nekoliko opcija za pokretanje datoteka za nekoliko najpopularnijih razvojnih okruženja. Većina STM32 porodica ima jednu datoteku. Porodica STM32F1 ima nekoliko datoteka za pokretanje:

  • startup_stm32f10x_cl.s - za STM32F105 / 107 mikrokontrolere
  • startup_stm32f10x_xl.s - za STM32F101 / STM32F103 mikrokontrolere 768kb i više
  • startup_stm32f10x_hd.s - za STM32F101 / STM32F103 mikrokontrolere sa 256-512 kb flash memorije
  • startup_stm32f10x_md.s - za STM32F101 / STM32F102 / STM32F103 mikrokontrolere sa 64-128 kb flash memorije
  • startup_stm32f10x_ld.s - za STM32F101 / STM32F102 / STM32F103 mikrokontrolere sa Flash memorijom manjom od 64 kb
  • startup_stm32f10x_hd_vl.s za STM32F100 mikrokontrolere sa 256-512 kb flash memorije
  • startup_stm32f10x_md_vl.s za STM32F100 mikrokontrolere sa 64-128 kb flash memorije
  • startup_stm32f10x_ld_vl.s za STM32F100 mikrokontrolere sa 32KB Flash memorije ili manje

Dakle, u zavisnosti od porodice, podporodice i razvojnog okruženja, dodajte datoteku za pokretanje projektu:

Ovo je mjesto gdje se mikrokontroler nalazi kada se program pokrene. Prekid sekvencijalno poziva funkciju SystemInit (), a zatim __iar_program_start. Druga funkcija nula ili upisuje unaprijed definirane vrijednosti globalnih varijabli, nakon čega se prebacuje na glavni () korisnički program. Funkcija SystemInit () podešava sat mikrokontrolera. Ona je ta koja daje odgovore na pitanja:

  • Trebam li preći na vanjski kvarc (HSE)?
  • Kako pomnožiti frekvenciju iz HSI / HSE?
  • Trebate li povezati red za preuzimanje naredbi?
  • Koliko je kašnjenja potrebno prilikom učitavanja naredbe (zbog male brzine Flash memorije)
  • Kako podijeliti taktiranje perifernih sabirnica?
  • Da li trebate staviti kod u vanjski RAM?

Funkcija SystemInit () može se ručno napisati u vašem projektu. Ako ovu funkciju uredite kao praznu, tada će kontroler raditi na internom RC oscilatoru sa frekvencijom od oko 8 MHz (ovisno o vrsti porodice). Opcija 2 - povežite datoteku system_stm32f10x.c sa projektom (ili sličnog imena, ovisno o vrsti porodice koja se koristi), koja se nalazi u biblioteci duž putanje: Libraries \ CMSIS \ CM3 \ DeviceSupport \ ST \ STM32F10x. Ova datoteka sadrži funkciju SystemInit (). Obratite pažnju na frekvenciju vanjskog kristala HSE_VALUE. Ovaj parametar je postavljen u datoteci zaglavlja stm32f10x.h. Standardna vrijednost je 8 i 25MHz, ovisno o STM32 porodici. Glavni zadatak funkcije SystemInit () je prebaciti taktiranje na vanjski kristal i pomnožiti ovu frekvenciju na određeni način. Šta se događa ako je vrijednost HSE_VALUE specificirana kao 8MHz, jezgra mora biti taktovana na 72MHz, ali u stvari postoji kristal od 16MHz na ploči? Kao rezultat takvih pogrešnih radnji, jezgro će dobiti takt od 144 MHz, što može biti iznad garantovanog rada sistema na STM32. One. kada povezujete datoteku system_stm32f10x.c, morat ćete navesti vrijednost HSE_VALUE. Sve ovo znači da fajlovi system_stm32f10x.c, system_stm32f10x.h i stm32f10x.h (ili slični po imenu za druge porodice) moraju biti individualni za svaki projekat. I

STMicroelectronics inženjeri su kreirali alat za konfiguraciju sata koji vam omogućava da ispravno konfigurišete sistemski takt. Ovo je Excel datoteka koja generiše datoteku system_stm32xxx.c (sličnu po imenu za datu porodicu porodica) nakon specificiranja ulaznih i izlaznih parametara sistema. Hajde da vidimo kako to funkcioniše koristeći porodicu STM32F4 kao primer.

Opcije su interni RC oscilator, interni RC oscilator sa množenjem frekvencije ili eksterni kristal sa množenjem frekvencije. Nakon odabira izvora takta, unesite parametre željene konfiguracije sistema, kao što su ulazna frekvencija (kada se koristi eksterni kristal), frekvencija takta jezgre, razdjelnici frekvencije takta periferne magistrale, rad bafera za dohvaćanje naredbi i drugo . Klikom na dugme "Generiraj" dobijamo prozor


Povezivanje datoteke system_stm32f4xx.c i njenih analoga zahtijevat će povezivanje još jedne datoteke standardne periferne biblioteke. Za kontrolu sata postoji čitav skup funkcija koje se pozivaju iz datoteke system_stm32xxxxxx.c. Ove funkcije se nalaze u datoteci stm32f10x_rcc.c i njenom zaglavlju. Shodno tome, kada povezujete datoteku system_stm32xxxxxx.c sa projektom, morate povezati stm32f10x_rcc.c, inače će linker okruženja prijaviti odsustvo opisa funkcija s imenom RCC_xxxxxxx. Navedena datoteka se nalazi u perifernoj biblioteci ispod putanje: Libraries \ STM32F10x_StdPeriph_Driver \ src, i njeno zaglavlje \ Libraries \ STM32F10x_StdPeriph_Driver \ inc.

Datoteke zaglavlja perifernog drajvera su povezane u datoteci stm32f10x_conf.h, koju referencira stm32f10x.h. Datoteka stm32f10x_conf.h je jednostavno skup datoteka zaglavlja za specifične drajvere periferije kontrolera koji će biti uključeni u projekat. U početku, sva "#include" zaglavlja su označena kao komentari. Povezivanje datoteke zaglavlja periferije sastoji se od uklanjanja komentara iz odgovarajućeg naziva datoteke. U našem slučaju, ovo je #include "stm32f10x_rcc.h" linija. Očigledno, datoteka stm32f10x_conf.h je individualna za svaki projekat, jer različiti projekti koriste različite periferne uređaje.

I poslednja stvar. Potrebno je navesti nekoliko direktiva za pretprocesor kompajlera i putanje do datoteka zaglavlja.



Putanja do datoteka zaglavlja mogu biti različite, ovisno o lokaciji periferne biblioteke u odnosu na mapu projekta, ali prisustvo “USE_STDPERIPH_DRIVER” je obavezno pri povezivanju perifernih drajvera standardne biblioteke.

Dakle, povezali smo standardnu ​​biblioteku sa projektom. Štaviše, na projekat smo povezali jedan od standardnih perifernih drajvera, koji kontroliše sistemski sat.

Naučili smo kako struktura biblioteke izgleda iznutra, a sada par riječi o tome kako izgleda izvana.



Dakle, povezivanje datoteke zaglavlja stm32f10x.h u aplikaciji podrazumijeva povezivanje drugih datoteka zaglavlja i kodnih datoteka. Neki od prikazanih na slici su gore opisani. Nekoliko riječi o ostalom. STM32F10x_PPP.x datoteke su datoteke drajvera periferije. Primjer povezivanja takve datoteke prikazan je gore, ovo je RCC - periferne jedinice za kontrolu sistemskog sata. Ako želimo da povežemo drajvere drugih perifernih uređaja, tada se naziv povezanih datoteka dobija zamenom "PPP" sa imenom periferije, na primer, ADC - STM32F10x_ADC.s, ili I/O portovi STM32F10x_GPIO.s, ili DAC - STM32F10x_DAC.s. Općenito, intuitivno je jasno koju datoteku treba povezati prilikom povezivanja date periferije. Fajlovi "misc.c", "misc.h" su u osnovi isti STM32F10x_PPP.x, samo što kontrolišu kernel. Na primjer, postavljanje vektora prekida, koji je ugrađen u kernel, ili upravljanje SysTick tajmerom, koji je dio kernela. Datoteke xxxxxxx_it.c opisuju vektore nemaskiranih prekida kontrolera. Mogu se dopuniti perifernim vektorima prekida. Datoteka core_m3.h opisuje CortexM3 jezgro. Ova jezgra je standardizirana i može se naći u mikrokontrolerima drugih proizvođača. Za univerzalizaciju na više platformi, STMicroelectronics je radio na stvaranju zasebne CortexM jezgrene biblioteke, nakon čega ju je ARM standardizovao i proširio na druge proizvođače mikrokontrolera. Tako će prelazak na STM32 sa kontrolera drugih proizvođača sa CortexM jezgrom biti malo lakši.

Dakle, možemo povezati standardnu ​​perifernu biblioteku na bilo koju STM32 familiju. Oni koji to nauče dobiće nagradu: vrlo jednostavno programiranje mikrokontrolera. Biblioteka, pored drajvera u obliku izvornih datoteka, sadrži mnogo primjera upotrebe perifernih uređaja. Na primjer, razmislite o kreiranju projekta koji uključuje izlaze za usporedbu tajmera. Uz tradicionalni pristup, pažljivo ćemo proučiti opis registara ove periferije. Ali sada možemo proučiti tekst programa koji radi. Idemo u mapu primjera standardnih perifernih uređaja, koja se nalazi duž putanje ProjectSTM32F10x_StdPeriph_Examples. Ovdje ćete pronaći primjere foldera s nazivima korištenih perifernih uređaja. Idemo u folder "TIM". Tajmeri u STM32 imaju mnogo funkcija i postavki, tako da je nemoguće demonstrirati na jednom primjeru mogućnosti kontrolera. Stoga, unutar navedenog direktorija postoji mnogo primjera upotrebe tajmera. Zanima nas generiranje PWM signala pomoću tajmera. Idemo u folder "7PWM_Output". Unutra se nalazi opis programa na engleskom i set fajlova:

main.c stm32f10x_conf.h stm32f10x_it.h stm32f10x_it.c system_stm32f10x.c

Ako projekat nema prekida, onda je sadržaj u potpunosti lociran u main.c. Ove datoteke kopiramo u direktorij projekta. Nakon što smo sastavili projekat, dobićemo program za STM32 koji će konfigurisati tajmer i I/O portove za generisanje 7 PWM signala iz tajmera 1. Zatim možemo prilagoditi već napisani kod za naš zadatak. Na primjer, smanjite broj PWM signala, promijenite radni ciklus, smjer brojanja, itd. Funkcije i njihovi parametri dobro su opisani u datoteci stm32f10x_stdperiph_lib_um.chm. Nazivi funkcija i njihovi parametri lako se povezuju s njihovom svrhom za one koji znaju malo engleski. Radi jasnoće, predstavljamo dio koda uzetog primjera:

/ * Konfiguracija vremenske baze * / TIM_TimeBaseStructure.TIM_Prescaler = 0; // nema pre-alokacije impulsa za brojanje (16-bitni registar) TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // smjer odbrojavanja prema gore TIM_TimeBaseStructure.TIM_Period = TimerPeriod; // broji do vrijednosti TimerPeriod (konstanta u programu) TIM_TimeBaseStructure.TIM_ClockDivision = 0; // nema brojanja pre-alokacije TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // brojač prekoračenja za generiranje događaja (ne koristi se u programu) TIM_TimeBaseInit (TIM1, & TIM_TimeBaseStructure); // unos vrijednosti TimeBaseStructure u registre tajmera 1 (unos podataka u ovu // varijablu je iznad) / * Konfiguracija kanala 1, 2, 3 i 4 u PWM modu * / // postavljanje PWM izlaza TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; // PWM2 način rada TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // omogućimo izlaz signala PWM tajmera TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // omogućavaju besplatni izlaz PWM tajmera TIM_OCInitStructure.TIM_Pulse = Channel1Pulse; // širina impulsa Channel1Pulse - konstanta u programu TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // postavljanje izlaznog polariteta TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; // postavljanje polariteta komplementarnog izlaza TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; // postavlja sigurno stanje PWM izlaza TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; // postavlja sigurno stanje komplementarnog PWM izlaza TIM_OC1Init (TIM1, & TIM_OCInitStructure); // unos vrijednosti varijable TIM_OCInitStructure u PWM registre kanala 1 // timer1 TIM_OCInitStructure.TIM_Pulse = Channel2Pulse; // mijenjamo širinu impulsa u varijabli OCInitStructure i unosimo je u TIM_OC2Init (TIM1, & TIM_OCInitStructure); // PWM registri kanala 2 timer1 TIM_OCInitStructure.TIM_Pulse = Channel3Pulse; // mijenjamo širinu impulsa u varijabli OCInitStructure i unosimo je u TIM_OC3Init (TIM1, & TIM_OCInitStructure); // PWM registri kanala 3 timer1 TIM_OCInitStructure.TIM_Pulse = Channel4Pulse; // mijenjamo širinu impulsa u varijabli OCInitStructure i unosimo je u TIM_OC4Init (TIM1, & TIM_OCInitStructure); // registruje PWM kanal 4 timer1 / * Omogućavanje brojača TIM1 * / TIM_Cmd (TIM1, ENABLE); // start timer1 / * TIM1 Glavni izlaz Omogući * / TIM_CtrlPWMOizlazi (TIM1, ENABLE); // omogućavanje izlaza za usporedbu tajmera 1

Na desnoj strani, autor je ostavio komentar na ruskom jeziku za svaki red programa. Ako otvorite isti primjer u opisu funkcija biblioteka stm32f10x_stdperiph_lib_um.chm, vidjet ćemo da svi korišteni parametri funkcije imaju vezu na vlastiti opis, gdje će biti naznačene njihove moguće vrijednosti. Same funkcije također imaju vezu do vlastitog opisa i izvornog koda. Ovo je veoma korisno jer znajući šta funkcija radi, možemo pratiti kako to radi, koji bitovi perifernih registara i kako to utječe. Ovo je, prvo, još jedan izvor informacija za savladavanje kontrolera, zasnovan na praktičnoj upotrebi kontrolera. One. prvo rješavate tehnički problem, a zatim proučavate samo rješenje. Drugo, ovo je polje za optimizaciju programa za one koji nisu zadovoljni bibliotekom u smislu brzine rada i količine koda.



Dakle, već smo se digli na noge, u smislu da je sve što nam treba spojeno na izlaze mikrokontrolera na STM32VL Discovery ploči, naučili smo da pričamo, u programskom jeziku C, bilo bi vrijeme da kreiramo projekat u prvoj klasi.

Pisanje programa

Kada završite sa kreiranjem i postavljanjem svog projekta, možete početi pisati pravi program. Kao što je uobičajeno za sve programere, prvi program napisan za rad na računaru je program koji prikazuje natpis "HelloWorld", a za sve mikrokontrolere prvi program za mikrokontroler treperi LED dioda. Nećemo biti izuzetak od ove tradicije i napisaćemo program koji će kontrolisati LD3 LED na STM32VL Discovery ploči.

Nakon kreiranja praznog projekta u IAR-u, on generiše minimalni programski kod:

Sada će se naš program uvijek "vrtjeti" u petlji dok.

Da bismo mogli da kontrolišemo LED, potrebno je da omogućimo taktiranje porta na koji je povezan i da konfigurišemo odgovarajući pin porta mikrokontrolera za izlaz. Kao što smo ranije govorili u prvom dijelu, za omogućavanje taktiranja porta WITH bit odgovara IOPCEN registar RCC_APB2ENR... Prema dokumentu " RM0041Referencapriručnik.pdf„Da bi se omogućilo taktiranje sabirnice porta WITH potrebno u registru RCC_APB2ENR postavite bit IOPCEN po jedinici. Tako da kada je ovaj bit postavljen, ne resetujemo ostale postavljene u ovom registru, moramo primijeniti operaciju logičkog sabiranja (logičko "ILI") na trenutno stanje registra i zatim upisati rezultirajuću vrijednost u sadržaj registar. U skladu sa strukturom ST biblioteke, pristup vrednosti registra za čitanje i upisivanje se vrši preko pokazivača na strukturu RCC-> APB2 ENR... Dakle, prisjećajući se materijala iz drugog dijela, možete napisati sljedeći kod koji postavlja bit IOPCEN u registru RCC_APB2ENR:

Kao što možete vidjeti iz datoteke "stm32f10x.h", vrijednost bita IOPCEN definiran kao 0x00000010, što odgovara četvrtom bitu ( IOPCEN) registar APB2ENR i odgovara vrijednosti navedenoj u podatkovnoj tablici.

Sada konfigurirajmo izlaz na isti način. 9 luka WITH... Da bismo to učinili, moramo konfigurirati ovaj pin porta za izlaz u push-pull modu. Registar je odgovoran za postavljanje režima porta za ulaz/izlaz GPIOC_CRH, već smo ga razmotrili u, njegov opis je takođe u odjeljku "7.2.2 Visoki registar konfiguracije porta" u tablici sa podacima. Za konfiguraciju izlaza na izlazni mod sa maksimalnom brzinom od 2 MHz potrebno je u registru GPIOC_CRH instalirati MODE9 na jedan i resetujte bit MODE9 na nulu. Bitovi su odgovorni za postavljanje načina rada izlaza kao glavne funkcije s push-pull izlazom. CNF9 i CNF9 , da bi se konfigurirao potreban način rada, oba ova bita moraju biti obrisana na nulu.

Sada je pin porta na koji je LED spojen postavljen na izlaz, da bismo kontrolirali LED, moramo promijeniti stanje pina porta postavljanjem izlaza na logički. Postoje dva načina da promenite stanje pina porta, prvi je da direktno upišete u registar statusa porta promenjeni sadržaj registra porta, baš kao što smo uradili podešavanje porta. Ova metoda se ne preporučuje zbog mogućnosti situacije u kojoj se netačna vrijednost može upisati u registar porta. Ova situacija može nastati ako se tokom promjene stanja registra, od trenutka kada je stanje registra već pročitano pa do trenutka kada se promijenjeno stanje upiše u registar, promijeni bilo koji periferni uređaj ili prekid. stanje ove luke. Po završetku operacije promjene stanja registra, vrijednost će biti upisana u registar bez uzimanja u obzir promjena koje su se dogodile. Iako je vjerovatnoća da će se ova situacija dogoditi vrlo mala, ipak vrijedi koristiti drugu metodu u kojoj je opisana situacija isključena. Za to postoje dva registra u mikrokontroleru GPIOx_BSRR i GPIOx_BRR... Prilikom upisivanja logičke jedinice u traženi bit registra GPIOx_BRR odgovarajući pin porta će biti resetovan na logičku nulu. Registrirajte se GPIOx_BSRR može i postaviti i resetirati stanje pinova porta, da bi se pin porta postavio na logičku jedinicu, potrebno je podesiti bitove BSn, u skladu sa brojem traženog bita, ovi bitovi se nalaze u nižim registrima bajta. Za resetiranje stanja izlaza porta na logičku nulu, potrebno je upisati bitove BRn odgovarajućim pinovima, ovi bitovi se nalaze u bitovima višeg reda port registra.

LD3 LED je spojen na pin 9 luka WITH... Da bismo uključili ovu LED diodu, moramo primijeniti logičku jedinicu na odgovarajući pin porta kako bismo "upalili" LED.

Dodajmo kod za postavljanje izlaza LED porta u naš program, a također dodamo i softversku funkciju kašnjenja za smanjenje frekvencije prebacivanja LED-a:

// Ne zaboravite povezati datoteku zaglavlja s opisom registara mikrokontrolera

#include "stm32f10x.h"

void Kašnjenje ( void);

void Kašnjenje ( void)
{
unsigned long i;
za(i = 0; i<2000000; i++);
}

// Naša glavna funkcija

void glavni ( void)
{


RCC-> APB2ENR | = RCC_APB2ENR_IOPCEN;

// obrišite MODE9 bitove (resetirajte bite MODE9_1 i MODE9_0 na nulu)
GPIOC-> CRH & = ~ GPIO_CRH_MODE9;

// Postavite bit MODE9_1 da konfigurišete izlaz na izlaz brzinom od 2MHz
GPIOC-> CRH | = GPIO_CRH_MODE9_1;

// obrisati CNF bitove (konfigurirati kao izlaz opće namjene, uravnotežen (push-pull))
GPIOC-> CRH & = ~ GPIO_CRH_CNF9;

dok(1)
{

// Postavite pin 9 porta C na logičku jedinicu (LED je uključen)
GPIOC-> BSRR = GPIO_BSRR_BS9;


Delay ();


GPIOC-> BSRR = GPIO_BSRR_BR9;


Delay ();

}
}

Arhivu sa izvornim kodom programa napisanog direktnom kontrolom registara mikrokontrolera možete preuzeti slijedeći link.

Naš prvi radni program je napisan, kada smo ga pisali, za rad i konfiguraciju perifernih uređaja, koristili smo podatke iz službenog datasheet-a " RM0041Referencapriručnik.pdf", Ovaj izvor informacija o registrima mikrokontrolera je najtačniji, ali da biste ga koristili morate ponovo pročitati mnogo informacija, što otežava pisanje programa. Da bi se olakšao proces konfiguracije perifernih uređaja mikrokontrolera, postoje različiti generatori koda, program Microxplorer je predstavljen kao službeni uslužni program kompanije ST, ali još uvijek nije vrlo funkcionalan i iz tog razloga su programeri treće strane kreirali alternativni program „STM32 Generator programskog koda » ... Ovaj program vam omogućava da lako dobijete periferni konfiguracioni kod koristeći pogodan, intuitivni grafički interfejs (vidi sliku 2).


Rice. 2 Snimak ekrana programa STM32 generator koda

Kao što možete vidjeti na slici 2, kod za podešavanje LED izlaza koji je generirao program poklapa se sa kodom koji smo ranije napisali.

Da biste pokrenuli napisani program, nakon kompajliranja izvornog koda, potrebno je učitati naš program u mikrokontroler i vidjeti kako se izvršava.

Video režima za otklanjanje grešaka programa koji treperi LED dioda

Video program koji treperi LED dioda na STM32VL Discovery ploči

Funkcije biblioteke za rad sa perifernim uređajima

Kako bi pojednostavila rad na postavljanju registara periferije mikrokontrolera, kompanija ST je razvila biblioteke, zahvaljujući čijoj upotrebi nije potrebno tako detaljno čitati datasheet, jer se prilikom korišćenja ovih biblioteka rad na pisanju program će postati bliži pisanju programa visokog nivoa, budući da se sve funkcije niskog nivoa implementiraju na nivou bibliotečkih funkcija. Međutim, ne treba u potpunosti napustiti upotrebu direktnog rada sa registrima mikrokontrolera, s obzirom na to da bibliotečke funkcije zahtijevaju više procesorskog vremena za svoje izvršavanje, zbog čega njihova upotreba u vremenski kritičnim dijelovima programa nije opravdano. Ali ipak, u većini slučajeva, stvari kao što je periferna inicijalizacija nisu kritične za vrijeme izvođenja, a upotrebljivost bibliotečkih funkcija je poželjna.

Sada napišimo naš program koristeći ST biblioteku. Program treba da konfiguriše ulazne/izlazne portove, da biste koristili funkcije biblioteke za konfigurisanje portova, potrebno je da povežete datoteku zaglavlja " stm32f10x_gpio.h(Vidi tabelu 1). Ovaj fajl se može povezati dekomentiranjem odgovarajuće linije u uključenom konfiguracionom fajlu zaglavlja “ stm32f10x_conf.h". Na kraju fajla " stm32f10x_gpio.h»Postoji lista deklaracija funkcija za rad sa portovima. Detaljan opis svih dostupnih funkcija možete pronaći u datoteci " stm32f10x_stdperiph_lib_um.chm», Kratak opis najčešće korištenih dat je u Tabeli 2.

Tabela 2: Opis osnovnih funkcija konfiguracije porta

Funkcija

Opis funkcije, proslijeđenih i vraćenih parametara

GPIO_DeInit (
GPIO_TypeDef * GPIOx)

Postavlja vrijednosti registara postavki GPIOx porta na njihove zadane vrijednosti

GPIO_Init (
GPIO_TypeDef * GPIOx,

Instalira registre postavki GPIOx porta u skladu sa navedenim parametrima u strukturi GPIO_InitStruct

GPIO_StructInit (
GPIO_InitTypeDef * GPIO_InitStruct)

Popunjava sva polja strukture GPIO_InitStruct sa zadanim vrijednostima

uint8_t GPIO_ReadInputDataBit (
GPIO_TypeDef * GPIOx,
uint16_t GPIO_Pin);

Pročitajte ulaznu vrijednost GPIO_Pin GPIOx porta

uint16_t GPIO_ReadInputData (
GPIO_TypeDef * GPIOx)

Čitanje ulaznih vrijednosti svih pinova GPIOx porta

GPIO_SetBits (
GPIO_TypeDef * GPIOx,
uint16_t GPIO_Pin)

Postavljanje izlazne vrijednosti GPIO_Pin pina GPIOx porta na logičku jedinicu

GPIO_ResetBits (
GPIO_TypeDef * GPIOx,
uint16_t GPIO_Pin)

Resetirajte izlaznu vrijednost GPIO_Pin pina GPIOx porta na logičku nulu

GPIO_WriteBit (
GPIO_TypeDef * GPIOx,
uint16_t GPIO_Pin,
BitAction BitVal)

Zapisivanje BitVal vrijednosti na GPIO_Pin pin GPIOx porta

GPIO_Write (
GPIO_TypeDef * GPIOx,
uint16_t PortVal)

Zapisivanje vrijednosti PortVal na GPIOx port

Kao što možete vidjeti iz opisa funkcija, kao parametri postavki porta, itd., funkciji se ne prenosi mnogo različitih pojedinačnih parametara, već jedna struktura. Strukture su kombinovani podaci koji imaju neki logički odnos. Za razliku od nizova, strukture mogu sadržavati podatke različitih tipova. Drugim riječima, struktura je skup različitih varijabli sa različitim tipovima kombiniranih u jednu vrstu varijable. Promenljive u ovoj strukturi nazivaju se polja strukture, a pristupa im se na sledeći način, prvo se upisuje naziv strukture, zatim tačka i naziv polja strukture (ime varijable u ovoj strukturi) napisano.

Popis varijabli uključenih u strukture za funkcije rada sa portovima opisan je u istoj datoteci malo iznad opisa funkcija. Tako, na primjer, struktura “ GPIO_InitTypeDef„Ima sljedeću strukturu:

typedef struct
{

uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured.
Ovaj parametar može biti bilo koja vrijednost @ref GPIO_pins_define * /

GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins.
Ovaj parametar može biti vrijednost @ref GPIOSpeed_TypeDef * /

GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins.
Ovaj parametar može biti vrijednost @ref GPIOMode_TypeDef * /

) GPIO_InitTypeDef;

Prvo polje ove strukture sadrži varijablu " GPIO_ Pin»Tip nepotpisan kratko, u ovu varijablu je potrebno upisati zastavice brojeva odgovarajućih pinova, za koje treba izvršiti potrebna podešavanja. Možete konfigurirati nekoliko pinova odjednom postavljanjem nekoliko konstanti kao parametra pomoću operatora OR(cm. ). Bitwise OR će "sakupiti" sve one iz navedenih konstanti, a same konstante su maska ​​upravo namijenjena za takvu upotrebu. Makro definicije konstanti su navedene u istoj datoteci ispod.

Drugo polje strukture" GPIO_InitTypeDef"Postavlja maksimalnu moguću izlaznu brzinu porta. Lista mogućih vrijednosti za ovo polje je navedena iznad:

Opis mogućih vrijednosti:

  • GPIO_Mode_AIN- analogni ulaz (engleski Analog INput);
  • GPIO_Mode_IN_FLOATING- ulaz bez povlačenja, visi (engleski Input float) u zraku
  • GPIO_Mode_IPD- Input Pull-down
  • GPIO_Mode_IPU- Input Pull-up
  • GPIO_Mode_Out_OD- Izlaz Otvoren odvod
  • GPIO_Mode_Out_PP- izlaz u dva stanja (engleski Output Push-Pull - naprijed i nazad)
  • GPIO_Mode_AF_OD- otvoreni izlaz za odvod za alternativne funkcije. Koristi se u slučajevima kada pin treba da se kontroliše pomoću perifernih uređaja koji su priključeni na ovaj pin porta (na primer, Tx USART1 pin, itd.)
  • GPIO_Mode_AF_PP- isto, ali sa dve države

Slično, možete vidjeti strukturu varijabli drugih struktura potrebnih za rad s funkcijama biblioteke.

Da biste radili sa strukturama, baš kao i sa varijablama, morate deklarirati i dodijeliti im jedinstveno ime, nakon čega se možete pozivati ​​na polja deklarirane strukture po imenu koje joj je dodijeljeno.

// Deklarirajte strukturu

/*
Pre nego što počnete da popunjavate polja strukture, preporučuje se da se sadržaj strukture inicijalizuje sa podrazumevanim podacima, to se radi kako bi se sprečilo upisivanje netačnih podataka ako iz nekog razloga nisu popunjena sva polja strukture.

Da biste proslijedili vrijednosti strukture funkciji, morate staviti simbol & ispred imena strukture. Ovaj simbol govori kompajleru da je potrebno proći u funkciju ne vrijednosti sadržane u samoj strukturi, već memorijsku adresu na kojoj se te vrijednosti nalaze. To je učinjeno kako bi se smanjio broj potrebnih radnji procesora za kopiranje sadržaja strukture, a također vam omogućava uštedu RAM-a. Dakle, umjesto prosljeđivanja skupa bajtova sadržanih u strukturi funkciji, samo će jedan biti prebačen koji sadrži adresu strukture.
*/

/ * Upišite u polje GPIO_Pin strukture GPIO_Init_struct pin broj porta, koji ćemo dalje konfigurirati * /

GPIO_Init_struct.GPIO_Pin = GPIO_Pin_9;

/ * Slično, popunite polje GPIO_Speed ​​* /

/*
Nakon što smo popunili potrebna polja strukture, ova struktura mora biti proslijeđena funkciji koja će izvršiti neophodan unos u odgovarajuće registre. Pored strukture sa postavkama ove funkcije, potrebno je proslediti i naziv porta za koji su podešavanja namenjena.
*/

Gotovo sve periferije su konfigurirane na približno isti način, razlike su samo u parametrima i naredbama specifičnim za svaki uređaj.

Sada napišimo naš LED trepćući program koristeći samo funkcije biblioteke.

// Ne zaboravite povezati datoteku zaglavlja s opisom registara mikrokontrolera

#include "stm32f10x.h"
#include "stm32f10x_conf.h"

// deklarirati funkciju kašnjenja programa

void Kašnjenje ( void);

// sama funkcija kašnjenja programa

void Kašnjenje ( void)
{
unsigned long i;
za(i = 0; i<2000000; i++);
}

// Naša glavna funkcija

void glavni ( void)
{

// Omogući port C sabirnice sata
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE);

// Deklarišite strukturu za konfigurisanje porta
GPIO_InitTypeDef GPIO_Init_struct;

// Ispuni strukturu početnim vrijednostima
GPIO_StructInit (& GPIO_Init_struct);

/ * Upišite u polje GPIO_Pin strukture GPIO_Init_struct pin broj porta, koji ćemo dalje konfigurirati * /
GPIO_Init_struct.GPIO_Pin = GPIO_Pin_9;

// Slično, popunite polja GPIO_Speed ​​i GPIO_Mode
GPIO_Init_struct.GPIO_Speed ​​= GPIO_Speed_2MHz;
GPIO_Init_struct.GPIO_Mode = GPIO_Mode_Out_PP;

// Proslijediti popunjenu strukturu za izvođenje radnji za postavljanje registara
GPIO_Init (GPIOC, & GPIO_Init_struct);

// Naša glavna beskonačna petlja
dok(1)
{
// Postavite pin 9 porta C na logičku jedinicu (LED je uključen)
GPIO_SetBits (GPIOC, GPIO_Pin_9);

// Dodajte softversko kašnjenje kako bi LED dioda bio uključen neko vrijeme
Delay ();

// Resetirajte stanje pina 9 porta C na logičku nulu
GPIO_ResetBits (GPIOC, GPIO_Pin_9);

// Dodajte ponovo softversko kašnjenje
Delay ();
}
}

veza.

Iz gornjeg primjera može se vidjeti da korištenje bibliotečkih funkcija za rad s perifernim uređajima omogućava da pisanje programa za mikrokontroler približite objektno orijentiranom programiranju, a također smanjuje potrebu za čestim pristupom podatkovnom listu za čitanje opisa registri mikrokontrolera, ali korištenje bibliotečkih funkcija zahtijeva veće poznavanje programskog jezika... S obzirom na to, za ljude koji nisu posebno upoznati sa programiranjem, jednostavnija opcija za pisanje programa biće način pisanja programa bez korišćenja bibliotečkih funkcija, sa direktnim pristupom registrima mikrokontrolera. Za one koji dobro poznaju programski jezik, ali su slabo upućeni u mikrokontrolere, posebno STM32, upotreba bibliotečkih funkcija uvelike pojednostavljuje proces pisanja programa.

Ova okolnost, kao i činjenica da je ST vodio računa o visokom stepenu kompatibilnosti, kako hardverske tako i softverske, svojih različitih mikrokontrolera, doprinosi njihovom lakšem proučavanju, s obzirom na to da se ne treba upuštati u strukturne karakteristike različitih kontrolera serije STM32 i omogućava vam da odaberete bilo koji od mikrokontrolera dostupnih u STM32 liniji kao mikrokontroler za proučavanje.

Obrađivač prekida

Mikrokontroleri imaju jednu izuzetnu sposobnost - da zaustave izvršavanje glavnog programa u određenom događaju i nastave da izvršavaju poseban potprogram - rukovalac prekida... Izvori prekida mogu biti i eksterni događaji - prekidi za prijem/prenos podataka kroz bilo koji interfejs za prenos podataka, ili promena izlaznog stanja, i unutrašnji - prelivanje tajmera itd. Lista mogućih izvora prekida za mikrokontrolere serije STM32 data je u datasheet-u " RM0041 Referentni priručnik"U poglavlju" 8 Prekidi i događaji».

Kako je rukovalac prekida ujedno i funkcija, biće napisan kao redovna funkcija, ali da bi prevodilac znao da je ova funkcija rukovalac za određeni prekid, kao naziv funkcije treba izabrati unapred definisana imena kojoj naznačena su preusmjeravanja vektora prekida. Lista naziva ovih funkcija sa kratkim opisom može se naći u datoteci asemblera " startup_stm32f10x_md_vl.s". Jedan rukovalac prekida može imati nekoliko izvora prekida, na primjer, funkciju rukovaoca prekidom " USART1_IRQHandler"Može se pozvati u slučaju kraja prijema i kraja prijenosa bajta, itd.

Da biste počeli raditi s prekidima, morate konfigurirati i inicijalizirati NVIC kontroler prekida. U Cortex M3 arhitekturi, svakom prekidu može biti dodeljena sopstvena grupa prioriteta za slučajeve kada se nekoliko prekida javlja istovremeno. Zatim biste trebali konfigurirati izvor prekida.

Polje NVIC_IRQChannel pokazuje koji prekid želimo da konfigurišemo. Konstanta USART1_IRQn označava kanal odgovoran za prekide povezane sa USART1. Definisan je u datoteci " stm32f10x.h", Tu su također definirane i druge slične konstante.

Sljedeća dva polja označavaju prioritet prekida (maksimalne vrijednosti ova dva parametra određuje odabrana prioritetna grupa). Posljednje polje zapravo omogućava korištenje prekida.

U funkciju NVIC_Init, kao i prilikom postavljanja portova, prosljeđuje se pokazivač na strukturu za primjenu izvršenih postavki i zapisivanje u odgovarajuće registre mikrokontrolera.

Sada, u postavkama modula, trebate postaviti parametre za koje će ovaj modul generirati prekid. Prvo morate uključiti prekid, to se radi pozivanjem funkcije ime_ITConfig () koji se nalazi u zaglavlju perifernog uređaja.

// Omogući prekide na kraju prijenosa bajtova na USART1
USART_ITConfig (USART1, USART_IT_TXE, ENABLE);

// Omogući prekide na kraju prijema bajta od strane USART1
USART_ITConfig (USART1, USART_IT_RXNE, ENABLE);

Opis parametara proslijeđenih funkciji može se naći u datoteci izvornog koda perifernog uređaja, neposredno iznad lokacije same funkcije. Ova funkcija omogućava ili onemogućuje prekide za različite događaje iz navedenog perifernog modula. Kada se ova funkcija izvrši, mikrokontroler će moći generirati prekide za događaje koji su nam potrebni.

Nakon što uđemo u funkciju rukovanja prekidom, moramo provjeriti iz kog događaja je došlo do prekida, a zatim obrisati nagnutu zastavicu, inače će po izlasku iz prekida mikrokontroler odlučiti da nismo obrađivali prekid, jer je zastavica prekida je još uvijek postavljeno.

Mikrokontroleri sa Cortex-M3 jezgrom imaju namenski sistemski tajmer za izvođenje različitih, malih radnji koje se ponavljaju sa preciznim periodom. Funkcije ovog tajmera uključuju samo poziv prekida u strogo određenim vremenskim intervalima. Tipično, u prekidu koji poziva ovaj tajmer, postavlja se kod za mjerenje trajanja različitih procesa. Deklaracija funkcije za postavljanje tajmera nalazi se u datoteci “ jezgro_ cm3. h". Argument proslijeđen funkciji je broj otkucaja sistemske sabirnice između intervala kada se poziva rukovalac prekida sistemskog tajmera.

SysTick_Config (clk);

Sada kada smo se pozabavili prekidima, ponovo ćemo napisati naš program koristeći sistemski tajmer kao element za podešavanje vremena. Od tajmera" SysTick„Ako je sistemski i mogu ga koristiti različiti funkcionalni blokovi našeg programa, bilo bi razumno premjestiti funkciju rukovanja prekidom iz sistemskog tajmera u zasebnu datoteku, iz ove funkcije u pozivanje funkcija za svaki funkcionalni blok posebno.

Primjer datoteke "main.c" programa za treptanje LED-a pomoću prekida:

// Povežite datoteku zaglavlja s opisom registara mikrokontrolera

#include "stm32f10x.h"
#include "stm32f10x_conf.h"
#include "main.h"

unsigned int LED_timer;

// Funkcija pozvana iz funkcije rukovaoca prekidom sistemskog tajmera

void SysTick_Timer_main ( void)
{
// Ako varijabla LED_timer još nije dosegla 0,
ako(LED_tajmer)
{
// Provjerite njegovu vrijednost, ako je veća od 1500, upalite LED
ako(LED_tajmer> 1500) GPIOC-> BSRR = GPIO_BSRR_BS9;

// inače, ako je manje od ili jednako 1500, onda se isključi
ostalo GPIOC-> BSRR = GPIO_BSRR_BR9;

// Smanjenje varijable LED_timer
LED_timer--;
}

// Ako vrijednost varijable dostigne nulu, postavite novu vrijednost na 2000
ostalo LED_timer = 2000;
}

// Naša glavna funkcija

void glavni ( void)
{

// Omogući port C sabirnice sata
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE);

// Deklarirajte strukturu za konfigurisanje porta
GPIO_InitTypeDef GPIO_Init_struct;

// Ispuni strukturu početnim vrijednostima
GPIO_StructInit (& GPIO_Init_struct);

/ * Upišite u polje GPIO_Pin strukture GPIO_Init_struct pin broj porta, koji ćemo dalje konfigurirati * /
GPIO_Init_struct.GPIO_Pin = GPIO_Pin_9;

// Slično, popunite polja GPIO_Speed ​​i GPIO_Mode
GPIO_Init_struct.GPIO_Speed ​​= GPIO_Speed_2MHz;
GPIO_Init_struct.GPIO_Mode = GPIO_Mode_Out_PP;

// Proslijediti popunjenu strukturu za izvođenje radnji za postavljanje registara
GPIO_Init (GPIOC, & GPIO_Init_struct);

// biramo grupu prioriteta za prekide
NVIC_PriorityGroupConfig (NVIC_PriorityGroup_0);

// Konfigurirajte rad sistemskog tajmera s intervalom od 1 ms
SysTick_Config (24000000/1000);

// Naša glavna beskonačna petlja
dok(1)
{
// Ovaj put je prazan, sva LED kontrola se odvija u prekidima
}
}

Dio izvornog koda u datoteci "stm32f10x_it.c":


#include "main.h"

/**
* @brief Ova funkcija obrađuje SysTick Handler.
* @param Nema
* @retval Ništa
*/

void SysTick_Handler ( void)
{
SysTick_Timer_main ();
}

Primjer radnog nacrta LED trepćućeg programa koji koristi prekid može se preuzeti sa linka.

Ovim završavam svoju priču o osnovama razvoja programa za STM32 mikrokontroler. Dao sam sve informacije koje su vam potrebne da biste mogli dalje samostalno proučavati STM32 mikrokontrolere. Navedeni materijal je samo početna tačka, jer se potpuni opis rada sa mikrokontrolerima ne može opisati ni u jednom članku. Osim toga, proučavanje mikrokontrolera bez sticanja praktičnog iskustva je nemoguće, a pravo iskustvo dolazi postepeno tokom godina rada, eksperimenata, sa gomilanjem raznih softverskih i hardverskih razvoja, kao i čitanjem raznih članaka i dokumentacije o mikrokontrolerima. Ali ne dozvolite da vas ovo uplaši, jer su informacije navedene u članku sasvim dovoljne da napravite svoj prvi uređaj na mikrokontroleru, a dodatno znanje i iskustvo možete steći sami, razvijajući svaki put sve složenije i bolje uređaje. i poboljšati svoje vještine.

Nadam se da bih mogao da vas zainteresujem za proučavanje mikrokontrolera i razvoj uređaja na njima, a moji radovi će vam biti korisni i zanimljivi.

Do sada smo koristili standardnu ​​biblioteku kernela - CMSIS. Kako bismo konfigurirali port na željeni način rada, morali smo se obratiti kako bismo pronašli registar odgovoran za određenu funkciju, kao i potražili druge informacije vezane za ovaj proces u velikom dokumentu. Stvari će postati još mučnije i svakodnevnije kada počnemo raditi sa tajmerom ili ADC-om. Broj registara tamo je mnogo veći od broja I/O portova. Ručna konfiguracija oduzima puno vremena i povećava mogućnost da napravite grešku. Stoga mnogi ljudi radije rade sa standardnom perifernom bibliotekom - StdPeriph. Šta to daje? Jednostavno - nivo apstrakcije raste, ne morate kopati po dokumentaciji i razmišljati o većini registara. U ovoj biblioteci svi načini rada i parametri perifernih uređaja MC opisani su u obliku struktura. Sada, da biste konfigurirali periferni uređaj, trebate samo pozvati funkciju inicijalizacije uređaja s popunjenom strukturom.

Ispod je slika sa šematskim prikazom nivoa apstrakcije.

Radili smo sa CMSIS-om (koji je "najbliži" kernelu) da pokažemo kako mikrokontroler radi. Sljedeći korak je standardna biblioteka, koju ćemo sada naučiti kako koristiti. Sljedeći su drajveri uređaja. Oni se shvataju kao * .c \ * .h -datoteke koje pružaju pogodan softverski interfejs za kontrolu bilo kojeg uređaja. Tako, na primjer, u ovom kursu ćemo vam pružiti drajvere za max7219 čip i esp8266 WiFi modul.

Standardni projekat će uključivati ​​sljedeće datoteke:


Prvo, naravno, ovo su CMSIS fajlovi koji omogućavaju standardnoj biblioteci da radi sa kernelom, o njima smo već govorili. Drugo, datoteke standardne biblioteke. I treće, prilagođeni fajlovi.

Datoteke biblioteke možete pronaći na stranici posvećenoj ciljnom MK-u (za nas je to stm32f10x4), u odjeljku Design Resources(u CooCox IDE, ove datoteke se preuzimaju iz spremišta razvojnog okruženja). Svaka periferija odgovara dvije datoteke - zaglavlju (* .h) i izvornom kodu (* .c). Detaljan opis možete pronaći u datoteci podrške koja se nalazi u arhivi sa bibliotekom na sajtu.

  • stm32f10x_conf.h - konfiguracijski fajl biblioteke. Korisnik može uključiti ili onemogućiti module.
  • stm32f10x_ppp.h - datoteka zaglavlja periferije. Umjesto toga, Ppp može biti gpio ili aDC.
  • stm32f10x_ppp.c je drajver za periferne uređaje napisan u C jeziku.
  • stm32f10x_it.h - datoteka zaglavlja koja uključuje sve moguće rukovaoce prekidima (njihove prototipove).
  • stm32f10x_it.c je izvorni fajl šablona koji sadrži rutinu usluge prekida (ISR) za Cortex M3 izuzetke. Korisnik može dodati vlastite ISR-ove za periferiju koja se koristi.

Standardna biblioteka i periferni uređaji imaju konvenciju za imenovanje funkcija i notacije.

  • PPP je akronim za periferne uređaje kao što je ADC.
  • Sistemske datoteke, datoteke zaglavlja i izvorne datoteke - sve počinje sa stm32f10x_.
  • Konstante koje se koriste u jednoj datoteci definirane su u ovoj datoteci. Konstante koje se koriste u više datoteka definirane su u datotekama zaglavlja. Sve konstante u perifernoj biblioteci najčešće se pišu VELIKIM SLOVIMA.
  • Registri se tretiraju kao konstante i takođe se nazivaju VELIKIM slovima.
  • Nazivi perifernih funkcija sadrže akronim kao što je USART_SendData ().
  • Za konfiguriranje svakog perifernog uređaja koristi se struktura PPP_InitTypeDef, koja se prosljeđuje funkciji PPP_Init ().
  • Za deinicijalizaciju (postavite zadanu vrijednost), možete koristiti funkciju PPP_DeInit ().
  • Funkcija za omogućavanje ili onemogućavanje perifernih uređaja naziva se PPP_Cmd ().
  • Funkcija za omogućavanje/onemogućavanje prekida se zove PPP_ITConfig.

Za kompletnu listu, ponovo pogledajte datoteku podrške biblioteke. Sada prepišimo LED koji treperi koristeći standardnu ​​perifernu biblioteku!

Prije početka rada, pogledajmo datoteku stm32f10x.h i pronađemo red:

#define USE_STDPERIPH_DRIVER

Ako postavljate projekat od nule koristeći datoteke biblioteke iz preuzete arhive, morat ćete dekomentirati ovaj red. To će vam omogućiti korištenje standardne biblioteke. Ova definicija (makro) će naložiti pretprocesoru da uključi datoteku stm32f10x_conf.h:

#ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

Moduli su uključeni u ovaj fajl. Ako trebate samo određene, onemogućite ostale, ovo će uštedjeti vrijeme kompilacije. Nama, kao što ste mogli pretpostaviti, trebaju RTC i GPIO moduli (međutim, u budućnosti će nam trebati i _bkp.h, _flash, _pwr.h, _rtc.h, _spi.h, _tim.h, _usart.h) :

#include "stm32f10x_flash.h" // za init_pll () #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h"

Kao i prošli put, prvo morate omogućiti taktiranje porta B. To radi funkcija deklarirana u stm32f10x_rcc.h:

Void RCC_APB2PeriphClockCmd (uint32_t RCC_APB2Periph, FunctionalState NewState);

FunctionalState enumeracija je definirana u stm32f10x.h:

Typedef enum (DISABLE = 0, ENABLE =! DISABLE) FunctionalState;

Hajde da deklarišemo strukturu za postavljanje naše noge (možete je pronaći u datoteci stm32f10x_gpio.h):

GPIO_InitTypeDef LED;

Sada ga moramo popuniti. Pogledajmo sadržaj ove strukture:

Typedef struktura (uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode;) GPIO_InitTypeDef;

Sve potrebne enumeracije i konstante mogu se naći u istoj datoteci. Tada će prepisana funkcija init_leds () poprimiti sljedeći oblik:

Void led_init () (// Uključi taktiranje RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOB, ENABLE); // Deklarišemo strukturu i popunjavamo je GPIO_InitTypeDef LED; LED.GPIO_Pin = GPIO_Pin_0; GIPIO_Pin_0; LED.GPIO;in_Pin_LED.GPIO;in.GPIO; LED);)

Prepišimo glavnu () funkciju:

Int main (void) (led_init (); dok (1) (GPIO_SetBits (GPIOB, GPIO_Pin_0); kašnjenje (10000000); GPIO_ResetBits (GPIOB, GPIO_Pin_0); kašnjenje (10000000);))

Glavna stvar je dobiti osjećaj za redoslijed inicijalizacije: uključite periferni takt, deklarirajte strukturu, popunite strukturu i pozovite metodu inicijalizacije. Ostali periferni uređaji se obično konfiguriraju na sličan način.

Softver potreban za razvoj. U ovom članku ću vam pokazati kako ga pravilno konfigurirati i povezati. Sva komercijalna okruženja kao što su IAR EWARM ili Keil uVision obično sami izvode ovu integraciju, ali u našem slučaju sve će morati da se konfiguriše ručno, trošeći dosta vremena na to. Prednost je što imate priliku da shvatite kako sve to funkcionira iznutra, a u budućnosti možete sve fleksibilno prilagoditi sebi. Prije početka postavljanja, razmotrite strukturu okruženja u kojem ćemo raditi:

Eclipse će se koristiti za praktično uređivanje datoteka implementacije funkcija ( .c), fajlovi zaglavlja ( .h) kao i datoteke za montažu ( .S). Pod "zgodnim" mislim na upotrebu dovršavanja koda, isticanje sintakse, refaktoring, navigaciju kroz funkcije i njihove prototipove. Datoteke se automatski šalju ispravnim kompajlerima koji generiraju objektni kod (u datotekama .o). Za sada, ovaj kod ne sadrži apsolutne adrese varijabli i funkcija, pa stoga nije pogodan za izvršenje. Rezultirajuće objektne datoteke se skupljaju pomoću povezivača. Da bi znao koje dijelove adresnog prostora koristiti, graditelj koristi posebnu datoteku ( .ld), koja se zove linker skripta. Obično sadrži definiciju adresa sekcija i njihove veličine (odsjek koda prikazan na flash-u, varijabilni dio prikazan na RAM-u, itd.).

Na kraju, linker generiše .elf datoteku (izvršni i povezivi format), koja sadrži, pored instrukcija i podataka, informacije za otklanjanje grešaka (Informacije o otklanjanju grešaka) koje koristi debuger. Za običan firmware vsprog, ovaj format nije prikladan, jer to zahtijeva primitivniju memorijsku datoteku slike (na primjer, Intel HEX - .hex). Tu je i alat iz Sourcery CodeBench skupa (arm-none-eabi-objcopy) za njegovo generiranje, a oni se savršeno integriraju u eclipse koristeći instalirani ARM dodatak.

Za izvođenje samog otklanjanja grešaka koriste se tri programa:

  1. sam eclipse, koji omogućava programeru da "vizuelno" koristi otklanjanje grešaka, prolazi kroz redove, drži pokazivač miša iznad varijabli da vidi njihove vrijednosti i druge pogodnosti
  2. arm-none-eabi-gdb - GDB klijent - debager, koji je tajno kontrolisan eclips-om (preko stdin) kao reakcija na akcije navedene u paragrafu 1. Zauzvrat, GDB se povezuje sa OpenOCD Debug serverom, a sve dolazne komande GDB debuger prevodi u komande koje OpenOCD razume. GDB kanal<->OpenOCD je implementiran preko TCP protokola.
  3. OpenOCD je debug server koji može komunicirati direktno sa programerom. Pokreće se ispred klijenta i čeka TCP vezu.

Ova šema vam se može učiniti vrlo beskorisnom: zašto koristiti klijenta i servera odvojeno i još jednom izvoditi translaciju naredbi, ako se sve to može učiniti jednim debagerom? Činjenica je da takva arhitektura teoretski omogućava zgodnu izmjenu klijenta i servera. Na primjer, ako trebate koristiti drugi programator umjesto versaloon-a, koji neće podržavati OpenOCD, ali će podržavati drugi poseban Debug server (na primjer, texane / stlink za stlink programator - koji se nalazi na STM32VLDiscovery ploči za otklanjanje grešaka), onda umjesto toga pokretanja OpenOCD-a jednostavno ćete pokrenuti traženi server i sve bi trebalo da radi, bez ikakvih dodatnih pokreta. Istovremeno, moguća je i suprotna situacija: recimo da želite da koristite okruženje IAR EWARM zajedno sa versaloonom umesto paketa Eclipse + CodeBench. IAR ima svoj ugrađeni Debug klijent, koji će se uspješno povezati na OpenOCD i kontrolirati ga, kao i primati potrebne podatke kao odgovor. Međutim, sve ovo ponekad ostaje samo u teoriji, budući da standardi za komunikaciju između klijenta i servera nisu striktno regulirani, a na nekim mjestima se mogu razlikovati, međutim, konfiguracije koje sam naveo sa st-link + eclipse i IAR + versaloon su bile uspješan za mene.

Obično klijent i server rade na istoj mašini i povezuju se sa serverom na adresi lokalni host: 3333(Za openocd), ili lokalni host: 4242(za teksan / stlink st-util). Ali niko se ne trudi da otvori port 3333 ili 4242 (i prosledi ovaj port na ruteru na spoljnu mrežu) i vaše kolege iz drugog grada će moći da se povežu i otklone greške na vašem hardveru. Ovaj trik često koriste embedderi koji rade na udaljenim objektima, pristup kojima je ograničen.

Hajde da počnemo

Pokrenite eclipse i odaberite File-> New-> C Project, odaberite tip projekta ARM Linux GCC (Sorcery G++ Lite) i naziv "stm32_ld_vl" (ako imate STV32VLDiscovery, bilo bi logičnije da ga nazovete "stm32_md_vl" ):

Kliknite na Završi, minimizirajte ili zatvorite prozor dobrodošlice. Dakle, projekat je kreiran i folder stm32_ld_vl bi se trebao pojaviti u vašem radnom prostoru. Sada ga treba popuniti potrebnim bibliotekama.

Kao što ste shvatili iz naziva projekta, kreiraću projekat za prikaz lenjira linija vrijednosti niske gustine(LD_VL). Da biste kreirali projekat za druge mikrokontrolere, morate zamijeniti sve datoteke i definicije u čijem nazivu se nalazi _LD_VL (ili_ld_vl) na one koje su Vam potrebne, u skladu sa tabelom:

Pogled vladara Oznaka Mikrokontroleri (x može varirati)
Linija vrijednosti niske gustine _LD_VL STM32F100x4 STM32F100x6
Mala gustina _LD STM32F101x4 STM32F101x6
STM32F102x4 STM32F102x6
STM32F103x4 STM32F103x6
Linija vrijednosti srednje gustine _MD_VL STM32F100x8 STM32F100xB
Srednje gustine
_MD
STM32F101x8 STM32F101xB
STM32F102x8 STM32F102xB
STM32F103x8 STM32F103xB
Linija vrijednosti visoke gustine _HD_VL STM32F100xC STM32F100xD STM32F100xE
Velika gustoća _HD STM32F101xC STM32F101xD STM32F101xE
STM32F103xC STM32F103xD STM32F103xE
XL-gustina _XL STM32F101xF STM32F101xG
STM32F103xF STM32F103xG
Linija povezivanja _CL STM32F105xx i STM32F107xx

Da biste razumjeli logiku tabele, morate biti upoznati sa STM32 označavanjem. Odnosno, ako imate VLDiscovery, tada ćete morati zamijeniti sve što se odnosi na _LD_VL sa _MD_VL, budući da je čip STM32F100RB, koji pripada liniji vrijednosti srednje gustine, zalemljen u otkriću.

Dodavanje biblioteke standardnih perifernih uređaja CMSIS i STM32F10x projektu

CMSIS(Cortex Microcontroller Software Interface Standard) je standardizovana biblioteka za rad sa Cortex mikrokontrolerima koja implementira nivo HAL (Hardware Abstraction Layer), odnosno omogućava vam da apstrahujete od detalja rada sa registrima, pronalaženja adresa registara prema podacima itd. . Biblioteka je zbirka C i Asm izvora. Osnovni dio biblioteke je isti za sve Cortexe (bilo da je ST, NXP, ATMEL, TI ili bilo šta drugo), a razvio ga je ARM. Drugi dio biblioteke je odgovoran za periferne uređaje, koji su prirodno različiti za različite proizvođače. Stoga, na kraju, potpunu biblioteku i dalje distribuira proizvođač, iako se osnovni dio i dalje može preuzeti zasebno sa ARM web stranice. Biblioteka sadrži definicije adresa, inicijalizacijski kod generatora takta (pogodno konfiguriran pomoću define-s), i sve ostalo što spašava programera od ručnog unošenja u svoje projekte definicije adresa svih perifernih registara i definicije bitova vrijednosti ovih registara.

Ali momci iz ST su otišli dalje. Osim CMSIS podrške, oni pružaju još jednu biblioteku za STM32F10x pod nazivom Standardna periferna biblioteka(SPL), koji se može koristiti kao dodatak CMSIS-u. Biblioteka omogućava brži i praktičniji pristup periferiji, a takođe kontroliše (u nekim slučajevima) ispravnost rada sa periferijama. Stoga se ova biblioteka često naziva skupom drajvera za periferne module. Dolazi s paketom primjera, kategoriziranih za različite periferne uređaje. Takođe postoji biblioteka ne samo za STM32F10x, već i za druge serije.

Možete preuzeti cijelu verziju SPL + CMSIS 3.5 ovdje: STM32F10x_StdPeriph_Lib_V3.5.0 ili na web stranici ST. Raspakujte arhivu. Kreirajte CMSIS i SPL foldere u folderu projekta i počnite kopirati datoteke u svoj projekt:

Šta kopirati

Gdje kopirati (uzimajući u obzir,
to je fascikla projekta stm32_ld_vl)

Opis datoteke
Biblioteke / CMSIS / CM3 /
CoreSupport / core_cm3.c
stm32_ld_vl / CMSIS / core_cm3.c Opis Cortex M3 jezgre
Biblioteke / CMSIS / CM3 /
CoreSupport / core_cm3.h
stm32_ld_vl / CMSIS / core_cm3.h Zaglavlja opisa kernela

ST / STM32F10x / system_stm32f10x.c
stm32_ld_vl / CMSIS /system_stm32f10x.c Funkcije inicijalizacije i
kontrola sata
Biblioteke / CMSIS / CM3 / DeviceSupport /
ST / STM32F10x / system_stm32f10x.h
stm32_ld_vl / CMSIS /system_stm32f10x.h Naslovi ovih funkcija
Biblioteke / CMSIS / CM3 / DeviceSupport /
ST / STM32F10x / stm32f10x.h
stm32_ld_vl / CMSIS /stm32f10x.h Osnovni opis periferije
Biblioteke / CMSIS / CM3 / DeviceSupport /
ST / STM32F10x / pokretanje / gcc_ride7 /
startup_stm32f10x_ld_vl.s
stm32_ld_vl / CMSIS /startup_stm32f10x_ld_vl.S
(!!! Upozorenje ekstenzija datoteke CAPITAL S)
Vektorska tabela
prekida i init-s na asm
Projekat / STM32F10x_StdPeriph_Template /
stm32f10x_conf.h
stm32_ld_vl / CMSIS / stm32f10x_conf.h Šablon za prilagođavanje
perifernih modula

inc / *
stm32_ld_vl / SPL / inc / * SPL zaglavlja
Biblioteke / STM32F10x_StdPeriph_Driver /
src / *
stm32_ld_vl / SPL / src / * SPL implementacija

Nakon kopiranja, idite na Eclipse i izvršite Refresh u kontekstualnom meniju projekta. Kao rezultat, u Project Exploreru bi trebali dobiti istu strukturu kao na slici desno.

Možda ste primijetili da u Libraries / CMSIS / CM3 / DeviceSupport / ST / STM32F10x / startup / folderu postoje folderi za različite IDE (različiti IDE koriste različite kompajlere). Odabrao sam IDE Ride7 jer koristi kompajler GNU Tools za ARM Embedded, koji je kompatibilan sa našim Sourcery CodeBench.

Cijela biblioteka je konfigurirana pomoću pretprocesora (koristeći define-s), što će omogućiti rješavanje svih potrebnih grana u fazi kompilacije (ili bolje rečeno, čak i prije nje) i izbjegavanje opterećenja u samom kontroleru (što bi se primijetilo ako bi se konfiguracija je izvršena u RunTime). Na primjer, sva oprema je različita za različite lenjire, i stoga da bi biblioteka "saznala" koji ravnalo želite koristiti, od vas se traži da dekomentirate u datoteci stm32f10x.h jedna od definicija (koja odgovara vašem vladaru):

/ * #define STM32F10X_LD * / / *!< STM32F10X_LD: STM32 Low density devices */
/ * #define STM32F10X_LD_VL * / / *!< STM32F10X_LD_VL: STM32 Low density Value Line devices */
/ * #define STM32F10X_MD * / / *!< STM32F10X_MD: STM32 Medium density devices */

itd...

Ali ne preporučujem da to radite. Za sada nećemo dirati datoteke biblioteke, ali ćemo kasnije napraviti definiciju koristeći postavke kompajlera u Eclipseu. A onda će Eslipse pozvati kompajler sa ključem -D STM32F10X_LD_VL, što je za pretprocesor apsolutno ekvivalentno situaciji ako ste dekomentirali "#define STM32F10X_LD_VL"... Dakle, nećemo mijenjati kod, kao rezultat toga, ako želite, jednog dana ćete moći premjestiti biblioteku u poseban direktorij, a ne kopirati je u mapu svakog novog projekta.

Linker skripta

U kontekstualnom izborniku projekta odaberite Novo-> Datoteka-> Ostalo-> Općenito-> Datoteka, Sljedeće. Odaberite korijenski folder projekta (stm32_ld_vl). Unesite naziv datoteke "stm32f100c4.ld" (ili "stm32f100rb.ld" za otkrivanje). Sada kopirajte i zalijepite u eclipse:

ENTRY (Reset_Handler) MEMORIJA (FLASH (rx): ORIGIN = 0x08000000, LENGTH = 16K RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K) _estack = ORIGIN (RAM) + LENGTH = ORIGIN (RAM) + LENGTH; MIN_HEAP_SIZE = 0; MIN_STACK_SIZE = 256; SEKCIJE (/ * Tablica vektora prekida * / .isr_vector: (. = ALIGN (4); KEEP (* (. Isr_vector)). = ALIGN (4);)> FLASH / * Programski kod i ostali podaci idu u FLASH * / .text: (. = ALIGN (4); / * Code * / * (. text) * (. text *) / * Konstante * / * (. rodata) * (. rodata *) / * ARM-> Thumb i Thumb-> ARM kod ljepila * / * (. glue_7) * (. glue_7t) KEEP (* (. init)) KEEP (* (. fini)). = ALIGN (4); _etext =.;)> FLASH. ARM.extab: (* (. ARM.extab * .gnu.linkonce.armextab. *))> FLASH .ARM: (__exidx_start =.; * (. ARM.exidx *) __exidx_end =.;)> FLASH .ARM. atributi: (* (. ARM.attributes))> FLASH .preinit_array: (PROVIDE_HIDDEN (__preinit_array_start =.); KEEP (* (. preinit_array *)) PROVIDE_HIDDEN (__preinit_array_end =.);)> FLASH_array: .iend. )> FLASH: .init_array_end =.);)> FLASH: .init_array_end =.); KEEP (* (SORT (.init_array. *))) KEEP (* (. Init_array *)) PROVIDE_HIDDEN (__init_array_end =.);) > FLASH .fini_array: (PROVIDE_HIDDEN (__fini_array_start = *.); KEEP (.fini_array *)) KEEP (* (SORT (.fini_array. *))) PROVIDE_HIDDEN (__fini_array_end =.); )> FLASH _sidata =.; / * Inicijalizirani podaci * / .data: AT (_sidata) (. = ALIGN (4); _sdata =.; / * Kreirajte globalni simbol na početku podataka * / * (. Data) * (. Data *). = ALIGN (4); _edata =.; / * Definirajte globalni simbol na kraju podataka * /)> RAM / * Neinicijalizirani podaci * /. = ALIGN (4); .bss: (/ * Ovo se koristi od strane pokretanja da bi inicijalizirao .bss sekciju * ​​/ _sbss =.; / * definirajte globalni simbol na početku bss * / __bss_start__ = _sbss; * (. bss) * (. bss *) * (COMMON). = ALIGN (4); _ebss =.; / * Definirajte globalni simbol na bss kraju * / __bss_end__ = _ebss;)> RAM PROVIDE (end = _ebss); PROVIDE (_end = _ebss); PROVIDE (__ HEAP_START = _ebss); / * User_heap_stack odjeljak, koristi se za provjeru da li je ostalo dovoljno RAM-a * / ._user_heap_stack: (. = ALIGN (4);. =. + MIN_HEAP_SIZE;. =. + MIN_STACK_SIZE;. = ALIGN (4);)> RAM / ODBACI /: (libc.a (*) libm.a (*) libgcc.a (*)))

S obzirom na l Inker skripta će biti dizajnirana posebno za STM32F100C4 kontroler (koji ima 16 KB flash i 4 KB RAM-a), ako imate drugu, morat ćete promijeniti parametre DUŽINE za FLASH i RAM područja na početku fajl (za STM32F100RB, koji je u Discoveryju: Flash 128K i RAM 8K).

Sačuvamo fajl.

Build Setup (C / C ++ Build)

Idite na Project-> Properties-> C / C ++ Build-> Settings-> Tool Settings i počnite konfigurirati alate za izgradnju:

1) Target Precessor

Mi biramo za koju Cortex jezgru će kompajler raditi.

  • Procesor: cortex-m3

2) ARM Sourcery Linux GCC C kompajler -> Preprocesor

Dodajte dva define-a tako što ćete ih proći kroz prekidač -D do kompajlera.

  • STM32F10X_LD_VL - definiše lenjir (pisao sam o ovoj definiciji gore)
  • USE_STDPERIPH_DRIVER - daje instrukcije CMSIS biblioteci da treba koristiti SPL drajver

3) ARM Sourcery Linux GCC C kompajler -> Direktoriji

Dodajte staze u uključene biblioteke.

  • "$ (workspace_loc: / $ (ProjName) / CMSIS)"
  • "$ (workspace_loc: / $ (ProjName) / SPL / inc)"

Sada, na primjer, ako napišemo:

#include "stm32f10x.h

Zatim kompajler prvo mora potražiti datoteku stm32f10x.h u direktoriju projekta (on to uvijek radi), on ga tamo neće pronaći i počeće da traži u fascikli CMSIS, putanju do koje smo naveli, pa, pronaći će je.

4) ARM Sourcery Linux GCC C kompajler -> Optimizacija

Uključite optimizaciju funkcija i podataka

  • -ffunction-sections
  • -fdata-sekcije

Kao rezultat toga, sve funkcije i elementi podataka bit će smješteni u zasebne sekcije, a kolektor će moći razumjeti koje sekcije se ne koriste i jednostavno će ih izbaciti.

5) ARM Sourcery Linux GCC C kompajler -> Općenito

Dodajte putanju našoj linker skripti: "$ (workspace_loc: / $ (ProjName) /stm32f100c4.ld)" (ili kako god to nazvali).

I postavite opcije:

  • Nemojte koristiti standardne početne datoteke - nemojte koristiti standardne početne datoteke.
  • Ukloni neiskorištene dijelove - uklonite neiskorištene dijelove

To je to, podešavanje je završeno. UREDU.

Od stvaranja projekta uradili smo mnogo, a ima nekoliko stvari koje je Eclipse možda propustio, pa mu moramo reći da revidira strukturu projektne datoteke. Da biste to učinili, iz kontekstnog izbornika projekta morate učiniti Indeks -> obnavljanje.

Zdravo LED diode na STM32

Vrijeme je da kreirate glavnu datoteku projekta: File -> New -> C / C ++ -> Source File. Sljedeći. Naziv izvornog fajla: main.c.

Kopirajte i zalijepite sljedeće u datoteku:

#include "stm32f10x.h" uint8_t i = 0; int main (void) (RCC-> APB2ENR | = RCC_APB2ENR_IOPBEN; // Omogući PORTB Periph sat RCC-> APB1ENR | = RCC_APB1ENR_TIM2EN; // Omogući TIM2 Periph sat // Onemogući JTAG za oslobađanje LEDB PIN RCCENBENAP-> | -> MAPR | = AFIO_MAPR_SWJ_CFG_JTAGDISABLE; // Clear PB4 i kontrolu PB5 bitove registra GPIOB-> CRL & = ~ (GPIO_CRL_MODE4 | GPIO_CRL_CNF4 | GPIO_CRL_MODE5 | GPIO_Cull_output max kao PBF5) 10MHz GPIOB-> CRL | = GPIO_CRL_MODE4_0 | GPIO_CRL_MODE5_0; TIM2-> PSC = SystemCoreClock / 1000 - 1; // 1000 otkucaja / sek TIM2-> ARR = 1000; // 1 prekid / 1 sek TIM2-> DIER | = TIM_DIER_UIE; // Omogući tim2 prekid TIM2-> CR1 | = TIM_CR1_CEN; Početni broj NVIC_EnableIRQ (TIM2_IRQn); // Omogući IRQ dok (1); // Beskonačna petlja) void TIM2_IRQHandler (void) (TIM2-> SR & = ~ TIM_SR_UIF ; // Očisti UIF zastavu if (1 == (i ++) & 0x1)) (GPIOB-> BSRR = GPIO_BSRR_BS4; // Postavi PB4 bit GPIOB-> BSRR = GPIO_BSRR_BR5; // Poništi PB5 bit) drugo (GPIOB-> BSRR = GPIO_BSRR_B S5; // Postavi PB5 bit GPIOB-> BSRR = GPIO_BSRR_BR4; // Resetuj PB4 bit))

Iako smo uključili SPL biblioteke, ona se ovdje nije koristila. Svi pozivi u polja poput RCC-> APB2ENR su u potpunosti opisani u CMSIS-u.

Možete pokrenuti Project -> Build All. Ako je sve uspjelo, tada bi se datoteka stm32_ld_vl.hex trebala pojaviti u mapi Debug projekta. Automatski je generisan od elf-a pomoću ugrađenih alata. Treperimo datoteku i vidimo kako LED diode trepću frekvencijom od jednom u sekundi:

Vsprog -sstm32f1 -ms -oe -owf -I /home/user/workspace/stm32_ld_vl/Debug/stm32_ld_vl.hex -V "tvcc.set 3300"

Naravno, umjesto / home / user / workspace / morate unijeti svoju putanju do radnog prostora.

Za STM32VLDiscovery

Kod se malo razlikuje od onog koji sam dao gore za moju ploču za otklanjanje grešaka. Razlika je u pinovima na kojima "vise" LED diode. Ako su na mojoj ploči bili PB4 i PB5, onda su u Discoveryju bili PC8 i PC9.

#include "stm32f10x.h" uint8_t i = 0; int main (void) (RCC-> APB2ENR | = RCC_APB2ENR_IOPCEN; // Omogući PORTC Periph sat RCC-> APB1ENR | = RCC_APB1ENR_TIM2EN; // Omogući TIM2 Periph sat // Obriši PC8 i PC9 bitova kontrolnog registra GPIOC-> (GPIO_CRH_MODE8 | GPIO_CRH_CNF8 | GPIO_CRH_MODE9 | GPIO_CRH_CNF9); // Konfigurišite PC8 i PC9 kao Push Pull izlaz na maks. 10MHz GPIOC-> CRH | = GPIO_CRH_MODE8_0 | GPIO_CRH_MODE8_0 | GPIO_CRH_CRH> - GPIO_CRH 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Prekid / sec (1000/100) TIM2-> DIER | = TIM_DIER_UIE; // Omogući tim2 prekid TIM2-> CR1 | = TIM_CR1_CEN; // Broj starta NVIC_EnableIRQ (TIM2_IRQn); // Omogući IRQ dok (1); // Beskonačnost petlja) void TIM2_IRQHandler (void) (TIM2-> SR & = ~ TIM_SR_UIF; // Očisti UIF zastavu if (1 == (i ++ & 0x1)) (GPIOC-> BSRR = GPIO_BSRR_BS8 ; // Postavi PC8 bit GPIOC- > BSRR = GPIO_BSRR_BR9; // Reset PC9 bit) drugo (GPIOC-> BSRR = GPIO_BSRR_BS9; // Postavi PC9 bit GPIOC-> BSRR = GPIO_BSRR_BR8; // Reset PC8 bit))

Pod Windowsom, možete flešovati rezultujući heksadecimalni (/workspace/stm32_md_vl/Debug/stm32_md_vl.hex) pomoću uslužnog programa iz ST.

Pa, pod linuxom, st-flash uslužni program. ALI!!! Uslužni program ne hakuje heksadecimalni format Intel HEX formata (koji se generira prema zadanim postavkama), pa je izuzetno važno odabrati binarni format u postavkama za kreiranje Flash slike:

Ekstenzija datoteke se neće promijeniti (hex će ostati kao što je bio), ali će se promijeniti format datoteke. I tek nakon toga možete izvršiti:

St-flash write v1 /home/user/workspace/stm32_md_vl/Debug/stm32_md_vl.hex 0x08000000

Usput, u vezi ekstenzije i formata: obično se binarne datoteke označavaju ekstenzijom .bin, dok se Intel HEX datoteke nazivaju ekstenzijom .hex. Razlika u ova dva formata je više tehnička nego funkcionalna: binarni format sadrži samo bajtove instrukcija i podataka, koje će programer jednostavno upisati u kontroler "kao što jesu". IntelHEX, s druge strane, nema binarni format, već tekstualni: potpuno isti bajtovi su podijeljeni na 4 bita i predstavljeni su znak po znak u ASCII formatu, a koriste se samo znakovi 0-9, AF (bin i heksadecimalni su sistemi brojeva sa više baza, to jest, 4 bita u bin mogu biti predstavljena kao jedna cifra u heksadecimala). Dakle, ihex format je više od 2 puta veći od obične binarne datoteke (svaka 4 bita se zamjenjuju bajtom + prijelom reda radi lakšeg čitanja), ali se može čitati u običnom uređivaču teksta. Stoga, ako ćete nekome poslati ovu datoteku, ili je koristiti u drugim programima, onda je preporučljivo preimenovati je u stm32_md_vl.bin kako ne biste zavarali one koji će pogledati njen naziv.

Dakle, konfigurisali smo verziju firmvera za stm32. Sljedeći put ću vam reći kako

Kada tek počnete da programirate mikrokontrolere ili niste programirali dugo vremena, nije lako razumjeti tuđi kod. Pitanja "Šta je?" i "Odakle je ovo došlo?" pojavljuju se na gotovo svakoj kombinaciji slova i brojeva. I što brže dođe do razumijevanja logike "šta? Zašto? I gdje?", lakše je proučavati tuđi kod, uključujući primjere. Istina, ponekad je potrebno više od jednog dana da se "preskoči kod" i "pregleda priručnik" za ovo.

Svi STM32F4xx mikrokontroleri imaju dosta perifernih uređaja. Svakoj periferiji mikrokontrolera dodijeljena je specifična, specifična memorijska oblast koja se ne može premjestiti. Svako memorijsko područje se sastoji od memorijskih registara, a ti registri mogu biti 8-bitni, 16-bitni, 32-bitni ili bilo koji drugi, ovisno o mikrokontroleru. U mikrokontroleru STM32F4 ovi registri su 32-bitni i svaki registar ima svoju svrhu i svoju specifičnu adresu. Ništa ne sprečava njihove programe da im direktno pristupe navođenjem adrese. Na kojoj adresi se nalazi ovaj ili onaj registar i na koji periferni uređaj je naznačen na memorijskoj kartici. Za STM32F4, takva memorijska kartica je u dokumentu DM00031020.pdf, koji se može naći na st.com. Dokument se zove

RM0090
Referentni priručnik
STM32F405xx / 07xx, STM32F415xx / 17xx, STM32F42xxx i STM32F43xxx napredni 32-bitni MCU bazirani na ARM-u

U poglavlju 2.3 Mapa memorije na stranici 64, tabela počinje s adresama registarskih područja i njihovom pripadnosti perifernom uređaju. U istoj tabeli nalazi se veza do odjeljka s detaljnijom dodjelom memorije za svaku periferiju.

Na lijevoj strani tabele je naznačen raspon adresa, u sredini je naziv periferije, au posljednjoj koloni gdje se nalazi detaljniji opis dodjele memorije.

Dakle, za GPIO U/I portove opšte namjene u tabeli alokacije memorije, možete pronaći da su im adrese dodijeljene počevši od 0x4002 0000. GPIOA U/I port opće namjene zauzima raspon adresa od 0x4002 000 do 0x4002 03FF . GPIOB port zauzima raspon adresa 0x4002 400 - 0x4002 07FF. itd.

Da biste vidjeli detaljniju distribuciju u samom asortimanu, potrebno je samo slijediti link.

Tu je i tabela, ali sa memorijskom karticom za opseg GPIO adresa. Prema ovoj memorijskoj mapi, prva 4 bajta pripadaju MODER registru, sljedeća 4 bajta pripadaju OTYPER registru i tako dalje. Adrese registra se broje od početka opsega koji pripada određenom GPIO portu. To jest, svaki GPIO registar ima specifičnu adresu koja se može koristiti pri razvoju programa za mikrokontroler.

Ali upotreba adresa registra za ljude je nezgodna i prepuna mnogo grešaka. Stoga proizvođači mikrokontrolera kreiraju standardne biblioteke koje olakšavaju rad s mikrokontrolerima. U ovim bibliotekama fizičkim adresama se dodeljuje slovna oznaka. Za STM32F4xx ove korespondencije su specificirane u datoteci stm32f4xx.h... File stm32f4xx.h pripada biblioteci CMSIS i nalazi se u folderu Libraries \ CMSIS \ ST \ STM32F4xx \ Include \.

Hajde da vidimo kako je GPIOA port definisan u bibliotekama. Sve ostalo je slično definisano. Dovoljno je razumjeti princip. File stm32f4xx.h prilično velika i stoga je bolje koristiti pretragu ili mogućnosti koje vaš alatni lanac pruža.

Za GPIOA port, nalazimo red koji spominje GPIOA_BASE

GPIOA_BASE je definiran preko AHB1PERIPH_BASE

AHB1PERIPH_BASE je zauzvrat definirana kroz PERIPH_BASE

A zauzvrat, PERIPH_BASE je definirana kao 0x4000 0000. Ako pogledate memorijsku mapu perifernih uređaja (u odjeljku 2.3 Mapa memorije na strani 64), videćemo ovu adresu na samom dnu tabele. Od ove adrese počinju registri čitave periferije mikrokontrolera STM32F4. Odnosno, PERIPH_BASE je početna adresa cjelokupne periferije mikrokontrolera STM32F4xx općenito, a posebno mikrokontrolera STM32F407VG ..

AHB1PERIPH_BASE je definiran kao zbir (PERIPH_BASE + 0x00020000). (pogledajte slike pozadi). Ovo će biti adresa 0x4002 0000. Na memorijskoj kartici, GPIO I/O portovi opšte namene počinju na ovoj adresi.

GPIOA_BASE je definiran kao (AHB1PERIPH_BASE + 0x0000), to jest, ovo je početna adresa grupe registara GPIOA porta.

Pa, sam GPIOA port je definisan kao struktura registara, čije postavljanje u memoriju počinje adresom GPIOA_BASE (pogledajte red #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE).

Struktura svakog GPIO porta je definirana kao tip GPIO_TypeDef.

Dakle, standardne biblioteke, u ovom slučaju fajl stm32f4xx.h, jednostavno humanizirajte mašinsko adresiranje. Ako vidite unos GPIOA-> ODR = 1234, to znači da će na adresi 0x40020014 biti upisan broj 1234. GPIOA ima početnu adresu 0x40020000 i ODR registar ima adresu 0x14 od početka opsega, stoga GPIOA-> ODR ima adresu 0x40020014.

Ili na primjer, ne sviđa vam se GPIOA-> ODR unos, onda možete definirati #define GPIOA_ODR ((uint32_t *) 0x40020014) i dobiti isti rezultat pisanjem GPIOA_ODR = 1234 ;. Koliko je to svrsishodno? Ako zaista želite da unesete sopstvene oznake, onda je bolje da jednostavno preraspodelite standardne. Kako se to radi može se vidjeti u fajlu stm32f4_discovery.h Na primjer, ovako je definirana jedna od LED dioda:

#define LED4_PIN GPIO_Pin_12
#define LED4_GPIO_PORT GPIOD
#define LED4_GPIO_CLK RCC_AHB1Periph_GPIOD

Detaljniji opis periferije portova nalazi se u stm32f4xx_gpio.h

Top srodni članci