Programmering STM32F4. Oppretter et nytt prosjekt i Keil. STM32F407(STM32F4-DISCOVERY) - Ikke-standard tilnærming - Standard bibliotek del 1

Frem til dette punktet har vi brukt standard kjernebibliotek - CMSIS. For å konfigurere en port til ønsket driftsmodus, måtte vi henvende oss for å finne registeret som er ansvarlig for en bestemt funksjon, og også søke gjennom et stort dokument for annen informasjon knyttet til denne prosessen. Ting vil bli enda mer smertefullt og rutinemessig når vi begynner å jobbe med en timer eller ADC. Antall registre der er mye større enn for I/O-portene. Manuell konfigurasjon tar mye tid og øker sjansen for å gjøre feil. Derfor foretrekker mange å jobbe med standard periferbibliotek - StdPeriph. Hva gir det? Det er enkelt – abstraksjonsnivået øker, du trenger ikke gå inn i dokumentasjonen og tenke på registre for det meste. I dette biblioteket er alle driftsmoduser og parametere til MK-periferien beskrevet i form av strukturer. Nå, for å konfigurere en perifer enhet, trenger du bare å kalle enhetens initialiseringsfunksjon med en fylt struktur.

Nedenfor er et bilde med en skjematisk representasjon av abstraksjonsnivåene.

Vi jobbet med CMSIS (som er "nærmest" kjernen) for å vise hvordan mikrokontrolleren fungerer. Neste trinn er standardbiblioteket, som vi skal lære å bruke nå. Neste kommer enhetsdrivere. De forstås som *.c \ *.h-filer som gir et praktisk programvaregrensesnitt for å kontrollere enhver enhet. For eksempel vil vi i dette kurset gi deg drivere for max7219-brikken og esp8266 WiFi-modulen.

Et standardprosjekt vil inneholde følgende filer:


For det første er dette selvfølgelig CMSIS-filene som lar standardbiblioteket fungere med kjernen, vi har allerede snakket om dem. For det andre standard bibliotekfiler. Og for det tredje, brukerfiler.

Bibliotekfilene finner du på siden dedikert til mål-MK (for oss er det stm32f10x4), i delen Designressurser(i CooCox IDE lastes disse filene ned fra utviklingsmiljøet). Hvert periferiutstyr tilsvarer to filer - header (*.h) og kildekode (*.c). En detaljert beskrivelse finner du i støttefilen som ligger i arkivet med biblioteket på nettsiden.

  • stm32f10x_conf.h - bibliotekkonfigurasjonsfil. Brukeren kan koble til eller fra moduler.
  • stm32f10x_ppp.h - perifer header-fil. I stedet for ppp kan det være gpio eller adc.
  • stm32f10x_ppp.c - driver for eksterne enheter skrevet på C-språk.
  • stm32f10x_it.h - overskriftsfil som inkluderer alle mulige avbruddsbehandlere (deres prototyper).
  • stm32f10x_it.c er en malkildekodefil som inneholder avbruddstjenesterutine (ISR) for unntakssituasjoner i Cortex M3. Brukeren kan legge til sine egne ISR-er for periferiutstyret som brukes.

Standardbiblioteket og periferiutstyret har en konvensjon når det gjelder navngivningsfunksjoner og notasjon.

  • PPP er et akronym for periferiutstyr, for eksempel ADC.
  • System-, header- og kildekodefiler - start med stm32f10x_.
  • Konstanter brukt i én fil er definert i den filen. Konstanter brukt i mer enn én fil er definert i overskriftsfiler. Alle konstanter i det perifere biblioteket er oftest skrevet med STORE bokstaver.
  • Registre behandles som konstanter og kalles også STORE bokstaver.
  • Periferispesifikke funksjonsnavn inkluderer et akronym, for eksempel USART_SendData() .
  • For å konfigurere hver perifer enhet brukes PPP_InitTypeDef-strukturen, som sendes til PPP_Init()-funksjonen.
  • For å deinitialisere (sett verdien til standard), kan du bruke PPP_DeInit()-funksjonen.
  • Funksjonen som lar deg aktivere eller deaktivere eksterne enheter kalles PPP_Cmd().
  • Avbruddsaktivering/deaktiveringsfunksjonen kalles PPP_ITConfig.

Du kan igjen se hele listen i bibliotekets støttefil. La oss nå omskrive lysdioden som blinker ved å bruke standard periferbibliotek!

Før du starter arbeidet, la oss se på filen stm32f10x.h og finne linjen:

#define USE_STDPERIPH_DRIVER

Hvis du konfigurerer prosjektet fra bunnen av ved hjelp av bibliotekfiler fra det nedlastede arkivet, må du oppheve kommentaren til denne linjen. Det vil tillate deg å bruke standardbiblioteket. Denne definisjonen (makro) vil beordre forprosessoren til å inkludere stm32f10x_conf.h-filen:

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

Denne filen inneholder moduler. Hvis du bare trenger spesifikke, deaktiver resten, dette vil spare tid under kompileringen. Vi, som du kanskje har gjettet, trenger RTC- og GPIO-moduler (men i fremtiden vil vi også trenge _bkp.h, _flash, _pwr.h, _rtc.h, _spi.h, _tim.h, _usart.h):

#inkluder "stm32f10x_flash.h" // for init_pll() #inkluder "stm32f10x_gpio.h" #inkluder "stm32f10x_rcc.h"

Som forrige gang må du først aktivere klokkefunksjonen for port B. Dette gjøres av funksjonen som er deklarert i stm32f10x_rcc.h:

Void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

FunctionalState enum er definert i stm32f10x.h:

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

La oss erklære en struktur for å sette opp beinet vårt (du finner det i filen stm32f10x_gpio.h):

GPIO_InitTypeDef LED;

Nå må vi fylle den ut. La oss se på innholdet i denne strukturen:

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

Alle nødvendige oppregninger og konstanter finnes i samme fil. Deretter vil den omskrevne init_leds()-funksjonen ha følgende form:

Void led_init() ( // Aktiver klokkeslett RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // Erklær strukturen og fyll den GPIO_InitTypeDef LED; LED.GPIO_Pin = GPIO_Pin_0; LED.GPIO_GPIO_SpeedMode=GPIO_GPIOSpeedMo _ Ut_PP; // Initialiser porten GPIO_Init( GPIOB, &LED); )

La oss omskrive hoved()-funksjonen:

Int main(void) ( led_init(); while (1) ( GPIO_SetBits(GPIOB, GPIO_Pin_0); delay(10000000); GPIO_ResetBits(GPIOB, GPIO_Pin_0); delay(10000000); ) )

Det viktigste er å få en følelse av initialiseringsrekkefølgen: slå på den perifere klokken, erklær strukturen, fyll strukturen, ring initialiseringsmetoden. Andre perifere enheter er vanligvis konfigurert på lignende måte.

I lang tid, til og med veldig lang tid, har det ikke vært noen nye artikler om artikkelen vår, så det er på tide å ta igjen 😉 I dag begynner vi å studere STM32F4. Og, sannsynligvis, vi starter med å lage et nytt prosjekt for disse kontrollerene, selv om jeg for å være ærlig ikke ønsket å skrive en artikkel om dette, siden et nytt prosjekt blir opprettet her, i prinsippet, på samme måte som for STM32F103 (). Men det skjer fortsatt at det oppstår noen vanskeligheter med STM32F4, så la oss likevel vurdere denne prosessen i detalj)

