STM32F407(STM32F4-DISCOVERY) - Abordare non-standard - Bibliotecă standard partea 1. Configurarea STM32F10x SPL folosind definiții macro

Până în acest moment, am folosit biblioteca standard de kernel - CMSIS. Pentru a configura un port în modul de operare dorit, a trebuit să apelăm la pentru a găsi registrul responsabil pentru o anumită funcție și, de asemenea, să căutăm printr-un document mare și alte informații legate de acest proces. Lucrurile vor deveni și mai dureroase și de rutină atunci când începem să lucrăm cu un cronometru sau ADC. Numărul de registre de acolo este mult mai mare decât cel al porturilor I/O. Setare manuală necesită mult timp și crește șansa de a greși. Prin urmare, mulți oameni preferă să lucreze cu biblioteca periferică standard - StdPeriph. Ce dă? Este simplu - nivelul de abstractizare crește, nu trebuie să intri în documentație și să te gândești la registre în cea mai mare parte. În această bibliotecă, toate modurile și parametrii de funcționare ai periferiei MK sunt descriși sub formă de structuri. Acum, pentru a configura un dispozitiv periferic, trebuie doar să apelați funcția de inițializare a dispozitivului cu o structură umplută.

Mai jos este o imagine cu o reprezentare schematică a nivelurilor de abstractizare.

Am lucrat cu CMSIS (care este „cel mai aproape” de nucleu) pentru a arăta cum funcționează microcontrolerul. Următorul pas este biblioteca standard, pe care vom învăța cum să o folosim acum. Urmează driverele de dispozitiv. Ele sunt înțelese ca fișiere *.c \ *.h care oferă o interfață software convenabilă pentru controlul oricărui dispozitiv. De exemplu, în acest curs vă vom oferi drivere pentru cipul max7219 și modulul WiFi esp8266.

Un proiect standard va include următoarele fișiere:


În primul rând, desigur, acestea sunt fișierele CMSIS care permit bibliotecii standard să lucreze cu nucleul, am vorbit deja despre ele. În al doilea rând, fișierele bibliotecii standard. Și în al treilea rând, fișierele utilizator.

Fișierele bibliotecii se găsesc pe pagina dedicată MK-ului țintă (pentru noi este stm32f10x4), în secțiunea Resurse de proiectare(în IDE-ul CooCox, aceste fișiere sunt descărcate din depozitul mediului de dezvoltare). Fiecare periferic corespunde a două fișiere - antet (*.h) și cod sursa(*.c). Descriere detaliata poate fi găsit în dosarul de suport, care se află în arhiva bibliotecii de pe site.

  • stm32f10x_conf.h - fișier de configurare a bibliotecii. Utilizatorul poate conecta sau deconecta module.
  • stm32f10x_ppp.h - fișier antet periferic. În loc de ppp poate fi gpio sau adc.
  • stm32f10x_ppp.c - driver de dispozitiv periferic scris în limbaj C.
  • stm32f10x_it.h - fișier antet care include toți manipulatorii de întreruperi posibili (prototipurile acestora).
  • stm32f10x_it.c este un fișier cod sursă șablon care conține rutina de întrerupere a serviciului (ISR) pentru situații de excepție în Cortex M3. Utilizatorul își poate adăuga propriile ISR-uri pentru perifericele utilizate.

Biblioteca standard și perifericele au o convenție în denumirea funcțiilor și a notației.

  • PPP este un acronim pentru periferice, cum ar fi ADC.
  • Fișiere de sistem, antet și cod sursă - începeți cu stm32f10x_.
  • Constantele utilizate într-un fișier sunt definite în acel fișier. Constanțele utilizate în mai multe fișiere sunt definite în fișierele antet. Toate constantele din biblioteca periferică sunt cel mai adesea scrise cu majuscule.
  • Registrele sunt tratate ca constante și sunt numite și litere MAJUSCULE.
  • Numele de funcții specifice perifericelor includ un acronim, cum ar fi USART_SendData() .
  • Pentru a configura fiecare dispozitiv periferic, se folosește structura PPP_InitTypeDef, care este transmisă funcției PPP_Init().
  • Pentru a deinițializa (setați valoarea implicită), puteți utiliza funcția PPP_DeInit().
  • Funcția care vă permite să activați sau să dezactivați periferice se numește PPP_Cmd().
  • Funcția de activare/dezactivare a întreruperii se numește PPP_ITConfig.

CU lista plina puteți să vă uitați din nou la fișierul de suport al bibliotecii. Acum să rescriem LED-ul care clipește folosind biblioteca standard de periferice!

Înainte de a începe lucrul, să ne uităm la fișierul stm32f10x.h și să găsim linia:

#define USE_STDPERIPH_DRIVER

Dacă configurați proiectul de la zero folosind fișiere de bibliotecă din arhiva descărcată, atunci va trebui să decomentați această linie. Vă va permite să utilizați biblioteca standard. Această definiție (macro) va comanda preprocesorului să includă fișierul stm32f10x_conf.h:

#ifdef USE_STDPERIPH_DRIVER #include „stm32f10x_conf.h” #endif

Acest fișier conține module. Dacă aveți nevoie doar de unele specifice, dezactivați restul, acest lucru va economisi timp în timpul compilării. După cum probabil ați ghicit, avem nevoie de module RTC și GPIO (cu toate acestea, în viitor vom avea nevoie și de _bkp.h, _flash, _pwr.h, _rtc.h, _spi.h, _tim.h, _usart.h):

#include „stm32f10x_flash.h” // pentru init_pll() #include „stm32f10x_gpio.h” #include „stm32f10x_rcc.h”

Ca și data trecută, mai întâi trebuie să activați tactarea portului B. Acest lucru se face de funcția declarată în stm32f10x_rcc.h:

Void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

Enumerația FunctionalState este definită în stm32f10x.h:

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

Să declarăm o structură pentru configurarea piciorului nostru (o puteți găsi în fișierul stm32f10x_gpio.h):

LED GPIO_InitTypeDef;

Acum trebuie să o completăm. Să ne uităm la conținutul acestei structuri:

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

Toate enumerările și constantele necesare pot fi găsite în același fișier. Apoi, funcția init_leds() rescrisă va lua următoarea formă:

