基于CH32V208开发板—FLASH读写、擦除

发布时间 2023-10-18 11:16:15作者: zyl4444

-------------------------------------------------------------------------------------------------------------------------------------

在CH32V208系列芯片中,各个型号的参数如下图:

FLASH的大小包含零等待区和非零等待区,一共是480K。
1、内部实际存储代码的flash为慢速flash;
2、芯片复位后由硬件根据配置把慢速flash的代码拷贝到 用ram工艺做的快速flash区域,然后从快速flash里面运行;
3、芯片内部的慢速flash通常都比较大,并且支持运行代码,只是速度慢了点;
4、WCH官网的宣传FLASH大小实际上是针对快速FLASH.


在手册中查到,可以将快速FLASH/RAM配置为以下三种;需要在WCHISPTOOL工具中配置,也需要修改LD文件与之对应。

在 Link.ld中,也需要修改对应位置的参数

 

通过V208的EVT中,使用FLASH的例程对flash进行读写、擦除操作以及标准编程和快速编程的过程。编程过程中,只有半字和字编程,没有字节编程

当主频率超过100MHz时,在操作FLASH时需要注意:将HCLK除以2会导致与HCLK相关的外设时钟也被除以2。在使用过程中需要注意这一点。


在程序中,先进行标准编程flash测试,

#include "debug.h"

/* Global define */
typedef enum
{
    FAILED = 0,
    PASSED = !FAILED
} TestStatus;

#define PAGE_WRITE_START_ADDR  ((uint32_t)0x08008000) /* Start from 32K */  //Flash存储器的起始地址,这里表示从地址0x08008000(32K)开始写入数据
#define PAGE_WRITE_END_ADDR    ((uint32_t)0x08009000) /* End at 36K */  //Flash存储器的结束地址,这里表示写入数据的结束地址为0x08009000(36K)。
#define FLASH_PAGE_SIZE                   4096    //Flash存储器的页大小,这里表示每个页的大小为4096字节(4KB)。
#define FLASH_PAGES_TO_BE_PROTECTED FLASH_WRProt_Pages60to63    //需要保护的Flash页范围,这里表示保护页为从60到63页。

/* Fast Mode define */
#define FAST_FLASH_PROGRAM_START_ADDR  ((uint32_t)0x08008000)  //快速模式下编程的起始地址,这里表示快速编程模式的起始地址为0x08008000。(32K)
#define FAST_FLASH_PROGRAM_END_ADDR  ((uint32_t)0x08010000)    //快速模式下编程的结束地址,这里表示快速编程模式的结束地址为0x08010000。(64K)
#define FAST_FLASH_SIZE  (64*1024)      //快速模式下编程的Flash大小,这里表示快速编程模式的Flash大小为64KB。

/* Global Variable */
uint32_t EraseCounter = 0x0;  //擦除计数器,用于记录擦除的次数。初始值为0。
uint32_t Address = 0x0;       //Flash操作的地址变量,用于指定Flash中的地址。初始值为0。

uint16_t Data = 0x1234;        //编程数据,用于存储要编程到Flash的16位数据。初始值为0xAAAA。
uint32_t WRPR_Value = 0xFFFFFFFF;  ////写保护寄存器的值,用于配置Flash的写保护。初始值为0xFFFFFFFF
uint32_t ProtectedPages = 0x0;      //受保护的页数,用于记录被写保护的Flash页的数量。初始值为0。
uint32_t NbrOfPage;                  //页数,用于记录需要擦除的Flash页的数量。该值由根据计算得出。

volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;    //页数,用于记录需要擦除的Flash页的数量。该值由根据计算得出。
volatile TestStatus MemoryProgramStatus = PASSED;     //存储程序操作状态的变量,用于跟踪编程操作的结果。初始值为PASSED。
volatile TestStatus MemoryEraseStatus = PASSED;     //存储擦除操作状态的变量,用于跟踪擦除操作的结果。初始值为PASSED。
u32 buf[64];

uint16_t flashdata;

//标准编程
void Flash_Test()
{
    printf("FLASH Test\n");
 /*When the main frequency exceeds 100MHz, attention should be paid when 
  *operating FLASH: dividing HCLK by two will result in the related peripheral 
  *clock of HCLK being divided by two. Attention should be paid when using.   //在执行FLASH操作时,如果主频率超过100MHz,需要注意将主频分为二并将与HCLK相关的外设时钟也除以二的情况
  */
    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;  //将主频分为二
    __disable_irq();
    USART_Printf_Init(115200);

    FLASH_Unlock();  //解锁FLASH

    //页面的起始地址 PAGE_WRITE_START_ADDR 和结束地址 PAGE_WRITE_END_ADDR
    //页面的大小 FLASH_PAGE_SIZE
    NbrOfPage = (PAGE_WRITE_END_ADDR - PAGE_WRITE_START_ADDR) / FLASH_PAGE_SIZE;  //计算需要擦除的页面数量,

    //忙标志位 FLASH_FLAG_BSY、
    //结束标志位 FLASH_FLAG_EOP 、
    //写保护错误标志位 FLASH_FLAG_WRPRTERR。
    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP |FLASH_FLAG_WRPRTERR);  //清除FLASH的状态标志位

    //擦除Flash每一页数据
    for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
    {
      FLASHStatus = FLASH_ErasePage(PAGE_WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));  //Erase 4KB  执行擦除操作

      if(FLASHStatus != FLASH_COMPLETE)  //判断是否擦除成功
      {
        printf("FLASH Erase Fail\r\n");  //失败
      }
      printf("FLASH Erase Suc\r\n");
    }
    Address = PAGE_WRITE_START_ADDR;   //初始化地址变量 Address 为页面的起始地址
    printf("Programing...\r\n");  //表示开始编程

    while((Address < PAGE_WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))  //编程Flash
    {
      FLASHStatus = FLASH_ProgramHalfWord(Address, Data);  //使用FLASH_ProgramHalfWord()函数逐个编程半字(16位)数据到Flash中
      // 打印地址和数据
      printf("Addr: %08X, Data: %04X", Address, Data);
      Address = Address + 2;
    }

    Address = PAGE_WRITE_START_ADDR;  //写入数据起始地址

    printf("Program Cheking...\r\n");   //检查Flash 中的数据是否与原始数据相同
    while((Address < PAGE_WRITE_END_ADDR) && (MemoryProgramStatus != FAILED))
    {
      if((*(__IO uint16_t*) Address) != Data)   // Flash 内容转换为 uint16_t 类型的数据,并与 Data 进行比较
      {
        MemoryProgramStatus = FAILED;
      }
      Address += 2;
    }

    if(MemoryProgramStatus == FAILED)
    {
       printf("Memory Program FAIL!\r\n");
    }
    else
    {
       printf("Memory Program PASS!\r\n");
    }

     FLASH_Lock();  //锁定Flash:调用FLASH_Lock()函数锁定Flash,确保保护已编程的数据。

     RCC->CFGR0 &= ~(uint32_t)RCC_HPRE_DIV2;  //清除 RCC_CFGR0 寄存器中的 RCC_HPRE_DIV2 位,恢复主频为原来的频率。
     __enable_irq();   //使能中断
     USART_Printf_Init(115200);

}

 

通过从串口打印,查看地址下将数据写入