Så, la oss lansere Keil, lage et nytt prosjekt - Prosjekt -> Nytt uVision-prosjekt. Vi lagrer det nye prosjektet i en mappe, og deretter blir vi bedt om å velge mikrokontrolleren som skal brukes. Vel, la oss velge, la det være STM32F407VG:

Ferdig, i dialogboksen som vises, klikk "Ja" og den første filen vil bli lagt til prosjektet vårt - startup_stm32f4xx.s. Akkurat som før vil vi bruke bibliotek CMSIS Og Standard perifert bibliotek, men naturligvis allerede for STM32F4xx-kontrollere. Så vi må definitivt laste dem ned og legge til de nødvendige filene til vårt fortsatt tomme prosjekt. Forresten, jeg har hørt mer enn en gang fra forskjellige mennesker at de kommer over noen "ikke så"-biblioteker for F4, og selv det enkleste prosjektet er ikke satt sammen. Jeg har selv ikke vært borti dette, men her er de testede bibliotekene som jeg selv bruker:

Så vi lastet ned det, alt er klart, nå legger vi til filene i prosjektet. Bildet viser hva du trenger:

Vel, forberedelsene er fullført, la oss nå lage en ny .c-fil, som vil inneholde koden vår. La oss gå til Fil->Ny, en tom fil åpnes i Keil, klikk Fil->Lagre som og lagre den under navnet test.c, for eksempel. Når du lagrer, ikke glem å spesifisere filtypen (.c). Filen ble opprettet, flott, men vi må også legge den til i prosjektet vårt. Vel, faktisk er det ikke noe komplisert med det 😉 La oss skrive et tomt testprogram inn i denne filen:

#inkluder "stm32f4xx.h" #inkluder "stm32f4xx_rcc.h" #inkluder "stm32f4xx_gpio.h" /*******************************************************************/ int main() ( while (1 ) ( __NOP() ; ) ) /*******************************************************************/

Nesten alt er klart, alt som gjenstår er å se på prosjektinnstillingene - Prosjekt->Alternativer for mål... Et vindu åpnes med mange faner, vi er kun interessert i noen få her. Åpne fanen C/C++ og i Definer-feltet skriver vi:

Vel, nede i feltet du må legge til stier til absolutt alle filer som er inkludert i prosjektet. Etter å ha fullført dette trinnet kan du trykke F7 (Bygg), og prosjektet vil bli bygget uten feil eller advarsler. Som du kan se, ingenting komplisert)

Men generelt gjør jeg personlig ting litt annerledes. Se på ulempen med denne tilnærmingen. Så vi lastet ned CMSIS- og SPL-bibliotekene et sted, la til filer fra disse mappene, skrev ned stiene til filene, alt er kult. MEN! Prosjektet vil ikke bygges på en annen datamaskin, siden banene alle er absolutte, det vil si at de peker til bestemte mapper på datamaskinen din. Og på en annen maskin må du faktisk utføre trinnene på nytt for å opprette et nytt prosjekt. Dette er et stort minus. Derfor lager jeg vanligvis en egen mappe for et nytt prosjekt, i den lager jeg undermapper for CMSIS, SPL og andre biblioteker som brukes, og i disse mappene legger jeg alle filene jeg trenger i hvert enkelt prosjekt. La oss for eksempel lage STM32F4_Test-mappen for vårt nye prosjekt og følgende mapper i den:

Jeg la alle nødvendige filer som vi la til da vi opprettet prosjektet i begynnelsen av artikkelen i CMSIS- og SPL-mappene. Nå lanserer vi Keil, oppretter et nytt prosjekt og lagrer det i undermappen vår Prosjekt slik at alle prosjektfilene er på ett sted og ikke forårsaker kaos)

Prosjektet er opprettet, nå, som før, legger vi ganske enkelt til alle filene fra STM32F4_CMSIS- og STM32F4_SPL-mappene til det. Vi legger vår test-.c-fil med main()-funksjonen i Source-mappen og legger den til i prosjektet også. Det gjenstår bare å konfigurere innstillingene =) Alt er det samme - i definisjonsfeltet skriver vi:

USE_STDPERIPH_DRIVER,STM32F4XX



Vi monterer prosjektet - det er ingen feil, flyturen er normal! I prinsippet fikk vi til slutt det samme, men nå vil prosjektet umiddelbart settes sammen på en hvilken som helst annen datamaskin uten problemer, og dette er veldig praktisk og nyttig) Absolutt alle prosjektfiler er nå plassert i nærheten, i samme mappe, og veiene har blitt relative og trenger ikke endres.
Det er alt, faktisk, i nær fremtid vil vi gjøre noe for å programmere STM32F4, definitivt, så vi sees snart!;)

Fullstendig prosjekt fra eksempelartikkel -

I denne publikasjonen vil jeg forsøke å fokusere på hovedpunktene for raskt å komme i gang med STM32F10x mikrokontrollere basert på biblioteket av standard periferiutstyr fra produksjonsselskapet STMicroelectronics.

Artikkelen vil bruke Eclipse CDT som utviklingsmiljø. Siden hovedfokuset vil være på programkoden, kan du trygt gjøre alle manipulasjonene i Code::Blocks.

Den generelle prosjektstrukturen for ARM-mikrokontrollere er beskrevet i artikkelen min.

Her vil jeg kort minne deg på at for å bygge et prosjekt for ARM-mikrokontrollere (spesielt STM32F10x), trenger du et linkerskript og en C-Startup-fil.

Et linkerskript er en fil med instruksjoner for plassering av programkode og data i mikrokontrollerens minne. Den kan beordre programkoden din til å lastes inn i Flash-programminnet eller SRAM-dataminnet.