Void led_init() ( // Activați sincronizarea RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // Declarați structura și completați-o GPIO_InitTypeDef LED; LED.GPIO_Pin = GPIO_Pin_0; LED.GPIO_Model_GPIO_Speed_2MHIO = GPIO_Speed_Speed. Out_PP; // Inițializați portul GPIO_Init( GPIOB, &LED); )

Să rescriem funcția main():

Int main(void) (led_init(); în timp ce (1) ( GPIO_SetBits(GPIOB, GPIO_Pin_0); delay(10000000); GPIO_ResetBits(GPIOB, GPIO_Pin_0); delay(10000000); ) )

Principalul lucru este să înțelegeți ordinea de inițializare: porniți ceasul periferic, declarați structura, completați structura, apelați metoda de inițializare. Alte dispozitive periferice sunt de obicei configurate într-un mod similar.

În această publicație, voi încerca să mă concentrez pe punctele principale pentru a începe rapid cu microcontrolerele STM32F10x bazate pe biblioteca de periferice standard de la compania producătoare STMicroelectronics.

Articolul va folosi Eclipse CDT ca mediu de dezvoltare. Deoarece accentul principal va fi pe codul programului, puteți face în siguranță toate manipulările din Code::Blocks.

Structura generală a proiectului pentru microcontrolerele ARM este descrisă în articolul meu.

Aici vă voi aminti pe scurt că pentru a construi un proiect pentru microcontrolere ARM (în special STM32F10x), veți avea nevoie de un script de linker și un fișier C-Startup.

Un script linker este un fișier cu instrucțiuni pentru plasarea codului programului și a datelor în memoria microcontrolerului. Poate comanda codul de program să fie încărcat în memoria programului Flash sau în memoria de date SRAM.

Microcontrolerele cu cantități diferite de memorie de programe și date necesită scripturi de layout diferite. Ele pot fi obținute de la producătorul de microcontrolere - STMicroelectronics.
Despachetați biblioteca de periferice standard STM32F10x din arhiva ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip.
Conține exemple de proiecte pentru diverse medii de dezvoltare (IAR EWB, Keil uVision, Atollic True Studio etc.). Cel mai apropiat pentru noi este Atollic True Studio, deoarece este o modificare a lui Eclipse.
Accesați directorul Project/StdPeriph_Template/TrueSTUDIO, există mai multe subdirectoare acolo, ale căror nume corespund cu numele plăcilor de dezvoltare STM3210x-EVAL.

Aflați care dintre aceste plăci folosește aceeași linie de microcontroler ca a dvs. Copiați fișierul stm32_flash.ld din directorul corespunzător în proiectul dvs.

De asemenea, este posibil să se creeze un script universal în care doar cantitatea de memorie de program și de date va fi modificată în conformitate cu microcontrolerul utilizat.

Codul de pornire (C-Startup) pentru microcontrolerele STM32 poate fi scris în C sau Assembler.
Deși STM32F10x Standard Peripheral Library (abreviat STM32F10x SPL) este adesea criticată pentru erorile sale, este cea mai simplă modalitate de a începe rapid la pornirea programării STM32.
Dar întotdeauna vrei să existe un fel de alternativă. De fapt, există multe dintre ele, de exemplu, programarea în limbaj de asamblare :)

Aceasta este calea cea mai dificilă și fără rost. A doua modalitate este de a folosi biblioteca CMSIS, care oferă sintaxă pentru accesarea structurilor limbajului C pentru a accesa diverse periferice de microcontroler. Cel mai simplu și mai logic mod (după părerea mea) este să folosești bibliotecile.

Dacă vă opuneți categoric STM32F10x SPL, atunci există o altă alternativă special pentru dvs. - biblioteca libopencm3. În ea, cea mai mare parte a exemplelor este concentrată în jurul seriei principale de microcontrolere STM32F10x, dar este doar o chestiune de timp până să apară exemple pentru alte serii (STM32F2xx/4xx). Puteți oricând să vă alăturați proiectului libopencm3 și să accelerați acest proces.

Standardul CMSIS este, de asemenea, opțional pentru utilizare în programele dumneavoastră.
Vă puteți descurca fără ea depunând ceva efort și timp pentru a implementa nivelul HAL (Hardware Abstraction Layer) în limbajul de programare C.

În unele cazuri, această metodă poate fi singura într-un mod accesibil. De exemplu, organizația dvs. utilizează cipuri personalizate bazate pe nuclee de calcul dezvoltate de ARM și periferice specifice industriei.

Sau trebuie să implementați software în C pentru microcontrolere cu un nucleu ARM9, pentru care producătorii se concentrează pe utilizarea gata făcute sisteme de operare(Linux, QNX, Windows CE), prin urmare, producătorii nu pot furniza biblioteci pentru programare în limbajul C în formă pură sau în combinație cu un RTOS mai ușor.

Din fericire, producătorii de microcontrolere bazate pe nucleul Cortex-M3 oferă dezvoltatorilor un număr mare de biblioteci de coduri. Acest lucru se aplică și microcontrolerelor STM32.
Să continuăm analiza bibliotecii STM32F10x SPL. O vom analiza folosind un exemplu.
Puteți deschide acest exemplu sau puteți crea propriul proiect de la zero pentru a înțelege mai bine întregul proces al ceea ce se întâmplă.

Pentru al doilea caz, voi enumera pașii necesari:

  • Creați un nou proiect gol în Eclipse
  • Copiați scriptul de aspect și porniți fișierul în proiect
  • Creați un nou sau copiați un șablon Makefile
  • Când utilizați Makefile din exemplul meu ca șablon, trebuie să creați directoarele src, inc, bin, obj în interiorul proiectului și să creați subdirectoarele Debug și Release în directoarele bin și obj.
  • Copiați fișierele sursă și antet necesare din bibliotecile CMSIS și STM32F10x SPL.
  • Faceți modificările necesare în secțiunea de setări utilizator a șablonului Makefile, dacă este utilizat.
  • Creați ținte noi „Debug”, „cleanDebug”, „Release”, „cleanRelease”, „Program” în fereastra „make target” Eclipse.
  • Lansați ținta „Debug” și monitorizați execuția acesteia în fereastra „Console”.

Pentru o mai bună înțelegere a materialului, am împărțit articolul în mai multe paragrafe independente, fiecare dintre acestea descriind doar un aspect al lucrului cu biblioteca STM32F10x SPL.

Configurarea STM32F10x SPL folosind definiții macro

Pentru a configura biblioteca, sunt utilizate valori macro predefinite, pe care acum le vom lua în considerare.
Ele pot fi setate în interiorul fișierelor antet folosind o directivă de preprocesor #defini sau treceți valorile definițiilor macro prin cheie -D compilator GCC.
În exemplul meu, folosesc a doua metodă.
În variabila Makefile DEFINI conține macrocomenzi necesare pentru a compila biblioteca STM32F10x SPL.
Definiție macro STM32F10X_MD specifică dacă microcontrolerul utilizat aparține liniei Densitate medie.
Aceasta include microcontrolere cu memorie Flash de la 64 la 128 kB.
Următorul tabel listează numele macrocomenzilor pentru diferite serii de microcontrolere:

Numele seriei Macro Descriere
Linie de valoare de densitate scăzută STM32F10X_LD_VL cu capacitate memorie flash 16 - 32 kB
Densitate scazuta STM32F10X_LD
cu capacitate memorie flash 16 - 32 kB
Linie de valoare de densitate medie STM32F10X_MD_VL Memorie flash
64 - 128 kB
Densitate medie STM32F10X_MD microcontrolere din seria STM32F101xx, STM32F102xx, STM32F103xx cu memorie Flash 64 - 128 kB
Linie de valoare de înaltă densitate STM32F10X_HD_VL microcontrolere din seria STM32F100xx cu volum
Flash - memorie 256 - 512kB
Densitate mare STM32F10X_HD cu volum
Memorie flash 256 - 512 kB
XL-densitate STM32F10X_XL
Memorie flash 512 - 1024 kB
Linie de conectivitate STM32F10X_CL

Pentru a seta frecvența de ceas a microcontrolerului, trebuie să decomentați macro-ul cu valoarea necesară a frecvenței de ceas din fișierul system_stm32f10x.c.

#dacă este definit (STM32F10X_LD_VL) || (definit STM32F10X_MD_VL) || (definit STM32F10X_HD_VL) #define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #define SYSCLK_FREQ_24MHz 240000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #define SYSCLK_FREQ_24MHz 240000000 *SYSCLK_0000000000000000000000000 00 */ /* #define SYSCLK_FREQ_48MHz 48000000 */ /* #define SYSCLK_FREQ_56MHz 56000000 * / #define SYSCLK_FREQ_72MHz 72000000 #endif

#dacă este definit (STM32F10X_LD_VL) || (definit STM32F10X_MD_VL) || (STM32F10X_HD_VL definit)

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

