存盤器映射
對于Cortex-M3來講,有一塊4G大小的存盤器空間,存盤器映射指的是芯片廠商為這個空間分配地址的操作,這4G空間被均勻地劃分為8個大小為512MB的存盤塊(block),并且每個塊都各具特色,下面主要介紹Block1~Block2,
Block0
Block0的地址范圍為0x0000_0000~0x1FFF_FFFF,它被設計用來存放代碼程式,其中主要有FLASH、SYSTEM MEMORY和OPTION BYTES:
FLASH:起始地址為0x0800_0000,存放用戶程式和掉電保存資料,FLASH容量從16k到512k不等,以STM32F10x8系列為例,8代表FLASH容量為64k,所以結束地址就為0x0801_FFFF,
SYSTEM MEMORY:系統存盤器,存放了BootLoader程式,禁止用戶改動,該程式主要用于串口下載,
OPTION BYTES:選項位元組,可以配置讀寫保護、看門狗等,
這里簡單說一下地址分配,整塊4G存盤器開始地址標為0x0000_0000,結束地址為0xFFFF_FFFF,地址表示采用了十六進制,一共8*4=32bit,而2^32剛好就是4G,存盤器的基本單元是一個位元組,每個地址都對應這樣一個單元,因此用32位地址來表示,其容量剛好就是4GB,同理,根據Block0的起止地址,也可以計算得到其容量為512MB,
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,
暫存器映射
暫存器映射主要針對于Block2,這種映射不同于存盤器映射的分配地址操作,而是在程式中對具有特定功能的記憶體單元進行命名的程序,每個記憶體單元都是四個位元組,稱作暫存器,例如GPIOA外設有個暫存器地址范圍為0x4001_0800~0x4001_0803,該暫存器是用來配置GPIOA部分埠作業模式的,因此被映射為GPIOA_CRL,由此可知,這種映射方便了對暫存器的訪問操作,因為如果每次訪問暫存器都要查地址范圍的話是很痛苦的,
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;
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/86884.html
標籤:其他
上一篇:知名KMS模擬器的官方發布網址