Mikrokontrollere med forskjellige mengder program- og dataminne krever forskjellige layout-skript. De kan fås fra mikrokontrollerprodusenten - STMicroelectronics.
Pakk ut STM32F10x standard periferbibliotek fra arkivet ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip.
Den inneholder eksempelprosjekter for ulike utviklingsmiljøer (IAR EWB, Keil uVision, Atollic True Studio, etc.). Den nærmeste for oss er Atollic True Studio, siden det er en modifikasjon av Eclipse.
Gå til katalogen Project/StdPeriph_Template/TrueSTUDIO, det er flere underkataloger der, hvis navn tilsvarer navnene på STM3210x-EVAL utviklingskort.

Finn ut hvilke av disse brettene som bruker samme mikrokontrollerlinje som din. Kopier filen stm32_flash.ld fra den aktuelle katalogen til prosjektet ditt.

Det er også mulig å lage et universelt skript der kun mengden program og dataminne vil endres i samsvar med mikrokontrolleren som brukes.

Oppstartskode (C-Startup) for STM32 mikrokontrollere kan skrives i C eller Assembler.
Selv om STM32F10x Standard Peripheral Library (forkortet STM32F10x SPL) ofte blir kritisert for sine feil, er det den enkleste måten å komme raskt i gang når du starter STM32-programmering.
Men du vil alltid at det skal være et slags alternativ. Faktisk er det mange av dem, for eksempel programmering i assemblerspråk :)

Dette er den vanskeligste og mest meningsløse veien. Den andre måten er å bruke CMSIS-biblioteket, som gir syntaks for å få tilgang til C-språkstrukturer for å få tilgang til ulike mikrokontrollerutstyr. Den enkleste og mest logiske måten (etter min mening) er å bruke biblioteker.

Hvis du er kategorisk motstander av STM32F10x SPL, så er det et annet alternativ spesielt for deg - libopencm3-biblioteket. I den er hovedantallet av eksempler konsentrert rundt hovedserien av mikrokontrollere STM32F10x, men det er bare et spørsmål om tid før eksempler for andre serier (STM32F2xx/4xx) dukker opp. Du kan alltid bli med i libopencm3-prosjektet og fremskynde denne prosessen.

CMSIS-standarden er også valgfri for bruk i programmene dine.
Du kan klare deg uten det ved å bruke litt krefter og tid på å implementere HAL-nivået (Hardware Abstraction Layer) i programmeringsspråket C.

Denne metoden kan i noen tilfeller være den eneste tilgjengelige metoden. Organisasjonen din bruker for eksempel tilpassede brikker basert på ARM-utviklede datakjerner og bransjespesifikke periferiutstyr.

Eller du må implementere programvare i C for mikrokontrollere med en ARM9-kjerne, hvor produsentene fokuserer på å bruke ferdige operativsystemer (Linux, QNX, Windows CE), slik at biblioteker for programmering i C i ren form eller i kombinasjon med en mer lettvekts RTOS-produsenter kan ikke levere det.

Heldigvis gir produsenter av mikrokontrollere basert på Cortex-M3-kjernen utviklere et stort antall kodebiblioteker. Dette gjelder også STM32 mikrokontrollere.
La oss fortsette vår vurdering av STM32F10x SPL-biblioteket. Vi vil vurdere det ved å bruke et eksempel.
Du kan åpne dette eksemplet eller lage ditt eget prosjekt fra bunnen av for bedre å forstå hele prosessen med hva som skjer.

For det andre tilfellet vil jeg liste opp de nødvendige trinnene:

  • Opprett et nytt tomt prosjekt i Eclipse
  • Kopier layoutskriptet og start filen inn i prosjektet
  • Lag en ny eller kopier en mal Makefile
  • Når du bruker Makefile fra mitt eksempel som en mal, må du opprette src, inc, bin, obj-katalogene inne i prosjektet, og lage underkatalogene Debug and Release inne i bin og obj-katalogene.
  • Kopier de nødvendige kilde- og overskriftsfilene fra CMSIS- og STM32F10x SPL-bibliotekene.
  • Gjør de nødvendige endringene i brukerinnstillingsdelen av malen Makefile, hvis den brukes.
  • Opprett nye mål "Debug", "cleanDebug", "Release", "cleanRelease", "Program" i Eclipse "make target"-vinduet.
  • Start "Debug"-målet og overvåk utførelsen i "Konsoll"-vinduet.

For en bedre forståelse av materialet delte jeg artikkelen inn i flere uavhengige avsnitt, som hver beskriver bare ett aspekt ved å jobbe med STM32F10x SPL-biblioteket.

Konfigurere STM32F10x SPL ved hjelp av makrodefinisjoner

For å konfigurere biblioteket brukes forhåndsdefinerte makroverdier, som vi nå skal vurdere.
De kan settes inne i overskriftsfiler ved hjelp av et forprosessordirektiv #definere eller send verdiene til makrodefinisjoner gjennom nøkkelen -D GCC kompilator.
I mitt eksempel bruker jeg den andre metoden.
I Makefile-variabel DEFINERE inneholder makroer som er nødvendige for å kompilere STM32F10x SPL-biblioteket.
Makrodefinisjon STM32F10X_MD spesifiserer om mikrokontrolleren som brukes tilhører linjen Middels tetthet.
Dette inkluderer mikrokontrollere med Flash-minne fra 64 til 128 kB.
Følgende tabell viser navnene på makroer for forskjellige serier med mikrokontrollere:

Serienavn Makro Beskrivelse
Verdilinje med lav tetthet STM32F10X_LD_VL med Flash-minnekapasitet 16 - 32 kB
Lav tetthet STM32F10X_LD
med Flash-minnekapasitet 16 - 32 kB
Middels tetthet Verdilinje STM32F10X_MD_VL Flashminne
64 - 128 kB
Middels tetthet STM32F10X_MD mikrokontrollere av STM32F101xx, STM32F102xx, STM32F103xx-serien med Flash-minne 64 - 128 kB
Verdilinje med høy tetthet STM32F10X_HD_VL mikrokontrollere av STM32F100xx-serien med volum
Flash - minne 256 - 512kB
Høy tetthet STM32F10X_HD med volum
Flash-minne 256 - 512 kB
XL-tetthet STM32F10X_XL
Flash-minne 512 - 1024 kB
Tilkoblingslinje STM32F10X_CL

For å stille inn klokkefrekvensen til mikrokontrolleren, må du fjerne kommentering av makroen med den nødvendige klokkefrekvensverdien i system_stm32f10x.c-filen.

#hvis definert (STM32F10X_LD_VL) || (definert STM32F10X_MD_VL) || (definert STM32F10X_HD_VL) #define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #define SYSCLK_FREQ_24MHz 24000000 *SYSC0000 *SYSC0EQ_0 /* #define SYSCLK_FREQ_HSE HSE_VALUE fine SYSCLK_FREQ_48MHz 48000000 */ /* #define SYSCLK_FREQ_56MHz 56000000 * / #define SYSCLK_FREQ_72MHz 72000000 #endif