#define SYSCLK_FREQ_24MHz 24000000

#altfel

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

/* #define SYSCLK_FREQ_24MHz 24000000 */

/* #define SYSCLK_FREQ_36MHz 36000000 */

/* #define SYSCLK_FREQ_48MHz 48000000 */

/* #define SYSCLK_FREQ_56MHz 56000000 */

#define SYSCLK_FREQ_72MHz 72000000

#endif

Utilizarea prevăzută rezonator cu cuarț cu o frecvență de 8 MHz pentru toate principalele
serie de microcontrolere, cu excepția liniei Connectivity, pentru care este necesară instalarea unui rezonator cuarț de 25 MHz.
Dacă utilizați rezonatoare de cuarț cu alte valori de frecvență, atunci trebuie să modificați valoarea macrocomenzii HSE_VALUE din fișierul antet stm32f10x.h și să adaptați toate funcțiile dependente în consecință.
Scopul macrocomenzii USE_STDPERIPH_DRIVER nu este greu de ghicit - de a utiliza biblioteca de periferice standard STM32F10x.
USE_FULL_ASSERT – utilizați macrocomanda ASSERT pentru a depana programul.

Utilizarea macrocomenzii assert_param din bibliotecă

Toate funcțiile bibliotecii SPL STM32F10x folosesc macrocomanda assert_param pentru a-și verifica argumentele.
Această macrocomandă verifică o expresie care implică argumentul funcției testat pentru egalitatea la zero. Dacă valoarea expresiei este zero, atunci funcția de gestionare a erorilor argumentului assert_failed este apelată, în caz contrar (expresia nu este zero), verificarea argumentelor reușește.
Trebuie să implementați funcția assert_failed în programul dvs.
Afișează mesajul de eroare, numele fișierului și numărul liniei de cod care a cauzat eroarea.
Macro-ul debug_printf poate ieși prin USART folosind biblioteca standard new_lib sau, de exemplu, biblioteca de la Mr. Chen.

#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT void assert_failed(fișier uint8_t*, linie uint32_t) ( debug_printf(„Valoare greșită a parametrilor: fișierul %s pe linia %d\r\n”, fișier, linie (int)) ; în timp ce (1) ( ) )/* assert_failed */ #endif/*USE_FULL_ASSERT*/

#define debug_printf xprintf /* printf */

#ifdef USE_FULL_ASSERT

void assert_failed (uint8_t * fișier , linie uint32_t )

debug_printf( „Valoare greșită a parametrilor: fișierul %s pe linia %d\r\n”, fișier , (int ) linie);

în timp ce (1)

) /* assert_failed */

#endif/*USE_FULL_ASSERT*/

Funcția assert_failed implementată în codul dvs. este utilizată numai atunci când macrocomanda USE_FULL_ASSERT este declarată. În caz contrar, tot codul de depanare este exclus din sursă. Această funcționalitate este implementată în fișierul antet cu setările bibliotecii de drivere stm32f10x_conf.h.

#ifdef USE_FULL_ASSERT #define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__)) void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */

#ifdef USE_FULL_ASSERT

#define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__))

void assert_failed (uint8_t * fișier , linie uint32_t );

#altfel

#define assert_param(expr) ((void)0)

#endif /* USE_FULL_ASSERT */

Nu sunt multe de explicat aici. Să ne uităm la un exemplu de utilizare a assert_param.

void set_param(uint8_t * param, uint8_t value) (​assert_param(param != NULL); *param = valoare; )/*set_param*/

void set_param (uint8_t * param , uint8_t value )

assert_param (param != NULL ) ;

* param = valoare ;

) /*set_param*/

Funcția setează valoarea parametrului printr-un pointer transmis ca argument. Dacă macrocomanda USE_FULL_ASSERT nu este declarată, atunci putem presupune că liniile
assert_param(param != NULL) pur și simplu nu este în cod, altfel parametrul este verificat în această definiție.
Dacă pointerul nu este definit, atunci valoarea param != NULL va fi falsă și va fi rulată funcția assert_failed, care va scoate numele fișierului și numărul de linie cu eroarea prin USART și apoi va fi buclă, prevenind astfel valoarea să fie atribuite unei adrese nedefinite din memorie.
Nu vi se cere deloc să utilizați macrocomanda assert_param în codul dvs., ci în codul bibliotecii
STM32F10x SPL este folosit peste tot.
Funcția set_param poate fi implementată cu verificarea erorilor de argument fără a utiliza assert_param.

#define ERROR (-1) #define OK (0) int set_param(uint8_t * param, uint8_t value) ( ​​​​int r = EROARE; if (param == NULL) return r; *param = valoare; r = OK; returnează r ; )/*set_param*/

#define EROARE (-1)

#define OK (0)

int set_param (uint8_t * param , uint8_t value )

int r = EROARE ;

dacă (param == NULL )

returnează r;

* param = valoare ;

r = OK;

returnează r;

) /*set_param*/

Fișierul C-Startup din biblioteca STM32F10x SPL

În codul de pornire, microcontrolerul este inițial inițial, stiva este configurată, secțiunea BSS este resetată și funcția principală main() este apelată.
Codul de pornire nu are o legătură directă cu biblioteca STM32F10x SPL. Totuși, în acest cod de pornire, înainte de a apela funcția main() a programului, este apelată funcția de inițializare a microcontrolerului SystemInit(), care face parte din CMSIS.
Poate fi găsit cu ușurință în biblioteca CMSIS.
Accesați directorul Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO și copiați fișierul necesar. Tot ce rămâne este să aflați cărei linie îi aparține microcontrolerul folosit în proiectul dvs.
Pentru a face acest lucru, priviți următorul tabel:

Numele seriei Nume de fișier Descriere
Linie de valoare de densitate scăzută startup_stm32f10x_ld_vl.s microcontrolere din seria STM32F100xx cu volum
Memorie flash 16 - 32 kB
Densitate scazuta startup_stm32f10x_ld.s seria de microcontrolere STM32F101xx, STM32F102xx, STM32F103xx
cu capacitate memorie flash 16 - 32 kB
Linie de valoare de densitate medie startup_stm32f10x_md_vl.s seria de microcontrolere STM32F100xx
Densitate medie startup_stm32f10x_md.s seria de microcontrolere STM32F101xx, STM32F102xx, STM32F103xx
cu capacitate memorie flash 64 - 128 kB
Linie de valoare de înaltă densitate startup_stm32f10x_hd_vl.s seria de microcontrolere STM32F100xx
Densitate mare startup_stm32f10x_hd.s microcontrolere seria STM32F101xx, STM32F103xx
cu capacitate memorie flash 256 - 512 kB
XL-densitate startup_stm32f10x_xl.s microcontrolere seria STM32F101xx, STM32F103xx
cu capacitate memorie flash 512 - 1024 kB
Linie de conectivitate startup_stm32f10x_cl.s microcontrolere din seriile STM32F105xx și STM32F107xx

Fișierul de pornire conține numele manipulatorilor de vectori de întrerupere și excepție, dar este implementat doar handlerul de vector de resetare, în cadrul căruia se realizează toată inițializarea inițială înainte de apelarea funcției main().
Implementarea tuturor celorlalți handlere de excepții este responsabilitatea programatorului aplicației. Dacă programul dvs. nu folosește niciun handler, atunci nu este nevoie să le înregistrați. Dacă apare o excepție, va fi folosit handlerul implicit - bucla codul programului.

Compoziția bibliotecii CMSIS

