HC32F460 内部flash驱动
内部flash写入的时候,需要将代码分配到内存中执行/*************************************************************************************************************
* 文件名 : hc32f46x_flash.c
* 功能 : HC32F46X 内部FLASH驱动
* 作者 : cp1300@139.com
* 创建时间 : 2021-07-27
* 最后修改时间 : 2021-07-27
* 详细 : flash操作时要禁止一切中断以及flash读取操作,相关接口函数都要定义到RAM中执行,不要调用任何其他函数
连续编程过程中,绝对不能调用非RAM函数,目前是先清除看门狗(有12秒以上时间),保证擦除时间不超过12秒即可
2021-10-09:解决了可能存在的读写错误,原因是擦写flash的时候访问了flash导致;
*************************************************************************************************************/
#include "hc32f46x.h"
#include "hc32f46x_map.h"
#include "system.h"
#include "hc32f46x_flash.h"
#define __at__IRAM3__ __attribute__((section("IRAM3")))
//FLASH编程模式
typedef enum
{
PEMOD_READ_ONLY = 0, //只读模式
PEMOD_SINGLE_PROGRAM = 1, //单编程模式
PEMOD_SINGLE_PROGRAM_RB = 2, //单编程回读模式
PEMOD_SEQUENCE_PROGRAM = 3, //连续编程模式
PEMOD_SECTOR_ERASE = 4, //扇区擦除模式
PEMOD_MASS_ERASE = 5, //全擦除模式
}FLASH_PEMOD;
/*************************************************************************************************************************
* 函数 : void HC32FLASH_Unlock(void)
* 功能 : 解锁HC32的FLASH编程
* 参数 : 无
* 返回 : 无
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-28
* 最后修改时间 : 2021-07-28
* 说明 : 解锁配置,并进入编程模式
*************************************************************************************************************************/
__at__IRAM3__
void HC32FLASH_Unlock(void)
{
SYS_EFM_CONFIG_Unlock(); //EFM配置解锁
EFM->FWMC |= BIT0; //允许修改编程模式
EFM->FWMC &= ~BIT8; //FLASH编程擦除期间,总线被占用
}
/*************************************************************************************************************************
* 函数 : void HC32FLASH_Lock(void)
* 功能 : 上锁HC32的FLASH
* 参数 : 无
* 返回 : 无
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2013-10-20
* 最后修改时间 : 2018-01-13
* 说明 : 上锁配置,并退出编程模式
*************************************************************************************************************************/
__at__IRAM3__
void HC32FLASH_Lock(void)
{
EFM->FWMC &= ~BIT0; //不允许修改编程模式
SYS_EFM_CONFIG_Lock(); //EFM配置上锁
}
/*************************************************************************************************************************
* 函数 : HC32FLASH_STATUS HC32FLASH_GetStatus(void)
* 功能 : 得到FLASH状态
* 参数 : 无
* 返回 : HC32FLASH_STATUS
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-27
* 最后修改时间 : 2021-07-27
* 说明 :
*************************************************************************************************************************/
__at__IRAM3__
HC32FLASH_STATUS HC32FLASH_GetStatus(void)
{
u32 temp=EFM->FSR;
if(!(temp&(1<<8))) return HC32FLASH_BUSY; //忙
else if(temp&(1<<1))return HC32FLASH_WPRERR; //写保护错误
else if(temp&(1<<2))return HC32FLASH_PGAERR; //编程对齐错误
else if(temp&(1<<0))return HC32FLASH_PEWERR; //在擦写不许可模式下擦写 FLASH
else if(temp&(1<<5))return HC32FLASH_COLERR; //读写访问错误
else if(temp&(1<<3))return HC32FLASH_PGMISMTCH; //单编程回读错误
return HC32FLASH_OK; //操作完成
}
/*************************************************************************************************************************
* 函数 : HC32FLASH_STATUS HC32FLASH_WaitDone(u32 time)
* 功能 : 等待操作完成
* 参数 : time:要延时的长短,单位us
* 返回 : HC32FLASH_STATUS
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-27
* 最后修改时间 : 2021-07-27
* 说明 :
*************************************************************************************************************************/
__at__IRAM3__
HC32FLASH_STATUS HC32FLASH_WaitDone(u32 time)
{
HC32FLASH_STATUS status;
u32 i;
if(time < 1) time = 1;
do
{
status=HC32FLASH_GetStatus(); //获取状态
if(status!=HC32FLASH_BUSY)break; //非忙,无需等待了,直接退出.
for(i = 0;i < 100;i ++)
{
nop;nop;nop;nop;nop;
}
time--;
}while(time);
return status;
}
/*************************************************************************************************************************
* 函数 : void HC32FLASH_SetErasePgmMode(FLASH_PEMOD mode)
* 功能 : 设置flash的擦除编程模式
* 参数 : mode:模式,见FLASH_PEMOD
* 返回 : 无
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-28
* 最后修改时间 : 2021-07-28
* 说明 : 必须先解锁才能调用
*************************************************************************************************************************/
__at__IRAM3__
void HC32FLASH_SetErasePgmMode(FLASH_PEMOD mode)
{
EFM->FWMC &= ~(0x7 << 4); //先清除之前配置
EFM->FWMC |= (mode & 0x07) << 4; //重新设置
}
/*************************************************************************************************************************
* 函数 : HC32FLASH_STATUS HC32FLASH_EraseSector(u32 u32Addr)
* 功能 : 扇区擦除
* 参数 : u32Addr:要擦除的数据所在地址(擦除数据所在扇区)
* 返回 : HC32FLASH_STATUS
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-28
* 最后修改时间 : 2021-07-28
* 说明 :
*************************************************************************************************************************/
__at__IRAM3__
HC32FLASH_STATUS HC32FLASH_EraseSector(u32 u32Addr)
{
HC32FLASH_STATUS status;
u32FRMC_Temp;
SYS_DisableIrq(); //关闭中断
EFM->FSCLR = 0x3F; //清除所有错误标记
HC32FLASH_Unlock(); //解锁
FRMC_Temp = EFM->FRMC; //记录之前寄存器值
if(FRMC_Temp & BIT16) //使能了缓存,则先关闭
{
EFM->FRMC &= ~BIT16; //关闭缓存
}
#if(SYS_WDG_EN_) //使能了看门狗
IWDG_Feed();
#endif //SYS_WDG_EN_
HC32FLASH_SetErasePgmMode(PEMOD_SECTOR_ERASE); //进入扇区擦除模式
//擦除模式,必须在RAM中执行
*(uint32_t*)u32Addr = 0x12345678; //往所在位置随便写个数据,触发擦除
status=HC32FLASH_WaitDone(1000000); //等待操作结束,最大1s
//擦除结束了
EFM->FSCLR = 0x3F; //清除所有错误标记
HC32FLASH_SetErasePgmMode(PEMOD_READ_ONLY); //退出擦除模式
if(FRMC_Temp & BIT16) //使能了缓存
{
EFM->FRMC |= BIT16 | BIT24; //开启缓存-并复位缓存
}
HC32FLASH_Lock(); //上锁
SYS_EnableIrq(); //使能中断
if(status != HC32FLASH_OK)
{
DEBUG("擦除扇区%d失败(错误:%d) \r\n",u32Addr, status);
}
return status; //返回状态
}
/*************************************************************************************************************************
* 函数 : HC32FLASH_STATUS HC32FLASH_WritedWord_NoCheck(u32 u32Addr, u32 data)
* 功能 : 不检查的在FLASH指定地址写入一个字的数据(32bit写入)
* 参数 : u32Addr:指定地址(此地址必须为4的倍数!!);data:要写入的数据
* 返回 : HC32FLASH_STATUS
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-28
* 最后修改时间 : 2021-07-28
* 说明 : 使用的单次编程方式
*************************************************************************************************************************/
__at__IRAM3__
HC32FLASH_STATUS HC32FLASH_WritedWord_NoCheck(u32 u32Addr, u32 data)
{
HC32FLASH_STATUS status;
u32FRMC_Temp;
SYS_DisableIrq(); //关闭中断
EFM->FSCLR = 0x3F; //清除所有错误标记
HC32FLASH_Unlock(); //解锁
FRMC_Temp = EFM->FRMC; //记录之前寄存器值
if(FRMC_Temp & BIT16) //使能了缓存,则先关闭
{
EFM->FRMC &= ~BIT16; //关闭缓存
}
#if(SYS_WDG_EN_) //使能了看门狗
IWDG_Feed();
#endif //SYS_WDG_EN_
HC32FLASH_SetErasePgmMode(PEMOD_SINGLE_PROGRAM_RB); //进入单编程回读模式
//擦除模式,必须在RAM中执行
*(uint32_t*)u32Addr = data; //往所在位置写数据
status=HC32FLASH_WaitDone(10000); //等待操作结束,最大10ms
//擦除结束了
EFM->FSCLR = 0x3F; //清除所有错误标记
HC32FLASH_SetErasePgmMode(PEMOD_READ_ONLY); //退出擦除模式
if(FRMC_Temp & BIT16) //使能了缓存
{
EFM->FRMC |= BIT16 | BIT24; //开启缓存-并复位缓存
}
HC32FLASH_Lock(); //上锁
SYS_EnableIrq(); //使能中断
if(status != HC32FLASH_OK)
{
DEBUG("写入%d失败(错误:%d) \r\n",u32Addr, status);
}
return status; //返回状态
}
/*************************************************************************************************************************
* 函数 : u32 HC32FLASH_ReaddWord(u32 u32Addr)
* 功能 : 读取指定地址的一个字(32位数据)
* 参数 : u32Addr:指定地址(此地址必须为4的倍数!!);
* 返回 : 数据
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-28
* 最后修改时间 : 2021-07-28
* 说明 : 警告:地址必须是4的整数倍
*************************************************************************************************************************/
__inline u32 HC32FLASH_ReaddWord(u32 u32Addr)
{
return *(vu32*)u32Addr;
}
/*************************************************************************************************************************
* 函数 : HC32FLASH_STATUS HC32FLASH_Write_NoCheck(u32 u32Addr,u32 *pBuffer,u32 NumToWrite)
* 功能 : 不检查的写入
* 参数 : u32Addr:起始地址(必须是4个整数倍);pBuffer:数据指针;NumToWrite:(32位)数据数量
* 返回 : 状态
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-28
* 最后修改时间 : 2021-07-28
* 说明 : 连续编程模式,必须以极快的速度写入,延时不能超过16us
连续编程模式会锁定flash总线,一切对falsh访问将会被禁止,看门狗清除在编程之前,溢出时间为13秒,只要保证
单次编程不超过13秒是不会有看门狗溢出风险,实际正常也不会超过;
*************************************************************************************************************************/
__at__IRAM3__
HC32FLASH_STATUS HC32FLASH_Write_NoCheck(u32 u32Addr,u32 *pBuffer,u32 NumToWrite)
{
HC32FLASH_STATUS status;
u32FRMC_Temp;
u32 i;
u32 *u32pDest = (u32 *)u32Addr;
u32 TimeOutCnt;
SYS_DisableIrq(); //关闭中断
EFM->FSCLR = 0x3F; //清除所有错误标记
HC32FLASH_Unlock(); //解锁
FRMC_Temp = EFM->FRMC; //记录之前寄存器值
if(FRMC_Temp & BIT16) //使能了缓存,则先关闭
{
EFM->FRMC &= ~BIT16; //关闭缓存
}
#if(SYS_WDG_EN_) //使能了看门狗
IWDG_Feed();
#endif //SYS_WDG_EN_
HC32FLASH_SetErasePgmMode(PEMOD_SEQUENCE_PROGRAM); //进入连续编程模式-进入后需要立即开始编程,中间不能有任何延时
EFM->FSCLR = BIT4; //清除等待操作完成状态
//擦除模式,必须在RAM中执行
for(i = 0;i < NumToWrite;i ++)
{
*u32pDest++ = pBuffer;
while((EFM->FSR & BIT4) == 0) //等待操作完成
{
nop;
}
EFM->FSCLR = BIT4; //清除等待操作完成状态
}
HC32FLASH_SetErasePgmMode(PEMOD_READ_ONLY); //退出擦除模式
status=HC32FLASH_WaitDone(2000000); //等待操作结束,最大2s
//擦除结束了
EFM->FSCLR = 0x3F; //清除所有错误标记
if(FRMC_Temp & BIT16) //使能了缓存
{
EFM->FRMC |= BIT16 | BIT24; //开启缓存-并复位缓存
}
HC32FLASH_Lock(); //上锁
#if(SYS_WDG_EN_) //使能了看门狗
IWDG_Feed();
#endif //SYS_WDG_EN_
SYS_EnableIrq(); //使能中断
if(status != HC32FLASH_OK)
{
DEBUG("写入%d失败(错误:%d) \r\n",u32Addr, status);
}
return status; //返回状态
}
/*************************************************************************************************************************
* 函数 : u32 HC32FLASH_Read(u32 u32Addr,u32 *pBuffer,u32 NumToRead)
* 功能 : 从指定地址开始读出指定长度的数据
* 参数 : ReadAddr:起始地址;pBuffer:数据指针;NumToWrite:(32位)数据数量
* 返回 : 读取的数据长度(字为单位)
* 依赖 : 底层
* 作者 : cp1300@139.com
* 时间 : 2021-07-28
* 最后修改时间 : 2021-07-28
* 说明 : 地址必须为4对齐
*************************************************************************************************************************/
u32 HC32FLASH_Read(u32 u32Addr,u32 *pBuffer,u32 NumToRead)
{
u32 i;
u32 cnt = 0;
for(i=0;i<NumToRead;i++)
{
pBuffer=HC32FLASH_ReaddWord(u32Addr); //读取4个字节.
cnt++;
u32Addr+=4; //偏移4个字节.
}
return cnt;
}
/*************************************************************************************************************
* 文件名 : hc32f46x_flash.h
* 功能 : HC32F46X 内部FLASH驱动
* 作者 : cp1300@139.com
* 创建时间 : 2021-07-27
* 最后修改时间 : 2021-07-27
* 详细 :
*************************************************************************************************************/
#ifndef _HC32F46X_FLASH_H_
#define _HC32F46X_FLASH_H_
#include "hc32f46x_system.h"
//FLASH起始地址
#define HC32_FLASH_BASE 0x00000000 //HC32 FLASH的起始地址
//单片机内部Flash操作状态
typedef enum
{
HC32FLASH_OK = 0, //操作完成-空闲
HC32FLASH_BUSY = 1, //忙
HC32FLASH_COLERR = 2, //读写访问错误
HC32FLASH_PGMISMTCH = 3, //单编程回读错误
HC32FLASH_PGAERR = 4, //编程对齐错误
HC32FLASH_WPRERR = 5, //写保护错误
HC32FLASH_PEWERR = 6, //在擦写不许可模式下擦写 FLASH
}HC32FLASH_STATUS;
//相关接口函数
HC32FLASH_STATUS HC32FLASH_GetStatus(void); //获得状态
HC32FLASH_STATUS HC32FLASH_EraseSector(u32 u32Addr); //擦除扇区
HC32FLASH_STATUS HC32FLASH_WritedWord_NoCheck(u32 u32Addr, u32 data); //不检查的在FLASH指定地址写入一个字的数据(32bit写入) 【警告:地址必须是4的整数倍】
u32 HC32FLASH_ReaddWord(u32 u32Addr); //读取指定地址的一个字(32位数据) 【警告:地址必须是4的整数倍】
HC32FLASH_STATUS HC32FLASH_Write_NoCheck(u32 u32Addr,u32 *pBuffer,u32 NumToWrite); //不检查的写入
u32 HC32FLASH_Read(u32 u32Addr,u32 *pBuffer,u32 NumToRead); //从指定地址开始读出指定长度的数据
#endif //_HC32F46X_FLASH_H_
用华大不多但不耽误我好好研究学习下 华大内部flash一页大小? 可能我不适合只看代码~ 连续编程在SRAM执行,那时候坑了我好久 谢谢分享了,请上传一下源码,谢谢了
页:
[1]