#hvis definert (STM32F10X_LD_VL) || (definert STM32F10X_MD_VL) || (definert STM32F10X_HD_VL)

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

#define SYSCLK_FREQ_24MHz 24000000

#ellers

/* #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

#slutt om

Det forutsettes å bruke en kvartsresonator med en frekvens på 8 MHz for all hoved
serie med mikrokontrollere, bortsett fra Connectivity-linjen, som det er nødvendig å installere en 25 MHz kvartsresonator for.
Hvis du bruker kvartsresonatorer med andre frekvensverdier, må du endre verdien til HSE_VALUE-makroen i stm32f10x.h header-filen og tilpasse alle avhengige funksjoner deretter.
Formålet med USE_STDPERIPH_DRIVER-makroen er ikke vanskelig å gjette - å bruke STM32F10x standard periferbibliotek.
USE_FULL_ASSERT – bruk ASSERT-makroen for å feilsøke programmet.

Bruke assert_param-makroen i biblioteket

Alle STM32F10x SPL-bibliotekfunksjoner bruker assert_param-makroen for å sjekke argumentene deres.
Denne makroen sjekker et uttrykk som involverer funksjonsargumentet som testes for lik null. Hvis verdien av uttrykket er null, kalles argumentfeilbehandlerfunksjonen assert_failed, ellers (uttrykket er ikke null), lykkes argumentkontrollen.
Du må implementere assert_failed-funksjonen i programmet ditt.
Den viser feilmeldingen, filnavnet og nummeret på kodelinjen som forårsaket feilen.
Makroen debug_printf kan sendes ut via USART ved å bruke standard new_lib-biblioteket eller, for eksempel, biblioteket fra Mr. Chen.

#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT void assert_failed(uint8_t* fil, uint32_t line) ( debug_printf("Feil parameterverdi: fil %s på linje %d\r\n", fil, (int)line) ; mens (1) ( ) )/* assert_failed */ #endif/*USE_FULL_ASSERT*/

#define debug_printf xprintf /* printf */

#ifdef USE_FULL_ASSERT

void assert_failed (uint8_t * file , uint32_t line )

debug_printf( "Feil parameterverdi: fil %s på linje %d\r\n", fil , (int ) linje ) ;

mens (1)

) /* assert_failed */

#endif/*USE_FULL_ASSERT*/

Assert_failed-funksjonen implementert i koden din brukes bare når USE_FULL_ASSERT-makroen er deklarert. Ellers ekskluderes all feilsøkingskode fra kilden. Denne funksjonaliteten er implementert i innstillingshodefilen for driverbiblioteket 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* fil, 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 * fil , uint32_t line ) ;

#ellers

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

#endif /* USE_FULL_ASSERT */

Det er ikke mye å forklare her. La oss se på et eksempel på bruk av assert_param.

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

void set_param (uint8_t * param , uint8_t verdi )

assert_param (param != NULL );

* param = verdi ;

) /*sett_param*/

Funksjonen setter verdien til parameteren via en peker sendt som et argument. Hvis USE_FULL_ASSERT-makroen ikke er deklarert, kan vi anta at linjene
assert_param(param != NULL) er rett og slett ikke i koden, ellers sjekkes parameteren i denne definisjonen.
Hvis pekeren ikke er definert, vil verdien param != NULL være falsk og assert_failed-funksjonen vil bli kjørt, som vil sende ut filnavnet og linjenummeret med feilen via USART, og deretter loop, og dermed forhindre at verdien blir tilordnet en udefinert adresse i minnet.
Du trenger ikke i det hele tatt å bruke assert_param-makroen i koden din, men i bibliotekkoden
STM32F10x SPL den brukes overalt.
Set_param-funksjonen kan implementeres med argumentfeilkontroll uten å bruke assert_param.

#define ERROR (-1) #define OK (0) int set_param(uint8_t * param, uint8_t verdi) (int r = ERROR; if (param == NULL) returner r; *param = verdi; r = OK; returner r ; )/*set_param*/

#define FEIL (-1)

#define OK (0)

int set_param (uint8_t * param , uint8_t verdi )

int r = FEIL;

if (param == NULL )

returnere r ;

* param = verdi ;

r = OK ;

returnere r ;

) /*sett_param*/

C-Startup-fil i STM32F10x SPL-biblioteket

I startkoden initialiseres mikrokontrolleren til å begynne med, stabelen konfigureres, BSS-seksjonen tilbakestilles og hovedfunksjonen main() kalles.
Startkoden har ingen direkte relasjon til STM32F10x SPL-biblioteket. Imidlertid, i denne oppstartskoden, før du kaller hoved()-funksjonen til programmet, kalles mikrokontrollerens initialiseringsfunksjon SystemInit(), som er en del av CMSIS.
Den kan enkelt finnes i CMSIS-biblioteket.
Gå til biblioteket/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO-katalogen og kopier den nødvendige filen. Alt som gjenstår er å finne ut hvilken linje mikrokontrolleren som brukes i prosjektet ditt tilhører.
For å gjøre dette, se på følgende tabell:

Serienavn Filnavn Beskrivelse
Verdilinje med lav tetthet startup_stm32f10x_ld_vl.s mikrokontrollere av STM32F100xx-serien med volum
Flash-minne 16 - 32 kB
Lav tetthet startup_stm32f10x_ld.s mikrokontrollere serien STM32F101xx, STM32F102xx, STM32F103xx
med Flash-minnekapasitet 16 - 32 kB
Middels tetthet Verdilinje startup_stm32f10x_md_vl.s mikrokontrollere serie STM32F100xx
Middels tetthet startup_stm32f10x_md.s mikrokontrollere serien STM32F101xx, STM32F102xx, STM32F103xx
med Flash-minnekapasitet 64 - 128 kB
Verdilinje med høy tetthet startup_stm32f10x_hd_vl.s mikrokontrollere serie STM32F100xx
Høy tetthet startup_stm32f10x_hd.s mikrokontrollere serien STM32F101xx, STM32F103xx
med Flash-minnekapasitet 256 - 512 kB
XL-tetthet startup_stm32f10x_xl.s mikrokontrollere serien STM32F101xx, STM32F103xx
med Flash-minnekapasitet 512 - 1024 kB
Tilkoblingslinje startup_stm32f10x_cl.s mikrokontrollere i seriene STM32F105xx og STM32F107xx

Oppstartsfilen inneholder navnene på avbrudds- og unntaksvektorbehandlerne, men bare ter implementert, der all initialisering utføres før hoved()-funksjonen kalles.
Implementeringen av alle andre unntaksbehandlere er applikasjonsprogrammererens ansvar. Hvis programmet ditt ikke bruker noen behandlere, er det ikke nødvendig å registrere dem. Hvis et unntak oppstår, vil standardbehandleren bli brukt - looping av programkoden.

