STM32存儲器映射和寄存器映射

存儲器映射

  對於Cortex-M3來說,有一塊4G大小的存儲器空間。存儲器映射指的是芯片廠商爲這個空間分配地址的操做。這4G空間被均勻地劃分爲8個大小爲512MB的存儲塊(block),而且每一個塊都各具特點。下面主要介紹Block1~Block2。ui

Block0

  Block0的地址範圍爲0x0000_0000~0x1FFF_FFFF。它被設計用來存放代碼程序,其中主要有FLASH、SYSTEM MEMORY和OPTION BYTES:spa

    FLASH:起始地址爲0x0800_0000,存放用戶程序和掉電保存數據。FLASH容量從16k到512k不等,以STM32F10x8系列爲例,8表明FLASH容量爲64k,因此結束地址就爲0x0801_FFFF。設計

    SYSTEM MEMORY:系統存儲器,存放了BootLoader程序,禁止用戶改動,該程序主要用於串口下載。指針

    OPTION BYTES:選項字節,能夠配置讀寫保護、看門狗等。code

  這裏簡單說一下地址分配。整塊4G存儲器開始地址標爲0x0000_0000,結束地址爲0xFFFF_FFFF,地址表示採用了十六進制,一共8*4=32bit,而2^32恰好就是4G。存儲器的基本單元是一個字節,每一個地址都對應這樣一個單元,所以用32位地址來表示,其容量恰好就是4GB。同理,根據Block0的起止地址,也能夠計算獲得其容量爲512MB。blog

 

Block1

  Block1的地址範圍爲0x2000_0000~0x3FFF_FFFF。其中0x2000_0000~0x2000_FFFF被劃爲SRAM,主要是用於程序運行的堆棧開銷。內存

 

Block2

  Block2的地址範圍爲0x4000_0000~0x5FFF_FFFF。這塊空間被充分用做外設寄存器。根據總線不一樣,將外設分爲三大塊,第一塊是APB1總線外設,起始地址爲0x4000_0000;第二塊是APB2總線外設,起始地址爲0x4001_0000;最後一塊爲AHB總線外設,起始地址爲0x4001_8000。it

 

 

寄存器映射

  寄存器映射主要針對於Block2。這種映射不一樣於存儲器映射的分配地址操做,而是在程序中對具備特定功能的內存單元進行命名的過程,每一個內存單元都是四個字節,稱做寄存器。例如GPIOA外設有個寄存器地址範圍爲0x4001_0800~0x4001_0803,該寄存器是用來配置GPIOA部分端口工做模式的,所以被映射爲GPIOA_CRL。由此可知,這種映射方便了對寄存器的訪問操做,由於若是每次訪問寄存器都要查地址範圍的話是很痛苦的。class

GPIOA_CRL

  如何實現這種映射的呢?以GPIOA_CRL爲例,其映射地址 = 外設總基地址(塊基地址)+ 總線相對於外設總基地址的偏移 + 具體外設基地址相對於總線基地址的偏移 + 寄存器相對於具體外設基地址的偏移。配置

  外設總基地址剛好就是Block2的起始地址0x4000_0000;

  GPIO屬於APB2總線外設,所以查閱芯片手冊以下圖所示,咱們其實直接能夠獲得APB2起始地址和GPIOA的起始地址,可是程序中通常不這麼作,而是以偏移量來表示層次關係。從圖中可計算到總線相對於外設總基地址的偏移爲0x1_0000,GPIOA相對於APB2基地址的偏移爲0x800。

    

  再查閱GPIO的寄存器組,以下圖所示。能夠獲得CRL寄存器相對於GPIO基地址偏移爲0x00。綜上GPIOA_CRL的基地址爲:0x4000_0000+0x1_0000+0x800+0x00。

    

 

程序中地址映射

  STM32固件庫中,有個頭文件叫stm32f10x.h,其中就定義了寄存器的映射,部分代碼以下:

 

  外設基地址PERIPH_BASE:

#define PERIPH_BASE           ((uint32_t)0x40000000)

 

  總線基地址,在外設基地址上加上偏移:

#define APB1PERIPH_BASE       PERIPH_BASE
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)

  

  GPIO外設基地址,在APB2總線基地址上加上偏移:

#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE            (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE            (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE            (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE            (APB2PERIPH_BASE + 0x2000)

 

  定義GPIO外設結構體,由於結構體成員在內存中是連續的,這種形式與寄存器組很是相似,因此用結構體可以很好的管理寄存器:

typedef struct { __IO uint32_t CRL; __IO uint32_t CRH; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR; } GPIO_TypeDef;

 

  定義GPIOA結構體指針,由於單單定義GPIO外設結構體,並不能肯定其內存地址,所以用指針將其綁定到GPIOA外設基地址:

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

 

  訪問寄存器方式的對比,映射訪問明顯更爲直觀:

//直接的地址訪問
*(unsigned int *)(0x4001_0800)|= 0x0001; //映射訪問
GPIOA->CRL |= 0x0001;
相關文章
相關標籤/搜索