Așa cum a fost scris mai devreme în această publicație, biblioteca CMSIS oferă acces la modulele periferice ale microcontrolerului folosind elemente ale structurilor limbajului C.
Implementarea acestei biblioteci este împărțită în două părți. Prima parte oferă acces la periferia de bază Cortex-M3, iar a doua parte oferă acces la periferie model specific microcontroler.
Deoarece standardul CMSIS este același pentru toate microcontrolerele cu un nucleu Cortex-M3, implementarea primei părți va fi aceeași pentru toți producătorii, dar a doua parte va fi diferită pentru fiecare producător.
CMSIS include mai multe fișiere de antet și sursă. Prima parte include fișierele:

  • miez_cm3.h
  • core_cm3.c

A doua parte a CMSIS include fișierul C-Startup, precum și următoarele fișiere:

  • stm32f10x.h
  • system_stm32f10x.h
  • system_stm32f10x.c

Fișierul antet stm32f10x.h conține definiții macro pentru accesarea modulelor periferice ale microcontrolerelor stm32f10x.
Fișierele system_stm32f10x.h și system_stm32f10x.c implementează inițializarea inițială a microcontrolerului.

Compoziția și configurația bibliotecii STM32F10x SPL

Biblioteca constă din fișiere sursă și antet cu același nume ca modulele periferice cu prefixul stm32f10x_.
De exemplu, implementarea interacțiunii cu modulul USART este conținută în fișierele stm32f10x_usart.h și stm32f10x_usart.c.
Există convenții pentru denumirea elementelor bibliotecii și anumite reguli de codificare, care sunt descrise în documentație.
Biblioteca conține implementarea driverelor pentru modulele de microcontrolere periferice.
Numele elementelor bibliotecii folosesc următoarele acronime pentru modulele periferice:

Acronim Modul periferic
ADC convertor analog-digital
BKP registre de rezervă
POATE SA interfață CAN
CEC regulator de consum
CRC modul de calcul al sumei de control
DAC convertor digital-analogic
DBGMCU depanarea microcontrolerului
DMA controler de acces direct la memorie
EXTI controler extern de întrerupere
FSMC controler de memorie extern
FLASH Memoria programului flash
GPIO porturi I/O de uz general
I2C Interfață I2C
I2S Interfață I2S (sunet).
IWDG temporizator de supraveghere independent
NVIC controler de întrerupere imbricat
PWR controler de putere
RCC resetare și controlul ceasului
RTC controler în timp real (ceas)
SDIO Interfață SDIO
SPI Interfață SPI
SysTick cronometrul sistemului
TIM temporizator de bază sau avansat
USART serial universal sincron-asincron
transceiver
WWDG caine de paza ferestrei

Pe baza acestor acronime se formează denumirile modulelor software ale bibliotecii. Nu trebuie să utilizați toate modulele din bibliotecă.
Pentru a utiliza doar modulele necesare în proiect, biblioteca trebuie configurată.
În aceste scopuri, fiecare proiect care utilizează biblioteca STM32F10x SPL trebuie să aibă un fișier antet stm32f10x_conf.h.

#include „stm32f10x_gpio.h” //#include „stm32f10x_i2c.h” //#include „stm32f10x_iwdg.h” //#include „stm32f10x_pwr.h” #include „stm32f10x_pwr.h” #include „stm32f10x_iwdg.h”.

#include „stm32f10x_gpio.h”

//#include „stm32f10x_i2c.h”

//#include „stm32f10x_iwdg.h”

//#include „stm32f10x_pwr.h”

#include „stm32f10x_rcc.h”

Pentru a activa modulul necesar, trebuie să decomentați directiva #include cu fișierele de antet corespunzătoare.
Fișierul antet stm32f10x_conf.h este inclus în stm32f10x.h, deci pentru a utiliza funcțiile bibliotecii SPL STM32F10x, trebuie să includeți doar un singur fișier antet stm32f10x.h în codul sursă.

// în fișierul stm32f10x.h #ifdef USE_STDPERIPH_DRIVER #include „stm32f10x_conf.h” #endif

Repet că proiectul trebuie să definească și macrocomenzile USE_STDPERIPH_DRIVER, USE_FULL_ASSERT și o macro care specifică seria microcontrolerului folosit (de exemplu, STM32F10X_MD pentru linia de densitate medie).
Dacă utilizați valoarea frecvenței standard de cuarț și controlerul funcționează la o frecvență maximă de ceas de 72 MHz, atunci nu va trebui să schimbați nimic altceva.
Trebuie să adăugați o listă de fișiere de bibliotecă de compilat în Makefile.
De exemplu:

SRC += stm32f10x_rcc.c SRC += stm32f10x_gpio.c

SRC += stm32f10x_rcc . c

SRC += stm32f10x_gpio . c

Folosind biblioteca STM32F10x SPL. Mecanisme de lucru

Pentru a începe programarea utilizând biblioteca periferică, cel mai simplu mod este să vă uitați la exemplele furnizate împreună cu biblioteca. Dar totuși, pentru a înțelege codul acestor exemple, trebuie să aveți cunoștințe de bază despre sintaxa și utilizarea bibliotecii.
Toate modulele de microcontroler periferice enumerate anterior sunt inițial dezactivate, nu le este furnizat un semnal de ceas și nu consumă energie electrică.
Pentru a utiliza un modul periferic, mai întâi trebuie să îi furnizați un semnal de ceas. Semnalul ceasului este furnizat de modulul de resetare și ceas RCC.
În aceste scopuri, biblioteca are următoarele funcții:

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_PPPx, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, ENABLE);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE);

RCC_APB2PeriphClockCmd (RCC_APB2Periph_PPPx, ENABLE) ;

RCC_APB1PeriphClockCmd (RCC_APB1Periph_PPPx, ENABLE) ;

Aici PPP denotă numele actonimului modulului (de exemplu ADC sau USART), iar x este numărul modulului periferic.
În primul rând, trebuie să aflați la ce magistrală este conectat modulul pe care îl utilizați.
În total, microcontrolerele cu arhitectură de bază Cortex-M3 au trei magistrale:
magistrală de instrucțiuni, magistrală de date și magistrală de sistem. Autobuzul de instrucțiuni conectează nucleul la memoria programului Flash. Autobuzele de date și de sistem sunt combinate într-o matrice de magistrală AHB (ARM Hi-Speed ​​​​Bus), care funcționează la frecvența de bază. Cu toate acestea, frecvența magistralei AHB poate fi redusă prin instalarea divizoarelor. Autobuzul AHB conectează dispozitive de mare viteză, cum ar fi nucleul și modulul DMA.
Dispozitivele I/O sunt conectate la magistrala AHB prin intermediul magistralelor intermediare APB1 și APB2 (ARM Peripheral Bus).
Frecvența maximă de funcționare a magistralei APB2 este de 72 MHz, frecvența magistralei APB1
limitat la 36 MHz.
Puteți afla la care dintre magistralele este conectat modulul periferic pe care îl utilizați din documentație sau căutați în fișierul antet stm32f10x_rcc.h.
Deschideți acest fișier și căutați valorile RCC_AHBPeriph, RCC_APB1Periph și RCC_APB2Periph în succesiune.

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) #define RCC_AHBPeriph_SRAM ((uint32_t)0x00000000000x00000010) #define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001)

#define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002)

#define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004)

#define RCC_AHBPeriph_FLITF ((uint32_t)0x00000010)

#define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

