====== 01 - GPIO LED ======
Základní nastavení GPIO pinu na platformě STM32F401 ve variantě v jazyce C a Assembleru
===== Jazyk C =====
Následující kód způsobí blikání LED na pinu PA5 umístěnou na vývojovém kitu v daném časovém intervalu.
#include "stm32f4xx.h"
#define setbit(reg, bit) ((reg) |= (1U << (bit)))
#define clearbit(reg, bit) ((reg) &= (~(1U << (bit))))
#define togglebit(reg, bit) ((reg) ^= (1U << (bit)))
int main(void)
{
/* klicovym slovem volatile vyradime promennou i z pripadne optimalizace */
volatile i = 0;
setbit(RCC->AHB1ENR, 0); // aktivace hodin brany GPIOA
setbit(GPIOA->MODER, 10); // nastaveni pinu PA5 jako digital out
clearbit(GPIOA->MODER, 11);
clearbit(GPIOA->OTYPER, 5); // nastaveni pinu PA5 jako dvoustavovy (push-pull)
setbit(GPIOA->OSPEEDR, 10); // nastaveni rychlosti brany na medium speed
clearbit(GPIOA->OSPEEDR, 11);
clearbit(GPIOA->PUPDR, 10); // vypnuti pull-up/pull-down
clearbit(GPIOA->PUPDR, 11);
setbit(GPIOA->ODR, 5); // nastaveni logickych urovni pinu
clearbit(GPIOA->ODR, 5);
while (1){
togglebit(GPIOA->ODR, 5); // prepnuti stavu LED
/* smycka, co jen inkrementuje promennou, tj. ceka */
for(i = 0; i < 500000; i++);
}
}
===== Assembler =====
Následující kódy ukazují, jak lze nastavit piny PC0-PC7 jako výstupy (MAM shield) a jak lze blikat se spodní polovinou brány PC.
==== Inicializace LED ====
.global leds_init
.equ rcc_reg, 0x40023800 @ adresa registru RCC
.equ rcc_ahb1enr_offset, 0x30 @ offset registru AHB1ENR
.equ rcc_gpioc_en, 0x0004 @ bit pro povoleni hodin pro GPIOC
.equ gpio_c, 0x40020800 @ adresa registru GPIOC
.equ moder_offset, 0x00 @ offset adresy registru MODER
.equ odr_offset, 0x14 @ offset adresy registru ODR
.equ moder_init, 0x00005555 @ inicializacni hodnota pro registr MODER (mode output)
.equ odr_init, 0x000000F0 @ inicializacni hodnota pro registr ODR (turn off upper 4 leds)
leds_init:
push {R0-R3};
@ Enable GPIOC in RCC->AHB1ENR
ldr R0, =rcc_reg;
ldr R1, =rcc_ahb1enr_offset;
ldr R2, [R0, R1];
ldr R3, =rcc_gpioc_en;
orr R2, R3;
str R2, [R0, R1];
@ Enable 8 Green leds as outputs
ldr R0, =gpio_c;
ldr R1, =moder_offset;
ldr R2, =moder_init;
str R2, [R0, R1];
@ Turn off upper 4 Green leds
ldr R1, =odr_offset;
ldr R2, =odr_init;
str R2, [R0, R1];
pop {R0-R3};
bx lr;
==== Blikání LED ====
.global leds_blink
.equ gpio_c, 0x40020800 @ adresa registru GPIOC
.equ odr_offset, 0x14 @ offset adresy registru ODR
.equ odr_led_xor, 0x000000FF @ XOR mask for bottom 8 bits (8 green leds)
leds_blink:
push {R0-R3};
@ Toggle 8 Green leds
ldr R0, =gpio_c;
ldr R1, =odr_offset;
ldr R2, [R0, R1];
ldr R3, =odr_led_xor;
eor R2, R3
str R2, [R0, R1];
pop {R0-R3};
bx lr;
==== 500ms Delay ====
Následující program předpokládá kmitočet procesoru 16 MHz pro zpoždění 500 ms
.global delay_loop
.equ count_1ms, 7999 @ pocet opakovani na 1 ms
.equ delay, 500 @ zpozdeni 500 ms
delay_loop:
push {R0-R1};
ldr R1, =delay
// Load counter for 1ms delay
load_1ms:
ldr R0, =count_1ms
loop:
// Loop through the counter to 1 ms
sub R0, #1
bne loop
// Loop through the number of ms (delay value)
sub R1, #1
bne load_1ms
pop {R0-R1};
bx lr;
==== Hlavní smyčka ====
Pokud se používá kombinace jazyka C a Assembleru, je třeba přejmenovat hlavní smyčku main jazyka C (pokud existuje) nebo daný soubor kompletně smazat, popřípadě přejmenovat název funkce, která se spouští po restartu mikrokontroléru. V opačném případě nastane konflikt názvů funkcí/podprogramů.
.global main
.extern leds_init
.extern leds_blink
.extern delay_loop
main:
bl leds_init;
loop:
bl leds_blink;
bl delay_loop;
b loop;