[RISC-V MCU 应用开发] 第八十九章、CH32V103应用教程——FLASH编程

[复制链接]
 楼主| RISCVLAR 发表于 2021-4-28 14:02 | 显示全部楼层 |阅读模式
本帖最后由 RISCVLAR 于 2021-8-24 09:54 编辑

CH32V103应用教程——FLASH编程

本章主要使用CH32V103进行FLASH的擦/读/写,以及快速编程。

1、FLASH简介及相关函数介绍
关于CH2V103的FLSAH,其支持2种编程/擦除方式,具体如下:
  • 标准编程:此方式是默认编程方式(兼容方式)。这种模式下CPU以单次2字节方式执行编程,单次1K字节执行擦除及整片擦除操作。
  • 快速编程:此方式采用页操作方式(推荐)。经过特定序列解锁后,执行单次128字节的编程及128字节擦除。
关于FLASH编程,本次所用库函数中具体函数如下:
(1)FLASH_Unlock函数:此函数主要用于解锁闪存程序擦除控制器。
(2)FLASH_GetWriteProtectionOptionByte函数:此函数主要用于返回闪存写保护选项字节寄存器值。
(3)FLASH_ClearFlag函数:此函数主要用于清除闪存的挂起标志。
(4)FLASH_ErasePage函数:此函数主要用于擦除指定的闪存页。
(5)FLASH_ProgramHalfWord函数:此函数主要用于在指定的地址编写半个字的程序。
(6)FLASH_Lock函数:此函数主要用于锁定闪存程序擦除控制器。
(7)FLASH_Unlock_Fast函数:此函数主要用于解锁快速程序擦除模式。
(8)FLASH_ErasePage_Fast函数:此函数主要用于擦除指定的闪存页(1页=128字节)。
(9)FLASH_BufReset函数:此函数主要用于闪存缓冲复位。
(10)FLASH_BufLoad函数:此函数主要用于闪存缓冲区加载(128位)。
(11)FLASH_ProgramPage_Fast函数:此函数主要用于编程指定的闪存页(1页=128字节)。
(12)FLASH_Lock_Fast函数:此函数主要用于锁定快速程序擦除模式。
以上就是本次程序中所要用到的函数,关于ch32v10x_flash.c文件中的其他函数,感兴趣可对照注释以及函数内容进行了解。关于FLASH操作流程,可参考CH32V103应用手册。

2、硬件设计
本章教程主要FLASH编程操作,无需进行硬件设计。

3软件设计
FLASH编程操作具体程序如下:
flash.h文件
  1. #ifndef  __FLASH_H
  2. #define  __FLASH_H

  3. #include "ch32v10x_conf.h"

  4. /* Global define */
  5. typedef enum
  6. {
  7.     FAILED = 0,
  8.     PASSED = !FAILED
  9. } TestStatus;

  10. #define  PAGE_WRITE_START_ADDR       ((uint32_t)0x0800F000) /* Start from 60K */
  11. //#define  PAGE_WRITE_START_ADDR       ((uint32_t)0x0800E000) /* Start from 56K */

  12. #define  PAGE_WRITE_END_ADDR         ((uint32_t)0x08010000) /* End at 63K */
  13. //#define  PAGE_WRITE_END_ADDR         ((uint32_t)0x0800F000) /* End at 59K */

  14. #define  FLASH_PAGE_SIZE             1024

  15. #define  FLASH_PAGES_TO_BE_PROTECTED FLASH_WRProt_Pages60to63
  16. //#define  FLASH_PAGES_TO_BE_PROTECTED FLASH_WRProt_Pages56to59

  17. void Flash_Test(void);
  18. void Flash_Test_Fast(void);


  19. #endif
