主要內容
- 如何辨別STM32芯片的正方向
- STM32芯片架構圖
- 什么叫存儲器映射
- 什么叫寄存器映射
一:如何辨別STM32芯片的正方向
- 看絲印左邊逆時針為第一個引腳
- 在芯片表面有一個小圓點逆時針為第一引腳
二:STM32芯片架構圖
(對於這兩個圖的理解可以參考STM32參考手冊 驅動單元由ARM 粉色部分位外設由ST設計,主要學習APB1 APB2 兩個總線(兩個總線速度不同)中的外設)
三:什么叫存儲器映射
存儲器本身不具有地址信息,它的地址是由芯片廠商(ST)或用戶分配,給存儲器分配地址的過程就稱為存儲器映射。
給存儲器分配地址的過程叫存儲器映射,再分配一個地址叫重映射。
下圖中的block0-7就相當於是存儲器。
ARM的Cortex內核位32位,共有2^32=4GB的內存,ARM將4GB的內存分為8塊,每塊512Mb,分別位block0-7,如圖
其中ARM規定block0中,規定ST等這類公司只能將flash(程序)在其中,雖然由很多剩余,但仍要這么放置,為以后着想。其他的block也規定。
下面我給出ARM規定block規定的block0-7放的相應外設圖以及相應的地址(結合第二個圖):
我們在學習的時候主要學習block中的外設。 我們編程的時候主要是對block2中的外設對應的地址進行編程,然后通過GPIO輸出相應的高低電平
四:什么叫寄存器映射
給有特定功能的內存單元取一個別名,這個別名就是我們經常說的寄存器,這個給已經分配好地址的有特定功能的內存單元取別名的過程就叫寄存器映射。
例如我們在51單片機中為什么可以用 P0=0xFF 點亮小燈;這是因為在其頭文件中reg52.h中利用sfr這個關鍵字定義了 sfr P0=0x80;這就意味這我們可以用P0代表80這個地址單元。但是在STM32中沒有這個關鍵字。那它是如何實現的呢,在STM32參考手冊中GPIOx-ODR的低十六位全位1即可點亮16個小燈,我們取x位B端口,GPIOB的起始地址位0x4001 0C00-0x4001 0FFF在這段地址中有很多的寄存器包括ODR(偏移地址位0Ch),這ODR這個寄存的地址為0x4001 0c0c(絕對地址)。
例如我們要實現GPIOB 16位全部輸出高電平,則
*(unsigned int*)(0x40010C0C) = 0xFFFF;
但是這樣有點麻煩可以這樣(宏定義)
#define GPIOB_ODR (unsignedint*)(0x40010C0C) * GPIOB_ODR = 0xFF;
或
#define GPIOB_ODR *(unsignedint*)(0x40010C0C) GPIOB_ODR = 0xFF;
這就是寄存器映射。
下面我們嘗試一下自己寫TM32的寄存器映射以GPIOB為例(ST公司其實已經寫好):
GPIOB掛載到APB2總線上
計算過程:
- 先找到外設所在總線的基地址0x4000 0000,然后在找到(APB2)偏移地址0x0001 0000 兩者相加 0x4001 0000
- 然后找到(GIOPB)相對於APB2總線的偏移地址為0x0000 0C00,加上一個結果得 0x4001 0C00
- 然后我們找到ODR相對於GPIOB的偏移地址為0x0c 加上上一個結果得0x4001 0C0C 就得到我們想要找的ODR的地址。
代碼:
第一種
總線和外設基址宏定義
- 上述我們想要實現的代碼(上圖的一部分)為
#define PERIPH_BASE ((unsigned int)0x40000000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) #define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) #define GPIOB_ODR *(unsignedint*)(GPIOB_BASE+0x0C) // PB0輸出輸出低電平 GPIOB_ODR &= ~(1<<0); // PB0輸出輸出高電平 GPIOB_ODR |= (1<<0);
2. &= ~ |= +移位操作 可以避免更改其它位。
第二種
1小方法(使用結構體指針訪問寄存器)
我們發現各個寄存器的相對地址相差4個字節,那么我們可以將這些寄存器定義位一個結構體,這些寄存器定義為無符號int型,將結構體的地址定義為GPIOB的地址0x4001 0C00 仍可實現上面的功能。
如圖(官方結構體封裝)
使用結構體指針訪問寄存器
2小方法(定義GPIO端口基地址指針)
其實這些官方都已經為我們寫好固件庫,我們只需要理解過程,這樣在以后運用的時候能夠加深印象。