查看: 1990|回复: 0
收起左侧

第二十三章:CH32V103应用教程——读写内部FLASH

[复制链接]

  离线 

  • TA的每日心情
    拍拍
    2022-6-27 11:09
  • 签到天数: 25 天

    [LV.4]

    发表于 2021-4-25 18:39:41 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 sky 于 2021-9-10 17:07 编辑

    本章教程将通过程序代码进行内部FLASH读写操作。


    1、CH32V103内部FLASH简介及相关函数介绍

    CH32V103芯片含有一个内部FLASH,其存储数据在掉电后不会丢失,主要用于存储程序代码。芯片在重新上电并复位后,可通过加载读取内部FLASH中程序代码运行。

    通常,我们可通过两种方式对内部FLASH进行读写:一是通过下载器等外部工具读写内部FLASH,二是通过芯片运行程序代码读取自身内部FLASH。本章即通过第二种方法进行内部FLASH读写。此外,就读写速度而言,读写内部FLASH比外部FLASH快的多,且由于内部FLASH掉电后数据不会丢失,因此内部FLASH剩余空间可用于存储重要数据和关键记录。

    由于内部FLASH可被通过外部工具或程序代码读写,为了防止内部FLASH中存储数据被获取,某些应用会禁止读写内部FLASH内容,或在第一次运行时计算加密信息并记录到某些区域,然后删除自身的部分加密代码,这些应用都涉及到内部FLASH的操作。

    CH32V103内部FLASH主要包含主存储器和信息块两块区域,其中信息块又可被分为两块系统引导代码存储区域、用户选择字和厂商配置字区域。其中,主存储器区域主要用于用户的应用程序存储,以4K字节(32 页)单位进行写保护划分;除了“厂商配置字”区域出厂锁定,用户不可访问,其他区域在一定条件下用户可操作。

    CH32V103内部FLASH具有2种编程/擦除方式,具体如下:


    • 标准编程:此方式是默认编程方式(兼容方式)。这种模式下CPU以单次2字节方式执行编程,单次1K字节执行擦除及整片擦除操作。
    • 快速编程:此方式采用页操作方式(推荐)。经过特定序列解锁后,执行单次128字节的编程及128字节擦除。

    关于CH32V103内部FLASH具体信息,可参考CH32V103应用手册。CH32V103内部FLASH标准库函数具体内容如下:
    1. /*Functions used for all CH32V10x devices*/
    2. void FLASH_SetLatency(uint32_t FLASH_Latency);
    3. void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);
    4. void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);
    5. void FLASH_Unlock(void);
    6. void FLASH_Lock(void);
    7. FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
    8. FLASH_Status FLASH_EraseAllPages(void);
    9. FLASH_Status FLASH_EraseOptionBytes(void);
    10. FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);
    11. FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
    12. FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);
    13. FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);
    14. FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);
    15. FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);
    16. uint32_t FLASH_GetUserOptionByte(void);
    17. uint32_t FLASH_GetWriteProtectionOptionByte(void);
    18. FlagStatus FLASH_GetReadOutProtectionStatus(void);
    19. FlagStatus FLASH_GetPrefetchBufferStatus(void);
    20. void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);
    21. FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);
    22. void FLASH_ClearFlag(uint32_t FLASH_FLAG);
    23. FLASH_Status FLASH_GetStatus(void);
    24. FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
    25. void FLASH_Unlock_Fast(void);
    26. void FLASH_Lock_Fast(void);
    27. void FLASH_BufReset(void);
    28. void FLASH_BufLoad(uint32_t Address, uint32_t Data0, uint32_t Data1, uint32_t Data2, uint32_t Data3);
    29. void FLASH_ErasePage_Fast(uint32_t Page_Address);
    30. void FLASH_ProgramPage_Fast(uint32_t Page_Address);

    31. /* New function used for all CH32V10x devices */
    32. void FLASH_UnlockBank1(void);
    33. void FLASH_LockBank1(void);
    34. FLASH_Status FLASH_EraseAllBank1Pages(void);
    35. FLASH_Status FLASH_GetBank1Status(void);
    36. FLASH_Status FLASH_WaitForLastBank1Operation(uint32_t Timeout);
    复制代码

    1.1、void FLASH_SetLatency(uint32_t FLASH_Latency)
    功  能:设置代码延迟值。
    输  入:FLASH_Latency:指定FLASH延迟值。

    1.2、void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess)
    功  能:启用或禁用半周期闪存访问。
    输  入:FLASH_HalfCycleAccess:指定闪存半周期访问模式。

    1.3、void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer)
    功  能:启用或禁用预取缓冲区。
    输  入:FLASH_PrefetchBuffer:指定预取缓冲区的状态。

    1.4、void FLASH_Unlock(void)
    功  能:解锁闪存程序擦除控制器。
    输  入:无

    1.5、void FLASH_UnlockBank1(void)
    功  能:解锁闪存组1程序擦除控制器。
    输  入:无

    1.6、void FLASH_Lock(void)
    功  能:锁定闪存程序擦除控制器。
    输  入:无

    1.7、void FLASH_LockBank1(void)
    功  能:锁定闪存组1程序擦除控制器。
    输  入:无

    1.8、FLASH_Status FLASH_ErasePage(uint32_t Page_Address)

    功  能:擦除指定的闪存页。
    输  入:Page_Address:要删除的页面地址。

    1.9、FLASH_Status FLASH_EraseAllPages(void)
    功  能:清除所有闪存页。
    输  入:无

    1.10、FLASH_Status FLASH_EraseAllBank1Pages(void)
    功  能:清除所有Bank1闪存页。
    输  入:无

    1.11、FLASH_Status FLASH_EraseOptionBytes(void)
    功  能:擦除闪存选项字节。
    输  入:无

    1.12、FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)
    功  能:在指定的地址编程一个字。
    输  入:Address:指定要编程的地址。Data:指定要编程的数据。

    1.13、FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
    功  能:在指定地址编程半个字。
    输  入:Address:指定要编程的地址。Data:指定要编程的数据。

    1.14、FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data)
    功  能:在指定的选项字节数据地址编程半个字。
    输  入:Address:指定要编程的地址。Data:指定要编程的数据。

    1.15、FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages)
    功  能:所需页面写保护。
    输  入:FLASH_Pages:指定要写保护的页的地址。

    1.16、FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState)
    功  能:启用或禁用读取保护。
    输  入:Newstate:读出保护的新状态(启用或禁用)。

    1.17、FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY)
    功  能:编程闪存用户选项字节:IWDG_SW/RST_STOP/RST_STDBY。
    输  入:OB_IWDG:选择IWDG模式。OB_IWDG_SW:选择软件IWDG;OB_IWDG_HW:已选择硬件IWDG。
    OB_STOP:进入停止模式时重置事件。OB_STOP_NoRST:进入STOP时不生成重置;OB_u STOP_RST:进入STOP时生成重置。
    OB _STDBY:进入待机状态时重置事件。OB_STDBY_NoRST:进入待机状态时不生成复位;OB STDBY_RST:进入停机位时生成复位。

    1.18、uint32_t FLASH_GetUserOptionByte(void)
    功  能:返回闪存用户选项字节值。
    输  入:无

    1.19、uint32_t FLASH_GetWriteProtectionOptionByte(void)
    功  能:返回闪存写入保护选项字节寄存器值。
    输  入:无

    1.20、FlagStatus FLASH_GetReadOutProtectionStatus(void)
    功  能:检查闪存读取保护状态是否设置。
    输  入:无

    1.21、FlagStatus FLASH_GetPrefetchBufferStatus(void)
    功  能:检查是否设置了闪存预取缓冲区状态。
    输  入:无

    1.22、void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState)
    功  能:启用或禁用指定的闪存中断。
    输  入:FLASH_IT:指定要启用或禁用的闪存中断源。NewState:指定的Flash中断的新状态(启用或禁用)。

    1.23、FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG)
    功  能:检查是否设置了指定的闪存标志。
    输  入:FLASH_FLAG:指定要检查的FLASH标志。

    1.24、void FLASH_ClearFlag(uint32_t FLASH_FLAG)
    功  能:清除闪存的挂起标志。
    输  入:FLASH_FLAG:指定要清除的FLASH标志。

    1.25、FLASH_Status FLASH_GetStatus(void)
    功  能:返回闪存状态。
    输  入:无

    1.26、FLASH_Status FLASH_GetBank1Status(void)
    功  能:返回闪存组1状态。
    输  入:无

    1.27、FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)
    功  能:等待闪存操作完成或超时。
    输  入:Timeout:闪存编程超时

    1.28、FLASH_Status FLASH_WaitForLastBank1Operation(uint32_t Timeout)
    功  能:等待Bank1上的闪存操作完成或超时。
    输  入:Timeout:闪存编程超时

    1.29、void FLASH_Unlock_Fast(void)
    功  能:解锁快速程序擦除模式。
    输  入:无

    1.30、void FLASH_Lock_Fast(void)
    功  能:锁定快速程序擦除模式。
    输  入:无

    1.31、void FLASH_BufReset(void)
    功  能:闪存缓冲复位。
    输  入:无

    1.32、void FLASH_BufLoad(uint32_t Address, uint32_t Data0, uint32_t Data1, uint32_t Data2, uint32_t Data3)
    功  能:闪存缓冲加载(128位)。
    输  入:无

    1.33、void FLASH_ErasePage_Fast(uint32_t Page_Address)
    功  能:擦除指定的闪存页(1页=128字节)。
    输  入:Page_Address:要删除的页面地址。

    1.34、void FLASH_ProgramPage_Fast(uint32_t Page_Address)
    功  能:编程指定的闪存页(1页=128字节)。
    输  入:Page_Address:要编程的页面地址。

    使用以上函数时,直接在程序中进行调用即可。


    2、硬件设计

    本章教程主要通过程序代码进行内部FLASH读写操作,使用CH32V103内部资源,无需进行硬件连接。


    3、软件设计

    CH32V103内部FLASH编程/擦除方式有两种,一种是标准编程,一种是快速编程,本章即使用上述这两种方式分别进行内部FLASH读写操作,程序编程主要分3个步骤:

    1、对内部FLASH进行解锁;

    2、对内部FLASH进行页擦除;
    3、对内部FLASH进行读写操作。

    根据上述操作步骤,编写具体程序,具体程序如下:

    flash.h文件
    1. #ifndef __FLASH_H
    2. #define __FLASH_H

    3. #include "ch32v10x_conf.h"

    4. typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
    5. #define PAGE_WRITE_START_ADDR  ((uint32_t)0x0800F000) /* Start from 60K */
    6. #define PAGE_WRITE_END_ADDR    ((uint32_t)0x08010000) /* End at 63K */
    7. #define FLASH_PAGE_SIZE         1024

    8. int Flash_Test(void);
    9. int Flash_Test_Fast(void);

    10. #endif
    复制代码
    flash.h文件主要包含相关定义和函数声明;

    flash.c文件
    1. #include "flash.h"

    2. /* Global Variable */
    3. uint32_t EraseCounter = 0x00; //记录要擦除多少页
    4. uint32_t Address = 0x00;      //记录写入的地址
    5. uint16_t Data = 0xAAAA;       //记录写入的数据
    6. uint32_t NbrOfPage;           //记录写入多少页

    7. volatile FLASH_Status FLASHStatus = FLASH_COMPLETE; //记录每次擦除的结果
    8. volatile TestStatus MemoryProgramStatus = PASSED;   //记录整个测试结果

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

    18.     NbrOfPage = (PAGE_WRITE_END_ADDR - PAGE_WRITE_START_ADDR) / FLASH_PAGE_SIZE; //计算要擦除多少页

    19.     //FLASH_FLAG_BSY:指示忙状态标志;FLASH_FLAG_EOP:指示操作结束标志;FLASH_FLAG_PGERR:闪存程序错误标志;FLASH_FLAG_WRPRTERR:指示写保护错误标志
    20.     FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP|FLASH_FLAG_PGERR |FLASH_FLAG_WRPRTERR); //清空所有标志位

    21.     for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++) //按页擦除
    22.     {
    23.       FLASHStatus = FLASH_ErasePage(PAGE_WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
    24.     }

    25.     Address = PAGE_WRITE_START_ADDR; //向内部FLASH写入数据起始地址

    26.     while((Address < PAGE_WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))
    27.     {
    28.       FLASHStatus = FLASH_ProgramHalfWord(Address, Data); //向指定地址写入半字
    29.       Address = Address + 2;
    30.     }

    31.     FLASH_Lock(); //上锁

    32.     Address = PAGE_WRITE_START_ADDR;

    33.     while((Address < PAGE_WRITE_END_ADDR) && (MemoryProgramStatus != FAILED))
    34.     {
    35.       if((*(__IO uint16_t*) Address) != Data)
    36.       {
    37.         MemoryProgramStatus = FAILED;
    38.       }
    39.         Address += 2;
    40.     }
    41.     return MemoryProgramStatus;

    42. }

    43. /*******************************************************************************
    44. * Function Name  : Flash_Test_Fast
    45. * Description    : Flash Fast Program Test.(128Byte)
    46. * Input          : None
    47. * Return         : None
    48. *******************************************************************************/
    49. int Flash_Test_Fast(void)
    50. {
    51.     u8 i, Verity_Flag=0;
    52.     u32 buf[32];

    53.     for(i=0; i<32; i++)
    54.     {
    55.         buf[i] = i;
    56.     }

    57.     FLASH_Unlock_Fast(); //快速编程模式解锁

    58.     FLASH_ErasePage_Fast(0x0800E000); //擦除指定闪存页,此处擦除0x0800E000这个地址所指定页

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

    60.     FLASH_BufReset(); //复位闪存缓冲区,即执行清除内部128字节缓存区操作

    61.     FLASH_BufLoad(0x0800E000, buf[0], buf[1], buf[2], buf[3]); //向指定地址开始连续写入16字节数据(4字节/次操作,写的地址每次偏移量为4),然后执行加载到缓冲区
    62.     FLASH_BufLoad(0x0800E000 + 0x10, buf[4], buf[5], buf[6], buf[7]);
    63.     FLASH_BufLoad(0x0800E000 + 0x20, buf[8], buf[9], buf[10], buf[11]);
    64.     FLASH_BufLoad(0x0800E000 + 0x30, buf[12], buf[13], buf[14], buf[15]);
    65.     FLASH_BufLoad(0x0800E000 + 0x40, buf[16], buf[17], buf[18], buf[19]);
    66.     FLASH_BufLoad(0x0800E000 + 0x50, buf[20], buf[21], buf[22], buf[23]);
    67.     FLASH_BufLoad(0x0800E000 + 0x60, buf[24], buf[25], buf[26], buf[27]);
    68.     FLASH_BufLoad(0x0800E000 + 0x70, buf[28], buf[29], buf[30], buf[31]);

    69.     FLASH_ProgramPage_Fast(0x0800E000); //启动一次快速页编程动作,编程指定的闪存页

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

    71.     FLASH_Lock_Fast();

    72.     for(i=0; i<32; i++) //读编程地址数据校验
    73.     {
    74.         if(buf[i] == *(u32*)(0x0800E000 + 4*i))
    75.         {
    76.             Verity_Flag = 0;
    77.         }
    78.         else
    79.         {
    80.             Verity_Flag = 1;
    81.             break;
    82.         }
    83.     }
    84.     return Verity_Flag;
    85. }
    复制代码

    flash.c文件主要包含两个函数,一个是内部FLASH标准编程函数Flash_Test,一个是内部FLASH快速编程函数Flash_Test_Fast,这两个函数具体执行过程如下:


    内部FLASH标准编程函数Flash_Test执行过程:


    (1)调用FLASH_Unlock函数进行解锁;

    (2) 根据起始地址及结束地址计算需要擦除页数;
    (3) 调用FLASH_ClearFlag函数清除各种标志位;
    (4) 使用for循环以及调用FLASH_ErasePage函数擦除页数,每次擦除一页;
    (5) 使用while循环并调用FLASH_ProgramWord函数向起始地址至结束地址的存储区域都写入变量“Data”存储的数值数值;
    (6) 调用FLASH_Lock函数进行上锁;
    (7) 使用指针读取写入的数据内容并校验。

    内部FLASH快速编程函数Flash_Test_Fast执行过程与标准编程执行过程类似,具体如下:


    (1)调用FLASH_Unlock_Fast函数进行解锁;

    (2) 调用FLASH_ErasePage_Fast函数擦除指定闪存页;
    (3) 调用FLASH_BufReset函数复位闪存缓冲区,执行清除内部128字节缓存区操作;
    (4) 调用FLASH_BufLoad函数向指定地址开始连续写入16字节数据(4字节/次操作,写的地址每次偏移量为4),然后执行加载到缓冲区;
    (5) 调用FLASH_ProgramPage_Fast函数启动一次快速页编程动作,编程指定的闪存页;
    (6) 调用FLASH_Lock_Fast函数进行上锁;
    (7) 使用for循环读取编程地址进行数据校验并返回校验值。

    以上两个函数执行过程可对照CH32V103应用手册第24章闪存操作流程进行程序编写,更有助于理解编程。

    main.c函数
    1. int main(void)
    2. {
    3.         Delay_Init();
    4.         USART_Printf_Init(115200);

    5.         printf("SystemClk:%d\r\n",SystemCoreClock);
    6.         printf("This is flash example\r\n");

    7.         if(Flash_Test()== PASSED)
    8.          {
    9.            printf("读写内部 FLASH 标准编程测试成功\r\n");
    10.          }
    11.         else
    12.          {
    13.            printf("读写内部 FLASH 标准编程测试失败\r\n");
    14.          }

    15.     if(Flash_Test_Fast())
    16.     {
    17.      printf("128Byte Page Verity Fail,快速编程失败\r\n");
    18.     }
    19.     else
    20.     {
    21.      printf("128Byte Page Verity Sucess,快速编程成功\r\n");
    22.     }

    23.       while(1)
    24.       {
    25.       }
    26. }
    复制代码
    main.c函数主要进行函数初始化以及根据flash.c文件两个函数返回值输出相应信息。


    4、下载验证


    将编译好的程序下载到开发板并复位,串口打印情况具体如下:
    CH32V CH573单片机芯片-第二十三章:CH32V103应用教程——读写内部FLASHrisc-v单片机中文社区(1)

    根据串口打印信息可知,内部FLASH标准编程和快速编程测试成功。


    读写内部FLASH.rar附件下载
    CH32V CH573单片机芯片-第二十三章:CH32V103应用教程——读写内部FLASHrisc-v单片机中文社区(2) 22、读写内部FLASH.rar (474.98 KB, 下载次数: 16)
    链接:https://pan.baidu.com/s/1wKMP7vZ92iB07_338GEnJQ
    提取码:93ea
    复制这段内容后打开百度网盘手机App,操作更方便哦







    上一篇:第二十二章:CH32V103应用教程——触摸按键检测(TKEY)
    下一篇:第二十四章:CH32V103应用教程——设置FLASH读写保护及解除
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-11-26 10:05 , Processed in 0.322857 second(s), 47 queries .

    快速回复 返回顶部 返回列表