华大单片机根据型号不同,涵盖了 16/32/64/128/256/512K 字节(Byte)容量的 FLASH存储器,每块 FLASH按照 Sector进行划分,每个 Sector容量为 512字节。本存储器支持对擦除(片/页擦除)、编程以及读取操作。此外,本模块还支持对 FLASH存储器擦写的保护,以及控制寄存器的写保护。
擦写时间
FLASH 存储器对擦除和编程操作的控制信号具有严格的时间要求,控制信号的时序不合格会造成擦除操作和编程操作失败或者数据写入深度不够。上电时默认装载了 HCLK 为 4MHz 时的擦写参数;如果对 Flash 进行擦写时的 HCLK 频率不为 4MHz,则用户程序应装载 HCLK频率所对应的擦写参数。对 FLASH 进行操作时,需要 HCLK 的频率范围为 1MHz ~48MHz。
擦写时序参数相关的寄存器为:FLASH_TNVS、FLASH_TPGS、FLASH_TPROG、FLASH_TSERASE 、 FLASH_TMERASE 、 FLASH_TPRCV 、 FLASH_TSRCV 、FLASH_TMRCV。
可以通过Flash_Init函数完成此操作。
读等待周期
本设备内置的 FLASH 支持的最快取指频率为 24MHz。当 HCLK 频率超过 24MHz 小于 48MHz 时,必须为 FLASH 的读取时间插入等待周期,即设置 FLASH_CR.WAIT 为1。当插入等待周期时,FLASH 每两个周期才会完成一次读取操作。
可以通过Flash_WaitCycle函数完成此操作。
操作源保护
华大单片机对容量超过 32K的 FLASH采用高安全性的硬件设计,具有 FLASH操作源防御功能:仅当 FLASH操作函数的地址位于 0~32K,才能正确执行 FLASH擦写操作。FLASH地址的 0~32K 具有更高的安全性,重要函数须放置此区域内,例如重要程序入口、中断入口函数、高安全算法模块、UID、AES、真随机数、RTC的算法配合,组成高安全认证系统。
在实际应用中,对于容量大于 32K的 MCU,如果需要将 FLASH的操作函数、安全功能函数等放置在 FLASH的 32K安全区,可通过以下便捷的方式实现。
- 本例为说明需要,主要示例将函数“ Flash_SectorErase()”放置在安全区“0x400”地址的方法,实际应用当中可以将“示例函数”和“地址”根据自己的需求进行替换。
基于 Keil MDK的编程方法
在 Keil MDK中,可以简单通过如下方式实现对安全函数的执行地址映射:
在目标函数的声明处增加以下代码:
en_result_t Flash_SectorErase(uint32_t u32SectorAddr) __attribute__((section(".ARM.__at_0x400")));
基于 IAR 的编程方法
1、在目标函数定义处增加以下代码:
en_result_t Flash_SectorErase(uint32_t u32SectorAddr) @".Flash_SectorErase"
2、在工程“*.icf”文件中增加以下代码:
place at address mem:0x00000400 { readonly section .Flash_SectorErase};
操作目标保护
整个 64K字节 FLASH存储器被划分为 128个页,每 4个页共用一个擦写保护位。当页被保护时,对该页进行的擦写操作均无效,并产生报警标志位和中断信号。当 FLASH存储器中的任意页被保护时,对该 FLASH 的全片擦写无效,并产生报警标志位和中断信号
可以使用库中的Flash_LockSet函数实现对页的加锁和解锁。
/**
*****************************************************************************
** \brief FLASH LOCK 设置
**
** \param [in] u32LockValue 32bits,对应bit=0:加锁,对应Sector不允许擦写;对应bit=1:解锁。
** \note 加解锁范围Sector:[i*4, i*4+3]
** (i表示u32LockValue的bit位置,0~31)
** 例如:u32LockValue = 0x00000002,
** 则加解锁范围为:[Sector8,Sector11]
** \retval Ok 解锁成功
** \retval ErrorInvalidParameter 参数错误
*****************************************************************************/
en_result_t Flash_LockSet(uint32_t u32LockValue)
{
FLASH_BYPASS();
M0P_FLASH->SLOCK = u32LockValue;
return Ok;
}
也可以使用Flash_LockAll函数对FLASH全部页进行加锁,使用Flash_UnlockAll函数对FLASH全部页进行解锁。
PC 地址擦写保护
CPU在 FLASH中运行程序时,如果当前 PC指针正好落在待擦写的页地址范围之内,那么该擦写操作无效并产生报警标志位和中断信号。
寄存器写保护
本模块的控制器屏蔽普通的写操作,必须用写序列方式才能修改。具体操作步骤如下图所示:
注意:
写 0x5a5a、0xa5a5、写目标寄存器,这三步写操作之间不可插入任何写操作(写 ROM、RAM、REG),否则无法改写目标寄存器的数值。如改写失败,需要重新进行这三步操作。
FLASH控制器支持对 eFLASH的 Byte(8bits)、Half-word(16bits)、Word(32bits)三种位宽读写操作。
注意:
Byte操作的地址必须按 Byte对齐,Half-word操作的目标地址必须按Half-word对齐(地址最低位为 1’b0),Word操作的地址必须按 Word对齐(地址最低两位为2’b00)。如果读写操作的地址没有按照位宽规定对齐,该操作无效,并且系统会进入 Hard Fault出错中断。
工作流程介绍
Sector擦除
可以使用Flash_SectorErase函数完成此操作。
Chip 擦除
可以使用Flash_ChipErase函数完成此操作。
写操作
可以分别使用Flash_WriteByte函数、Flash_WriteHalfWord函数、Flash_WriteWord函数完成FLASH按字节写,按半字写,按字写操作。
读操作
读操作比较简单,直接对要操作的地址行指针操作就可以完成。支持读出 3 种数据长度:Byte(8bits)、Half-word(16bits)、Word(32bits),读出的数据为小端模式,即低地址存放数据的低字节。读操作无需操作步骤,任何时刻都可以读出 FLASH 内的数据。
Byte 读操作示例: temp = *((unsigned char *)0x00001231) 可以是任意地址
Half-word 读操作示例 temp = *((unsigned short*)0x00001232) 最低位地址必须为0
Word 读操作示例 temp = *((unsigned long*)0x00001234) 最低两位地址必须为0
|