flash.h文件主要进行相关定义和函数声明;
flash.c文件
  1. #include "flash.h"

  2. /* Global Variable */
  3. uint32_t EraseCounter = 0x0, Address = 0x0;
  4. uint16_t Data = 0xAAAA;
  5. uint32_t WRPR_Value = 0xFFFFFFFF, ProtectedPages = 0x0;
  6. uint32_t NbrOfPage;
  7. volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;

  8. volatile TestStatus MemoryProgramStatus = PASSED;
  9. volatile TestStatus MemoryEraseStatus = PASSED;

  10. /*******************************************************************************
  11. * Function Name  : Flash_Test
  12. * Description    : Flash Program Test.
  13. * Input          : None
  14. * Return         : None
  15. *******************************************************************************/
  16. void Flash_Test(void)
  17. {

  18.   //系统复位后,闪存控制器(FPEC)和 FLASH_CTLR 寄存器是被锁定的,不可访问。通过写入序列到 FLASH_KEYR 寄存器可解锁闪存控制器模块。
  19.   //解锁序列:
  20.   //1)向 FLASH_KEYR 寄存器写入 KEY1 = 0x45670123(第 1 步必须是 KEY1);
  21.   //2)向 FLASH_KEYR 寄存器写入 KEY2 = 0xCDEF89AB(第 2 步必须是 KEY2)。
  22.   //解锁闪存器
  23.   FLASH_Unlock();
  24.   
  25.   //读取写保护寄存器的值  1:写保护失效  0:写保护有效
  26.   //每个比特位代表 4K 字节(32 页)存储写保护状态
  27.   //WPR在系统复位后从用户选择字区域加载
  28.   WRPR_Value = FLASH_GetWriteProtectionOptionByte();
  29.   printf("WRPR_Value = %x\n",WRPR_Value);

  30.   //PAGE_WRITE_START_ADDR:写入的起始地址     PAGE_WRITE_END_ADDR:结束地址     FLASH_PAGE_SIZE:一页大小,1024字节     NbrOfPage:记录要擦除的页数
  31.   NbrOfPage = (PAGE_WRITE_END_ADDR - PAGE_WRITE_START_ADDR) / FLASH_PAGE_SIZE;


  32.   if ( (WRPR_Value & FLASH_PAGES_TO_BE_PROTECTED) != 0x00)
  33.   {
  34.     //FLASH_FLAG_BSY:指示忙状态  1:表示闪存操作正在进行;0:操作结束或发生错误
  35.     //FLASH_FLAG_EOP:指示操作结束,写1清零
  36.     //FLASH_FLAG_PGERR:指示编程错误,写1清零
  37.     //FLASH_FLAG_WRPRTERR:只是写保护错误,写1清零
  38.     //清除挂起标志
  39.     FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP|FLASH_FLAG_PGERR |FLASH_FLAG_WRPRTERR);

  40.     //EraseCounter:擦除计数     NbrOfPage:记录要擦除的页数
  41.     for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
  42.     {
  43.       //FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
  44.       //FLASH_ErasePage:擦除指定的闪存页,此函数包含应用手册介绍主存储器标准擦除操作的2、3、4步
  45.       FLASHStatus = FLASH_ErasePage(PAGE_WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));

  46.       //FLASH_COMPLETE:FLASH擦除完成标志
  47.       if(FLASHStatus != FLASH_COMPLETE)
  48.       {
  49.         printf("FLASH Erase ERR at Page%d\r\n",EraseCounter+60);
  50.       }

  51.       printf("FLASH Erase Page%d...\r\n",EraseCounter+60);
  52.     }

  53.     //Address:写入地址     PAGE_WRITE_START_ADDR:写入的起始地址
  54.     Address = PAGE_WRITE_START_ADDR;

  55.     printf("Erase Cheking...\r\n");
  56.     while((Address < PAGE_WRITE_END_ADDR) && (MemoryEraseStatus != FAILED))
  57.     {
  58.       if((*(__IO uint16_t*) Address) != 0xFFFF)
  59.       {
  60.         MemoryEraseStatus = FAILED;
  61.        }
  62.         Address += 2;
  63.     }
  64.     if(MemoryEraseStatus == FAILED)
  65.     {
  66.       printf("Erase Flash FAIL!\r\n");
  67.       printf("\r\n");
  68.     }
  69.     else
  70.     {
  71.       printf("Erase Flash PASS!\r\n");
  72.       printf("\r\n");
  73.     }


  74.     Address = PAGE_WRITE_START_ADDR;
  75.     printf("Programing...\r\n");
  76.     while((Address < PAGE_WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))
  77.     {
  78.       FLASHStatus = FLASH_ProgramHalfWord(Address, Data);
  79.       Address = Address + 2;
  80.       //printf("Write address:%08x\r\n",Address);
  81.     }

  82.     Address = PAGE_WRITE_START_ADDR;
  83.     printf("Program Cheking...\r\n");
  84.     while((Address < PAGE_WRITE_END_ADDR) && (MemoryProgramStatus != FAILED))
  85.     {
  86.       if((*(__IO uint16_t*) Address) != Data)
  87.       {
  88.         MemoryProgramStatus = FAILED;
  89.        }
  90.         Address += 2;
  91.      }
  92.      if(MemoryProgramStatus == FAILED)
  93.      {
  94.        printf("Memory Program FAIL!\r\n");
  95.        printf("\r\n");
  96.      }
  97.      else
  98.      {
  99.        printf("Memory Program PASS!\r\n");
  100.        printf("\r\n");
  101.      }

  102.    }
  103.    else
  104.    {
  105.      MemoryProgramStatus = FAILED;
  106.      printf("Error to program the flash : The desired pages are write protected\r\n");
  107.    }

  108.    FLASH_Lock();

  109. }

  110. /*******************************************************************************
  111. * Function Name  : Flash_Test_Fast
  112. * Description    : Flash Fast Program Test.(128Byte±à³Ì)
  113. * Input          : None
  114. * Return         : None
  115. *******************************************************************************/
  116. void Flash_Test_Fast(void)
  117. {
  118.     u8 i, Verity_Flag=0;
  119.     u32 buf[32];

  120.     for(i=0; i<32; i++)
  121.     {
  122.         buf[i] = i;
  123.     }

  124.     //快速变成模式解锁
  125.     FLASH_Unlock_Fast();

  126.     //擦除指定的闪存页
  127.     FLASH_ErasePage_Fast(0x0800E000);

  128.     printf("128Byte Page Erase Sucess\r\n");

  129.     //闪存缓冲复位
  130.     FLASH_BufReset();

  131.     //闪存缓冲区加载(128位)。
  132.     FLASH_BufLoad(0x0800E000, buf[0], buf[1], buf[2], buf[3]);
  133.     FLASH_BufLoad(0x0800E000 + 0x10, buf[4], buf[5], buf[6], buf[7]);
  134.     FLASH_BufLoad(0x0800E000 + 0x20, buf[8], buf[9], buf[10], buf[11]);
  135.     FLASH_BufLoad(0x0800E000 + 0x30, buf[12], buf[13], buf[14], buf[15]);
  136.     FLASH_BufLoad(0x0800E000 + 0x40, buf[16], buf[17], buf[18], buf[19]);
  137.     FLASH_BufLoad(0x0800E000 + 0x50, buf[20], buf[21], buf[22], buf[23]);
  138.     FLASH_BufLoad(0x0800E000 + 0x60, buf[24], buf[25], buf[26], buf[27]);
  139.     FLASH_BufLoad(0x0800E000 + 0x70, buf[28], buf[29], buf[30], buf[31]);

  140.     //编程指定的闪存页(1页=128字节)。
  141.     FLASH_ProgramPage_Fast(0x0800E000);

  142.     printf("128Byte Page Program Sucess\r\n");

  143.     FLASH_Lock_Fast();

  144.     for(i=0; i<32; i++)
  145.     {
  146.         if(buf[i] == *(u32*)(0x0800E000 + 4*i))
  147.         {
  148.             Verity_Flag = 0;
  149.         }
  150.         else
  151.         {
  152.             Verity_Flag = 1;
  153.             break;
  154.         }
  155.     }

  156.     if(Verity_Flag) printf("128Byte Page Verity Fail\r\n");
  157.     else printf("128Byte Page Verity Sucess\r\n");
  158. }
