/****************************************************************************** *Copyright(C)2018, Huada Semiconductor Co.,Ltd All rights reserved. * * This software is owned and published by: * Huada Semiconductor Co.,Ltd("HDSC"). * * BY DOWNLOADING, INSTALLING OR USING THIS SOFTWARE, YOU AGREE TO BE BOUND * BY ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT. * * This software contains source code for use with HDSC * components. This software is licensed by HDSC to be adapted only * for use in systems utilizing HDSC components. HDSC shall not be * responsible for misuse or illegal use of this software for devices not * supported herein. HDSC is providing this software "AS IS" and will * not be responsible for issues arising from incorrect user implementation * of the software. * * Disclaimer: * HDSC MAKES NO WARRANTY, EXPRESS OR IMPLIED, ARISING BY LAW OR OTHERWISE, * REGARDING THE SOFTWARE (INCLUDING ANY ACOOMPANYING WRITTEN MATERIALS), * ITS PERFORMANCE OR SUITABILITY FOR YOUR INTENDED USE, INCLUDING, * WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, THE IMPLIED * WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE OR USE, AND THE IMPLIED * WARRANTY OF NONINFRINGEMENT. * HDSC SHALL HAVE NO LIABILITY (WHETHER IN CONTRACT, WARRANTY, TORT, * NEGLIGENCE OR OTHERWISE) FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT * LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, * LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING FROM USE OR * INABILITY TO USE THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS OF DATA, * SAVINGS OR PROFITS, * EVEN IF Disclaimer HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * YOU ASSUME ALL RESPONSIBILITIES FOR SELECTION OF THE SOFTWARE TO ACHIEVE YOUR * INTENDED RESULTS, AND FOR THE INSTALLATION OF, USE OF, AND RESULTS OBTAINED * FROM, THE SOFTWARE. * * This software may be replicated in part or whole for the licensed use, * with the restriction that this Disclaimer and Copyright notice must be * included with each copy of this software, whether used in part or whole, * at all times. */ /** \file flash.c ** ** Common API of flash. ** @link flashGroup Some description @endlink ** ** - 2018-05-08 ** ******************************************************************************/ /******************************************************************************* * Include files ******************************************************************************/ #include "hc32l196_flash.h" /** ******************************************************************************* ** \addtogroup FlashGroup ******************************************************************************/ //@{ /******************************************************************************* * Local pre-processor symbols/macros ('#define') ******************************************************************************/ #define FLASH_END_ADDR (0x0003FFFFu) #define FLASH_BYPASS() M0P_FLASH->BYPASS = 0x5A5A;\ M0P_FLASH->BYPASS = 0xA5A5; #define FLASH_IE_TRUE (0x03) #define FLASH_IE_FALSE (0x00) #define FLASH_TIMEOUT_INIT (0xFFFFFFu) #define FLASH_TIMEOUT_PGM (0xFFFFFFu) #define FLASH_TIMEOUT_ERASE (0xFFFFFFu) #define FLASH_LOCK_ALL (0u) #define FLASH_UNLOCK_ALL (0xFFFFFFFFu) /******************************************************************************* * Global variable definitions (declared in header file with 'extern') ******************************************************************************/ /******************************************************************************* * Local type definitions ('typedef') ******************************************************************************/ /** ****************************************************************************** ** \brief FLASH OP ** ** Flash 操作控制数据类型重定义 ******************************************************************************/ typedef enum en_flash_op { Read = 0u, ///<读配置值 Program = 1u, ///<编程配置值 SectorErase = 2u, ///<扇区擦除配置值 ChipErase = 3u, ///<全片擦除配置值 } en_flash_op_t; /** ****************************************************************************** ** \brief FLASH 编程时间参数配置 ** ** FLASH编程时间参数配置数组定义 (4MHz) ******************************************************************************/ const uint32_t pu32PcgTimer4M[] = { 0x20u, //Tnvs 0x17u, //Tpgs 0x1Bu, //Tprog 0x4650u, //Tserase 0x222E0u, //Tmerase 0x18u, //Tprcv 0xF0u, //Tsrcv 0x3E8u //Tmrcv }; /******************************************************************************* * Local variable definitions ('static') ******************************************************************************/ /******************************************************************************* * Local function prototypes ('static') ******************************************************************************/ /******************************************************************************* * Function implementation - global ('extern') and local ('static') ******************************************************************************/ /** ***************************************************************************** ** \brief Flash中断标志获取 ** ** ** \param [in] enFlashIntType Flash中断类型 ** ** \retval TRUE or FALSE *****************************************************************************/ boolean_t Flash_GetIntFlag(en_flash_int_type_t enFlashIntType) { boolean_t bRetVal = FALSE; if(M0P_FLASH->IFR & enFlashIntType) { bRetVal = TRUE; } return bRetVal; } /** ***************************************************************************** ** \brief Flash中断标志清除 ** ** ** \param [in] enFlashIntType Flash中断类型 ** ** \retval Ok or Error *****************************************************************************/ en_result_t Flash_ClearIntFlag(en_flash_int_type_t enFlashIntType) { en_result_t enResult = Error; M0P_FLASH->ICLR &= ~(uint32_t)enFlashIntType; enResult = Ok; return enResult; } /** ***************************************************************************** ** \brief Flash中断使能 ** ** ** \param [in] enFlashIntType Flash中断类型 ** ** \retval Ok or Error *****************************************************************************/ en_result_t Flash_EnableIrq (en_flash_int_type_t enFlashIntType) { en_result_t enResult = Error; FLASH_BYPASS(); M0P_FLASH->CR_f.IE |= enFlashIntType; enResult = Ok; return enResult; } /** ***************************************************************************** ** \brief Flash中断禁止 ** ** ** \param [in] enFlashIntType Flash中断类型 ** ** \retval Ok or Error *****************************************************************************/ en_result_t Flash_DisableIrq(en_flash_int_type_t enFlashIntType) { en_result_t enResult = Error; FLASH_BYPASS(); M0P_FLASH->CR_f.IE &= ~(uint32_t)enFlashIntType; enResult = Ok; return enResult; } /** ***************************************************************************** ** \brief FLASH 初始化函数——中断服务程序、编程时间配置及低功耗模式 ** ** 该函数用于配置中断服务函数、低功耗模式、根据系统时钟配置FLASH编程时间相关寄存器. ** ** \param [in] u8FreqCfg FLASH编程时钟频率配置(根据HCLK的频率选择配置值): ** 1 - 4MHz; ** 2 - 8MHz; ** 4 - 16MHz; ** 6 - 24MHz; ** 8 - 32MHz; ** 12 - 48MHz; ** other - 无效值 ** \param [in] bDpstbEn TRUE - 当系统进入DeepSleep模式,FLASH进入低功耗模式; ** FALSE - 当系统进入DeepSleep模式,FLASH不进入低功耗模式; ** ** \retval Ok 操作成功. ** \retval ErrorInvalidParameter 参数无效. ** \retval ErrorUninitialized 初始化失败。 *****************************************************************************/ en_result_t Flash_Init(uint8_t u8FreqCfg, boolean_t bDpstbEn) { uint32_t u32Index = 0; volatile uint32_t u32TimeOut = FLASH_TIMEOUT_INIT; en_result_t enResult = Ok; uint32_t u32PrgTimer[8] = {0}; volatile uint32_t *pu32PrgTimerReg = (volatile uint32_t*)M0P_FLASH; if ((1 != u8FreqCfg) && (2 != u8FreqCfg) && (4 != u8FreqCfg) && (6 != u8FreqCfg) && (8 != u8FreqCfg) && (12 != u8FreqCfg)) { enResult = ErrorInvalidParameter; return (enResult); } M0P_FLASH->CR_f.DPSTB_EN = bDpstbEn; //flash时间参数配置值计算 for(u32Index=0; u32Index<8; u32Index++) { u32PrgTimer[u32Index] = u8FreqCfg * pu32PcgTimer4M[u32Index]; } //flash时间参数寄存器配置 for(u32Index=0; u32Index<8; u32Index++) { u32TimeOut = FLASH_TIMEOUT_INIT; while(pu32PrgTimerReg[u32Index] != u32PrgTimer[u32Index]) { if(u32TimeOut--) { FLASH_BYPASS(); pu32PrgTimerReg[u32Index] = u32PrgTimer[u32Index]; } else { return ErrorUninitialized; } } } return (enResult); } /** ***************************************************************************** ** \brief FLASH 字节写 ** ** 用于向FLASH写入1字节数据. ** ** \param [in] u32Addr Flash地址 ** \param [in] u8Data 1字节数据 ** ** \retval Ok 写入成功. ** \retval ErrorInvalidParameter FLASH地址无效 ** \retval ErrorTimeout 操作超时 *****************************************************************************/ en_result_t Flash_WriteByte(uint32_t u32Addr, uint8_t u8Data) { en_result_t enResult = Ok; volatile uint32_t u32TimeOut = FLASH_TIMEOUT_PGM; if (FLASH_END_ADDR < u32Addr) { enResult = ErrorInvalidParameter; return (enResult); } //busy? u32TimeOut = FLASH_TIMEOUT_PGM; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //set OP u32TimeOut = FLASH_TIMEOUT_PGM; while(Program != M0P_FLASH->CR_f.OP) { if(u32TimeOut--) { FLASH_BYPASS(); M0P_FLASH->CR_f.OP = Program; } else { return ErrorTimeout; } } //Flash 解锁 Flash_UnlockAll(); //write data *((volatile uint8_t*)u32Addr) = u8Data; //busy? u32TimeOut = FLASH_TIMEOUT_PGM; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //Flash 加锁 Flash_LockAll(); return (enResult); } /** ***************************************************************************** ** \brief FLASH 半字写 ** ** 用于向FLASH写入半字(2字节)数据. ** ** \param [in] u32Addr Flash地址 ** \param [in] u16Data 半字(2字节)数据 ** ** \retval Ok 写入成功. ** \retval ErrorInvalidParameter FLASH地址无效 ** \retval ErrorTimeout 操作超时 *****************************************************************************/ en_result_t Flash_WriteHalfWord(uint32_t u32Addr, uint16_t u16Data) { en_result_t enResult = Ok; volatile uint32_t u32TimeOut = FLASH_TIMEOUT_PGM; if (FLASH_END_ADDR < u32Addr) { enResult = ErrorInvalidParameter; return (enResult); } //busy? u32TimeOut = FLASH_TIMEOUT_PGM; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //set OP u32TimeOut = FLASH_TIMEOUT_PGM; while(Program != M0P_FLASH->CR_f.OP) { if(u32TimeOut--) { FLASH_BYPASS(); M0P_FLASH->CR_f.OP = Program; } else { return ErrorTimeout; } } //Flash 解锁 Flash_UnlockAll(); //write data *((volatile uint16_t*)u32Addr) = u16Data; //busy? u32TimeOut = FLASH_TIMEOUT_PGM; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //Flash 加锁 Flash_LockAll(); return (enResult); } /** ***************************************************************************** ** \brief FLASH 字写 ** ** 用于向FLASH写入1个字的数据. ** ** \param [in] u32Addr Flash地址 ** \param [in] u32Data 1个字数据 ** ** \retval Ok 写入成功. ** \retval ErrorInvalidParameter FLASH地址无效 ** \retval ErrorTimeout 操作超时 *****************************************************************************/ en_result_t Flash_WriteWord(uint32_t u32Addr, uint32_t u32Data) { en_result_t enResult = Ok; volatile uint32_t u32TimeOut = FLASH_TIMEOUT_PGM; if (FLASH_END_ADDR < u32Addr) { enResult = ErrorInvalidParameter; return (enResult); } //busy? u32TimeOut = FLASH_TIMEOUT_PGM; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //Flash 解锁 Flash_UnlockAll(); //set OP u32TimeOut = FLASH_TIMEOUT_PGM; while(Program != M0P_FLASH->CR_f.OP) { if(u32TimeOut--) { FLASH_BYPASS(); M0P_FLASH->CR_f.OP = Program; } else { return ErrorTimeout; } } //write data *((volatile uint32_t*)u32Addr) = u32Data; //busy? u32TimeOut = FLASH_TIMEOUT_PGM; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //Flash 加锁 Flash_LockAll(); return (enResult); } /** ***************************************************************************** ** \brief FLASH 扇区擦除 ** ** FLASH 扇区擦除. ** ** \param [in] u32SectorAddr 所擦除扇区内的地址 ** ** \retval Ok 擦除成功. ** \retval ErrorInvalidParameter FLASH地址无效 ** \retval ErrorTimeout 操作超时 *****************************************************************************/ en_result_t Flash_SectorErase(uint32_t u32SectorAddr) { en_result_t enResult = Ok; volatile uint32_t u32TimeOut = FLASH_TIMEOUT_ERASE; if (FLASH_END_ADDR < u32SectorAddr) { enResult = ErrorInvalidParameter; return (enResult); } //busy? u32TimeOut = FLASH_TIMEOUT_ERASE; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //Flash 解锁 Flash_UnlockAll(); //set OP u32TimeOut = FLASH_TIMEOUT_ERASE; while(SectorErase != M0P_FLASH->CR_f.OP) { if(u32TimeOut--) { FLASH_BYPASS(); M0P_FLASH->CR_f.OP = SectorErase; } else { return ErrorTimeout; } } //write data *((volatile uint8_t*)u32SectorAddr) = 0; //busy? u32TimeOut = FLASH_TIMEOUT_ERASE; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //Flash 加锁 Flash_LockAll(); return (enResult); } /** ***************************************************************************** ** \brief FLASH 全片擦除(该函数仅限RAM中运行!!!) ** ** FLASH 全片擦除. ** ** ** \retval Ok 擦除成功. ** \retval ErrorTimeout 操作超时 ** *****************************************************************************/ en_result_t Flash_ChipErase(void) { en_result_t enResult = Ok; volatile uint32_t u32TimeOut = FLASH_TIMEOUT_ERASE; //busy? u32TimeOut = FLASH_TIMEOUT_ERASE; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //set OP u32TimeOut = FLASH_TIMEOUT_ERASE; while(ChipErase != M0P_FLASH->CR_f.OP) { if(u32TimeOut--) { FLASH_BYPASS(); M0P_FLASH->CR_f.OP = ChipErase; } else { return ErrorTimeout; } } //Flash 解锁 Flash_UnlockAll(); //write data *((volatile uint8_t*)0) = 0; //busy? u32TimeOut = FLASH_TIMEOUT_ERASE; while (TRUE == M0P_FLASH->CR_f.BUSY) { if(0 == u32TimeOut--) { return ErrorTimeout; } } //Flash 加锁 Flash_LockAll(); return (enResult); } /** ***************************************************************************** ** \brief FLASH 编程保护加锁 ** ** ** \retval Null *****************************************************************************/ void Flash_LockAll(void) { FLASH_BYPASS(); M0P_FLASH->SLOCK0 = FLASH_LOCK_ALL; FLASH_BYPASS(); M0P_FLASH->SLOCK1 = FLASH_LOCK_ALL; FLASH_BYPASS(); M0P_FLASH->SLOCK2 = FLASH_LOCK_ALL; FLASH_BYPASS(); M0P_FLASH->SLOCK3 = FLASH_LOCK_ALL; } /** ***************************************************************************** ** \brief FLASH 编程保护解锁 ** ** ** \retval Null *****************************************************************************/ void Flash_UnlockAll(void) { FLASH_BYPASS(); M0P_FLASH->SLOCK0 = FLASH_UNLOCK_ALL; FLASH_BYPASS(); M0P_FLASH->SLOCK1 = FLASH_UNLOCK_ALL; FLASH_BYPASS(); M0P_FLASH->SLOCK2 = FLASH_UNLOCK_ALL; FLASH_BYPASS(); M0P_FLASH->SLOCK3 = FLASH_UNLOCK_ALL; } /** ***************************************************************************** ** \brief FLASH 读等待周期设置 ** ** \param [in] enWaitCycle 插入FLASH读等待周期数枚举类型 ** ** \retval Ok 解锁成功 ** \retval ErrorInvalidParameter 参数错误 *****************************************************************************/ en_result_t Flash_WaitCycle(en_flash_waitcycle_t enWaitCycle) { en_result_t enResult = Ok; FLASH_BYPASS(); M0P_FLASH->CR_f.WAIT = enWaitCycle; return enResult; } /** ***************************************************************************** ** \brief FLASH LOCK 设置 ** ** \param [in] enLock @ref en_flash_lock_t ** \param [in] u32LockValue 32bits,对应bit=0:加锁,对应Sector不允许擦写;对应bit=1:解锁。 ** \note 加解锁范围Sector:[enLock*128 + i*4, enLock*128 + i*4+3] ** (i表示u32LockValue的bit位置,0~31) ** 例如:enLock = FlashLock1, u32LockValue = 0x00000002, ** 则加解锁范围为:[Sector128,Sector131] ** \retval Ok 解锁成功 ** \retval ErrorInvalidParameter 参数错误 *****************************************************************************/ en_result_t Flash_LockSet(en_flash_lock_t enLock, uint32_t u32LockValue) { FLASH_BYPASS(); *((&M0P_FLASH->SLOCK0) + enLock) = u32LockValue; return Ok; } //@} // FlashGroup /******************************************************************************* * EOF (not truncated) ******************************************************************************/