HC32 flash 读写操作

本文详细介绍了HC32F4A0微控制器的Flash特性,包括其双Bank结构、OTP区域配置以及编程、擦除操作。重点讲述了Flash操作与时钟的关系,强调了编程时等待周期的设置,并提供了初始化和编程示例代码。此外,还阐述了单次编程无回读、有回读和连续编程模式,以及扇区和全擦除功能。示例代码展示了如何进行安全的Flash读写操作,包括解锁寄存器、扇区保护以及错误处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HC32 flash 简介

HC32F4A0 的flash是两块独立 FLASH 构成 dual bank。容量高2Mbytes,由两块 1Mbytes 的 FLASH 构成,共 256 个扇区,每个扇区为8Kbytes。 块 0 中扇区 0~扇区 15 为可配置为 OTP 区域。

  • OTP(One Time Program)区域共 134KBytes, 其中 128Kbytes 配置在块 0 地址0x0000_0000~0x0001_FFFF, 6Kbytes 配置在地址 0x0300_00000x0300_17FF。地址0x0300_18000x0300_1AD7 为 OTP 数据锁存区。
  • 编程单位为 4bytes,擦除单位为 8Kbytes
    +在这里插入图片描述

HC32 flash 操作和时钟之间的关系

要正确读取 FLASH 数据,用户需要根据 CPU 动作频率在 FLASH 读模式寄存器
(EFM_FRMC)中正确设定等待周期数(FLWT[3:0])。具体可以参照下表进行相关设置。

在这里插入图片描述
对应相关处理在flash 初始化的时候,更改stc_efm_cfg_t结构体中的u32waitcycle.
eg

int Init(void)
{
   
    /*
     * Clock  <= 40MHZ            EFM_WAIT_CYCLE_0
     * 40MHZ  < Clock <= 80MHZ    EFM_WAIT_CYCLE_1
     * 80MHZ  < Clock <= 120MHZ   EFM_WAIT_CYCLE_2
     * 120MHZ < Clock <= 160MHZ   EFM_WAIT_CYCLE_3
     * 160MHZ < Clock <= 200MHZ   EFM_WAIT_CYCLE_4
     * 200MHZ < Clock <= 240MHZ   EFM_WAIT_CYCLE_5
     */
     
    stc_efm_cfg_t stcEfmCfg;
    en_int_status_t flag1;
    en_int_status_t flag2;

    //解锁对应的寄存器
    UnLock_Flash();

    EFM_StructInit(&stcEfmCfg);     //初始化结构体
    //stcEfmCfg.u32BusStatus  = EFM_BUS_RELEASE; /* Bus release while programming or erasing */
    stcEfmCfg.u32WaitCycle = EFM_WAIT_CYCLE_5; // 5-wait @ 240MHz 
    EFM_Init(&stcEfmCfg);                      // 初始化
    
    do{
   
        flag1 = EFM_GetFlagStatus(EFM_FLAG_RDY0);
        flag2 = EFM_GetFlagStatus(EFM_FLAG_RDY1);
    }while((Set != flag1) || (Set != flag2));  // 等待flash0 和 flash1 准备就绪
    
    /* 加锁所有扇区 */
    Lock_Flash();
    return 0;
}

Flash 的读写操作

FLASH 支持编程,扇区擦除,全擦除操作。FLASH 编程,扇区/全擦除地址末位必须以 4 对齐(末位地址为: 0x0, 0x4, 0x8, 0xC),编程单位是 4bytes, 扇区擦除单位为 8Kbytes,全擦除根据寄存器设定可以是单个 FLASH块也可是两个 FLASH 块。 FLASH 编程方式分为单次编程无回读模式,单次编程回读模式,连续编程模式三种。 FLASH 编程,擦除期间,设定 EFM_FWMC.BUSHLDCTL=0,则总线被占有,直至擦写结束; EFM_FWMC.BUSHLDCTL=1, 则总线被释放,总线可以继续访问另一块 FLASH 地址。 FLASH 编程,擦除前,请把缓存使能及预取指无效

解锁寄存器

复位解除后, FLASH 编程,擦除模式寄存器( EFM_FWMC)处于写禁止状态,需要先解除 FLASH 访问保护寄存器( EFM_FAPRT),然后再解除 EFM_KEY1 的保护.

  • 解除 FLASH 寄存器访问写保护(EFM_FAPRT 先写 0x0123, 再写 0x3210)
  • 解除 EFM_KEY1 锁定(EFM_KEY1 先写 0x01234567, 再写 0xFEDCBA98)
    对应的库函数为EFM_Unlock(),EFM_FWMC_Unlock();在调用的时候一定是先EFM_Unloc() 后EFM_FWMC_Unlock;