După numele macrocomenzilor, determinăm care module sunt conectate la ce magistrale. De asemenea, puteți folosi bunul simț pentru a determina ce anvelopă aparține uneia dintre cele trei. De exemplu, modulul USART este un dispozitiv de intrare/ieșire, ceea ce înseamnă că este conectat la una dintre magistralele APB. USART este o interfață de viteză destul de mică, deci este probabil conectată la magistrala APB1.

#define RCC_APB1Periph_USART2 ((uint32_t)0x00020000) #define RCC_APB1Periph_USART3 ((uint32_t)0x00040000) #define RCC_APB1Periph_UART4 ((uint32_0B1Periph_USART3) #define RCC_APB1Periph_UART4 ((uint32_0000000000000) ((uint32_t)0x00100000)

După trimiterea unui semnal de ceas către modulul periferic, puteți configura parametrii acestuia apelând funcția de inițializare:

PPP_Init(PPP, &PPP_InitStructure);

PPP_Init (PPP, & amp; PPP_InitStructure);

Deoarece mulți parametri trebuie să fie trecuți funcției de inițializare pentru a inițializa un modul periferic, un pointer către o structură este folosit ca argument. Structura însăși cu parametrii de inițializare trebuie creată în memorie înainte de a apela funcția de inițializare; elementelor structurii trebuie să li se atribuie valorile necesare:

PPP_InitTypeDef PPP_InitStructure = (val1, val2, ..., valN);/* inițializarea structurii când este declarată */

Puteți crea mai întâi o structură și apoi să atribuiți valorile necesare elementelor sale:

PPP_InitTypeDef PPP_InitStructure; PPP_InitStructure.member1 = val1; PPP_InitStructure.member2 = val2; PPP_InitStructure.memberN = valN;

PPP_InitTypeDef PPP_InitStructure ;

PPP_InitStructure . membru1 = val1 ;

PPP_InitStructure . membru2 = val2 ;

PPP_InitStructure . membruN = valN ;

Să ne uităm la un exemplu din proiectul stm32f10xQuickstart:

GPIO_InitTypeDef GPIO_InitStructure; #ifdef USE_STM32H_103 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed ​​​​= GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_InitTypeDef GPIO_InitStructure ;

#ifdef USE_STM32H_103

RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE) ;

GPIO_InitStructure . GPIO_Pin = GPIO_Pin_12 ;

GPIO_InitStructure . GPIO_Speed ​​​​= GPIO_Speed_50MHz;

GPIO_InitStructure . GPIO_Mode = GPIO_Mode_Out_PP ;

GPIO_Init(GPIOC, & GPIO_InitStructure);

Elementelor structurii GPIO_InitStructure li se atribuie valoarea numărului de pin, modul și viteza portului.
Prin apelarea funcției GPIO_Init, linia 12 a portului GPIOC este inițializată.
Primul argument la funcția GPIO_Init este un pointer către zona de memorie a perifericului GPIOC, convertit într-un pointer la o structură GPIO_TypeDef.

// stm32f10x.h #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) PERIPH_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) PERIPH_BASE (tipul PERIPH_0x10000) #320_0) def struct ( __IO uint32_t CRL; __IO uint32_t CRH ; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; ) GPIO_TypeDef;

// stm32f10x.h

#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)

#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)

#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

#define PERIPH_BASE ((uint32_t)0x40000000)

typedef struct

IO uint32_t CRL;

IO uint32_t CRH ;

IO uint32_t IDR;

IO uint32_t ODR;

IO uint32_t BSRR;

IO uint32_t BRR;

IO uint32_t LCKR ;

) GPIO_TypeDef ;

Structura GPIO_InitStructure este de tip GPIO_InitTypeDef, descrisă în fișierul antet
stm32f10x_gpio.h:

//stm32f10x_gpio.h typedef struct ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; )GPIO_InitTypeDef; typedef enumerare ( GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz )GPIOSpeed_TypeDef; typedef enum ( GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_GPO_1 =, GPIO_Mode_GPO_10 =, GPIO_Mode_PCO_1 , GPIO_Mode_AF_PP = 0x18 )GPIOMode_TypeDef;

//stm32f10x_gpio.h

typedef struct

uint16_t GPIO_Pin ;

GPIOSpeed_TypeDef GPIO_Speed ​​​​;

GPIOMode_TypeDef GPIO_Mode ;

) GPIO_InitTypeDef ;

typedef enumerare

GPIO_Speed_10MHz = 1,

GPIO_Speed_2MHz,

GPIO_Speed_50MHz

) GPIOSpeed_TypeDef ;

typedef enumerare

(GPIO_Mode_AIN = 0x0,

GPIO_Mode_IN_FLOATING = 0x04 ,

GPIO_Mode_IPD = 0x28,

GPIO_Mode_IPU = 0x48,

GPIO_Mode_Out_OD = 0x14,

GPIO_Mode_Out_PP = 0x10,

GPIO_Mode_AF_OD = 0x1C,

GPIO_Mode_AF_PP = 0x18

) GPIOMode_TypeDef ;

După cum puteți vedea, tipurile de date ale structurii inițializate pot fi utilizate ca tipuri personalizate, cum ar fi GPIOSpeed_TypeDef și tipuri de date cu valori specifice pentru confortul inițializării registrelor periferice, cum ar fi GPIOMode_TypeDef.
Pentru configurarea fiecărui pin GPIO sunt alocați 4 biți.
Următoarea imagine arată formatul pentru bitul zero al GPIO:

Mod – mod de funcționare ieșire (intrare/ieșire). Mai precis, aceste valori sunt puțin mai mari; porturile configurate ca porturi de ieșire au o limitare a frecvenței maxime a semnalului de ieșire.

Modul Descriere
00 Intrare
01 frecventa de iesire de pana la 10 MHz
10 frecventa de iesire pana la 2 MHz
11 frecventa de iesire pana la 50 MHz

CNF – biți de configurare a ieșirii. Depinde de modul de operare:

Sunteți de acord că, cu această structură a registrului de configurare a pinului, setarea dvs. a tuturor biților pentru configurație va fi extrem de incomod. Va fi mult mai ușor să faceți acest lucru folosind funcția de bibliotecă GPIO_Init.
După ce inițializați modulul periferic, acesta trebuie activat folosind funcția PPP_Cmd:

PPP_Cmd(PPP, ACTIVARE);

PPP_Cmd(PPP, ACTIVARE);

Această funcție nu există pentru modulele GPIO; după inițializare, puteți utiliza imediat pinii GPIO. Trebuie reținut că biblioteca oferă doar o interfață cu hardware-ul microcontrolerului. Dacă modulul hardware nu are un steag de activare/dezactivare, atunci apelul de funcție PPP_Cmd(PPP, ACTIVARE) imposibil.
Pentru a controla starea pinului GPIOx în modul de ieșire și pentru a citi valoarea în modul de intrare sau de ieșire, biblioteca oferă următoarele funcții:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

void GPIO_SetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin );

void GPIO_ResetBits (GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin );

uint8_tGPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin) ;

uint16_tGPIO_ReadOutputData(GPIO_TypeDef* GPIOx) ;

uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin) ;

uint16_tGPIO_ReadInputData(GPIO_TypeDef* GPIOx) ;

Restul modulelor periferice sunt configurate și lucrate în același mod. Cu toate acestea, există unele diferențe din cauza specificului modulului hardware specific, așa că vă recomand cu tărie să vedeți mai întâi exemple de utilizare a modulului selectat pentru biblioteca STM32F10x SPL.

Gestionarea întreruperilor și excepțiilor

