開發(fā)環(huán)境:
MDK:Keil 5.30
開發(fā)板:GD32F207I-EVAL
MCU:GD32F207IK
1 GD32存儲(chǔ)結(jié)構(gòu)的工作原理
1.1 Cortex-M內(nèi)核的存儲(chǔ)器映射
存儲(chǔ)器映射是指把芯片中或芯片外的FLASH,RAM,外設(shè),BOOTBLOCK等進(jìn)行統(tǒng)一編址。即用地址來表示對(duì)象。這個(gè)地址絕大多數(shù)是由廠家規(guī)定好的,用戶只能用而不能改。用戶只能在掛外部RAM或FLASH的情況下可進(jìn)行自定義。
如下圖,是Cortex-M3存儲(chǔ)器映射結(jié)構(gòu)圖。
Cortex-M3是32位的內(nèi)核,因此其PC指針可以指向2^32=4G的地址空間,也就是0x0000_0000 - 0xFFFF_FFFF這一大塊空間。根據(jù)圖中描述,Cortex-M3內(nèi)核將0x0000_0000 - 0xFFFF_FFFF這塊4G大小的空間分成8大塊:代碼、SRAM、外設(shè)、外部RAM、外部設(shè)備、專用外設(shè)總線-內(nèi)部、專用外設(shè)總線-外部、特定廠商等,因此使用該內(nèi)核的設(shè)計(jì)者必須按照這個(gè)進(jìn)行各自芯片的存儲(chǔ)器結(jié)構(gòu)設(shè)計(jì)。
1.2 GD32存儲(chǔ)器結(jié)構(gòu)
首先,我們對(duì)比一下Cortex-M3存儲(chǔ)器結(jié)構(gòu)和GD32存儲(chǔ)器結(jié)構(gòu):
圖中可以很清晰的看到,GD32的存儲(chǔ)器結(jié)構(gòu)和Cortex-M3的很相似,不同的是,GD32加入了很多實(shí)際的東西,如:Flash、SRAM等。只有加入了這些東西,才能成為一個(gè)擁有實(shí)際意義的、可以工作的處理芯片-GD32。
GD32的存儲(chǔ)器地址空間被劃分為大小相等的8塊區(qū)域,每塊區(qū)域大小為512MB。
對(duì)GD32存儲(chǔ)器知識(shí)的掌握,實(shí)際上就是對(duì)Flash和SRAM這兩個(gè)區(qū)域知識(shí)的掌握。
2 FLASH讀寫數(shù)據(jù)
2.1 GD32的Flash
GD32的Flash,嚴(yán)格說,應(yīng)該是Flash模塊。該Flash模塊包括:Flash主存儲(chǔ)區(qū)(Main memory)、Flash信息區(qū)(Information block),以及Flash存儲(chǔ)接口寄存器區(qū)(Flash memory interface)。三個(gè)組成部分分別在0x0000 0000 - 0xFFFF FFFF不同的區(qū)域,GD32F2的Flash結(jié)構(gòu)如下表所示。
【注】信息塊存儲(chǔ)了boot loader,不能被用戶編程或擦除。
GD32的閃存模塊由:主存儲(chǔ)閃存塊、信息塊和選項(xiàng)字節(jié)塊3部分組成。
主存儲(chǔ)器 ,該部分用來存放代碼和數(shù)據(jù)常數(shù)(如加const類型的數(shù)據(jù))。對(duì)于主存儲(chǔ)閃存容量不多于512KB的GD32F20x_CL,閃存頁大小為2KB。對(duì)于主存儲(chǔ)閃存容量不少于768KB的GD32F20x_CL,使用了兩片閃存;前512KB容量在第一片閃存(bank0)中,后續(xù)的容量在第二片閃存(bank1)中。其中bank0的閃存頁大小為2KB, bank1的閃存頁大小為4KB。主存儲(chǔ)閃存的每頁都可以單獨(dú)擦除。
__信息__塊,是用來存儲(chǔ)GD自帶的啟動(dòng)程序,用于串口下載,當(dāng)B0接3.3V,B1接GND時(shí),運(yùn)行的就這部分代碼,用戶選擇字節(jié),則一般用于配置保護(hù)等功能。
選項(xiàng)字節(jié)塊 ,該部分用于控制閃存儲(chǔ)器讀取等,是整個(gè)閃存儲(chǔ)器的控制機(jī)構(gòu)。
對(duì)于主存儲(chǔ)器和信息塊的寫入有內(nèi)嵌的閃存編程管理;編程與擦除的高壓由內(nèi)部產(chǎn)生。
在執(zhí)行閃存寫操作時(shí),任何對(duì)閃存的讀操作都會(huì)鎖定總線,在寫完成后才能正確進(jìn)行,在進(jìn)行讀取或擦除操作時(shí),不能進(jìn)行代碼或者數(shù)據(jù)的讀取操作。
下面對(duì)GD32的存儲(chǔ)器進(jìn)行總結(jié)。
圖中淡藍(lán)色就是你需要知道的。
- Peripherals:外設(shè)的存儲(chǔ)器映射,對(duì)該區(qū)域操作,就是對(duì)相應(yīng)的外設(shè)進(jìn)行操作;
- SRAM:運(yùn)行時(shí)臨時(shí)存放代碼的地方;
- Flash:存放代碼的地方;
- System Memory:GD32出廠時(shí)自帶的你只能使用,不能寫或擦除;
- Option Bytes:可以按照用戶的需要進(jìn)行配置(如配置看門狗為硬件實(shí)現(xiàn)還是軟件實(shí)現(xiàn));
今后,你的編寫代碼、程序運(yùn)行、寄存器設(shè)置、ICP、IAP都依靠這些東西。
2.2 FLASH讀寫實(shí)現(xiàn)
GD32F20x 系列產(chǎn)品的片上 Flash 起始地址時(shí) 0x0800 0000,最大容量可達(dá) 3072 KB。讀操作為 0 等待,可支持字節(jié)、半字(16 bits)和字(32 bits)訪問。 Flash 編程以半字(16 bits)或字(32bits)為單位。擦除可以以頁(page)為單位,也可以進(jìn)行全片擦除(information blocks 除外)。
Flash的寄存器有很多,當(dāng)時(shí)GD的工程師已經(jīng)封裝好了,直接用就可以,我這里就不在貼出來了。
Flash操作很簡單,我們將數(shù)據(jù)寫入到Flash中,再將其讀出來。主要有以下步驟:
1.Flash解鎖操作
2.清除Flash標(biāo)志
3.頁擦除
4.讀寫操作
5.鎖定
核心代碼如下:
#define FLASH_ADR 0x0807F800
/**
* @brief flash test
* @param WriteAddr, InData
* @retval OutData
*/
uint32_t flash_test(uint32_t WriteAddr, uint32_t InData)
{
uint32_t OutData = 0;
//解鎖
fmc_unlock();
//清除標(biāo)志位
fmc_flag_clear(FMC_FLAG_BANK0_PGERR | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_END | FMC_FLAG_BANK1_PGERR | FMC_FLAG_BANK1_WPERR |
FMC_FLAG_BANK1_END);
//要擦出頁的起始地址
fmc_page_erase(WriteAddr);
//寫數(shù)據(jù)
fmc_word_program(WriteAddr, InData);
//鎖定
fmc_lock();
OutData=(*(__IO uint32_t*)(WriteAddr));
return OutData;
}
程序就不講了,這里需要注意一個(gè)C語言的知識(shí)點(diǎn)。
OutData=(*(__IO uint32_t*)(WriteAddr));
這一句很多新手很懵逼,也就是從一個(gè)地址中讀取數(shù)據(jù),多看看指針相關(guān)的知識(shí)就好理解了。
主函數(shù)如下:
/*
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
uint32_t InData = 12345678;
uint32_t OutData;
// systick init
sysTick_init();
//usart init 115200 8-N-1
com_init(COM1, 115200, 0, 1);
// led1 init
led_init(LED1);
printf("InData = %d\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n",InData);
// flash test
OutData= flash_test(FLASH_ADR, InData);
printf("OutData = %d\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n",OutData);
if(OutData == InData)
{
printf("Flash test success !\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\r\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
}
else