本帖最后由 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、下载验证 将编译好的程序下载到开发版并复位,串口打印显示如下:
|