Sammensetning av CMSIS-biblioteket

Som skrevet tidligere i denne publikasjonen, gir CMSIS-biblioteket tilgang til perifere mikrokontrollermoduler ved å bruke elementer av C-språkstrukturer.
Implementeringen av dette biblioteket er delt inn i to deler. Den første delen gir tilgang til periferien av Cortex-M3-kjernen, og den andre - til periferien til en spesifikk mikrokontrollermodell.
Siden CMSIS-standarden er den samme for alle mikrokontrollere med Cortex-M3-kjerne, vil implementeringen av den første delen være den samme for alle produsenter, men den andre delen vil være forskjellig for hver produsent.
CMSIS inkluderer flere header- og kildefiler. Den første delen inkluderer filene:

  • kjerne_cm3.h
  • kjerne_cm3.c

Den andre delen av CMSIS inkluderer C-Startup-filen, samt følgende filer:

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

Overskriftsfilen stm32f10x.h inneholder makrodefinisjoner for tilgang til perifere moduler til stm32f10x mikrokontrollere.
Filene system_stm32f10x.h og system_stm32f10x.c implementerer den første initialiseringen av mikrokontrolleren.

Sammensetning og konfigurasjon av STM32F10x SPL-biblioteket

Biblioteket består av kilde- og overskriftsfiler med samme navn som perifere moduler med prefikset stm32f10x_.
For eksempel er implementeringen av interaksjon med USART-modulen inneholdt i filene stm32f10x_usart.h og stm32f10x_usart.c.
Det er konvensjoner for navngivning av bibliotekelementer og visse kodingsregler, som er beskrevet i dokumentasjonen.
Biblioteket inneholder implementering av drivere for perifere mikrokontrollermoduler.
Navnene på bibliotekelementer bruker følgende akronymer for perifere moduler:

Akronym Perifermodul
ADC analog-til-digital omformer
BKP backup registre
KAN CAN-grensesnitt
CEC forbrukskontroller
CRC sjekksumberegningsmodul
DAC digital-til-analog omformer
DBGMCU feilsøking av mikrokontroller
DMA kontroller for direkte minnetilgang
EXTI ekstern avbruddskontroller
FSMC ekstern minnekontroller
BLITS Flash-programminne
GPIO generelle I/O-porter
I2C I2C-grensesnitt
I2S I2S (lyd) grensesnitt
IWDG uavhengig vakthundtimer
NVIC nestet avbruddskontroller
PWR strømkontroller
RCC tilbakestilling og klokkekontroller
RTC sanntidskontroller (klokke)
SDIO SDIO-grensesnitt
SPI SPI-grensesnitt
SysTick systemtimer
TIM grunnleggende eller avansert timer
USART universell seriell synkron-asynkron
sender/mottaker
WWDG vindusvakthund

Basert på disse akronymene dannes navnene på bibliotekets programvaremoduler. Du trenger ikke bruke alle modulene i biblioteket.
For å kun bruke de nødvendige modulene i prosjektet, må biblioteket konfigureres.
For disse formålene må hvert prosjekt som bruker STM32F10x SPL-biblioteket ha en overskriftsfil stm32f10x_conf.h.

#include "stm32f10x_gpio.h" //#include "stm32f10x_i2c.h" //#include "stm32f10x_iwdg.h" //#include "stm32f10x_pwr.h" #include "stm32f10x_i2c.h"_rcc

#include "stm32f10x_gpio.h"

//#include "stm32f10x_i2c.h"

//#include "stm32f10x_iwdg.h"

//#inkluder "stm32f10x_pwr.h"

#include "stm32f10x_rcc.h"

For å aktivere den nødvendige modulen, må du fjerne kommentarene til direktivet #inkludere med de tilsvarende overskriftsfilene.
Header-filen stm32f10x_conf.h er inkludert i stm32f10x.h, så for å bruke funksjonene til STM32F10x SPL-biblioteket, trenger du bare å inkludere kun én header-fil stm32f10x.h i kildekoden din

// i filen stm32f10x.h #ifdef USE_STDPERIPH_DRIVER #inkluder "stm32f10x_conf.h" #endif

Jeg gjentar at prosjektet også må definere makroene USE_STDPERIPH_DRIVER, USE_FULL_ASSERT og en makro som spesifiserer serien til mikrokontrolleren som brukes (for eksempel STM32F10X_MD for Medium density-linjen).
Hvis du bruker standard kvartsfrekvensverdi og kontrolleren opererer med en maksimal klokkefrekvens på 72 MHz, trenger du ikke å endre noe annet.
Du må legge til en liste over bibliotekfiler for å kompilere til Makefilen.
For eksempel:

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

SRC += stm32f10x_rcc . c

SRC += stm32f10x_gpio . c

Bruke STM32F10x SPL-biblioteket. Arbeidsmekanismer

For å begynne å programmere ved hjelp av det perifere biblioteket, er den enkleste måten å se på eksemplene som følger med biblioteket. Men likevel, for å forstå koden til disse eksemplene, må du ha grunnleggende kunnskap om syntaksen og bruken av biblioteket.
Alle de tidligere oppførte perifere mikrokontrollermodulene er i utgangspunktet deaktivert, et klokkesignal leveres ikke til dem og de bruker ikke strøm.
For å bruke en perifer modul, må du først gi et klokkesignal til den. Klokkesignalet leveres av RCC-klokke- og tilbakestillingsmodulen.
For disse formålene har biblioteket følgende funksjoner:

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) ;

Her betegner PPP navnet på modulens aktonym (for eksempel ADC eller USART), og x er nummeret på den perifere modulen.
Først av alt må du finne ut hvilken buss modulen du bruker er koblet til.
Totalt har mikrokontrollere med Cortex-M3 kjernearkitektur tre busser:
instruksjonsbuss, databuss og systembuss. Instruksjonsbussen kobler kjernen til Flash-programminnet. Data- og systembussene er kombinert til en AHB (ARM Hi-Speed ​​​​Bus) bussmatrise, som opererer på kjernefrekvensen. Imidlertid kan AHB-bussfrekvensen reduseres ved å installere skillevegger. AHB-bussen kobler sammen høyhastighetsenheter som kjernen og DMA-modulen.
I/O-enheter er koblet til AHB-bussen via mellombussen APB1 og APB2 (ARM Peripheral Bus).
Den maksimale driftsfrekvensen til APB2-bussen er 72 MHz, frekvensen til APB1-bussen
begrenset til 36MHz.
Du kan finne ut hvilken av bussene perifermodulen du bruker er koblet til fra dokumentasjonen eller se i header-filen stm32f10x_rcc.h.
Åpne denne filen og søk etter RCC_AHBPeriph, RCC_APB1Periph og RCC_APB2Periph verdier i rekkefølge.

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) #define RCC_AHBPeriph_SRAM ((uint32_t)0x0CC400000x0CC4_AH0000x0CC4AHIT) 0x00000010) #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)

