一、简介
1.1 NVMC
nRF52832 的非易失性存储器是通过 NVMC 来管理的,NVMC 是 Non-volatile memory controller(非易失性存储器控制器)的缩写,NVMC 提供了写或擦除 Flash 区域和 UICR(用户信息配置寄存器)的功能。
写 Flash 之前必须通过写寄存器 CONFIG.WEN 来使能 Flash 的写操作,同样,擦除 Flash 之前必须通过写寄存器 CONFIG.WEN 来使能 Flash 的擦除操作。并且,对 Flash 进行操作的时候要特别注意,不能同时使能 Flash 的写和擦除,否则将导致无法预测的后果。
1.2 片内 Flash 分布
nRF52832-QFAA 片内 Flash 大小如下:
nRF52832 的 Flash 地址范围是:0x0000 0000 ~ 0x0008 0000,共 512k 字节。Flash 区域分为 128 个 4k 字节大小的页面, 每个页面包含 8 个 512 字节大小的块,需要注意的是 Flash 分布的最小单位是块,但是擦除操作最小的单位是页。
Flash 是有使用寿命的,nRF52832 片内 Flash 可擦除/写的次数是 10000 次。写和擦除所需的时间如下:
二、SDK配置
2.1 添加文件
读写 Flash 需要加入的文件如下:
文件名 | SDK中的目录 | 描述 |
---|---|---|
nrf_nvmc.c | ...\modules\nrfx\hal | NVMC 驱动文件 |
2.2 添加及引用头文件
#include "nrf_nvmc.h"
三、API
3.1 擦除页
函数原型 | void nrf_nvmc_page_erase(uint32_t address) |
---|---|
函数功能 | 擦除页 |
参数 | address:页起始地铁 |
返回值 | 无 |
- 示例:擦除第 127 页(第 127 页的起始地址是:127 * 4 * 1024 = 0x0007F000)。
nrf_nvmc_page_erase(0x0007F000);
3.2 写
函数原型 | void nrf_nvmc_write_word(uint32_t address, uint32_t value) |
---|---|
函数功能 | 向 Flash 指定地址写入一个字。注意 Flash 写之前必须擦除。 |
参数 | address:写入的地址 value:写入的 Flash 的数据 |
返回值 | 无 |
- 示例:向 Flash 地址 0x0007F000 写入数据“0x12345678”。
nrf_nvmc_write_word(0x0007F000, 0x12345678);
函数原型 | void nrf_nvmc_write_words(uint32_t address, const uint32_t * src, uint32_t num_words) |
---|---|
函数功能 | 向 Flash 指定地址连续写入多个字。注意 Flash 写之前必须擦除。 |
参数 | address:写入的地址 src:写入的 Flash 的数据 num_words:写入字的数量 |
返回值 | 无 |
函数原型 | void nrf_nvmc_write_byte(uint32_t address, uint8_t value) |
---|---|
函数功能 | 向 Flash 指定地址写入一字节数据。注意 Flash 写之前必须擦除。由于写 Flash 的最小单位是字,将自动补齐剩余3字节。 |
参数 | address:写入的地址 value:写入的 Flash 的数据 |
返回值 | 无 |
函数原型 | void nrf_nvmc_write_bytes(uint32_t address, const uint8_t * src, uint32_t num_bytes) |
---|---|
函数功能 | 向 Flash 指定地址写入一字节数据。注意 Flash 写之前必须擦除。由于写 Flash 的最小单位是字,不够部分将自动补齐。 |
参数 | address:写入的地址 src:写入的 Flash 的数据 num_bytes:写入字节的数量 |
返回值 | 无 |
3.3 读
Flash 中的数据需要通过指针来读取。读取的过程是先定义指针变量,然后将该指针指向数据存放的地址,这样就可以获取 Flash 中该地址上的数据。
- 示例:从地址 0x0007F000 读取一个字。
uint32_t *pdat; // 定义指针变量
pdat = (uint32_t *)0x0007F000; // 指针指向地址0x0007F000
printf("%x", *pdat); // 打印出读取的数据
上述代码中,因为 pdat 是指针变量,0x0007F000 是一个常数,所以要将 0x0007F000 强制转换为指针类型后赋值给 pdat。
四、读写示例(仅限于没有协议栈的工程或协议栈工作以前)
执行 Flash 写操作时,首先要规划写入数据的 Flash 空间,如第 127 页(第 127 页的起始地址是:127 * 4 * 1024 = 0x0007F000),0x0007F000 就是第 127 页的起始地址。
#include "nrf_nvmc.h"
int main(void)
{
uint32_t addr = 0x0007F000;
uint32_t *pdat;
nrf_nvmc_page_erase(addr);
nrf_nvmc_write_word(addr, 0x12345678);
pdat = (uint32_t *)addr;
printf("0x%x", *pdat);
}
五、读写示例(对于有softdevice协议栈的工程)
使用 sd_flash_page_erase
和 sd_flash_write
两个函数,并且每次操作需要延时,等待协议栈有空时才执行 Flash 操作。
int main(void)
{
uint32_t *addr;
addr = (uint32_t *)0x7F000;
uint32_t value = 0x12345678;
sd_flash_page_erase(127); // 擦除第 127 页
nrf_delay_ms(100);
sd_flash_write(addr, (uint32_t *)&value, 1);
nrf_delay_ms(100);
uint32_t *pdat;
pdat = (uint32_t *)0x7F000;
printf("0x%x", *pdat);
}
• 由 Leung 写于 2020 年 9 月 24 日
• 参考:[艾克姆科技]
网友评论