本帖最后由 口天土立口 于 2025-9-8 19:29 编辑
APM32E030有64KB的主存储区,支持页/片擦除;
每页大小为1KB,有64页;
本次代码基于开发板:APM32E030R Micro-EVB
FLASH的驱动代码如下:
- /* FLASH大小: 64KB */
- #define FLASH_SIZE_MAX ((uint32_t)0x10000)
- /* 页大小: 1KB */
- #define FLASH_PAGE_SIZE ((uint32_t)0x400)
- /*
- * @brief 擦除
- *
- * @param addr: 擦除起始地址
- * len: 擦除长度
- *
- * @retval 擦除长度
- *
- */
- uint32_t bsp_flash_erase(uint32_t addr, uint32_t len)
- {
- uint32_t ret_len = 0U;
- uint32_t cur_len = 0;
- uint32_t erase_addr = addr;
-
- if ((addr < FMC_BASE) || (addr >= (FMC_BASE + FLASH_SIZE_MAX)) || (len == 0)) {
- ;
- } else {
- __disable_irq();
- /* 解锁 */
- FMC_Unlock();
-
- do {
- if ((erase_addr & (FLASH_PAGE_SIZE - 1)) != 0) {
- cur_len = FLASH_PAGE_SIZE - (erase_addr & (FLASH_PAGE_SIZE - 1));
- erase_addr = erase_addr & (~(FLASH_PAGE_SIZE - 1));
- } else {
- cur_len = FLASH_PAGE_SIZE;
- }
- if (FMC_ErasePage(erase_addr) != FMC_STATE_COMPLETE) {
- FMC_ClearStatusFlag(FMC_FLAG_BUSY | FMC_FLAG_PE | FMC_FLAG_WPE | FMC_FLAG_OC); /* 清除异常标志,重试 */
- if (FMC_ErasePage(erase_addr) != FMC_STATE_COMPLETE) {
- FMC_ClearStatusFlag(FMC_FLAG_BUSY | FMC_FLAG_PE | FMC_FLAG_WPE | FMC_FLAG_OC); /* 清除异常标志 */
- break;
- }
- }
- erase_addr += FLASH_PAGE_SIZE;
- ret_len += cur_len;
- } while ((ret_len < len) && (erase_addr < (FMC_BASE + FLASH_SIZE_MAX)));
-
- /* 上锁 */
- FMC_Lock();
- __enable_irq();
- }
-
- return ret_len;
- }
- /*
- * @brief 写
- * 需先手动调用擦除函数,确保待更新区域的字节全部为FF,才能正确执行写操作
- * @param addr: 写起始地址
- * buf: 写缓存
- * len: 写长度
- *
- * @retval 写长度
- *
- */
- uint32_t bsp_flash_write(uint32_t addr, uint8_t *buf, uint32_t len)
- {
- uint32_t ret_len = 0U;
- uint32_t write_len = 0U;
- uint32_t write_addr = 0U;
- uint16_t data = 0;
- FMC_STATE_T state = FMC_STATE_COMPLETE;
-
- if ((addr < FMC_BASE) || (addr >= (FMC_BASE + FLASH_SIZE_MAX)) || (buf == NULL) || (len == 0)) {
- ;
- } else {
- __disable_irq();
- /* 解锁 */
- FMC_Unlock();
-
- /* 先处理单字节 */
- if ((addr & 0x01) != 0) {
- write_addr = addr & (0xFFFFFFFEU);
- data = *(uint16_t *)write_addr;
- data &= 0x00FF;
- data += (((uint16_t)buf[0]) << 8);
- if (FMC_ProgramHalfWord(write_addr, data) != FMC_STATE_COMPLETE) {
- FMC_ClearStatusFlag(FMC_FLAG_BUSY | FMC_FLAG_PE | FMC_FLAG_WPE | FMC_FLAG_OC); /* 清除异常标志 */
- /* 上锁 */
- FMC_Lock();
- __enable_irq();
- return ret_len;
- }
- ret_len += 1;
- write_addr += 2;
- } else {
- write_addr = addr;
- }
-
- if (ret_len >= len) {
- /* 上锁 */
- FMC_Lock();
- __enable_irq();
- return ret_len;
- }
-
- state = FMC_WaitForReady(FMC_DELAY_PROGRAM);
- if (state == FMC_STATE_COMPLETE) {
- /* 开启编程 */
- FMC->CTRL2_B.PG = BIT_SET;
- do {
- /* 填充数据 */
- data = 0;
- if ((ret_len + 2) <= len) {
- data = (((uint16_t)buf[ret_len + 1]) << 8) + buf[ret_len];
- write_len = 2;
- } else {
- data = buf[ret_len];
- write_len = 1;
- }
- /* 写数据 */
- *(__IO uint16_t *)write_addr = data;
- /* 等待编程结束 */
- state = FMC_WaitForReady(FMC_DELAY_PROGRAM);
- if (state != FMC_STATE_COMPLETE) {
- FMC_ClearStatusFlag(FMC_FLAG_BUSY | FMC_FLAG_PE | FMC_FLAG_WPE | FMC_FLAG_OC); /* 清除异常标志 */
- break;
- }
- write_addr += write_len;
- ret_len += write_len;
- } while ((ret_len < len) && (write_addr < (FMC_BASE + FLASH_SIZE_MAX)));
- /* 结束编程 */
- FMC->CTRL2_B.PG = BIT_RESET;
- }
-
- /* 上锁 */
- FMC_Lock();
- __enable_irq();
- }
-
- return ret_len;
- }
- /*
- * @brief 读
- *
- * @param addr: 读起始地址
- * buf: 读缓存
- * len: 读长度
- *
- * @retval 读长度
- *
- */
- uint32_t bsp_flash_read(uint32_t addr, uint8_t *buf, uint32_t len)
- {
- uint32_t ret_len = 0U;
-
- if ((addr < FMC_BASE) || (addr >= (FMC_BASE + FLASH_SIZE_MAX)) || (buf == NULL) || (len == 0)) {
- ;
- } else {
- /* 计算可读取的长度 */
- if ((addr + len) > (FMC_BASE + FLASH_SIZE_MAX)) {
- ret_len = (FMC_BASE + FLASH_SIZE_MAX) - addr;
- } else {
- ret_len = len;
- }
- memcpy(buf, (uint32_t *)addr, ret_len);
- }
-
- return ret_len;
- }
注意:频繁的中断,可能会导致FLASH的擦写产生异常,进而死机,所以需加入禁止中断操作!
驱动测试代码如下:
- // FLASH测试
- int8_t flag_flash_test_e_w_r, flag_flash_test_w_direct;
- uint32_t test_addr = 0;
- static void flash_test(void)
- {
- #define TEST_SIZE_SINGLE (11)
- #define TEST_FLASH_ST_ADDR (FMC_BASE + 0x400 * 3 + 5) /* 程序自身需 2KB+ FLASH空间 */
- uint32_t flash_max_addr = FMC_BASE + 0x10000;
- uint32_t cur_test_len = 0;
- uint8_t test_buf_w[TEST_SIZE_SINGLE], test_buf_r[TEST_SIZE_SINGLE];
- uint8_t test_magic_num = 0;
- uint8_t i = 0;
- static uint8_t flag_flash_test = 0;
-
- if (flag_flash_test != 0) {
- return;
- }
-
- /* FLASH 擦除/写/读测试 */
- flag_flash_test_e_w_r = 0;
- test_addr = TEST_FLASH_ST_ADDR;
- do {
- /* 计算测试的数据长度 */
- if ((test_addr + TEST_SIZE_SINGLE) <= flash_max_addr) {
- cur_test_len = TEST_SIZE_SINGLE;
- } else {
- cur_test_len = flash_max_addr - test_addr;
- }
- /* 填充数据 */
- for (i = 0; i < TEST_SIZE_SINGLE; i++) {
- test_buf_w[i] = test_magic_num++;
- }
- /* 擦除 */
- if (bsp_flash_erase(test_addr, cur_test_len) < cur_test_len) {
- flag_flash_test_e_w_r = -1;
- break;
- }
- /* 写 */
- if (bsp_flash_write(test_addr, test_buf_w, cur_test_len) != cur_test_len) {
- flag_flash_test_e_w_r = -1;
- break;
- }
- /* 读 */
- memset(test_buf_r, 0, sizeof(test_buf_r));
- if (bsp_flash_read(test_addr, test_buf_r, cur_test_len) != cur_test_len) {
- flag_flash_test_e_w_r = -1;
- break;
- }
- /* 比较 */
- for (i = 0; i < cur_test_len; i++) {
- if (test_buf_w[i] != test_buf_r[i]) {
- flag_flash_test_e_w_r = -1;
- break;
- }
- }
- test_addr += cur_test_len;
- } while (test_addr < flash_max_addr);
-
- if (flag_flash_test_e_w_r == 0) {
- flag_flash_test_e_w_r = 2;
- }
-
- /* FLASH 直写测试 */
- flag_flash_test_w_direct = 0;
- test_addr = TEST_FLASH_ST_ADDR;
- do {
- /* 计算测试的数据长度 */
- if ((test_addr + TEST_SIZE_SINGLE) <= flash_max_addr) {
- cur_test_len = TEST_SIZE_SINGLE;
- } else {
- cur_test_len = flash_max_addr - test_addr;
- }
- /* 填充数据 */
- for (i = 0; i < TEST_SIZE_SINGLE; i++) {
- test_buf_w[i] = test_magic_num++;
- }
- /* 直写 */
- if (bsp_flash_write_direct(test_addr, test_buf_w, cur_test_len) != cur_test_len) {
- flag_flash_test_w_direct = -1;
- break;
- }
- /* 读 */
- memset(test_buf_r, 0, sizeof(test_buf_r));
- if (bsp_flash_read(test_addr, test_buf_r, cur_test_len) != cur_test_len) {
- flag_flash_test_w_direct = -1;
- break;
- }
- /* 比较 */
- for (i = 0; i < cur_test_len; i++) {
- if (test_buf_w[i] != test_buf_r[i]) {
- flag_flash_test_w_direct = -1;
- break;
- }
- }
- test_addr += cur_test_len;
- } while (test_addr < flash_max_addr);
-
- if (flag_flash_test_w_direct == 0) {
- flag_flash_test_w_direct = 2;
- }
-
- flag_flash_test = 1;
- }
- // 应用初始化
- void app_init(void)
- {
- flash_test();
- }
- // 应用任务
- void app_task(void)
- {
- }
详细代码,请查看附件:
Flash.zip
(2.11 MB, 下载次数: 0)
|