零基础国产GD32单片机编程入门(八)内部片上FLASH读写实战含源码

一.概要

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读写操作。

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值