STM32F429開箱與GPIO測試

最近買了一塊 STM32F429IDISCOVERY 來玩玩

STM32應該算是想學embedded system的經典款,網路上資料也挺多

想說就從這一塊來入手吧

之後應該會陸續寫寫我玩這塊板子的心得

以下先簡單介紹一下這塊板子~

STM32F429IDISCOVERY overview

  • ARM cortex-M4
  • 2MB flash memory
  • 64-MBIT DRAM
  • 3-axis gyroscope
  • LCD display 240x320 resolution touchscreen

今天先測試 STM3 的GPIO功能,做一個LED blink的demo
實作參考 jserv 的 嵌入式系統建構:開發運作於STM32的韌體程式

STM32 reset

首先我們想知道的是,當ARM cortex-M4 reset後,第一步會做什麼
這部份我們可以參考STM32F429的reference mananul
STM32F429有兩根pin : BOOT0, BOOT1, CPU reset後會從這兩根pin的狀態來決定哪一塊memory當boot space

從schematic可以看出來,STM32F429IDISCOVERY選用的default boot space是Main Flash memory

然後我們從 User manual中可以看出來,Flash memory的start address是0x08000000
等開機時,會自動將0x08000000-0x080FFFFF 映射到 0x00000000-0x000FFFFF,所以將bin檔燒在0x08000000,
STM32F429就可以從0x00000000開始執行

Reset後,STM32F429會從 0x00000000 得到 MSP(Main Stack Pointer)。 也就是說,如果你在 0x00000000填0x20001000,
那CPU reset 後 stack將是 0x20000000 - 0x20001000。
接下來 從0x00000001得到 Program Counter,及code第一個指令開始的位址

以上行為可以用C語言達成 :

1
2
asm(".word 0x20001000");
asm(".word main "); //指定起始 為main()的address

講完了reset flow,接下來來實作 LED blink吧!

STM32F429IDISCOVERY 有兩顆可控制的LED

我們這次實作一個讓這兩顆LED交錯閃爍的demo,以下是 C code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#define RCC_AHB1_PERI_ENBLR_ADDR	(*((volatile unsigned long*) (0x40023800 + 0x30) )) 
#define GPIO_G_PORTMODE (*((volatile unsigned long*) 0x40021800 ))
#define GPIO_G_OUTPUT_TYPE (*((volatile unsigned long*) (0x40021800 + 0x4 ) ))
#define GPIO_G_PUPD (*((volatile unsigned long*) (0x40021800 + 0xC ) ))
#define GPIO_G_PORT_SETRESET (*((volatile unsigned long*) (0x40021800 + 0x18) ))


asm(".word 0x20001000");
asm(".word main ");

int main()
{

int i;

RCC_AHB1_PERI_ENBLR_ADDR |= (0x00000001 << 6); /*Enalbe GPIO G clock*/

GPIO_G_PORTMODE |= (0x00000001 << 26 | 0x00000001 << 28); /* Set PG13 PG14 mode to GPIO */
GPIO_G_PORTMODE &= ~(0x00000001 << 27 | 0x00000001 << 29);

GPIO_G_OUTPUT_TYPE &= ~(0x00000001 << 13 | 0x00000001 << 14); /*Set PG13 PG14 to push-pull*/
GPIO_G_PUPD |= (0x00000001 << 27 | 0x00000001 << 29); /*Set PG13 PG14 to pull-down*/

while(1)
{
GPIO_G_PORT_SETRESET = 0x20004000; /*PG13 off, PG14 on*/
for(i = 0 ; i < 100000 ; i++);
GPIO_G_PORT_SETRESET = 0x40002000; /*PG14 off, PG13 on*/
for(i = 0 ; i < 100000 ; i++);
}


return 0;
}

我們可以從User mananul查詢各個 register的memory map

GPIO的控制步驟如下 :

  1. 開啟 AHB1 peripheral clock for GPIO G

  2. PG13 PG14初始化設定 ( GPIO output, push-pull, pull-down )

  3. 輪流閃爍 PG13, PG14

    想要讓 GPIO 輸出HIGH,可以在 15:0 對應的bit set 1
    想要讓 GPIO 輸出LOW, 可以在 31:16 對應的bit set 1
    分開設定的理由是,當你只想控制某跟pin,可以直接寫value,而不用管其他的pin
    做到 atomic的效果

Makefile and loader

Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CROSS_COMPILE ?= arm-none-eabi-

.PHONY: all

all: blink.bin

blink.o: blink.c
$(CROSS_COMPILE)gcc -mcpu=cortex-m4 -mthumb -nostartfiles -c blink.c -o blink.o

blink.out: blink.o blink.ld
$(CROSS_COMPILE)ld -T blink.ld -o blink.out blink.o

blink.bin: blink.out
$(CROSS_COMPILE)objcopy -j .text -O binary blink.out blink.bin

clean:
rm -rf *.o *.out *.bin
1
2
3
4
5
6
7
8
9
SECTIONS 
{
. = 0x0;
.text :
{
*(.text)
}

}

我們使用gcc-arm-none-eabi,這是一款適用於 ARM bare-metal的tool chain
blink.o由blink.c gcc compile後編譯而成

  • -mcpu=cortex-m4:指定mcu為cortex-M4
  • -mthumb: 指定產生Thumb指令,ARM Cortex-M3/M4只支援Thumb2指令
  • -nostartfile: 因為我們自己處理了 ARM reset的動作,所以指定link階段不要使用startup file

blink.out 為 blink.o 經過blink.ld link之後生成的 ELF檔
因為我們的code沒有全域變數,所以 blink.ld中只需要 .text,不需要 .data .bss

最後生成的blink.bin,就是我們要燒進flash的bin file

燒錄

從schematic看的出來,STM32F429IDISCOVERY的電路已經包含ST-Link了,所以USB-mini插上去後就可以直接燒錄,不需要額外的燒錄器。
我們使用官網的 STM32 ST-LINK Utility

燒錄成功後就可以看到 紅、綠兩顆LED開始交替閃爍了
完整code放在 github

Reference