单次编程无回读功能

在这里插入图片描述

单编程有回读

在这里插入图片描述
eg

int32_t main(void)
{
   
    stc_efm_cfg_t stcEfmCfg;
    en_int_status_t flag1;
    en_int_status_t flag2;
    uint32_t u32Data = 0xAA5555AAU;
    uint32_t u32Addr;

    /* Unlock peripherals or registers */
    Peripheral_WE();

    /* Configure system clock. HClK = 240MHZ */
    BSP_CLK_Init();
    /* EFM default config. */
    (void)EFM_StructInit(&stcEfmCfg);
    /*
     * Clock <= 40MHZ             EFM_WAIT_CYCLE_0
     * 40MHZ < Clock <= 80MHZ     EFM_WAIT_CYCLE_1
     * 80MHZ < Clock <= 120MHZ    EFM_WAIT_CYCLE_2
     * 120MHZ < Clock <= 160MHZ   EFM_WAIT_CYCLE_3
     * 160MHZ < Clock <= 200MHZ   EFM_WAIT_CYCLE_4
     * 200MHZ < Clock <= 240MHZ   EFM_WAIT_CYCLE_5
     */
    stcEfmCfg.u32WaitCycle = EFM_WAIT_CYCLE_5;
    /* EFM config */
    (void)EFM_Init(&stcEfmCfg);

    /* Wait flash0, flash1 ready. */
    do{
   
        flag1 = EFM_GetFlagStatus(EFM_FLAG_RDY0);
        flag2 = EFM_GetFlagStatus
### HC32L13x 微控制器 Flash 存储器读写操作 #### 1. 配置Flash访问控制寄存器 (FLASH_ACR) 为了确保在不同频率下正确读取Flash内容,需设置合适的等待周期。通过修改`FLASH_ACR`寄存器中的LATENCY位来调整这一参数。 ```c // 设置 FLASH_ACR 寄存器的 LATENCY 值 void Set_FLASH_Latency(uint8_t latency) { MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, latency); } ``` 此函数允许动态改变延迟时间以适应不同的HCLK频率需求[^1]。 #### 2. 编程前准备 编程之前应先解锁Flash程序擦除保护机制: ```c // 解锁 Flash 控制寄存器 HAL_FLASH_Unlock(); ``` 执行完毕后记得重新锁定以防意外更改: ```c // 锁定 Flash 控制寄存器 HAL_FLASH_Lock(); ``` 上述命令确保只有经过验证的操作才能影响到内部闪存区域[^2]。 #### 3. 数据写入流程 向指定地址写入单字节或多字节数组时遵循如下过程: - 清除所有待处理的状态标志; - 启用页/半页编程模式; - 将目标位置设为可写状态; - 执行实际的数据传输动作; 具体实现方式取决于所使用的库版本及其API设计风格,在这里给出一个通用的例子: ```c /** * @brief 写入数据至 Flash 中给定的位置 * * @param address 起始地址 * @param data 指向要写入的数据缓冲区指针 * @param length 数据长度(单位:字) */ static void Write_Data_To_Flash(uint32_t address, uint32_t* data, size_t length) { HAL_StatusTypeDef status; // 清除所有挂起的 EOP 和错误中断标记 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); // 如果当前处于读保护状态下,则解除之 if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_RDPRT)) HAL_FLASHEx_DisableRunTimeProtection(); // 开启页面编程请求 SET_BIT(FLASH->CR, FLASH_CR_PG); while (length--) { // 等待上一次操作结束 do {} while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)); // 进行内存映射式 I/O 操作完成真正意义上的 "写" *(volatile uint32_t*)address++ = *data++; // 检查是否有任何异常情况发生 if ((status != HAL_OK) || \ (__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR)) || \ (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR))) { CLEAR_BIT(FLASH->CR, FLASH_CR_PG); // 关闭 PG 请求 break; } } // 结束本次事务 CLEAR_BIT(FLASH->CR, FLASH_CR_PG); // 返回最终结果 return status == HAL_OK ? true : false; } ``` 这段代码展示了如何安全有效地将用户定义的信息保存到非易失性存储空间内。 #### 4. 数据读取方法 对于大多数应用场景而言,直接利用C语言提供的指针运算即可轻松获取所需信息: ```c uint32_t Read_Word_From_Flash(uint32_t addr) { volatile uint32_t value = *((__IO uint32_t *)addr); return value; } void Read_Buffer_From_Flash(uint32_t srcAddr, uint32_t dstBuf[], int count) { memcpy((void*)dstBuf, (const void*)srcAddr, sizeof(uint32_t)*count); } ``` 以上两段简单的辅助函数分别实现了针对单一机器码单元以及连续区块的整体拷贝功能。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值