為了學習STM32時比較踏實,有必要了解固件庫底層是怎么操作的
GPIOA~F首地址
GPIOA | 0x4002 0000 |
GPIOB | 0x4002 0400 |
GPIOC | 0x4002 0800 |
GPIOD | 0x4002 0C00 |
GPIOE | 0x4002 1000 |
GPIOF | 0x4002 1400 |
以GPIOF口的GPIO_OSPEEDR寄存器為例
1 typedef unsigned int uint32; 2 //GPIOF內存塊的首地址 3 #define GPIOF_BASE (0x4002 1400) 4 //GPIO口寄存器 5 #define GPIO_MODER *(uint32 *)(GPIO_BASE+0x00) 6 #defien GPIO_OTYPER *(uint32 *)(GPIO_BASE+0x04) 7 #define GPIO_OSPEEDR *(uint32 *)(GPIO_BASE+0x08) 8 #define GPIO_PUPDR *(uint32 *)(GPIO_BASE+0x0C) 9 #define GPIO_IDR *(uint32 *)(GPIO_BASE+0x10) 10 #define GPIO_ODR *(uint32 *)(GPIO_BASE+0x14) 11 #define GPIO_LCKR *(uint32 *)(GPIO_BASE+0x1C) 12 #define GPIO_AFRL *(uint32 *)(GPIO_BASE+0x20) 13 #define GPIO_AFRH *(uint32 *)(GPIO_BASE+0x24)
這樣的話,我們如果要令GPIO_MODE寄存器的值全為F,GPIO_MODE=0xFFFF FFFF.
像上面這樣定義寄存器有一個缺點,就是這只是定義了一個GPIO口,如果要把所有GPIO口都定義了,那將會有很多這樣的定義,這樣太麻煩,而且也不太好閱讀。為了方便定義寄存器,我將用結構體,從上面寄存器的偏移地址可以看出,每個寄存器都是一個接着一個有序的排列,這就類似於C語言中的結構體。所以我們可以利用結構體來簡化定義。
1 typedef unsigned int uint32; 2 typedef unsigned short int uint16; 3 #define GPIOA_BASE (0x4002 0000) 4 #define GPIOB_BASE (0x4002 0400) 5 #define GPIOC_BASE (0x4002 0800) 6 typedef struct 7 { 8 uint32 GPIO_MODER; 9 uint32 GPIO_OTYPER; 10 uint32 GPIO_OSPEEDR; 11 uint32 GPIO_PUPDR; 12 uint32 GPIO_IDR; 13 uint32 GPIO_ODR; 14 uint32 GPIO_LCKR; 15 uint16 GPIO_AFRL; 16 uint16 GPIO_AFRH; 17 }GPIO_TypeDef; 18 19 #define GPIOA (GPIO_TypeDef *)GPIOA_BASE; 20 #define GPIOB (GPIO_TypeDef *)GPIOB_BASE; 21 #define GPIOC (GPIO_TypeDef *)GPIOC_BASE; 22 23 GPIOA->GPIO_MODER=0xffffff;
首先,我們定義每個GPIO的內存塊的首地址,然后定義一個結構體,里面的成員要按順序寫好寄存器的別名,接着我們用第19的宏定義,將GPIO的內存塊首地址強制轉換成指向結構體的指針,也就是結構體的首地址就是GPIO內存塊的首地址,最后我們可以利用成員符號,對每個寄存器進行寫入數據或者讀取數據。
STM32中固件庫到底是什么
STM32內部里有一個叫總線的東西有APB1,APB2,APB3,AHB1,AHB2總線,總線也是有地址的,固件庫是怎么利用總線的地址來尋到每個寄存器呢?
1 #define PERIPH_BASE ((uint32_t)0x40000000) 2 #define APB1PERIPH_BASE PERIPH_BASE 3 #define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) 4 #define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000) 5 #define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000) 6 7 #define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000) 8 #define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400) 9 #define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800) 10 #define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00) 11 #define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000) 12 #define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400) 13 #define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800) 14 #define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00) 15 #define GPIOI_BASE (AHB1PERIPH_BASE + 0x2000) 16 #define GPIOJ_BASE (AHB1PERIPH_BASE + 0x2400) 17 #define GPIOK_BASE (AHB1PERIPH_BASE + 0x2800)
原理跟上面不一樣只不過,固件庫利用總線的首地址來尋找每個外設的地址。