5.1 實(shí)驗(yàn)內(nèi)容
通過本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容:
? FMC控制器原理;
? FMC擦寫讀操作;
5.2 實(shí)驗(yàn)原理
5.2.1 FMC控制器原理
FMC即Flash控制器,其提供了片上Flash操作所需要的所有功能,在GD32F303系列MCU中,F(xiàn)lash前256K字節(jié)空間內(nèi), CPU執(zhí)行指令零等待,具有相同主頻下最快的代碼執(zhí)行效率。FMC也提供了頁擦除,整片擦除,以及32位整字/16位半字/位編程等閃存操作。GD32F303系列MCU支持最大3M Flash空間,可以提供業(yè)內(nèi)最大Flash的相關(guān)產(chǎn)品。
GD32F303系列MCU的Flash結(jié)構(gòu)如下圖所示。由該圖可知,GD32F303系列MCU可以支持最大3M的Flash空間,前256頁為2KB每頁,共512KB空間,后面的空間為4KB每頁,信息塊為存儲內(nèi)部出廠BOOTLOADER,中容量的GD32F303系列產(chǎn)品空間為2KB,大容量的GD32F303系列產(chǎn)品空間為6KB,互聯(lián)型的GD32F305/307系列產(chǎn)品空間為18KB,主要是由于不同的產(chǎn)品所支持的ISP燒錄接口不同,所需要的代碼空間也會有差別。可選字節(jié)塊存儲的是選項(xiàng)字節(jié),其空間大小為16個(gè)字節(jié),地址范圍為0x1FFFF800-0x1FFFF80F,本章主要講解FMC的操作,有關(guān)選項(xiàng)字節(jié)操作可以參考選項(xiàng)字節(jié)操作實(shí)驗(yàn)。
有關(guān)Flash擦寫操作均需要先解鎖Flash,然后進(jìn)行擦寫操作,擦寫完成后再進(jìn)行鎖Flash,注意Flash特性只能由1寫0,也就是Flash需要先擦除才能寫入新的數(shù)據(jù),如果確保寫入地址的數(shù)據(jù)為全0xFF,也可以直接寫入。讀取Flash數(shù)據(jù)可以采取直接尋址的方式進(jìn)行讀取。
下面為各位讀者介紹Flash擦寫讀的相關(guān)操作。
5.2.2 Flash擦除操作原理
Flash擦除可分為頁擦除以及整片擦除,如下圖所示,頁擦除時(shí)間典型值為48ms,256KB Flash的塊擦除時(shí)間典型值為2S。
有關(guān)Flash的相關(guān)操作均在gd32f30x_fmc.c中實(shí)現(xiàn),下面介紹下擦除實(shí)現(xiàn)的函數(shù),如下表所示。
5.2.3 Flash寫入編程操作原理
GD32F303系列MCU可支持32位整字編程/16位板字以及位編程,如下圖所示,F(xiàn)lash 32位整字編程時(shí)間典型值為47.5us。
有關(guān)Flash編程實(shí)現(xiàn)函數(shù)如下表所示。
? 注意:fmc_word_reprogram可以在不用擦除的情況下直接進(jìn)行位編程,但僅可實(shí)現(xiàn)將1編程為0,比如若調(diào)用以上fmc_word_reprogram(0x08001000,0xFE)語句,即實(shí)現(xiàn)將最低位編程為0,若0x08001000原始數(shù)據(jù)為0x81,則執(zhí)行完后改地址數(shù)據(jù)為0x80。
5.2.4 Flash讀取操作原理
Flash讀取可以采用直接尋址的方式進(jìn)行操作,具體可參考以下示例代碼。
C
uint32_t read_data;
read_data = *(uint32_t *)0x08001000;
? 注意:有關(guān)Flash有以下參數(shù)讀者需要了解,GD32F303系列MCU的內(nèi)部Flash具有至少10萬次的擦寫次數(shù)以及20年的數(shù)據(jù)保持能力,但需注意,隨著擦寫次數(shù)的增加數(shù)據(jù)保持時(shí)間會下降。
5.3 硬件設(shè)計(jì)
本例程不涉及硬件電路。
5.4 代碼解析
5.4.1 Flash寫入16bit雙字節(jié)函數(shù)
Flash寫入雙字節(jié)操作函數(shù)如下所示,寫入的過程主要分為擦寫兩個(gè)操作,由于Flash特有特性,需要先擦除才可以寫入,因而需要確保寫入地址的初識數(shù)據(jù)為0xFF。另外GD32F303具有雙bank,且不同bank的頁大小具有差異,本函數(shù)可以實(shí)現(xiàn)根據(jù)地址識別對應(yīng)頁并進(jìn)行擦除的功能,使用上非常方便,使用者只需要關(guān)心擦寫的起始地址以及數(shù)據(jù)和長度即可,擦寫的位置函數(shù)中會進(jìn)行實(shí)現(xiàn)。
C
void fmc_write_data_16b(uint32_t write_start_addr, uint16_t *data_buf, uint16_t data_lengh)
{
uint32_t write_addr,erase_addr;
uint16_t data_write_num=0;
int16_t data_earse_num;
/* 解鎖FMC */
fmc_unlock();
/* 清除BANK0和BANK1的錯(cuò)誤標(biāo)志 */
fmc_flag_clear(FMC_FLAG_BANK0_PGERR|FMC_FLAG_BANK0_WPERR|FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK1_PGERR|FMC_FLAG_BANK1_WPERR|FMC_FLAG_BANK1_END);
erase_addr = write_start_addr;
data_earse_num = data_lengh;
/* 若寫入起始地址加上總長*2小于0x08080000,說明需要擦寫的數(shù)據(jù)均在BANK0,頁大小為2K/頁 */
if((write_start_addr+data_lengh*2)<0x08080000)
{
/* 若寫入地址為頁起始地址 */
if(write_start_addr%2048 == 0)
{
for(;data_earse_num>0;)
{
fmc_page_erase(erase_addr);
erase_addr+=2048;
data_earse_num-=1024;
}
/*若寫入地址不是頁起始地址*/
}else{
for(;(data_earse_num>0||erase_addr>=write_start_addr+data_lengh*2);)
{
fmc_page_erase(erase_addr);
erase_addr+=2048;
data_earse_num-=1024;
}
}
/* 若寫入地址加上寫入長度*2大于0x08080000,說明擦寫的數(shù)據(jù)可能跨BANK或者均在BANK1,頁大小有差別 */
}else{
/* 如果起始地址小于0x08080000,說明跨BANK */
if(write_start_addr<0x08080000)
{
/* 首先擦除BANK0部分所需頁 */
for(;erase_addr<0x08080000;)
{
fmc_page_erase(erase_addr);
erase_addr+=2048;
}
/* 然后擦除BANK1部分所需頁 */
erase_addr = 0x08080000;
for(;erase_addr<=write_start_addr+data_lengh*2;)
{
fmc_page_erase(erase_addr);
erase_addr+=4096;
}
}else{
/*若寫入地址大于等于0x08080000,說明均在BANK1,頁大小為4K/頁*/
if(write_start_addr%4096 == 0) ?/* 若寫入地址為頁起始地址 */
{
for(;data_earse_num>0;)
{
fmc_page_erase(erase_addr);
erase_addr+=4096;
data_earse_num-=2048;
}
}else{
/*若寫入地址不是頁起始地址*/
for(;(data_earse_num>0||erase_addr>=write_start_addr+data_lengh*2);)
{
fmc_page_erase(erase_addr);
erase_addr+=4096;
data_earse_num-=2048;
}
}
}
}
/* 寫入數(shù)據(jù) */
write_addr = write_start_addr;
for(data_write_num = 0; data_write_num<data_lengh;data_write_num++)
{
fmc_halfword_program(write_addr, data_buf[data_write_num]);
write_addr += 2;
}
fmc_lock();
}
5.4.2 Flash讀取數(shù)據(jù)函數(shù)
Flash讀取數(shù)據(jù)函數(shù)如下所示,采用直接尋址的方式,讀取雙字節(jié)數(shù)據(jù)。
C
uint16_t fmc_read_data_16b(uint32_t write_read_addr)
{
return *(uint16_t *)write_read_addr;
}
5.4.3 主函數(shù)
主函數(shù)如下所示,通過該函數(shù)實(shí)現(xiàn)對flash起始地址為0x08001000的前20個(gè)字節(jié)擦寫以及讀取的驗(yàn)證。
C
int main(void)
{
uint16_t read_num =0;
uint8_t i_num;
bsp_led_group_init();
fmc_write_data_16b(WRITE_START_ADDR,write_data,10);
for(read_num=0;read_num<10;read_num++)
{
read_data[read_num] = fmc_read_data_16b(WRITE_START_ADDR+read_num*2);
}
for(i_num=0;i_num<10;i_num++)
{
if(read_data[i_num]!=write_data[i_num])
{
bsp_led_on(&LED0);
}else{
bsp_led_on(&LED1);
}
}
while (1)
{
}
}
5.5 實(shí)驗(yàn)結(jié)果
將本實(shí)驗(yàn)燒錄到紅楓派實(shí)驗(yàn)板中,運(yùn)行后可以觀察到LED1常亮,表明擦寫以及讀取實(shí)驗(yàn)正常。
紅楓派開發(fā)板使用手冊:??????????????????????????????????????????????????GD32F303紅楓派使用手冊 - 飛書云文檔 (feishu.cn)