flash.c文件主要包括。关于几个函数的具体介绍,在程序中都有详细注释,在此不再赘述。
main.c文件
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2020/04/30
  6. * Description        : Main program body.
  7. *******************************************************************************/

  8. #include "debug.h"
  9. #include "flash.h"


  10. /* Global typedef */

  11. /* Global define */

  12. /* Global Variable */


  13. /*******************************************************************************
  14. * Function Name  : main
  15. * Description    : Main program.
  16. * Input          : None
  17. * Return         : None
  18. *******************************************************************************/
  19. int main(void)
  20. {
  21.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  22.     Delay_Init();
  23.     USART_Printf_Init(115200);
  24.     printf("SystemClk:%d\r\n",SystemCoreClock);
  25.     printf("Flash Program Test\r\n");

  26.     Flash_Test();
  27.     Flash_Test_Fast();

  28.     while(1)
  29.     {
  30.         ;
  31.     }
  32. }
main.c文件主要进行函数初始化。

4下载验证
将编译好的程序下载到开发版并复位,串口打印显示如下:
图片1.png


88、Flash编程.rar

474.88 KB, 下载次数: 73

豌豆爹 发表于 2021-5-6 15:54 | 显示全部楼层
很不错的,学习了解一下
onlycook 发表于 2021-5-12 14:50 | 显示全部楼层
最近版主上了不少教程啊
guijial511 发表于 2021-5-20 12:39 来自手机 | 显示全部楼层
不断更新啊
luck刘备 发表于 2021-8-23 23:12 | 显示全部楼层
请问:printf("FLASH Erase ERR at Page%d\r\n",EraseCounter+60);中的60是什么意思呢?

评论

因为FLASH标准编程和STM32编程一样,每次擦除1页(1K),而编程是从第60K开始的,因此加60  发表于 2021-8-24 09:52
您需要登录后才可以回帖 登录 | 注册

本版积分规则

133

主题

296

帖子

44

粉丝
快速回复 在线客服 返回列表 返回顶部

133

主题

296

帖子

44

粉丝
快速回复 在线客服 返回列表 返回顶部