19 内置 Flash(EFlash)
注意: 20xx系列mcu对于flash的写入存在硬件限制,理论硬件支持单次最大写入32字节数据, 实际受限于硬件,单次写入不能超过32字节数据,sdk通过循环写入32字节或调用DMA模块通道0搬运 的方式实现单次写入256字节的数据。两种方式的影响如下。
- 循环写入: 每次最大写入32字节数据,每次写入32字节之后都要执行约1.2ms的等待时间,单次写入超32字节速度较慢。
- DMA写入:会占用硬件DMA的通道0,写入过程会修改DMA的通道配置,其他外设不能使用DMA通道0, 并且写入flash之前需要降低flash的时钟频率,否则可能出现写入失败只能写入16字节数据的情况。
19.1 功能概述
芯片内置一定容量的 Flash,可编程擦写。擦除时以扇区(sector)为单位进行,每个扇区大小为
EFLASH_SECTOR_SIZE 字节;写入时以 32bit 为单位。
20XX系列芯片FLAH在使用不同的工作电压时支持的最大工作频率不同。总结于表 19.1。
| 电压(V) | 最大工作频率(MHz) |
|---|---|
| 1.65-2.7 | 40 |
| 2.7-3.6 | 104 |
20XX系列芯片FLASH擦写典型时间: | 行为 | 时间(ms) | |———:|————:| | page program | 1.2 | | sector erase | 2.8 | | block erase | 2.8 |
表中的 Flash 时钟频率可通过 SYSCTRL_GetFlashClk()
读取。Flash 内部会对这个时钟 2 分频,
实际工作频率是这个时钟频率的一半。
为了保证芯片工作的最大兼容性,芯片默认设置FLAH的工作频率为76.8MHz(实际工作频率约38.4MHz),
当确认芯片的工作电压一定大于2.7V时候,可通过SYSCTRL_SelectFlashClk()手动调整flash的
工作频率,以获取更高的芯片性能.最高设置的工作频率208MHz(实际工作频率约104MHz)。
请用户注意FLASH的工作电压与最大工作频率的关系,避免频率不匹配造成芯片工作异常,程序出现异常跑飞等问题。
19.2 使用说明
19.2.1 擦除并写入新数据
通过 program_flash 擦除并写入一段数据。
int program_flash(
// 待写入的地址
const uint32_t dest_addr,
// 数据源的地址
const uint8_t *buffer,
// 数据长度(以字节为单位,必须是 4 的倍数)
uint32_t size);dest_addr 为统一编址后的地址,而非 Flash 内部从 0 开始的地址。dest_addr
必须对应于某个扇区的起始地址。数据源不可位于 Flash 内。
program_flash 将根据 size 自动擦除一个或多个扇区并写入数据。
本函数如果成功,则返回 0,否则返回非 0。
19.2.2 不擦除直接写入数据
通过 write_flash 不擦除直接写入数据。
int write_flash(
// 待写入的地址
const uint32_t dest_addr,
// 数据源的地址
const uint8_t *buffer,
// 数据长度(以字节为单位,必须是 4 的倍数)
uint32_t size);dest_addr 为统一编址后的地址,必须 32bit 对齐。write_data 不擦除 Flash,而是直接写入。
数据源不可位于 Flash 内。如果对应的 Flash 空间未被擦除,将无法写入。
本函数如果成功,则返回 0,否则返回非 0。
19.2.3 单独擦除
通过 erase_flash_sector 擦除一个指定的扇区。
int erase_flash_sector(
// 待擦除的地址
const uint32_t addr);addr 必须对应于某个扇区的起始地址。本函数如果成功,则返回 0,否则返回非 0。
19.2.4 Flash 数据升级
通过 flash_do_update 可以升级 Flash 里的数据。这个函数可用于 FOTA 升级。
int flash_do_update(
// 数据块数目
const int block_num,
// 每个数据块的信息
const fota_update_block_t *blocks,
// 用于缓存一个扇区的内存
uint8_t *ram_buffer);每个数据块的定为为:
typedef struct fota_update_block
{
uint32_t src;
uint32_t dest;
uint32_t size;
} fota_update_block_t;这个函数的行为大致如下:
flash_do_update() {
for (block in blocks) {
flash_copy(block.dest,
block.src,
block.size);
}
}如前所述,program_flash 的数据源不能位于 Flash,所以 flash_copy 需要把各扇区逐个读入
ram_buffer,然后使用 program_flash 擦除、写入。
这个函数如果成功,将自动重启系统,否则返回非 0。