STM32學習之存儲器映射及位帶 (STM32F401ZGT6)

  STM32是32位的芯片,意味着有從0x00000000~0xFFFFFFFF 4G也就是32位的尋址空間,在設計芯片的時候,採用的是ARM所設計的架構,ST(意法半導體)公司在基於ARM的對芯片添加了本身的外設。架構

注意:這裏是一個地址空間存放一個字節,即1Byte學習

  ARM規定:ui

Vendor-specific memory 511MB 存放特定廠商的代碼spa

Private peripheral bus  1M 物理總線設計

External device  1.0GB 片上外設不夠用時,外擴在此區域3d

Extermal RAM  1.0GB  RAM空間不夠用時,外擴在此區域指針

peripheral 0.5GB 外設都在此區域 如 GPIO口,定時器等等code

SRAM 0.5GB 用來存放運行時的數據blog

Code(Flash) 0.5GB 用來存放相應的代碼和數據 ip

 

ST公司又根據ARM的劃分添加了相應的外設

 

 以GPIO口爲例:咱們操做GPIO口其實是操做地址爲0x40020000~0x400223FF的寄存器

ST的封裝以下:

 

GPIO_TypeDef * 是一個結構體指針類型,而這個結構體的地址爲各個端口號的基地址,

 

地址計算爲:PERIPH_BASE設備的基地址加上0x00020000的偏移地址爲AHB1的地址,AHB1的地址加上各個端口的偏移地址即爲各個GPIO口的基地址,再加上每一個端口上寄存器的偏移量就獲得了該寄存器的地址。

重寫GPIOF的寄存器

#define GPIOF_BASEADDR   0x40021400
#define rGPIOF_MODER    *(uint32_t *)(GPIOF_BASEADDR+0x00)
#define rGPIOF_OTYPER   *(uint32_t *)(GPIOF_BASEADDR+0x04)
#define rGPIOF_OSPEEDR  *(uint32_t *)(GPIOF_BASEADDR+0x08)
#define rGPIOF_PUPDR    *(uint32_t *)(GPIOF_BASEADDR+0x0C)


void LED_myCOnfig(void) { RCC->AHB1ENR |= (1<<5); rGPIOF_MODER &=~ (3<<12); rGPIOF_MODER |= (1<<12); rGPIOF_OTYPER &=~ (1<<6); rGPIOF_OSPEEDR &=~ (3<<12); rGPIOF_OSPEEDR |= (2<<12); rGPIOF_PUPDR &=~ (3<<12); }

位帶:

 在stm32中由於是對寄存器的位操做,若是咱們想要像51單片機那樣相似p1=1的位變量操做,就要使用ARM在設計內核架構時留的位帶操做。

什麼是位帶?

位帶是基於ARM提供的位段機制,將位操做變爲字操做的一種操做機制。

只有0x20000000~0x200FFFFF和0x40000000~0x400FFFFF這兩部分有位段的映射,其中0x20000000~0x200FFFFF和0x40000000~0x400FFFFF這兩個1MB的空間叫作位段區,0x22000000~0x23FFFFFF和0x42000000~0x43FFFFFF這兩部分叫作別名區,位段區的每個位(1bit)都對應別名區的每個字(4Byte),咱們向別名區相應的字中寫入0或1就是向對應的位段區寫入0或1.

 

而位帶的使用方法是根據位段區的相應位計算出別名區的地址,而後再經過指針對該地址進行操做便可。

以PF6爲例  GPIOF的基地址爲 0x40021414

計算出GPIOF的基地址相對於位段基地址偏移量  -- 字節

0x40021414 - 0x40000000 = 0x21414

再乘以8轉換成GPIOF端口的第六個管腳偏移多少位

0x21414 * 8 + 6

計算別名區的偏移量

(0x21414 * 8 + 6)*4

這裏由於是位段區每偏移一位,別名區偏移4個字節,因此得出來的值要乘以4來轉換成偏移的字節數

別名區的地址  --偏移量 + 基地址

0x42000000 + (0x21414 * 8 + 6)*4 

 

換算的公式以下:

位段區addr  bit

別名區基地址:

       (Adrr &0xF0000000) +0x2000000

別名區的偏移量:

       ((Addr & 0xFFFFF)*8 + bit)*4

別名區地址:

       (Adrr &0xF0000000) +0x2000000 +( (Addr & 0xFFFFF)*8 + bit)*4

 

 

#include "stm32f4xx.h"
//先計算別名區對應的地址
#define BITBAND(addr,bit) (((addr&0xf0000000)+0x2000000)+((addr&0xfffff)*8+bit)*4)

//操道別名區
#define MEM_ADDR(addr,bit)  *(volatile unsigned int *)BITBAND(addr,bit)
    
//ODR
#define PAout(bit) MEM_ADDR((unsigned int)&GPIOA->ODR,bit) 
#define PBout(bit) MEM_ADDR((unsigned int)&GPIOB->ODR,bit)
#define PCout(bit) MEM_ADDR((unsigned int)&GPIOC->ODR,bit)
#define PDout(bit) MEM_ADDR((unsigned int)&GPIOD->ODR,bit)
#define PEout(bit) MEM_ADDR((unsigned int)&GPIOE->ODR,bit)
#define PFout(bit) MEM_ADDR((unsigned int)&GPIOF->ODR,bit)
#define PGout(bit) MEM_ADDR((unsigned int)&GPIOG->ODR,bit)
#define PHout(bit) MEM_ADDR((unsigned int)&GPIOG->ODR,bit)
    
//IDR
#define PAin(bit) MEM_ADDR((unsigned int)&GPIOA->IDR,bit)
#define PBin(bit) MEM_ADDR((unsigned int)&GPIOB->IDR,bit)
#define PCin(bit) MEM_ADDR((unsigned int)&GPIOC->IDR,bit)
#define PDin(bit) MEM_ADDR((unsigned int)&GPIOD->IDR,bit)
#define PEin(bit) MEM_ADDR((unsigned int)&GPIOE->IDR,bit)
#define PFin(bit) MEM_ADDR((unsigned int)&GPIOF->IDR,bit)
#define PGin(bit) MEM_ADDR((unsigned int)&GPIOG->IDR,bit)
#define PHin(bit) MEM_ADDR((unsigned int)&GPIOG->IDR,bit)

這樣,在操做時就能夠直接將PF(6)=0使led亮了。

 

 

想要一塊兒學習的須要資料的小夥伴,或者有疑問的小夥伴均可以聯繫我共同窗習,交流QQ:1459059585

相關文章
相關標籤/搜索