Nucleul Cortex-M3 include un controler de întrerupere vectorizat imbricat. Controlerul acceptă până la 240 de surse care pot cauza întreruperi în nucleul procesorului. Câți vectori din 240 posibili sunt implementați într-un anumit model de microcontroler depinde de producător. Microcontrolerele Stm32f10x pot avea până la 43 dintre acești vectori.Aceste linii de întrerupere sunt numite mascabile. În plus, există 15 vectori de întrerupere de bază Cortex-M3 și o întrerupere EXTI externă nemascabilă.
Controlerul acceptă întreruperi imbricate, unde poate apărea o altă întrerupere într-un singur handler. În acest sens, fiecare sursă de întrerupere are propria sa prioritate. Sunt acceptate 16 niveluri de prioritate de întrerupere.
Vectorii de întrerupere de bază Cortex-M3 au cele mai mari valori de prioritate.
Cele mai înalte trei niveluri de întrerupere sunt atribuite vectorilor și nu pot fi modificate:

Număr Handler O prioritate Descriere
1 Reset_Handler -3 (cel mai mare) Resetați vectorul
2 NMI_Handler -2 Întreruperea nemascabilă
3 HardFault_Handler -1 Condiții de urgență

Tuturor celorlalți vectori de întrerupere li se pot atribui niveluri de prioritate de la 0 la 15.
Nivelul de prioritate cel mai înalt corespunde unei valori mai mici. Nivelul de prioritate poate fi atribuit nu numai unui vector individual, ci și unui întreg grup de vectori. Această caracteristică facilitează lucrul cu un număr mare de vectori de întrerupere.
Pentru a seta grupul de prioritate, este utilizată o funcție din biblioteca STM32F10x SPL.

De mult timp, chiar și foarte mult timp, nu au existat articole noi despre articolul nostru, așa că este timpul să ne prindem din urmă 😉 Astăzi vom începe să studiem STM32F4. Și, probabil, vom începe prin a crea un nou proiect pentru acești controlere, deși, sincer să fiu, nu am vrut să scriu un articol despre asta, pentru că proiect nou aici este creat, în principiu, la fel ca pentru STM32F103 (). Dar se întâmplă totuși să apară unele dificultăți cu STM32F4, așa că, totuși, să luăm în considerare acest proces în detaliu)

Deci, hai să lansăm Keil, să creăm un nou proiect - Proiect -> Proiect nou uVision. Salvăm noul proiect într-un folder și apoi ni se va cere să selectăm microcontrolerul de utilizat. Ei bine, să alegem, să fie STM32F407VG:

Gata, în caseta de dialog care apare, faceți clic pe „Da” și primul fișier va fi adăugat la proiectul nostru - startup_stm32f4xx.s. La fel ca înainte, vom folosi biblioteci CMSISȘi Biblioteca periferică standard, dar, firește, deja pentru controlerele STM32F4xx. Deci trebuie neapărat să le descarcăm și să adăugăm fișierele necesare în proiectul nostru încă gol. Apropo, am auzit de mai multe ori de la diferiți oameni că au dat peste niște biblioteci „nu așa” pentru F4 și chiar și cel mai simplu proiect nu este pus cap la cap. Eu însumi nu am întâlnit acest lucru, totuși, iată bibliotecile testate pe care eu însumi le folosesc:

Deci, l-am descărcat, totul este gata, acum adăugăm fișierele în proiect. Imaginea arată de ce aveți nevoie:

Ei bine, pregătirea este completă, acum să creăm un nou fișier .c, care va conține codul nostru. Să mergem la Fișier->Nou, se deschide un fișier gol în Keil, faceți clic Fișier->Salvare cași salvați-l sub numele test.c, de exemplu. Când salvați, nu uitați să specificați extensia fișierului (.c). Fișierul a fost creat, grozav, dar trebuie să îl adăugăm și la proiectul nostru. Ei bine, de fapt, nu este nimic complicat în asta 😉 Să scriem un program de testare gol în acest fișier:

#include „stm32f4xx.h” #include „stm32f4xx_rcc.h” #include „stm32f4xx_gpio.h” /*******************************************************************/ int main() ( în timp ce (1 ) ( __NOP() ; ) ) /*******************************************************************/

Aproape totul este gata, tot ce rămâne este să te uiți la setările proiectului - Proiect->Opțiuni pentru țintă... Se deschide o fereastră cu multe file, aici ne interesează doar câteva. Deschide fila C/C++ iar în câmpul Definiți scriem:

Ei bine, jos pe câmp trebuie să adăugați căi la absolut toate fișierele incluse în proiect. După finalizarea acestui pas, puteți apăsa F7 (Build), iar proiectul va fi construit fără erori sau avertismente. După cum puteți vedea, nimic complicat)

Dar, în general, eu personal fac lucrurile puțin diferit. Uită-te la dezavantajul acestei abordări. Așa că am descărcat bibliotecile CMSIS și SPL undeva, am adăugat fișiere din aceste foldere, am notat căile către fișiere, totul este cool. DAR! Proiectul nu va fi construit pe alt computer, deoarece căile sunt toate absolute, adică indică anumite foldere de pe computer. Și pe o altă mașină va trebui de fapt să repetați pașii pentru a crea un nou proiect. Acesta este un minus imens. Prin urmare, de obicei creez un folder separat pentru un proiect nou, în el creez subfoldere pentru CMSIS, SPL și alte biblioteci utilizate, iar în aceste foldere pun toate fișierele de care am nevoie în fiecare proiect specific. De exemplu, să creăm folderul STM32F4_Test pentru noul nostru proiect și următoarele foldere din acesta:

Am pus totul în folderele CMSIS și SPL fisierele necesare, pe care l-am adăugat la crearea proiectului la începutul articolului. Acum lansăm Keil, creăm un nou proiect și îl salvăm în subdosarul Proiect, astfel încât toate fișierele de proiect să fie într-un singur loc și să nu provoace haos)

Proiectul a fost creat, acum, ca și înainte, adăugăm pur și simplu toate fișierele din folderele STM32F4_CMSIS și STM32F4_SPL. Am pus fișierul nostru de testare .c cu funcția main() în folderul Sursă și l-am adăugat și la proiect. Tot ce rămâne este să configurați setările =) Totul este la fel - în câmpul de definire scriem:

USE_STDPERIPH_DRIVER,STM32F4XX



Asamblam proiectul - nu sunt erori, zborul este normal! În principiu, în cele din urmă am obținut același lucru, dar acum proiectul va fi asamblat imediat pe orice alt computer fără probleme, iar acest lucru este foarte convenabil și util) Absolut toate fișierele de proiect sunt acum localizate în apropiere, în același folder, iar căile au devenit relative şi nu trebuie schimbate .
Asta e tot, de fapt, în viitorul apropiat vom face ceva pentru a programa STM32F4, cu siguranță, așa că ne vedem curând!;)

Proiect complet din articol exemplu -

Am indicat că biblioteca standard este conectată la sistem. De fapt, CMSIS este conectat - sistemul de reprezentare structurală generalizată a MK, precum și SPL - biblioteca periferică standard. Să ne uităm la fiecare dintre ele:

