打印
[综合信息]

HC32F460 内部flash驱动

[复制链接]
4014|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2021-10-10 11:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
内部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;
        u32  FRMC_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;                                                        //返回状态
}








使用特权

评论回复
沙发
tpgf|  楼主 | 2021-10-10 11:59 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        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;
        u32  FRMC_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;
        u32  FRMC_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;
}



使用特权

评论回复
板凳
tpgf|  楼主 | 2021-10-10 11:59 | 只看该作者
/*************************************************************************************************************
* 文件名                :        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_


使用特权

评论回复
地板
两只袜子| | 2021-10-10 17:13 | 只看该作者
用华大不多但不耽误我好好研究学习下

使用特权

评论回复
5
guijial511| | 2021-10-10 17:14 | 只看该作者
华大内部flash一页大小?

使用特权

评论回复
6
carpsnow| | 2021-10-12 18:16 | 只看该作者
可能我不适合只看代码~

使用特权

评论回复
7
傻傻执着| | 2021-10-12 21:01 | 只看该作者
连续编程在SRAM执行,那时候坑了我好久

使用特权

评论回复
8
gerage000| | 2021-10-19 10:18 | 只看该作者
谢谢分享了,请上传一下源码,谢谢了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1383

主题

14108

帖子

8

粉丝