文章目录
一.概要
GD32F103C8T6是一款强大而灵活的微控制器,它的片内Flash存储器可以用来存储有关代码和数据,在实际应用中,我们也需要对这个存储器进行读写操作。
GD32F103C8T6单片机的FLASH主存储块按页组织,每页1KB。页面典型的用途就是用于按页擦除FLASH,从这点来看,页面有点像通用FLASH的扇区。
本文介绍了GD32F103C8T6的FLASH存储空间,FLASH数据的读写,以及读写保护等。
二.内部FLASH地址空间排布
根据用途,GD32片内的FLASH分成两部分:主存储块、信息块。
主存储块用于存储程序,我们写的程序一般存储在这里,用户还可以存储数据。
信息块又分成两部分:系统存储器、选项字节。 系统存储器存储用于存放在系统存储器自举模式下的启动程序(BootLoader),当使用ISP方式加载程序时,就是由这个程序执行。这个区域由芯片厂写入BootLoader,然后锁死,用户是无法改变这个区域的。 选项字节存储芯片的配置信息及对主存储块的保护信息,主要有写保护字节,读保护字节等。
GD32F103C8T6是中容量产品主存储块64-128KB, 每页1KB,系统存储器2KB(启动代码),存储空间如下图:
三.内部FLASH主要特色
闪存控制器(FMC),提供了片上闪存需要的所有功能。在闪存的前256K字节空间内,CPU执行指令零等待。FMC也提供了页擦除,整片擦除,以及32位整字或16位半字编程闪存等操作。
1.最多支持高达3M字节的片上闪存可用于存储指令或数据;
2.在闪存的前256K字节空间内,CPU执行指令零等待;在此范围外,CPU读取指令存在较
长延时;
3.对于闪存大于512KB的GD32F10x_CL和GD32F10x_XD,使用了两片闪存;前512KB容
量在第一片闪存(bank0)中,后续的容量在第二片闪存(bank1)中;
4.对于主存储闪存容量不多于512KB的GD32F10x_CL和GD32F10x_HD,只使用了bank0;
5.对于GD32F10x_MD,闪存页大小为1KB。GD32F10x_CL和GD32F10x_HD,
GD32F10x_XD,bank0的闪存页大小为2KB,bank1的闪存页大小为4KB;
6.支持32位整字或16位半字编程,页擦除和整片擦除操作;
7.大小为16字节的可选字节块可根据用户需求配置;
8.具有安全保护状态,可阻止对代码或数据的非法读访问;
9.具有擦除和编程保护状态,可阻止意外写操作。
四.内部FLASH读写操作
1.FLASH数据读取
内置闪存模块可以在通用地址空间直接寻址,任何32位数据的读操作都能访问闪存模块的内容并得到相应的数据。
以下是一个示例代码,展示了如何在C语言中读取GD32F103的内部Flash数据
// 假设我们要读取的数据在Flash地址0x8000000的位置
#define FLASH_ADDRESS 0x8000000
uint32_t data = (uint32_t)FLASH_ADDRESS;
2.FLASH数据擦除
GD32F103的FLASH在写入数据前确实需要先进行擦除操作。这是因为FLASH存储器的特性决定的,与其它FLASH存储器一样,GD32F103的FLASH也是按页(扇区)进行管理的,FLASH可以按页擦除,也可以整片擦除。
按页擦除操作流程:
3.FLASH数据写入
对主存储器数据写入每次可以写入16位。
FLASH数据写入操作流程:
五.内部FLASH的各种保护
1.写保护
GD32F103的FLASH写保护可以通过编程特定的选项字节来启用或禁用,以便保护特定的内存区域免受未经授权的写入,用于避免误写/误擦除操作。通过配置可选字节块的WP [31:0]某位为0可以单独使能某几页的保护功能。
2.读保护
将Flash设置为读保护的目的,是为了防止其他人通过STLINK等仿真器,将Flash中的程序读取出来(设想一下,你辛辛苦苦研发的产品,别人通过仿真器将程序读取出来,再copy一下产品的硬件,就可以生产),所以可以通过将Flash设置为读保护来保护自己的程序。
FMC提供了一个安全保护功能来阻止非法读取闪存。此功能可以很好地保护软件和固件免受非法的用户操作。
未保护状态:当将SPC字节和它的补字节被设置为0x5AA5,系统复位以后,闪存将处于非安全保护状态。主存储块和可选字节块可以被所有操作模式访问。
已保护状态:当设置SPC字节和它的补字节值为任何除0x5AA5外的值,系统复位以后,安全保护状态生效。需要注意的是,若该修改过程中,MCU的调试模块依然和外部JTAG/SWD设备相连,需要用上电复位代替系统复位以使得修改后的保护状态生效。在安全保护状态下,主存储闪存块仅能被用户代码访问且前4KB的闪存自动处于页擦除/编程保护状态下。在调试模式下,或从SRAM中启动时,以及从boot loader区启动时,这些模式下对主存储块的操作都被禁止。如果在这些模式下读主存储块,将产生总线错误。
六.FLASH读写例程
刷写FLASH地址从0x08004000开始的地址,内容是0x01234567
硬件准备:
STLINK接GD32F103C8T6开发板,STLINK接电脑USB口。
主要代码
#define FMC_PAGE_SIZE ((uint16_t)0x400U)
#define FMC_WRITE_START_ADDR ((uint32_t)0x08004000U)
#define FMC_WRITE_END_ADDR ((uint32_t)0x08004800U)
uint32_t *ptrd;
uint32_t address = 0x00;
uint32_t data0 = 0x01234567U;
/* calculate the num of page to be programmed/erased */
uint32_t page_num = (FMC_WRITE_END_ADDR - FMC_WRITE_START_ADDR) / FMC_PAGE_SIZE;
/* calculate the num of page to be programmed/erased */
uint32_t word_num = ((FMC_WRITE_END_ADDR - FMC_WRITE_START_ADDR) >> 2);
/*!
\brief erase fmc pages from FMC_WRITE_START_ADDR to FMC_WRITE_END_ADDR
\param[in] none
\param[out] none
\retval none
*/
void fmc_erase_pages(void)
{
uint32_t erase_counter;
/* unlock the flash program/erase controller */
fmc_unlock();
/* clear all pending flags */
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
/* erase the flash pages */
for(erase_counter = 0; erase_counter < page_num; erase_counter++){
fmc_page_erase(FMC_WRITE_START_ADDR + (FMC_PAGE_SIZE * erase_counter));
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
}
/* lock the main FMC after the erase operation */
fmc_lock();
}
/*!
\brief program fmc word by word from FMC_WRITE_START_ADDR to FMC_WRITE_END_ADDR
\param[in] none
\param[out] none
\retval none
*/
void fmc_program(void)
{
/* unlock the flash program/erase controller */
fmc_unlock();
address = FMC_WRITE_START_ADDR;
/* program flash */
while(address < FMC_WRITE_END_ADDR){
fmc_word_program(address, data0);
address += 4;
fmc_flag_clear(FMC_FLAG_BANK0_END);
fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
}
/* lock the main FMC after the program operation */
fmc_lock();
}
/*!
\brief check fmc erase result
\param[in] none
\param[out] none
\retval none
*/
void fmc_erase_pages_check(void)
{
uint32_t i;
ptrd = (uint32_t *)FMC_WRITE_START_ADDR;
/* check flash whether has been erased */
for(i = 0; i < word_num; i++){
if(0xFFFFFFFF != (*ptrd)){
break;
}else{
ptrd++;
}
}
}
/*!
\brief check fmc program result
\param[in] none
\param[out] none
\retval none
*/
void fmc_program_check(void)
{
uint32_t i;
ptrd = (uint32_t *)FMC_WRITE_START_ADDR;
/* check flash whether has been programmed */
for(i = 0; i < word_num; i++){
if((*ptrd) != data0){
break;
}else{
ptrd++;
}
}
}
int main(void)
{
rcu_apb2_clock_config(RCU_APB2_CKAHB_DIV1);//设置主频108M(#define __SYSTEM_CLOCK_108M_PLL_HXTAL (uint32_t)(108000000)),8M外部晶振 (#define HXTAL_VALUE ((uint32_t)8000000))
systick_config();//配置1ms SysTick
rcu_periph_clock_enable(RCU_AF);//AF时钟使能
fmc_erase_pages();//FLASH 擦除
fmc_erase_pages_check();//读出来验证
/* step2: program and check if it is successful. If not, light the LED2. */
fmc_program();//FLASH写入
fmc_program_check();//写入的数据验证
while(1);
}
七.工程源代码下载
通过网盘分享的文件:9.内部FLASH读写.zip
链接: https://pan.baidu.com/s/1B68cERK39wvmuSpiReyWIQ 提取码: g2pe
如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行
CSDN代码
八.小结
在GD32单片机的开发过程中,保存用户数据、实现程序的自我更新等应用场景都离不开对FLASH读写操作。