CMSIS
Este un set de fișiere antet și un mic set de cod pentru unificarea și structurarea muncii cu nucleul și periferia MK. De fapt, fără aceste fișiere este imposibil să lucrezi normal cu MK. Puteți obține biblioteca pe pagina de documentație însoțitoare pentru MK.
Această bibliotecă, conform descrierii, a fost creată pentru a unifica interfețele atunci când lucrați cu orice MK din familia Cortex. Cu toate acestea, în realitate, se dovedește că acest lucru este valabil doar pentru un producător, adică. Trecând la un microcontroler de la o altă companie, ești forțat să-i studiezi perifericele aproape de la zero.
Deși acele fișiere care se referă la nucleul procesorului MK sunt identice de la toți producătorii (fie și doar pentru că au același model de nucleu de procesor - furnizate sub formă de blocuri IP de ARM).
Prin urmare, lucrul cu părți ale nucleului precum registre, instrucțiuni, întreruperi și unități de coprocesor este standard pentru toată lumea.
În ceea ce privește periferia, STM32 și STM8 (brut) sunt aproape similare, iar acest lucru este parțial adevărat și pentru alte MK-uri lansate de ST. În partea practică, voi arăta cât de ușor este să utilizați CMSIS. Cu toate acestea, dificultățile în utilizarea acestuia sunt asociate cu reticența oamenilor de a citi documentația și de a înțelege designul MK.

SPL
Biblioteca periferică standard - bibliotecă periferică standard. După cum sugerează și numele, scopul acestei biblioteci este de a crea o abstractizare pentru periferia MK. Biblioteca constă din fișiere antet în care sunt declarate constante care pot fi citite de om pentru configurarea și lucrul cu periferice MK, precum și fișiere de cod sursă colectate în biblioteca însăși pentru operațiuni cu periferice.
SPL este o abstractizare asupra CMSIS, prezentând utilizatorului o interfață comună pentru toate MCU-urile nu numai de la un producător, ci în general toate MCU-urile cu un nucleu de procesor Cortex-Mxx.
Se crede că este mai convenabil pentru începători, deoarece... vă permite să nu vă gândiți la modul în care funcționează perifericele, dar calitatea codului, universalitatea abordării și constrângerea interfețelor impun anumite restricții dezvoltatorului.
De asemenea, funcționalitatea bibliotecii nu vă permite întotdeauna să implementați cu acuratețe configurația unor componente precum USART (port serial universal sincron-asynchron) în anumite condiții. În partea practică, voi descrie și lucrul cu această parte a bibliotecii.

Salutare tuturor. După cum vă amintiți în ultimul articol pe care l-am creat pachete software pentru a lucra cu microcontrolere STM32 și a compilat primul program. În această postare ne vom familiariza cu arhitectura acestei plăci, microcontroler și bibliotecile disponibile pentru lucru.

Mai jos este o poză cu placa Descoperirea STM32F3 , unde: 1 — Senzor MEMS. L3GD20 giroscop digital cu 3 axe. 2 - Sistem MEMS într-o carcasă care conține un accelerometru liniar digital cu 3 axe și un senzor geomagnetic digital cu 3 axe LSM303DLHC. 4 – LD1 (PWR) – sursă de alimentare 3.3V. 5 – LD2 – LED roșu/verde. Implicit este roșu. Verde înseamnă comunicare între ST-LINK/v2 (sau V2-B) și PC. Am ST-LINK/v2-B, precum și un afișaj personalizat port USB. 6. -LD3/10 (roșu), LD4/9 (albastru), LD5/8 (portocaliu) și LD6/7 (verde). În ultimul post am aprins LED-ul LD4. 7. – Două butoane: personalizat UTILIZATOR și resetați RESET. 8. - UTILIZATOR USB cu conector Mini-B.

9 - Depanator/programator USB ST-LINK/V2. 1 0. - Microcontroler STM32F303VCT6. 11. — Generator extern de înaltă frecvență 8 MHz. 12. – Aici ar trebui să existe un generator de joasă frecvență, din păcate nu este lipit. 13. – SWD – interfață. 14. – Jumperele pentru selectarea programarii controlerelor externe sau interne, in primul caz trebuie scoase. 15 – Jumper JP3 – un jumper conceput pentru a conecta un ampermetru pentru a măsura consumul controlerului. Este clar că dacă este șters, atunci piatra noastră nu va începe. 16. – STM32F103C8T6 există o placă de depanare. 17. - Regulator LD3985M33R cu cădere de tensiune și nivel de zgomot scăzut, 150mA, 3.3V.

Acum să aruncăm o privire mai atentă asupra arhitecturii microcontrolerului STM32F303VCT6. A lui specificatii tehnice: carcasă LQFP-100, miez ARM Cortex-M4, frecvență maximă de bază 72 MHz, capacitate memorie program 256 KB, tip memorie programe FLASH, volum memorie cu acces aleator SRAM 40 kbytes, RAM 8 kbytes, număr de intrări/ieșiri 87, interfețe (CAN, I²C, IrDA, LIN, SPI, UART/USART, USB), periferice (DMA, I2S, POR, PWM, WDT), ADC/DAC 4 *12 biți/2*12 biți, tensiune de alimentare 2...3,6 V, temperatură de funcționare –40...+85 C. În figura de mai jos există un pinout, unde vedem 87 de porturi de intrare/ieșire, 45 dintre ele I/O normale (TC, TTa), 42 I/O tolerante de 5 volți (FT, FTf) – compatibile cu 5 V. (pe placă sunt pini de 5V în dreapta, 3.3V în stânga). Fiecare linie digitală I/O poate servi ca o linie generală I/O.
destinație sau funcție alternativă. Pe măsură ce proiectele progresează, ne vom familiariza treptat cu periferia.

Luați în considerare diagrama bloc de mai jos. Inima este un nucleu ARM Cortex-M4 pe 32 de biți care funcționează până la 72 MHz. Are o unitate în virgulă mobilă FPU și o unitate de protecție a memoriei MPU, celule de urmărire macro încorporate - Embedded Trace Macrocell (ETM), care pot fi folosite pentru a monitoriza execuția programului principal în interiorul microcontrolerului. Ei sunt capabili să transmită continuu aceste observații prin contactele ETM atâta timp cât dispozitivul funcționează. NVIC (controler de întrerupere cu vector imbricat) – modul de control al întreruperii. TPIU (Trace Port Interface Unit). Conține memorie FLASH – 256 KB, SRAM 40 KB, RAM 8 KB. Între nucleu și memorie se află o matrice Bus, care permite conectarea directă a dispozitivelor. Tot aici vedem două tipuri de matrice de magistrală AHB și APB, unde primul este mai productiv și este folosit pentru comunicații de mare viteză componente interne, iar acesta din urmă este pentru periferice (dispozitive de intrare/ieșire). Controlerul are 4 ADC-uri pe 12 biți (ADC) (5 Mbit/s) și un senzor de temperatură, 7 comparatoare (GP Comparator1...7), 4 amplificatoare operaționale programabile (OpAmp1...4) (PGA (Programmable Gain Array) )), 2 canale DAC pe 12 biți (DAC), RTC (ceas în timp real), două temporizatoare watchdog - independente și cu ferestre (WinWatchdog și Ind. WDG32K), 17 temporizatoare de uz general și multifuncționale.

În termeni generali, ne-am uitat la arhitectura controlerului. Acum uitați-vă la bibliotecile de software disponibile. După ce am făcut o imagine de ansamblu, putem evidenția următoarele: CMSIS, SPL și HAL. Să ne uităm la fiecare folosind un exemplu simplu de clipire a unui LED.