Ved navnene på makroene bestemmer vi hvilke moduler som er koblet til hvilke busser. Du kan også bruke sunn fornuft til å finne ut hvilket dekk som tilhører ett av de tre. For eksempel er USART-modulen en inngangs-/utgangsenhet, som betyr at den er koblet til en av APB-bussene. USART er et ganske lavhastighetsgrensesnitt, så det er sannsynligvis koblet til APB1-bussen.

#define RCC_APB1Periph_USART2 ((uint32_t)0x00020000) #define RCC_APB1Periph_USART3 ((uint32_t)0x00040000) #define RCC_APB1Periph_UART4 ((uint32_0fine)RCCUART4 ((uint00000_0)8P000x00_t) #define ((uint32_t)0x00100000)

Etter å ha sendt et klokkesignal til den perifere modulen, kan du konfigurere parameterne ved å ringe initialiseringsfunksjonen:

PPP_Init(PPP, &PPP_InitStructure);

PPP_Init (PPP, & amp; PPP_InitStructure);

Siden mange parametere må sendes til initialiseringsfunksjonen for å initialisere en perifer modul, brukes en peker til en struktur som et argument. Selve strukturen med initialiseringsparametere må opprettes i minnet før initialiseringsfunksjonen kalles; elementene i strukturen må tildeles de nødvendige verdiene:

PPP_InitTypeDef PPP_InitStructure = (val1, val2, ..., valN);/* initialisering av strukturen når den er deklarert */

Du kan først lage en struktur og deretter tilordne de nødvendige verdiene til elementene:

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

PPP_InitTypeDef PPP_InitStructure ;

PPP_InitStructure . medlem1 = val1;

PPP_InitStructure . medlem2 = val2;

PPP_InitStructure . medlemN = valN;

La oss se på et eksempel fra stm32f10xQuickstart-prosjektet:

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);

Elementene i GPIO_InitStructure-strukturen er tildelt verdien til pin-nummeret, modusen og hastigheten til porten.
Ved å kalle opp GPIO_Init-funksjonen initialiseres linje 12 i GPIOC-porten.
Det første argumentet til GPIO_Init-funksjonen er en peker til GPIOC-periferiens minneområde, konvertert til en peker til en GPIO_TypeDef-struktur.

// stm32f10x.h #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x100000) #define_PERI00int)_3B40 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 ;

GPIO_InitStructure-strukturen er av typen GPIO_InitTypeDef, beskrevet i overskriftsfilen
stm32f10x_gpio.h:

//stm32f10x_gpio.h typedef struct ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; )GPIO_InitTypeDef; typedef enum (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, GPIOxIO_PPMode =_0ODxIO_PP_0_0 , 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 enum

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_Out_PP = 0x10,

GPIO_Mode_AF_OD = 0x1C ,

GPIO_Mode_AF_PP = 0x18

) GPIOMode_TypeDef ;

Som du kan se, kan både brukerdefinerte typer, som GPIOSpeed_TypeDef, og datatyper med spesifikke verdier for å gjøre det enklere å initialisere perifere registre, som GPIOMode_TypeDef, brukes som datatyper for den initialiserte strukturen.
4 biter er tildelt for å konfigurere hver GPIO-pinne.
Følgende bilde viser formatet for nullbiten til GPIO:

Modus – driftsmodus for utgang (inngang/utgang). Mer presist er disse verdiene litt større; porter konfigurert som utgangsporter har en begrensning på den maksimale frekvensen til utgangssignalet.

Modus Beskrivelse
00 inngang
01 utgangsfrekvens opp til 10 MHz
10 utgangsfrekvens opptil 2 MHz
11 utgangsfrekvens opp til 50 MHz

CNF – utgangskonfigurasjonsbiter. Avhenger av driftsmodus:

Enig i at med denne strukturen til pin-konfigurasjonsregisteret vil det være ekstremt upraktisk å sette alle bitene for konfigurasjonen selv. Det vil være mye enklere å gjøre dette ved å bruke bibliotekfunksjonen GPIO_Init.
Etter at du har initialisert den perifere modulen, må den aktiveres ved hjelp av PPP_Cmd-funksjonen:

PPP_Cmd(PPP, ENABLE);

PPP_Cmd(PPP, ENABLE);

Denne funksjonen eksisterer ikke for GPIO-moduler; etter initialisering kan du umiddelbart bruke GPIO-pinnene. Det må huskes at biblioteket bare gir et grensesnitt til mikrokontrollerens maskinvare. Hvis maskinvaremodulen ikke har et aktiverings-/deaktiveringsflagg, så funksjonsanropet PPP_Cmd(PPP, ENABLE) umulig.
For å kontrollere tilstanden til GPIOx-pinnen i utgangsmodus og lese verdien i inngangs- eller utgangsmodus, tilbyr biblioteket følgende funksjoner:

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) ;

Resten av de perifere modulene er konfigurert og fungert på samme måte. Det er imidlertid noen forskjeller på grunn av spesifikasjonene til den spesifikke maskinvaremodulen, så jeg anbefaler på det sterkeste at du først ser eksempler på bruk av den valgte modulen for STM32F10x SPL-biblioteket.

Håndtering av avbrudd og unntak

Cortex-M3-kjernen inkluderer en nestet vektorisert avbruddskontroller. Kontrolleren støtter opptil 240 kilder som kan forårsake prosessorkjerneavbrudd. Hvor mange vektorer av 240 mulige som er implementert i en spesifikk mikrokontrollermodell avhenger av produsenten. Stm32f10x mikrokontrollere kan ha opptil 43 av disse vektorene. Disse avbruddslinjene kalles maskerbare. I tillegg er det 15 Cortex-M3 kjerneavbruddsvektorer og ett eksternt ikke-maskerbart EXTI-avbrudd.
Kontrolleren støtter nestede avbrudd, der et annet avbrudd kan oppstå innenfor én behandler. I denne forbindelse har hver avbruddskilde sin egen prioritet. 16 avbruddsprioritetsnivåer støttes.
Cortex-M3 kjerneavbruddsvektorer har de høyeste prioritetsverdiene.
De tre høyeste avbruddsnivåene er tilordnet vektorer og kan ikke endres:

Antall Handler En prioritet Beskrivelse
1 Reset_Handler -3 (høyest) Tilbakestill vektor
2 NMI_Handler -2 Ikke-maskerbart avbrudd
3 HardFault_Handler -1 Nødforhold

