1251 lines
40 KiB
C
1251 lines
40 KiB
C
|
|
/**
|
||
|
|
*******************************************************************************
|
||
|
|
* @file hc32_ll_efm.c
|
||
|
|
* @brief This file provides firmware functions to manage the Embedded Flash
|
||
|
|
* Memory unit (EFM).
|
||
|
|
@verbatim
|
||
|
|
Change Logs:
|
||
|
|
Date Author Notes
|
||
|
|
2022-03-31 CDT First version
|
||
|
|
2022-10-31 CDT Add API EFM_Protect_Enable & EFM_WriteSecurityCode
|
||
|
|
Modify API EFM_Read & EFM_Program
|
||
|
|
2023-01-15 CDT Code refine
|
||
|
|
2023-06-30 CDT Modify API EFM_Program()
|
||
|
|
Modify assert IS_EFM_ADDR() range
|
||
|
|
Modify API EFM_Protect_Enable()
|
||
|
|
Modify typo
|
||
|
|
Modify API EFM_WriteSecurityCode(), switch to read_only mode before exit
|
||
|
|
2023-09-30 CDT Remove address assert from EFM_ReadByte()
|
||
|
|
Refine EFM_SequenceProgram() & EFM_ChipErase(), and put them in RAM
|
||
|
|
Fix bug of EFM_GetSwapStatus()
|
||
|
|
@endverbatim
|
||
|
|
*******************************************************************************
|
||
|
|
* Copyright (C) 2022-2023, Xiaohua Semiconductor Co., Ltd. All rights reserved.
|
||
|
|
*
|
||
|
|
* This software component is licensed by XHSC under BSD 3-Clause license
|
||
|
|
* (the "License"); You may not use this file except in compliance with the
|
||
|
|
* License. You may obtain a copy of the License at:
|
||
|
|
* opensource.org/licenses/BSD-3-Clause
|
||
|
|
*
|
||
|
|
*******************************************************************************
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*******************************************************************************
|
||
|
|
* Include files
|
||
|
|
******************************************************************************/
|
||
|
|
#include "hc32_ll_efm.h"
|
||
|
|
#include "hc32_ll_utility.h"
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @addtogroup LL_Driver
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @defgroup LL_EFM EFM
|
||
|
|
* @brief Embedded Flash Management Driver Library
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
|
||
|
|
#if (LL_EFM_ENABLE == DDL_ON)
|
||
|
|
|
||
|
|
/*******************************************************************************
|
||
|
|
* Local type definitions ('typedef')
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
/*******************************************************************************
|
||
|
|
* Local pre-processor symbols/macros ('#define')
|
||
|
|
******************************************************************************/
|
||
|
|
/**
|
||
|
|
* @defgroup EFM_Local_Macros EFM Local Macros
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
#ifndef __EFM_FUNC
|
||
|
|
#define __EFM_FUNC __RAM_FUNC
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define REG_LEN (32U)
|
||
|
|
#define EFM_TIMEOUT (HCLK_VALUE / 20000UL) /* EFM wait read timeout */
|
||
|
|
#define EFM_PGM_TIMEOUT (HCLK_VALUE / 20000UL) /* EFM Program timeout max 53us */
|
||
|
|
#define EFM_ERASE_TIMEOUT (HCLK_VALUE / 50UL) /* EFM Erase timeout max 20ms */
|
||
|
|
#define EFM_SEQ_PGM_TIMEOUT (HCLK_VALUE / 62500UL) /* EFM Sequence Program timeout max 16us */
|
||
|
|
|
||
|
|
#define REMCR_REG(x) (*(__IO uint32_t *)((uint32_t)(&CM_EFM->MMF_REMCR0) + (4UL * (x))))
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @defgroup EFM_Configuration_Bit_Mask EFM Configuration Bit Mask
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
#define EFM_CACHE_ALL (EFM_FRMC_CRST | EFM_FRMC_CACHE)
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @defgroup EFM_protect EFM protect define
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
#define EFM_SECURITY_LEN (12UL)
|
||
|
|
#define EFM_PROTECT1_KEY (0xAF180402UL)
|
||
|
|
#define EFM_PROTECT2_KEY (0xA85173AEUL)
|
||
|
|
|
||
|
|
#define EFM_PROTECT1_ADDR (0x00000410UL)
|
||
|
|
#define EFM_PROTECT2_ADDR (0x00000414UL)
|
||
|
|
#define EFM_SECURITY_ADDR (0x0317FFECUL)
|
||
|
|
#define EFM_SECURITY_ADDR1 (0x0317FFE0UL)
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @defgroup EFM_Check_Parameters_Validity EFM Check Parameters Validity
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
/* Parameter validity check for efm chip . */
|
||
|
|
#define IS_EFM_CHIP(x) ((x) == EFM_CHIP_ALL)
|
||
|
|
|
||
|
|
/* Parameter validity check for flash latency. */
|
||
|
|
#define IS_EFM_WAIT_CYCLE(x) ((x) <= EFM_WAIT_CYCLE15)
|
||
|
|
|
||
|
|
/* Parameter validity check for operate mode. */
|
||
|
|
#define IS_EFM_OPERATE_MD(x) \
|
||
|
|
( ((x) == EFM_MD_PGM_SINGLE) || \
|
||
|
|
((x) == EFM_MD_PGM_READBACK) || \
|
||
|
|
((x) == EFM_MD_PGM_SEQ) || \
|
||
|
|
((x) == EFM_MD_ERASE_SECTOR) || \
|
||
|
|
((x) == EFM_MD_ERASE_ALL_CHIP) || \
|
||
|
|
((x) == EFM_MD_READONLY))
|
||
|
|
|
||
|
|
/* Parameter validity check for flash interrupt select. */
|
||
|
|
#define IS_EFM_INT_SEL(x) (((x) | EFM_INT_ALL) == EFM_INT_ALL)
|
||
|
|
|
||
|
|
/* Parameter validity check for flash flag. */
|
||
|
|
#define IS_EFM_FLAG(x) (((x) | EFM_FLAG_ALL) == EFM_FLAG_ALL)
|
||
|
|
|
||
|
|
/* Parameter validity check for flash clear flag. */
|
||
|
|
#define IS_EFM_CLRFLAG(x) (((x) | EFM_FLAG_ALL) == EFM_FLAG_ALL)
|
||
|
|
|
||
|
|
/* Parameter validity check for bus status while flash program or erase. */
|
||
|
|
#define IS_EFM_BUS_STATUS(x) \
|
||
|
|
( ((x) == EFM_BUS_HOLD) || \
|
||
|
|
((x) == EFM_BUS_RELEASE))
|
||
|
|
|
||
|
|
/* Parameter validity check for efm address. */
|
||
|
|
#define IS_EFM_ADDR(x) \
|
||
|
|
( ((x) <= EFM_END_ADDR) || \
|
||
|
|
(((x) >= EFM_OTP_START_ADDR) && ((x) <= EFM_OTP_END_ADDR)) || \
|
||
|
|
(((x) >= EFM_SECURITY_START_ADDR) && ((x) <= EFM_SECURITY_END_ADDR)))
|
||
|
|
|
||
|
|
/* Parameter validity check for efm erase address. */
|
||
|
|
#define IS_EFM_ERASE_ADDR(x) ((x) <= EFM_END_ADDR)
|
||
|
|
|
||
|
|
/* Parameter validity check for efm erase mode . */
|
||
|
|
#define IS_EFM_ERASE_MD(x) \
|
||
|
|
( ((x) == EFM_MD_ERASE_ONE_CHIP) || \
|
||
|
|
((x) == EFM_MD_ERASE_FULL))
|
||
|
|
|
||
|
|
/* Parameter validity check for EFM lock status. */
|
||
|
|
#define IS_EFM_REG_UNLOCK() (CM_EFM->FAPRT == 0x00000001UL)
|
||
|
|
|
||
|
|
/* Parameter validity check for EFM_FWMC register lock status. */
|
||
|
|
#define IS_EFM_FWMC_UNLOCK() (bCM_EFM->FWMC_b.PEMODE == 1U)
|
||
|
|
|
||
|
|
/* Parameter validity check for EFM remap lock status. */
|
||
|
|
#define IS_EFM_REMAP_UNLOCK() (CM_EFM->MMF_REMPRT == 0x00000001UL)
|
||
|
|
|
||
|
|
/* Parameter validity check for EFM remap index */
|
||
|
|
#define IS_EFM_REMAP_IDX(x) \
|
||
|
|
( ((x) == EFM_REMAP_IDX0) || \
|
||
|
|
((x) == EFM_REMAP_IDX1))
|
||
|
|
|
||
|
|
/* Parameter validity check for EFM remap size */
|
||
|
|
#define IS_EFM_REMAP_SIZE(x) \
|
||
|
|
( ((x) >= EFM_REMAP_4K) && \
|
||
|
|
((x) <= EFM_REMAP_512K))
|
||
|
|
|
||
|
|
/* Parameter validity check for EFM remap address */
|
||
|
|
#define IS_EFM_REMAP_ADDR(x) \
|
||
|
|
( ((x) <= EFM_REMAP_ROM_END_ADDR) || \
|
||
|
|
(((x) >= EFM_REMAP_RAM_START_ADDR) && \
|
||
|
|
((x) <= EFM_REMAP_RAM_END_ADDR)))
|
||
|
|
|
||
|
|
/* Parameter validity check for EFM remap state */
|
||
|
|
#define IS_EFM_REMAP_STATE(x) \
|
||
|
|
( ((x) == EFM_REMAP_OFF) || \
|
||
|
|
((x) == EFM_REMAP_ON))
|
||
|
|
|
||
|
|
/* Parameter validity check for EFM security code length */
|
||
|
|
#define IS_EFM_SECURITY_CODE_LEN(x) ((x) <= EFM_SECURITY_LEN)
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*******************************************************************************
|
||
|
|
* Global variable definitions (declared in header file with 'extern')
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
/*******************************************************************************
|
||
|
|
* Local function prototypes ('static')
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
/*******************************************************************************
|
||
|
|
* Local variable definitions ('static')
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
/*******************************************************************************
|
||
|
|
* Function implementation - global ('extern') and local ('static')
|
||
|
|
******************************************************************************/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @defgroup EFM_Local_Functions EFM Local Functions
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
/**
|
||
|
|
* @brief Wait EFM flag.
|
||
|
|
* @param [in] u32Flag Specifies the flag to be wait. @ref EFM_Flag_Sel
|
||
|
|
* @param [in] u32Time Specifies the time to wait while the flag not be set.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Flag was set.
|
||
|
|
* - LL_ERR_TIMEOUT: Flag was not set.
|
||
|
|
*/
|
||
|
|
static int32_t EFM_WaitFlag(uint32_t u32Flag, uint32_t u32Time)
|
||
|
|
{
|
||
|
|
__IO uint32_t u32Timeout = 0UL;
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
|
||
|
|
while (SET != EFM_GetStatus(u32Flag)) {
|
||
|
|
u32Timeout++;
|
||
|
|
if (u32Timeout > u32Time) {
|
||
|
|
i32Ret = LL_ERR_TIMEOUT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @defgroup EFM_Global_Functions EFM Global Functions
|
||
|
|
* @{
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable or disable EFM.
|
||
|
|
* @param [in] u32Flash Specifies the FLASH. @ref EFM_Chip_Sel
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_Cmd(uint32_t u32Flash, en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_CHIP(u32Flash));
|
||
|
|
|
||
|
|
if (ENABLE == enNewState) {
|
||
|
|
CLR_REG32_BIT(CM_EFM->FSTP, u32Flash);
|
||
|
|
} else {
|
||
|
|
SET_REG32_BIT(CM_EFM->FSTP, u32Flash);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Set the efm read wait cycles.
|
||
|
|
* @param [in] u32WaitCycle Specifies the efm read wait cycles.
|
||
|
|
* @arg This parameter can be of a value of @ref EFM_Wait_Cycle
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Program successfully.
|
||
|
|
* - LL_ERR_TIMEOUT: EFM is not ready.
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
int32_t EFM_SetWaitCycle(uint32_t u32WaitCycle)
|
||
|
|
{
|
||
|
|
uint32_t u32Timeout = 0UL;
|
||
|
|
|
||
|
|
/* Param valid check */
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_WAIT_CYCLE(u32WaitCycle));
|
||
|
|
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_FRMC_FLWT, u32WaitCycle);
|
||
|
|
while (u32WaitCycle != READ_REG32_BIT(CM_EFM->FRMC, EFM_FRMC_FLWT)) {
|
||
|
|
u32Timeout++;
|
||
|
|
if (u32Timeout > EFM_TIMEOUT) {
|
||
|
|
return LL_ERR_TIMEOUT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return LL_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable or disable the flash data cache reset.
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_DataCacheResetCmd(en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
|
||
|
|
WRITE_REG32(bCM_EFM->FRMC_b.CRST, enNewState);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable or disable the flash data cache and instruction cache.
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval None
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
void EFM_CacheCmd(en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
|
||
|
|
WRITE_REG32(bCM_EFM->FRMC_b.CACHE, enNewState);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable or disable the Read of low-voltage mode.
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval None
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
void EFM_LowVoltageReadCmd(en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
|
||
|
|
WRITE_REG32(bCM_EFM->FRMC_b.SLPMD, enNewState);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable or disable the EFM swap function.
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Program successfully.
|
||
|
|
* - LL_ERR_NOT_RDY: EFM is not ready.
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
int32_t EFM_SwapCmd(en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
|
||
|
|
if (enNewState == ENABLE) {
|
||
|
|
/* Set Program single mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_SINGLE);
|
||
|
|
/* Enable flash swap function */
|
||
|
|
RW_MEM32(EFM_SWAP_ADDR) = EFM_SWAP_DATA;
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY, EFM_PGM_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND);
|
||
|
|
} else {
|
||
|
|
/* Set Sector erase mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_ERASE_SECTOR);
|
||
|
|
/* Disable flash switch function */
|
||
|
|
RW_MEM32(EFM_SWAP_ADDR) = 0x0UL;
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY, EFM_ERASE_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND);
|
||
|
|
}
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
|
||
|
|
/* recover CACHE */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Checks whether the swap function enable or disable.
|
||
|
|
* @param None
|
||
|
|
* @retval An @ref en_flag_status_t enumeration type value.
|
||
|
|
*/
|
||
|
|
en_flag_status_t EFM_GetSwapStatus(void)
|
||
|
|
{
|
||
|
|
return ((0UL == READ_REG32(bCM_EFM->FSWP_b.FSWP)) ? SET : RESET);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable or disable the EFM low-voltage mode.
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval None
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
void EFM_LowVoltageCmd(en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
WRITE_REG32(bCM_EFM->FRMC_b.LVM, enNewState);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Set the FLASH erase program mode .
|
||
|
|
* @param [in] u32Mode Specifies the FLASH erase program mode.
|
||
|
|
* @arg This parameter can be of a value of @ref EFM_OperateMode_Sel
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Set mode successfully.
|
||
|
|
* - LL_ERR_NOT_RDY: EFM is not ready.
|
||
|
|
*/
|
||
|
|
int32_t EFM_SetOperateMode(uint32_t u32Mode)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
DDL_ASSERT(IS_EFM_OPERATE_MD(u32Mode));
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY, EFM_SEQ_PGM_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (i32Ret == LL_OK) {
|
||
|
|
/* Set the program or erase mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, u32Mode);
|
||
|
|
}
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable or Disable EFM interrupt.
|
||
|
|
* @param [in] u32EfmInt Specifies the FLASH interrupt source and status. @ref EFM_Interrupt_Sel
|
||
|
|
* @arg EFM_INT_OPTEND: End of EFM Operation Interrupt source
|
||
|
|
* @arg EFM_INT_PEERR: Program/erase error Interrupt source
|
||
|
|
* @arg EFM_INT_COLERR: Read collide error Interrupt source
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval None
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
void EFM_IntCmd(uint32_t u32EfmInt, en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_INT_SEL(u32EfmInt));
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
|
||
|
|
if (ENABLE == enNewState) {
|
||
|
|
SET_REG32_BIT(CM_EFM->FITE, u32EfmInt);
|
||
|
|
} else {
|
||
|
|
CLR_REG32_BIT(CM_EFM->FITE, u32EfmInt);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Check any of the specified flag is set or not.
|
||
|
|
* @param [in] u32Flag Specifies the FLASH flag to check.
|
||
|
|
* @arg This parameter can be of a value of @ref EFM_Flag_Sel
|
||
|
|
* @retval An @ref en_flag_status_t enumeration type value.
|
||
|
|
*/
|
||
|
|
en_flag_status_t EFM_GetAnyStatus(uint32_t u32Flag)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_EFM_FLAG(u32Flag));
|
||
|
|
|
||
|
|
return ((0UL == READ_REG32_BIT(CM_EFM->FSR, u32Flag)) ? RESET : SET);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Check all the specified flag is set or not.
|
||
|
|
* @param [in] u32Flag Specifies the FLASH flag to check.
|
||
|
|
* @arg This parameter can be of a value of @ref EFM_Flag_Sel
|
||
|
|
* @retval An @ref en_flag_status_t enumeration type value.
|
||
|
|
*/
|
||
|
|
en_flag_status_t EFM_GetStatus(uint32_t u32Flag)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_EFM_FLAG(u32Flag));
|
||
|
|
|
||
|
|
return ((u32Flag == READ_REG32_BIT(CM_EFM->FSR, u32Flag)) ? SET : RESET);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Clear the flash flag.
|
||
|
|
* @param [in] u32Flag Specifies the FLASH flag to clear.
|
||
|
|
* @arg This parameter can be of a value of @ref EFM_Flag_Sel
|
||
|
|
* @retval None
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
void EFM_ClearStatus(uint32_t u32Flag)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_CLRFLAG(u32Flag));
|
||
|
|
|
||
|
|
SET_REG32_BIT(CM_EFM->FSCLR, u32Flag);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Set bus status while flash program or erase.
|
||
|
|
* @param [in] u32Status Specifies the new bus status while flash program or erase.
|
||
|
|
* This parameter can be one of the following values:
|
||
|
|
* @arg EFM_BUS_HOLD: Bus busy while flash program or erase.
|
||
|
|
* @arg EFM_BUS_RELEASE: Bus release while flash program or erase.
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_SetBusStatus(uint32_t u32Status)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_BUS_STATUS(u32Status));
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
|
||
|
|
WRITE_REG32(bCM_EFM->FWMC_b.BUSHLDCTL, u32Status);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM read byte.
|
||
|
|
* @param [in] u32Addr The specified address to read.
|
||
|
|
* @param [in] pu8ReadBuf The specified read buffer.
|
||
|
|
* @param [in] u32ByteLen The specified length to read.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Read successfully
|
||
|
|
* - LL_ERR_INVD_PARAM: Invalid parameter
|
||
|
|
* - LL_ERR_NOT_RDY: EFM is not ready.
|
||
|
|
*/
|
||
|
|
int32_t EFM_ReadByte(uint32_t u32Addr, uint8_t *pu8ReadBuf, uint32_t u32ByteLen)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_ERR_INVD_PARAM;
|
||
|
|
__IO uint8_t *pu8Buf = (uint8_t *)u32Addr;
|
||
|
|
uint32_t u32Len = u32ByteLen;
|
||
|
|
uint32_t u32ReadyFlag = EFM_FLAG_RDY;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_ADDR(u32Addr));
|
||
|
|
DDL_ASSERT(IS_EFM_ADDR(u32Addr + u32ByteLen - 1UL));
|
||
|
|
|
||
|
|
if (NULL != pu8ReadBuf) {
|
||
|
|
|
||
|
|
if (LL_OK == EFM_WaitFlag(u32ReadyFlag, EFM_TIMEOUT)) {
|
||
|
|
while (0UL != u32Len) {
|
||
|
|
*(pu8ReadBuf++) = *(pu8Buf++);
|
||
|
|
u32Len--;
|
||
|
|
}
|
||
|
|
i32Ret = LL_OK;
|
||
|
|
} else {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM program (single program mode).
|
||
|
|
* @param [in] u32Addr The specified program address.
|
||
|
|
* @param [in] pu8Buf The pointer of specified program data.
|
||
|
|
* @param [in] u32Len The length of specified program data.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Program successful.
|
||
|
|
* - LL_ERR_NOT_RDY: EFM if not ready.
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
int32_t EFM_Program(uint32_t u32Addr, uint8_t *pu8Buf, uint32_t u32Len)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
uint8_t u8Shift;
|
||
|
|
uint32_t u32LoopWords = u32Len >> 2UL;
|
||
|
|
uint32_t u32RemainBytes = u32Len % 4UL;
|
||
|
|
uint32_t *u32pSource = (uint32_t *)(uint32_t)pu8Buf;
|
||
|
|
uint32_t *u32pDest = (uint32_t *)u32Addr;
|
||
|
|
uint32_t u32LastWord;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_ADDR(u32Addr));
|
||
|
|
DDL_ASSERT(IS_EFM_ADDR(u32Addr + u32Len - 1UL));
|
||
|
|
DDL_ASSERT(IS_ADDR_ALIGN_WORD(u32Addr));
|
||
|
|
|
||
|
|
u8Shift = 0U;
|
||
|
|
|
||
|
|
/* CLear the error flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_ALL);
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
|
||
|
|
/* Set single program mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_SINGLE);
|
||
|
|
|
||
|
|
while (u32LoopWords-- > 0UL) {
|
||
|
|
/* program data. */
|
||
|
|
*u32pDest++ = *u32pSource++;
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY << u8Shift, EFM_PGM_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND << u8Shift);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (0U != u32RemainBytes) {
|
||
|
|
u32LastWord = *u32pSource;
|
||
|
|
u32LastWord |= 0xFFFFFFFFUL << (u32RemainBytes * 8UL);
|
||
|
|
*u32pDest++ = u32LastWord;
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY << u8Shift, EFM_PGM_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND << u8Shift);
|
||
|
|
|
||
|
|
}
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
/* Reset cache data */
|
||
|
|
/* Recover CACHE function */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM single program mode(Word).
|
||
|
|
* @param [in] u32Addr The specified program address.
|
||
|
|
* @param [in] u32Data The specified program data.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Program successfully
|
||
|
|
* - LL_ERR_NOT_RDY: EFM is not ready.
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
int32_t EFM_ProgramWord(uint32_t u32Addr, uint32_t u32Data)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
uint8_t u8Shift;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_ADDR(u32Addr));
|
||
|
|
DDL_ASSERT(IS_ADDR_ALIGN_WORD(u32Addr));
|
||
|
|
|
||
|
|
/* Clear the error flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_ALL);
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE function */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
u8Shift = 0U;
|
||
|
|
/* Set single program mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_SINGLE);
|
||
|
|
/* Program data. */
|
||
|
|
RW_MEM32(u32Addr) = u32Data;
|
||
|
|
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY << u8Shift, EFM_PGM_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND << u8Shift);
|
||
|
|
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
|
||
|
|
/* Recover CACHE function */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM single program with read back(Word).
|
||
|
|
* @param [in] u32Addr The specified program address.
|
||
|
|
* @param [in] u32Data The specified program data.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Program successfully
|
||
|
|
* - LL_ERR: program error
|
||
|
|
* - LL_ERR_NOT_RDY: EFM is not ready.
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
int32_t EFM_ProgramWordReadBack(uint32_t u32Addr, uint32_t u32Data)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
uint8_t u8Shift;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_ADDR(u32Addr));
|
||
|
|
DDL_ASSERT(IS_ADDR_ALIGN_WORD(u32Addr));
|
||
|
|
|
||
|
|
/* Clear the error flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_ALL);
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
u8Shift = 0U;
|
||
|
|
/* Set Program and read back mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_READBACK);
|
||
|
|
/* Program data. */
|
||
|
|
RW_MEM32(u32Addr) = (uint32_t)u32Data;
|
||
|
|
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY << u8Shift, EFM_PGM_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Get the flag PGMISMTCH */
|
||
|
|
if (SET == EFM_GetStatus(EFM_FLAG_PGMISMTCH << u8Shift)) {
|
||
|
|
/* Clear flag PGMISMTCH */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_PGMISMTCH << u8Shift);
|
||
|
|
i32Ret = LL_ERR;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND << u8Shift);
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
|
||
|
|
/* recover CACHE function */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM program (sequence program mode).
|
||
|
|
* @param [in] u32Addr The specified program address.
|
||
|
|
* @param [in] pu8Buf The pointer of specified program data.
|
||
|
|
* @param [in] u32Len The length of specified program data.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Program successfully
|
||
|
|
* - LL_ERR_TIMEOUT: program error timeout
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
* __EFM_FUNC default value is __RAM_FUNC.
|
||
|
|
*/
|
||
|
|
__EFM_FUNC int32_t EFM_SequenceProgram(uint32_t u32Addr, uint8_t *pu8Buf, uint32_t u32Len)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
uint32_t u32LoopWords = u32Len >> 2UL;
|
||
|
|
uint32_t u32RemainBytes = u32Len % 4UL;
|
||
|
|
uint32_t *u32pSource = (uint32_t *)(uint32_t)pu8Buf;
|
||
|
|
uint32_t *u32pDest = (uint32_t *)u32Addr;
|
||
|
|
uint32_t u32Timeout;
|
||
|
|
uint32_t u32LastWord;
|
||
|
|
|
||
|
|
/* Assert */
|
||
|
|
if (!IS_EFM_REG_UNLOCK()) {
|
||
|
|
return LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
if ((!IS_EFM_FWMC_UNLOCK()) || (!IS_EFM_ADDR(u32Addr)) || (!IS_EFM_ADDR(u32Addr + u32Len - 1UL))) {
|
||
|
|
return LL_ERR_INVD_PARAM;
|
||
|
|
}
|
||
|
|
if (!IS_ADDR_ALIGN_WORD(u32Addr)) {
|
||
|
|
return LL_ERR_INVD_PARAM;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* CLear the error flag. */
|
||
|
|
SET_REG32_BIT(CM_EFM->FSCLR, EFM_FLAG_ALL);
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Set sequence program mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_SEQ);
|
||
|
|
|
||
|
|
while (u32LoopWords-- > 0UL) {
|
||
|
|
/* program data. */
|
||
|
|
*u32pDest++ = *u32pSource++;
|
||
|
|
/* wait for operation end flag. */
|
||
|
|
u32Timeout = 0UL;
|
||
|
|
while (EFM_FLAG_OPTEND != READ_REG32_BIT(CM_EFM->FSR, EFM_FLAG_OPTEND)) {
|
||
|
|
if (u32Timeout++ >= EFM_PGM_TIMEOUT) {
|
||
|
|
i32Ret = LL_ERR_TIMEOUT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/* Clear operation end flag */
|
||
|
|
u32Timeout = 0UL;
|
||
|
|
while (EFM_FLAG_OPTEND == READ_REG32_BIT(CM_EFM->FSR, EFM_FLAG_OPTEND)) {
|
||
|
|
SET_REG32_BIT(CM_EFM->FSCLR, EFM_FLAG_OPTEND);
|
||
|
|
if (u32Timeout++ >= EFM_TIMEOUT) {
|
||
|
|
i32Ret = LL_ERR_TIMEOUT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (0U != u32RemainBytes) {
|
||
|
|
u32LastWord = *u32pSource;
|
||
|
|
u32LastWord |= 0xFFFFFFFFUL << (u32RemainBytes * 8UL);
|
||
|
|
*u32pDest++ = u32LastWord;
|
||
|
|
|
||
|
|
/* wait for operation end flag. */
|
||
|
|
u32Timeout = 0UL;
|
||
|
|
while (EFM_FLAG_OPTEND != READ_REG32_BIT(CM_EFM->FSR, EFM_FLAG_OPTEND)) {
|
||
|
|
if (u32Timeout++ >= EFM_PGM_TIMEOUT) {
|
||
|
|
i32Ret = LL_ERR_TIMEOUT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/* Clear operation end flag */
|
||
|
|
u32Timeout = 0UL;
|
||
|
|
while (EFM_FLAG_OPTEND == READ_REG32_BIT(CM_EFM->FSR, EFM_FLAG_OPTEND)) {
|
||
|
|
SET_REG32_BIT(CM_EFM->FSCLR, EFM_FLAG_OPTEND);
|
||
|
|
if (u32Timeout++ >= EFM_TIMEOUT) {
|
||
|
|
i32Ret = LL_ERR_TIMEOUT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
u32Timeout = 0UL;
|
||
|
|
while (EFM_FLAG_RDY != READ_REG32_BIT(CM_EFM->FSR, EFM_FLAG_RDY)) {
|
||
|
|
if (u32Timeout++ >= EFM_PGM_TIMEOUT) {
|
||
|
|
i32Ret = LL_ERR_TIMEOUT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Recover CACHE */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM sector erase.
|
||
|
|
* @param [in] u32Addr The address in the specified sector.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Erase successful.
|
||
|
|
* - LL_ERR_NOT_RDY: EFM is not ready.
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
int32_t EFM_SectorErase(uint32_t u32Addr)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
uint8_t u8Shift;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_ERASE_ADDR(u32Addr));
|
||
|
|
DDL_ASSERT(IS_ADDR_ALIGN_WORD(u32Addr));
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
|
||
|
|
/* CLear the error flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_ALL);
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
u8Shift = 0U;
|
||
|
|
/* Set sector erase mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_ERASE_SECTOR);
|
||
|
|
|
||
|
|
/* Erase */
|
||
|
|
RW_MEM32(u32Addr) = 0UL;
|
||
|
|
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY << u8Shift, EFM_ERASE_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* Clear the operation end flag */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND << u8Shift);
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
/* Recover CACHE */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM chip erase.
|
||
|
|
* @param [in] u8Chip Specifies the chip to be erased @ref EFM_Chip_Sel
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Erase successfully
|
||
|
|
* - LL_ERR_NOT_RDY: EFM is not ready.
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
* __EFM_FUNC default value is __RAM_FUNC.
|
||
|
|
*/
|
||
|
|
__EFM_FUNC int32_t EFM_ChipErase(uint8_t u8Chip)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
uint32_t u32Addr = 0UL;
|
||
|
|
uint8_t u8Shift;
|
||
|
|
uint32_t u32Timeout;
|
||
|
|
|
||
|
|
/* Assert */
|
||
|
|
if (!IS_EFM_REG_UNLOCK()) {
|
||
|
|
return LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
if ((!IS_EFM_FWMC_UNLOCK()) || !IS_EFM_CHIP(u8Chip)) {
|
||
|
|
return LL_ERR_INVD_PARAM;
|
||
|
|
}
|
||
|
|
|
||
|
|
u8Shift = 0U;
|
||
|
|
|
||
|
|
/* CLear the error flag. */
|
||
|
|
SET_REG32_BIT(CM_EFM->FSCLR, EFM_FLAG_ALL);
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
|
||
|
|
if (EFM_CHIP_ALL == u8Chip) {
|
||
|
|
if (1UL == (READ_REG32(bCM_EFM->FSWP_b.FSWP))) {
|
||
|
|
/* Set Sector erase mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_ERASE_SECTOR);
|
||
|
|
/* Disable flash switch function */
|
||
|
|
RW_MEM32(EFM_SWAP_ADDR) = 0x0UL;
|
||
|
|
/* wait for operation end flag. */
|
||
|
|
u32Timeout = 0UL;
|
||
|
|
while (EFM_FLAG_OPTEND != READ_REG32_BIT(CM_EFM->FSR, EFM_FLAG_OPTEND)) {
|
||
|
|
if (u32Timeout++ >= EFM_PGM_TIMEOUT) {
|
||
|
|
i32Ret = LL_ERR_TIMEOUT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag */
|
||
|
|
SET_REG32_BIT(CM_EFM->FSCLR, EFM_FLAG_OPTEND);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Set chip erase mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_ERASE_ALL_CHIP);
|
||
|
|
/* Erase */
|
||
|
|
RW_MEM32(u32Addr) = 0UL;
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
u32Timeout = 0UL;
|
||
|
|
while ((EFM_FLAG_RDY << u8Shift) != READ_REG32_BIT(CM_EFM->FSR, EFM_FLAG_RDY << u8Shift)) {
|
||
|
|
if (u32Timeout++ >= EFM_ERASE_TIMEOUT) {
|
||
|
|
i32Ret = LL_ERR_TIMEOUT;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
SET_REG32_BIT(CM_EFM->FSCLR, EFM_FLAG_OPTEND << u8Shift);
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
|
||
|
|
/* recover CACHE */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief FWMC register write enable or disable.
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_FWMC_Cmd(en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
|
||
|
|
WRITE_REG32(bCM_EFM->FWMC_b.PEMODE, enNewState);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM OTP lock.
|
||
|
|
* @param [in] u32Addr Specifies the OTP block
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Lock successfully
|
||
|
|
* - LL_ERR_NOT_RDY: EFM is not ready.
|
||
|
|
* @note The address should be word align.
|
||
|
|
* Call EFM_REG_Unlock() and EFM_OTP_WP_Unlock() unlock EFM_FWMC register first.
|
||
|
|
*/
|
||
|
|
int32_t EFM_OTP_Lock(uint32_t u32Addr)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
|
||
|
|
if ((u32Addr >= EFM_OTP_LOCK_ADDR_START) && (u32Addr < EFM_OTP_LOCK_ADDR_END)) {
|
||
|
|
DDL_ASSERT(IS_ADDR_ALIGN_WORD(u32Addr));
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
|
||
|
|
/* Set single program mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_SINGLE);
|
||
|
|
|
||
|
|
/* OTP latch */
|
||
|
|
RW_MEM32(u32Addr) = (uint32_t)0UL;
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY, EFM_ERASE_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND);
|
||
|
|
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
|
||
|
|
/* Recover CACHE */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
}
|
||
|
|
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Set flash protect area.
|
||
|
|
* @param [in] u32StartAddr Start address of protect area.
|
||
|
|
* @param [in] u32EndAddr End address of protect area.
|
||
|
|
* @retval None
|
||
|
|
* @note Call EFM_REG_Unlock() unlock EFM register first.
|
||
|
|
*/
|
||
|
|
void EFM_SetWindowProtectAddr(uint32_t u32StartAddr, uint32_t u32EndAddr)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_ADDR(u32StartAddr));
|
||
|
|
DDL_ASSERT(IS_EFM_ADDR(u32EndAddr));
|
||
|
|
/* Set protect area start address */
|
||
|
|
WRITE_REG32(CM_EFM->FPMTSW, u32StartAddr);
|
||
|
|
/* Set protect area end address */
|
||
|
|
WRITE_REG32(CM_EFM->FPMTEW, u32EndAddr);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Get unique ID.
|
||
|
|
* @param [out] pstcUID Unique ID struct
|
||
|
|
* @retval Returns the value of the unique ID
|
||
|
|
*/
|
||
|
|
void EFM_GetUID(stc_efm_unique_id_t *pstcUID)
|
||
|
|
{
|
||
|
|
if (NULL != pstcUID) {
|
||
|
|
pstcUID->u32UniqueID0 = READ_REG32(CM_EFM->UQID0);
|
||
|
|
pstcUID->u32UniqueID1 = READ_REG32(CM_EFM->UQID1);
|
||
|
|
pstcUID->u32UniqueID2 = READ_REG32(CM_EFM->UQID2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Init REMAP initial structure with default value.
|
||
|
|
* @param [in] pstcEfmRemapInit specifies the Parameter of REMAP.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Initialize success
|
||
|
|
* - LL_ERR_INVD_PARAM: NULL pointer
|
||
|
|
*/
|
||
|
|
int32_t EFM_REMAP_StructInit(stc_efm_remap_init_t *pstcEfmRemapInit)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
if (NULL == pstcEfmRemapInit) {
|
||
|
|
i32Ret = LL_ERR_INVD_PARAM;
|
||
|
|
} else {
|
||
|
|
pstcEfmRemapInit->u32State = EFM_REMAP_OFF;
|
||
|
|
pstcEfmRemapInit->u32Addr = 0UL;
|
||
|
|
pstcEfmRemapInit->u32Size = EFM_REMAP_4K;
|
||
|
|
}
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief REMAP initialize.
|
||
|
|
* @param [in] u8RemapIdx Specifies the remap ID.
|
||
|
|
* @param [in] pstcEfmRemapInit specifies the Parameter of REMAP.
|
||
|
|
* @retval int32_t:
|
||
|
|
* - LL_OK: Initialize success
|
||
|
|
* - LL_ERR_INVD_PARAM: NULL pointer
|
||
|
|
*/
|
||
|
|
int32_t EFM_REMAP_Init(uint8_t u8RemapIdx, stc_efm_remap_init_t *pstcEfmRemapInit)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
__IO uint32_t *REMCRx;
|
||
|
|
|
||
|
|
if (NULL == pstcEfmRemapInit) {
|
||
|
|
i32Ret = LL_ERR_INVD_PARAM;
|
||
|
|
} else {
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_IDX(u8RemapIdx));
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_SIZE(pstcEfmRemapInit->u32Size));
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_ADDR(pstcEfmRemapInit->u32Addr));
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_STATE(pstcEfmRemapInit->u32State));
|
||
|
|
if ((pstcEfmRemapInit->u32Addr % (1UL << pstcEfmRemapInit->u32Size)) != 0U) {
|
||
|
|
i32Ret = LL_ERR_INVD_PARAM;
|
||
|
|
} else {
|
||
|
|
REMCRx = &REMCR_REG(u8RemapIdx);
|
||
|
|
MODIFY_REG32(*REMCRx, EFM_MMF_REMCR_EN | EFM_MMF_REMCR_RMTADDR | EFM_MMF_REMCR_RMSIZE, \
|
||
|
|
pstcEfmRemapInit->u32State | pstcEfmRemapInit->u32Addr | pstcEfmRemapInit->u32Size);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief EFM REMAP de-initialize.
|
||
|
|
* @param None
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_REMAP_DeInit(void)
|
||
|
|
{
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_UNLOCK());
|
||
|
|
|
||
|
|
WRITE_REG32(CM_EFM->MMF_REMCR0, 0UL);
|
||
|
|
WRITE_REG32(CM_EFM->MMF_REMCR1, 0UL);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable or disable REMAP function.
|
||
|
|
* @param [in] u8RemapIdx Specifies the remap ID.
|
||
|
|
* @param [in] enNewState An @ref en_functional_state_t enumeration value.
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_REMAP_Cmd(uint8_t u8RemapIdx, en_functional_state_t enNewState)
|
||
|
|
{
|
||
|
|
__IO uint32_t *REMCRx;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_IDX(u8RemapIdx));
|
||
|
|
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
|
||
|
|
|
||
|
|
REMCRx = &REMCR_REG(u8RemapIdx);
|
||
|
|
if (ENABLE == enNewState) {
|
||
|
|
SET_REG32_BIT(*REMCRx, EFM_MMF_REMCR_EN);
|
||
|
|
} else {
|
||
|
|
CLR_REG32_BIT(*REMCRx, EFM_MMF_REMCR_EN);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Set specified REMAP target address.
|
||
|
|
* @param [in] u8RemapIdx Specifies the remap ID.
|
||
|
|
* @param [in] u32Addr Specifies the target address.
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_REMAP_SetAddr(uint8_t u8RemapIdx, uint32_t u32Addr)
|
||
|
|
{
|
||
|
|
__IO uint32_t *REMCRx;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_IDX(u8RemapIdx));
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_ADDR(u32Addr));
|
||
|
|
|
||
|
|
REMCRx = &REMCR_REG(u8RemapIdx);
|
||
|
|
MODIFY_REG32(*REMCRx, EFM_MMF_REMCR_RMTADDR, u32Addr);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Set specified REMAP size.
|
||
|
|
* @param [in] u8RemapIdx Specifies the remap ID.
|
||
|
|
* @param [in] u32Size Specifies the remap size.
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_REMAP_SetSize(uint8_t u8RemapIdx, uint32_t u32Size)
|
||
|
|
{
|
||
|
|
__IO uint32_t *REMCRx;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_IDX(u8RemapIdx));
|
||
|
|
DDL_ASSERT(IS_EFM_REMAP_SIZE(u32Size));
|
||
|
|
|
||
|
|
REMCRx = &REMCR_REG(u8RemapIdx);
|
||
|
|
MODIFY_REG32(*REMCRx, EFM_MMF_REMCR_RMSIZE, u32Size);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Enable efm protect.
|
||
|
|
* @param [in] u8Level Specifies the protect level. @ref EFM_Protect_Level
|
||
|
|
* @retval None
|
||
|
|
*/
|
||
|
|
void EFM_Protect_Enable(uint8_t u8Level)
|
||
|
|
{
|
||
|
|
uint8_t u8Code[12] = {0};
|
||
|
|
|
||
|
|
(void)EFM_Program(EFM_SECURITY_ADDR1, u8Code, sizeof(u8Code));
|
||
|
|
if (EFM_PROTECT_LEVEL1 == u8Level) {
|
||
|
|
(void)EFM_ProgramWord(EFM_PROTECT1_ADDR, EFM_PROTECT1_KEY);
|
||
|
|
} else if (EFM_PROTECT_LEVEL2 == u8Level) {
|
||
|
|
(void)EFM_ProgramWord(EFM_PROTECT2_ADDR, EFM_PROTECT2_KEY);
|
||
|
|
} else {
|
||
|
|
/* rsvd */
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Write the security code.
|
||
|
|
* @param [in] pu8Buf Specifies the security code.
|
||
|
|
* @param [in] u32Len Specified the length of the security code.
|
||
|
|
* @retval int32_t
|
||
|
|
*/
|
||
|
|
int32_t EFM_WriteSecurityCode(uint8_t *pu8Buf, uint32_t u32Len)
|
||
|
|
{
|
||
|
|
int32_t i32Ret = LL_OK;
|
||
|
|
uint32_t u32Tmp;
|
||
|
|
uint32_t u32LoopWords = u32Len >> 2UL;
|
||
|
|
uint32_t *u32pSource = (uint32_t *)(uint32_t)pu8Buf;
|
||
|
|
uint32_t *u32pDest = (uint32_t *)EFM_SECURITY_ADDR;
|
||
|
|
|
||
|
|
DDL_ASSERT(IS_EFM_REG_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_FWMC_UNLOCK());
|
||
|
|
DDL_ASSERT(IS_EFM_SECURITY_CODE_LEN(u32Len));
|
||
|
|
|
||
|
|
/* CLear the error flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_ALL);
|
||
|
|
/* Get CACHE status */
|
||
|
|
u32Tmp = READ_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
/* Disable CACHE */
|
||
|
|
CLR_REG32_BIT(CM_EFM->FRMC, EFM_CACHE_ALL);
|
||
|
|
|
||
|
|
/* Set sector erase mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_ERASE_SECTOR);
|
||
|
|
/* Erase */
|
||
|
|
RW_MEM32(EFM_SECURITY_ADDR) = 0UL;
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY, EFM_PGM_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND);
|
||
|
|
|
||
|
|
/* Set single program mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_PGM_SINGLE);
|
||
|
|
|
||
|
|
while (u32LoopWords-- > 0UL) {
|
||
|
|
/* program data. */
|
||
|
|
*u32pDest++ = *u32pSource++;
|
||
|
|
/* Wait for ready flag. */
|
||
|
|
if (LL_ERR_TIMEOUT == EFM_WaitFlag(EFM_FLAG_RDY, EFM_PGM_TIMEOUT)) {
|
||
|
|
i32Ret = LL_ERR_NOT_RDY;
|
||
|
|
}
|
||
|
|
/* CLear the operation end flag. */
|
||
|
|
EFM_ClearStatus(EFM_FLAG_OPTEND);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Set read only mode. */
|
||
|
|
MODIFY_REG32(CM_EFM->FWMC, EFM_FWMC_PEMOD, EFM_MD_READONLY);
|
||
|
|
|
||
|
|
/* Recover CACHE function */
|
||
|
|
MODIFY_REG32(CM_EFM->FRMC, EFM_CACHE_ALL, u32Tmp);
|
||
|
|
return i32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
#endif /* LL_EFM_ENABLE */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @}
|
||
|
|
*/
|
||
|
|
|
||
|
|
/******************************************************************************
|
||
|
|
* EOF (not truncated)
|
||
|
|
*****************************************************************************/
|