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