Alle andre avbruddsvektorer kan tildeles prioritetsnivåer fra 0 til 15.
Det høyeste prioritetsnivået tilsvarer en lavere verdi. Prioritetsnivået kan tildeles ikke bare til en individuell vektor, men også til en hel gruppe vektorer. Denne funksjonen gjør det lettere å jobbe med et stort antall avbruddsvektorer.
For å sette prioritetsgruppen brukes en funksjon fra STM32F10x SPL-biblioteket.

Hei alle sammen. Som du husker i den siste artikkelen, konfigurerte vi programvarepakken til å fungere med STM32-mikrokontrollere og kompilerte det første programmet. I dette innlegget vil vi bli kjent med arkitekturen til dette brettet, mikrokontrolleren og tilgjengelige biblioteker for arbeid.

Nedenfor er et bilde av brettet STM32F3 Discovery , hvor: 1 — MEMS-sensor. L3GD20 3-akset digitalt gyroskop. 2 - MEMS-system-i-en-etui som inneholder et 3-akset digitalt lineært akselerometer og en 3-akset digital geomagnetisk sensor LSM303DLHC. 4 – LD1 (PWR) – 3,3V strømforsyning. 5 – LD2 – rød/grønn LED. Standard er rødt. Grønt betyr kommunikasjon mellom ST-LINK/v2 (eller V2-B) og PC. Jeg har ST-LINK/v2-B, samt en egendefinert USB-portindikasjon. 6. -LD3/10 (rød), LD4/9 (blå), LD5/8 (oransje) og LD6/7 (grønn). I det siste innlegget blinket vi LD4 LED. 7. – To knapper: bruker BRUKER og RESET. 8. - USB-BRUKER med Mini-B-kontakt.

9 - USB debugger/programmerer ST-LINK/V2. 1 0. - Mikrokontroller STM32F303VCT6. 11. — Ekstern høyfrekvent generator 8 MHz. 12. – Det burde være en lavfrekvent generator her, den er dessverre ikke loddet. 13. – SWD – grensesnitt. 14. – Jumpere for valg av programmering av eksterne eller interne kontrollere, i det første tilfellet må fjernes. 15 – Jumper JP3 – en jumper designet for å koble til et amperemeter for å måle kontrollerens forbruk. Det er klart at hvis den slettes, så starter ikke steinen vår. 16. – STM32F103C8T6 det er et feilsøkingskort på den. 17. — LD3985M33R Regulator med lavt spenningsfall og støynivå, 150mA, 3,3V.

La oss nå se nærmere på arkitekturen til STM32F303VCT6 mikrokontrolleren. Dens tekniske egenskaper: LQFP-100-deksel, ARM Cortex-M4-kjerne, maksimal kjernefrekvens 72 MHz, programminnekapasitet 256 KB, programminnetype FLASH, RAM-kapasitet SRAM 40 KB, RAM 8 KB, antall innganger/utganger 87, grensesnitt ( CAN, I²C, IrDA, LIN, SPI, UART/USART, USB), periferiutstyr (DMA, I2S, POR, PWM, WDT), ADC/DAC 4*12 bit/2*12bit, forsyningsspenning 2 ... 3,6 V, arbeidstemperatur –40...+85 C. I figuren under er det en pinout, hvor vi ser 87 I/O-porter, 45 av dem Normal I/Os (TC, TTa), 42 5-volt tolerant I /Os (FT, FTf) – kompatibel med 5 V (på brettet er det 5V pinner til høyre, 3,3V til venstre). Hver digital I/O-linje kan fungere som en generell I/O-linje.
destinasjon eller alternativ funksjon. Etter hvert som prosjektene skrider frem, vil vi gradvis bli kjent med periferien.

Tenk på blokkdiagrammet nedenfor. Hjertet er en 32-biters ARM Cortex-M4-kjerne som opererer opp til 72 MHz. Den har en innebygd flyttallsenhet FPU og en minnebeskyttelsesenhet MPU, innebygde makrosporingsceller - Embedded Trace Macrocell (ETM), som kan brukes til å overvåke utførelsesprosessen til hovedprogrammet inne i mikrokontrolleren. De er i stand til kontinuerlig å sende ut disse observasjonene gjennom ETM-kontaktene så lenge enheten er i drift. NVIC (Nested vectored interrupt controller) – avbruddskontrollmodul. TPIU (Trace Port Interface Unit). Inneholder FLASH-minne – 256 KB, SRAM 40 KB, RAM 8 KB. Mellom kjernen og minnet er en bussmatrise, som lar enheter kobles direkte. Også her ser vi to typer bussmatrise AHB og APB, hvor den første er mer produktiv og brukes til å kommunisere høyhastighets interne komponenter, og den siste for periferiutstyr (inn-/utgangsenheter). Kontrolleren har 4 12-bits ADC-er (ADC) (5Mbit/s) og en temperatursensor, 7 komparatorer (GP Comparator1...7), 4 programmerbare operasjonsforsterkere (OpAmp1...4) (PGA (Programmable Gain Array) ), 2 12-bits DAC-kanaler (DAC), RTC (sanntidsklokke), to watchdog-timere - uavhengige og vinduer (WinWatchdog og Ind. WDG32K), 17 generelle og multifunksjonelle tidtakere.

Generelt sett så vi på kontrollerarkitekturen. Se nå på de tilgjengelige programvarebibliotekene. Etter å ha laget en oversikt kan vi fremheve følgende: CMSIS, SPL og HAL. La oss se på hver enkelt ved å bruke et enkelt eksempel på blinking av en LED.

1). CMSIS(Cortex Microcontroller Software Interface Standard) - standardbibliotek for Cortex®-M. Gir enhetsstøtte og forenkler programvaregrensesnitt. CMSIS gir konsistente og enkle grensesnitt til kjernen, dens periferiutstyr og sanntidsoperativsystemer. Bruken er en profesjonell måte å skrive programmer på, fordi... innebærer direkte skriving til registre, og derfor er konstant lesing og studier av datablad nødvendig. Uavhengig av maskinvareprodusenten.
CMSIS inkluderer følgende komponenter:
- CMSIS-CORE: Konsekvent systemoppstart og perifer tilgang;
- CMSIS-RTOS: Deterministic Real-Time Software Execution (Deterministisk utførelse av sanntids programvare);
— CMSIS-DSP: Rask implementering av digital signalbehandling;
- CMSIS-driver: Generiske perifere grensesnitt for mellomvare og applikasjonskode (Generelle perifere grensesnitt for mellomvare og applikasjonskode);
— CMSIS-Pack: Enkel tilgang til gjenbrukbare programvarekomponenter (Enkel tilgang til gjenbrukbare programvarekomponenter);
- CMSIS-SVD: Konsekvent visning av enhet og periferiutstyr;
- CMSIS-DAP: Tilkobling til rimelig evalueringsmaskinvare. Feilsøkingsprogramvare.