1). CMSIS(Cortex Microcontroller Software Interface Standard) - bibliotecă standard pentru Cortex®-M. Oferă suport pentru dispozitiv și simplifică interfețe software. CMSIS oferă coerente și interfețe simple pentru nucleu, perifericele sale și sistemele de operare în timp real. Utilizarea sa este o modalitate profesională de a scrie programe, deoarece... presupune scrierea directă în registre și, în consecință, este necesară citirea și studiul constant al fișelor de date. Independent de producătorul hardware.
CMSIS include următoarele componente:
- CMSIS-CORE: Pornire constantă a sistemului și acces periferic;
- CMSIS-RTOS: Execuție software deterministă în timp real softwareîn timp real);
- CMSIS-DSP: Implementarea rapidă a procesării semnalului digital prelucrare digitală semnale);
- CMSIS-Driver: Interfețe periferice generice pentru middleware și cod de aplicație (Interfețe periferice generale pentru middleware și cod de aplicație);
- CMSIS-Pack: Acces ușor la componente software reutilizabile componente software);
- CMSIS-SVD: vizualizare constantă a dispozitivului și perifericelor dispozitiv periferic);
- CMSIS-DAP: Conectivitate la hardware de evaluare cu costuri reduse. Software de depanare.

De exemplu, să scriem un program - clipește un LED. Pentru aceasta avem nevoie de documentație care să descrie registrele. În cazul meu RM0316 Manual de referință STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE MCU avansate bazate pe ARM ®, precum și o descriere a segmentului specific pentru care este responsabil DS9118: MCU+FPU Cortex®-M4 32b bazat pe ARM®, până la 256KB Flash+ 48KB SRAM, 4 ADC-uri, 2 canale DAC, 7 comp, 4 PGA, temporizatoare, 2,0-3,6 V. Pentru început, vom cronometra portul în program, deoarece În mod implicit, totul este dezactivat, ceea ce realizează un consum redus de energie. Deschideți manualul de referință și uitați-vă la secțiunea Resetare și control ceas, apoi harta registrului RCC și vedeți ce registru este responsabil pentru activarea IOPEEN

Să trecem la descrierea tacării perifericelor acestui registru Registrul de activare a ceasului periferic AHB (RCC_AHBENR), unde vedem că acest port este sub al 21-lea bit. Porniți-l RCC->AHBENR|=(1<<21) . Далее сконфигурируем регистры GPIO. Нас интересует три: GPIOE_MODER и GPIOx_ODR . C помощью них повторим программу с предыдущей статьи, затактируем PE8. Первый отвечает за конфигурацию входа выхода, выбираем 01: General purpose output mode. GPIOE->MODER|=0×10000 . Al doilea este pentru pornirea nivelului scăzut/înalt pe picior. Mai jos este programul:

#include „stm32f3xx.h " //Fișier antet microcontroler
unsigned int i;
întârziere anulată () (
pentru (i=0;i<500000;i++);
}
int main (void) (
RCC->AHBENR|=(1<<21);
GPIOE->MODER|=0×10000;
în timp ce (1)(
întârziere();
GPIOE->ODR|=0×100;
întârziere();
GPIOE->ODR&=~(0×100);
} }

2). SPL(Bibliotecă de periferice standard)- această bibliotecă este destinată să combine toate procesoarele de la ST Electronics. Conceput pentru a îmbunătăți portabilitatea codului și este destinat în primul rând dezvoltatorilor începători. ST a lucrat la un înlocuitor pentru SPL numit „low layer”, care este compatibil cu HAL. Driverele Low Layer (LL) sunt proiectate pentru a oferi un strat aproape ușor, orientat către experți, care este mai aproape de hardware decât HAL. Pe lângă HAL, sunt disponibile și API-uri LL. Un exemplu de același program în SPL.

#include
#include
#include
#define LED GPIO_Pin_8
int main() (
i lung;
GPIO_InitTypeDef gpio;
// LED-ul albastru este conectat la portul E, pin 8 (autobuz AHB)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
// Configurați portul E (LED)
GPIO_StructInit(&gpio); //declară și inițializează o variabilă de structură de date
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_Pin = LED;
GPIO_Init(GPIOE, &gpio);
// LED-uri care clipesc
în timp ce (1) (
//Pe
GPIO_SetBits(GPIOE, LED);
pentru (i = 0; i< 500000; i++);
// Toate oprite
GPIO_ResetBits(GPIOE, LED);
pentru (i = 0; i< 500000; i++);
} }

Fiecare funcție este descrisă în documentația tehnică UM1581 Manual de utilizare Descrierea bibliotecii de periferice standard STM32F30xx/31xx. Aici conectăm trei fișiere antet care conțin datele necesare, structurile, funcțiile de control de resetare și sincronizare, precum și pentru configurarea porturilor de intrare/ieșire.

3). HAL- (Nivel de acces hardware, strat de abstracție hardware)- O altă bibliotecă comună pentru dezvoltare. Cu care a fost lansat și programul CubeMX pentru configurația pe care am folosit-o în ultimul articol. Acolo am scris și un program pentru a clipi un LED folosind această bibliotecă. După cum vedem în figura de mai jos, cubul generează drivere HAL și CMSIS. Ei bine, să descriem principalele fișiere utilizate:
- system_stm32f3x.c și system_stm32f3x.h- asigura seturi minime de functii pentru configurarea sistemului de cronometrare;
— core_cm4.h – oferă acces la registrele nucleului și perifericelor acestuia;
- stm32f3x.h - fișier antet microcontroler;
— startup_system32f3x.s — cod de pornire, conține un tabel de vectori de întrerupere etc.

#include „principal.h”
#include „stm32f3xx_hal.h”
void SystemClock_Config(void); /*Declară funcțiile de configurare a ceasului*/
static void MX_GPIO_Init(void); /*Inițializați I/O*/
int main (void) (
/*Resetarea tuturor perifericelor, Inițializează interfața Flash și Systick-ul.*/
HAL_Init();
/* Configurați ceasul sistemului */
SystemClock_Config();
/* Inițializați toate perifericele configurate */
MX_GPIO_Init();
în timp ce (1) (
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8); //Schimbați starea piciorului
HAL_Delay(100); )
}
void SystemClock_Config (void){
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
dacă (HAL_RCC_OscConfig (&RCC_OscInitStruct) != HAL_OK){

}
/**Inițializează ceasurile magistralelor CPU, AHB și APB */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
dacă (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){
_Error_Handler(__FILE__, __LINE__);
}
/**Configurați timpul de întrerupere Systick*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configurați Systick-ul */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* Configurarea întreruperii SysTick_IRQn */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/** Configurați pinii ca intrare analogică ieșire EVENT_OUT EXTI */
static void MX_GPIO_Init (void){
GPIO_InitTypeDef GPIO_InitStruct;
/* Activare ceas porturi GPIO */
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Configurați nivelul de ieșire a pinului GPIO */
HAL_GPIO_WritePin (GPIOE, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
/*Configurați pinii GPIO: PE8 PE9 PE10 PE11 PE12 PE13 PE14 PE15 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed ​​​​= GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}
void _Error_Handler (car * fișier, linie int){
în timp ce (1) (
} }
#ifdef USE_FULL_ASSERT

Void assert_failed (fișier uint8_t*, linie uint32_t){
}
#endif
Aici, la fel ca în exemplul anterior, putem vizualiza, de exemplu, descrierea fiecărei funcții din documentație Manual de utilizare UM1786 Descrierea driverelor STM32F3 HAL și de nivel inferior.

Putem rezuma că prima opțiune, folosind CMSIS, este mai puțin greoaie. Există documentație pentru fiecare bibliotecă. În proiectele ulterioare, vom folosi HAL și CMSIS folosind programul de configurare STCube și, dacă este posibil, vom folosi registre direct, fără wrapper software. Să ne oprim aici astăzi. În articolul următor ne vom uita la principiile de bază ale construcției casă inteligentă. Pa tuturor; la revedere tuturor.




Top