打印
[RISC-V MCU 应用开发]

第八十九章、CH32V103应用教程——FLASH编程

[复制链接]
6424|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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文件
#ifndef  __FLASH_H
#define  __FLASH_H

#include "ch32v10x_conf.h"

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

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

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

#define  FLASH_PAGE_SIZE             1024

#define  FLASH_PAGES_TO_BE_PROTECTED FLASH_WRProt_Pages60to63
//#define  FLASH_PAGES_TO_BE_PROTECTED FLASH_WRProt_Pages56to59

void Flash_Test(void);
void Flash_Test_Fast(void);


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

/* Global Variable */
uint32_t EraseCounter = 0x0, Address = 0x0;
uint16_t Data = 0xAAAA;
uint32_t WRPR_Value = 0xFFFFFFFF, ProtectedPages = 0x0;
uint32_t NbrOfPage;
volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;

volatile TestStatus MemoryProgramStatus = PASSED;
volatile TestStatus MemoryEraseStatus = PASSED;

/*******************************************************************************
* Function Name  : Flash_Test
* Description    : Flash Program Test.
* Input          : None
* Return         : None
*******************************************************************************/
void Flash_Test(void)
{

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

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


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

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

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

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

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

    printf("Erase Cheking...\r\n");
    while((Address < PAGE_WRITE_END_ADDR) && (MemoryEraseStatus != FAILED))
    {
      if((*(__IO uint16_t*) Address) != 0xFFFF)
      {
        MemoryEraseStatus = FAILED;
       }
        Address += 2;
    }
    if(MemoryEraseStatus == FAILED)
    {
      printf("Erase Flash FAIL!\r\n");
      printf("\r\n");
    }
    else
    {
      printf("Erase Flash PASS!\r\n");
      printf("\r\n");
    }


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

    Address = PAGE_WRITE_START_ADDR;
    printf("Program Cheking...\r\n");
    while((Address < PAGE_WRITE_END_ADDR) && (MemoryProgramStatus != FAILED))
    {
      if((*(__IO uint16_t*) Address) != Data)
      {
        MemoryProgramStatus = FAILED;
       }
        Address += 2;
     }
     if(MemoryProgramStatus == FAILED)
     {
       printf("Memory Program FAIL!\r\n");
       printf("\r\n");
     }
     else
     {
       printf("Memory Program PASS!\r\n");
       printf("\r\n");
     }

   }
   else
   {
     MemoryProgramStatus = FAILED;
     printf("Error to program the flash : The desired pages are write protected\r\n");
   }

   FLASH_Lock();

}

/*******************************************************************************
* Function Name  : Flash_Test_Fast
* Description    : Flash Fast Program Test.(128Byte±à³Ì)
* Input          : None
* Return         : None
*******************************************************************************/
void Flash_Test_Fast(void)
{
    u8 i, Verity_Flag=0;
    u32 buf[32];

    for(i=0; i<32; i++)
    {
        buf[i] = i;
    }

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

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

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

    //闪存缓冲复位
    FLASH_BufReset();

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

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

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

    FLASH_Lock_Fast();

    for(i=0; i<32; i++)
    {
        if(buf[i] == *(u32*)(0x0800E000 + 4*i))
        {
            Verity_Flag = 0;
        }
        else
        {
            Verity_Flag = 1;
            break;
        }
    }

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

#include "debug.h"
#include "flash.h"


/* Global typedef */

/* Global define */

/* Global Variable */


/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Return         : None
*******************************************************************************/
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\r\n",SystemCoreClock);
    printf("Flash Program Test\r\n");

    Flash_Test();
    Flash_Test_Fast();

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

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


88、Flash编程.rar

474.88 KB

使用特权

评论回复
沙发
豌豆爹| | 2021-5-6 15:54 | 只看该作者
很不错的,学习了解一下

使用特权

评论回复
板凳
onlycook| | 2021-5-12 14:50 | 只看该作者
最近版主上了不少教程啊

使用特权

评论回复
地板
guijial511| | 2021-5-20 12:39 | 只看该作者
不断更新啊

使用特权

评论回复
5
luck刘备| | 2021-8-23 23:12 | 只看该作者
请问:printf("FLASH Erase ERR at Page%d\r\n",EraseCounter+60);中的60是什么意思呢?

使用特权

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

本版积分规则

132

主题

293

帖子

41

粉丝