La oss for eksempel skrive et program - blink en LED. Til dette trenger vi dokumentasjon som beskriver registrene. I mitt tilfelle RM0316 Referansemanual STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE avanserte ARM ® -baserte MCUer, samt en beskrivelse av den spesifikke delen den er ansvarlig for DS9118: ARM®-basert Cortex®-M4 32b MCU+FPU, opptil 256KB Flash+ 48KB SRAM, 4 ADC-er, 2 DAC-kanaler, 7 komp, 4 PGA, tidtakere, 2,0-3,6 V. Til å begynne med vil vi klokke porten i programmet, pga Som standard er alt deaktivert, noe som gir redusert strømforbruk. Åpne referansehåndboken og se på Tilbakestill og klokkekontroll-delen, deretter RCC-registerkart og se hvilket register som er ansvarlig for å aktivere IOPEEN

La oss gå videre til beskrivelsen av clocking av periferiutstyret til dette registeret AHB perifer klokke aktiveringsregister (RCC_AHBENR), hvor vi ser at denne porten er under 21. bit. Slå den på RCC->AHBENR|=(1<<21) . Далее сконфигурируем регистры GPIO. Нас интересует три: GPIOE_MODER и GPIOx_ODR . C помощью них повторим программу с предыдущей статьи, затактируем PE8. Первый отвечает за конфигурацию входа выхода, выбираем 01: General purpose output mode. GPIOE->MODER|=0×10000 . Den andre er for å skru på lavt/høyt nivå på benet. Nedenfor er programmet:

#include "stm32f3xx.h " // Header-fil for mikrokontroller
usignert int i;
void delay() (
for (i=0;i<500000;i++);
}
int main (void) (
RCC->AHBENR|=(1<<21);
GPIOE->MODER|=0×10000;
mens (1)(
forsinkelse();
GPIOE->ODR|=0×100;
forsinkelse();
GPIOE->ODR&=~(0×100);
} }

2). SPL(Standard Peripherals Library)- dette biblioteket er ment å kombinere alle prosessorer fra ST Electronics. Designet for å forbedre kodeportabilitet og er først og fremst rettet mot nybegynnere. ST har jobbet med en erstatning for SPL kalt "low layer" som er kompatibel med HAL. Low Layer (LL)-drivere er designet for å gi et nesten lett, ekspertorientert lag som er nærmere maskinvaren enn HAL. I tillegg til HAL er LL APIer også tilgjengelige. Et eksempel på samme program i SPL.

#inkludere
#inkludere
#inkludere
#define LED GPIO_Pin_8
int main() (
lang i;
GPIO_InitTypeDef gpio;
// Blå LED er koblet til port E, pin 8 (AHB buss)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
// Konfigurer port E (LED)
GPIO_StructInit(&gpio); //erklære og initialisere en datastrukturvariabel
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_Pin = LED;
GPIO_Init(GPIOE, &gpio);
// Blinkende lysdioder
mens (1) (
// På
GPIO_SetBits(GPIOE, LED);
for (i = 0; i< 500000; i++);
// Alt av
GPIO_ResetBits(GPIOE, LED);
for (i = 0; i< 500000; i++);
} }

Hver funksjon er beskrevet i den tekniske dokumentasjonen UM1581 Brukerhåndbok Beskrivelse av STM32F30xx/31xx standard perifert bibliotek. Her kobler vi sammen tre header-filer som inneholder nødvendige data, strukturer, tilbakestillings- ogr, samt for å konfigurere input/output-porter.

3). HAL- (Maskinvaretilgangsnivå, maskinvareabstraksjonslag)– Nok et felles bibliotek for utvikling. Som CubeMX-programmet for konfigurasjonen som vi brukte i forrige artikkel også ble utgitt. Der skrev vi også et program for å blinke en LED ved hjelp av dette biblioteket. Som vi ser i figuren nedenfor, genererer kuben HAL- og CMSIS-drivere. Vel, la oss beskrive hovedfilene som brukes:
- system_stm32f3x.c og system_stm32f3x.h- gi minimale sett med funksjoner for å konfigurere tidssystemet;
— core_cm4.h – gir tilgang til registre over kjernen og dens periferiutstyr;
- stm32f3x.h - headerfil for mikrokontroller;
— startup_system32f3x.s — oppstartskode, inneholder en tabell med avbruddsvektorer, etc.

#inkluder "main.h"
#include "stm32f3xx_hal.h"
void SystemClock_Config(void); /*Erklære klokkekonfigurasjonsfunksjoner*/
statisk tomrom MX_GPIO_Init(void); /*Initialiser I/O*/
int main (void) (
/*Tilbakestill alle periferiutstyr, initialiserer Flash-grensesnittet og Systick.*/
HAL_Init();
/* Konfigurer systemklokken */
SystemClock_Config();
/* Initialiser alle konfigurerte periferiutstyr */
MX_GPIO_Init();
mens (1) (
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_8); //Skift benets tilstand
HAL_Delay(100); )
}
void SystemClock_Config (ugyldig){
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;
if (HAL_RCC_OscConfig (&RCC_OscInitStruct) != HAL_OK){

}
/**Initialiserer CPU-, AHB- og APB-bussklokkene */
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;
if (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){
_Error_Handler(__FILE__, __LINE__);
}
/**Konfigurer Systick-avbruddstiden*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Konfigurer Systick */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn avbruddskonfigurasjon */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/** Konfigurer pinner som analog inngangsutgang EVENT_OUT EXTI */
statisk tomrom MX_GPIO_Init (ugyldig){
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO-porter Klokkeaktivering */
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Konfigurer GPIO pin utgangsnivå */
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);
/*Konfigurer GPIO-pinner: 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(char * file, int line){
mens (1) (
} }
#ifdef USE_FULL_ASSERT

Void assert_failed (uint8_t*-fil, uint32_t-linje){
}
#slutt om
Her kan vi, akkurat som i forrige eksempel, se beskrivelsen av hver funksjon i for eksempel dokumentasjonen UM1786 Brukerhåndbok Beskrivelse av STM32F3 HAL og lavlagsdrivere.

Vi kan oppsummere at det første alternativet, ved å bruke CMSIS, er mindre tungvint. Det finnes dokumentasjon for hvert bibliotek. I påfølgende prosjekter vil vi bruke HAL og CMSIS ved å bruke STCube-konfigurasjonsprogrammet og om mulig bruke registre direkte, uten programvareinnpakninger. La oss stoppe der i dag. I den neste artikkelen skal vi se på de grunnleggende prinsippene for å bygge et smart hjem. Ha det alle sammen.