828eco基于GD32H7mcu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1984 lines
77 KiB

/*!
\file gd32h75e_fmc.c
\brief FMC driver
\version 2025-08-07, V1.2.0, firmware for GD32H75E
*/
/*
Copyright (c) 2025, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#include "gd32h75e_fmc.h"
#define FLASH_DENSITY_ADDRESS ((uint32_t)0x1FF0F7E0U) /*!< memory density information address */
#define FLASH_DENSITY_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of FLASH_DENSITY in memory density information */
/* FMC register bit offset */
#define BTADDR_BOOT_ADDR0_OFFSET ((uint32_t)0x00000000U) /*!< bit offset of BOOT_ADDR0 in FMC_BTADDR_EFT/FMC_BTADDR_MDF register*/
#define BTADDR_BOOT_ADDR1_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of BOOT_ADDR1 in FMC_BTADDR_EFT/FMC_BTADDR_MDF register */
#define SCRADDR_SCR_AREA_START_OFFSET ((uint32_t)0x00000000U) /*!< bit offset of SCR_AREA_START in FMC_SCRADDR_EFT/FMC_SCRADDR_MDF register */
#define SCRADDR_SCR_AREA_END_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of SCR_AREA_END in FMC_SCRADDR_EFT/FMC_SCRADDR_MDF register */
#define DCRPADDR_DCRP_AREA_START_OFFSET ((uint32_t)0x00000000U) /*!< bit offset of DCRP_AREA_START in FMC_DCRPADDR_EFT/FMC_DCRPADDR_MDF register */
#define DCRPADDR_DCRP_AREA_END_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of DCRP_AREA_END in FMC_DCRPADDR_EFT/FMC_DCRPADDR_MDF register */
#define OBSTAT0_SPC_OFFSET ((uint32_t)0x00000008U) /*!< bit offset of SPC in FMC_OBSTAT0_EFT/FMC_OBSTAT0_MDF register */
#define OBSTAT1_DATA_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of DATA in FMC_OBSTAT1_EFT/FMC_OBSTAT1_MDF register */
#define NODEC_NODEC_AREA_START_OFFSET ((uint32_t)0x00000000U) /*!< bit offset of SCR_AREA_START in FMC_SCRADDR_EFT/FMC_SCRADDR_MDF register */
#define NODEC_NODEC_AREA_END_OFFSET ((uint32_t)0x00000010U) /*!< bit offset of SCR_AREA_END in FMC_SCRADDR_EFT/FMC_SCRADDR_MDF register */
/* option byte factory value */
#define OB_OBSTAT0_FACTORY_VALUE ((uint32_t)0x01C6AAD0U) /*!< the factory value of option byte in FMC_OBSTAT0_EFT/FMC_OBSTAT0_MDF */
#define OB_OBSTAT1_FACTORY_VALUE ((uint32_t)0x00000087U) /*!< the factory value of option byte in FMC_OBSTAT1_EFT/FMC_OBSTAT1_MDF */
#define OB_BTADDR_FACTORY_VALUE ((uint32_t)0x1FF00800U) /*!< the factory value of option byte in FMC_BTADDR_EFT/FMC_BTADDR_MDF */
#define OB_DCRPADDR_FACTORY_VALUE ((uint32_t)0x000000FFU) /*!< the factory value of option byte in FMC_DCRPADDR_EFT/FMC_DCRPADDR_MDF */
#define OB_SCRADDR_FACTORY_VALUE ((uint32_t)0x000000FFU) /*!< the factory value of option byte in FMC_SCRADDR_EFT/FMC_SCRADDR_MDF */
#define OB_WP_FACTORY_VALUE ((uint32_t)0x3FFFFFFFU) /*!< the factory value of option byte in FMC_WP_EFT/FMC_WP_MDF */
/* invalid DCRP area value */
#define INVALID_DCRP_START_ADDR ((uint32_t)0x000000FFU) /*!< the start address to make DCRP area invalid */
#define INVALID_DCRP_END_ADDR ((uint32_t)0x00000000U) /*!< the end address to make DCRP area invalid */
/* invalid SCR area value */
#define INVALID_SCR_START_ADDR ((uint32_t)0x000000FFU) /*!< the start address to make SCR area invalid */
#define INVALID_SCR_END_ADDR ((uint32_t)0x00000000U) /*!< the end address to make SCR area invalid */
/* get FMC state */
static fmc_state_enum fmc_state_get(void);
/* check whether FMC is ready or not */
static fmc_state_enum fmc_ready_wait(uint32_t timeout);
/*!
\brief unlock FMC_CTL register (API_ID(0x0001U))
\param[in] none
\param[out] none
\retval none
*/
void fmc_unlock(void)
{
if((RESET != (FMC_CTL & FMC_CTL_LK))) {
/* write the FMC key */
FMC_KEY = UNLOCK_KEY0;
FMC_KEY = UNLOCK_KEY1;
}
}
/*!
\brief lock FMC_CTL register (API_ID(0x0002U))
\param[in] none
\param[out] none
\retval none
*/
void fmc_lock(void)
{
/* set the LK bit*/
FMC_CTL |= FMC_CTL_LK;
}
/*!
\brief FMC erase sector (API_ID(0x0003U))
\param[in] address: address to erase
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_sector_erase(uint32_t address)
{
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_VALID_PAGEERASE_ADDR(address)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0003U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
FMC_CTL |= FMC_CTL_SER;
/* write the sector address */
FMC_ADDR = address;
/* start sector erase */
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the SER bit */
FMC_CTL &= (~FMC_CTL_SER);
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC typical mass erase (API_ID(0x0004U))
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_typical_mass_erase(void)
{
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
/* enable mass erase operation */
FMC_CTL |= FMC_CTL_MER;
/* start whole chip erase */
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the MER bit */
FMC_CTL &= ~FMC_CTL_MER;
}
/* return the fmc state */
return fmc_state;
}
/*!
\brief FMC protection-removed mass erase (API_ID(0x0005U))
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_protection_removed_mass_erase(void)
{
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
/* remove DCRP area */
ob_dcrp_area_config(OB_DCRP_AREA_ERASE_ENABLE, INVALID_DCRP_START_ADDR, INVALID_DCRP_END_ADDR);
/* remove secure-access area */
ob_secure_area_config(OB_SCR_AREA_ERASE_ENABLE, INVALID_SCR_START_ADDR, INVALID_SCR_END_ADDR);
/* disable all sectors' erase/program protection */
ob_write_protection_disable(OB_WP_ALL);
/* enable mass erase operation */
FMC_CTL |= FMC_CTL_MER;
/* start chip erase */
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the MER bit */
FMC_CTL &= ~FMC_CTL_MER;
}
/* return the fmc state */
return fmc_state;
}
/*!
\brief FMC program a word at the corresponding address (API_ID(0x0006U))
\param[in] address: address to program
\param[in] data: word to program
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
{
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_VALID_PROGRAM_ADDR(address)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0006U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
/* set the PG bit to start program */
FMC_CTL |= FMC_CTL_PG;
__ISB();
__DSB();
REG32(address) = data;
__ISB();
__DSB();
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PG bit */
FMC_CTL &= ~FMC_CTL_PG;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC program a double-word at the corresponding address (API_ID(0x0007U))
\param[in] address: address to program
\param[in] data: double word to program
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_doubleword_program(uint32_t address, uint64_t data)
{
uint32_t data0, data1;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_VALID_PROGRAM_ADDR(address)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0007U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
data0 = (uint32_t)(data & 0xFFFFFFFFU);
data1 = (uint32_t)((data >> 32U) & 0xFFFFFFFFU);
if(FMC_READY == fmc_state) {
/* set the PG bit to start program */
FMC_CTL |= FMC_CTL_PG;
__ISB();
__DSB();
REG32(address) = data0;
REG32(address + 4U) = data1;
__ISB();
__DSB();
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PG bit */
FMC_CTL &= ~FMC_CTL_PG;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief enable check programming area (API_ID(0x0008U))
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_check_programming_area_enable(void)
{
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
fmc_unlock();
FMC_CTL |= FMC_CTL_PGCHEN;
fmc_lock();
/* return the FMC state */
return fmc_state;
}
/*!
\brief disable check programming area (API_ID(0x0009U))
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_check_programming_area_disable(void)
{
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
fmc_unlock();
FMC_CTL &= ~FMC_CTL_PGCHEN;
fmc_lock();
/* return the FMC state */
return fmc_state;
}
/*!
\brief unlock the option byte operation (API_ID(0x000AU))
\param[in] none
\param[out] none
\retval none
*/
void ob_unlock(void)
{
if(RESET != (FMC_OBCTL & FMC_OBCTL_OBLK)) {
/* write the FMC key */
FMC_OBKEY = OB_UNLOCK_KEY0;
FMC_OBKEY = OB_UNLOCK_KEY1;
}
}
/*!
\brief lock the option byte operation (API_ID(0x000BU))
\param[in] none
\param[out] none
\retval none
*/
void ob_lock(void)
{
/* set the OB_LK bit */
FMC_OBCTL |= FMC_OBCTL_OBLK;
}
/*!
\brief send option bytes modification start command (API_ID(0x000CU))
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_start(void)
{
fmc_state_enum fmc_state = FMC_READY;
/* set the OB_START bit in OBCTL register */
FMC_OBCTL |= FMC_OBCTL_OBSTART;
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
return fmc_state;
}
/*!
\brief modify option byte to factory value (API_ID(0x000DU))
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_factory_value_config(void)
{
uint32_t obstat0_reg;
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
/* get the option byte security protection value */
obstat0_reg = (FMC_OBSTAT0_EFT & FMC_OBSTAT0_EFT_SPC);
/* write factory value to FMC_OBSTAT0_MDF */
FMC_OBSTAT0_MDF = obstat0_reg | OB_OBSTAT0_FACTORY_VALUE;
/* write factory value to FMC_OBSTAT1_MDF */
FMC_OBSTAT1_MDF = OB_OBSTAT1_FACTORY_VALUE;
/* write factory value to FMC_BTADDR_MDF */
FMC_BTADDR_MDF = OB_BTADDR_FACTORY_VALUE;
/* write factory value to FMC_DCRPADDR_MDF */
FMC_DCRPADDR_MDF = OB_DCRPADDR_FACTORY_VALUE;
/* write factory value to FMC_SCRADDR_MDF */
FMC_SCRADDR_MDF = OB_SCRADDR_FACTORY_VALUE;
/* write factory value to FMC_WP_MDF */
FMC_WP_MDF = OB_WP_FACTORY_VALUE;
}
fmc_state = ob_start();
return fmc_state;
}
/*!
\brief enable secure access mode (API_ID(0x000EU))
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_secure_access_mode_enable(void)
{
uint32_t obstat0_reg;
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat0_reg = FMC_OBSTAT0_EFT;
/* enable secure access mode */
obstat0_reg |= FMC_OBSTAT0_MDF_SCR;
FMC_OBSTAT0_MDF = obstat0_reg;
}
return fmc_state;
}
/*!
\brief disable secure access mode (API_ID(0x000FU))
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_secure_access_mode_disable(void)
{
uint32_t obstat0_reg;
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat0_reg = FMC_OBSTAT0_EFT;
/* disable secure access mode */
obstat0_reg &= ~FMC_OBSTAT0_MDF_SCR;
FMC_OBSTAT0_MDF = obstat0_reg;
}
return fmc_state;
}
/*!
\brief configure the option byte security protection level (API_ID(0x0010U))
\param[in] ob_spc: specify security protection level
only one parameter can be selected which is shown as below:
\arg FMC_NSPC: no protection
\arg FMC_LSPC: protection level low
\arg FMC_HSPC: protection level high
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
{
uint32_t obstat0_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_SPC_VALUE(ob_spc)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0010U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat0_reg = FMC_OBSTAT0_EFT;
/* reset the OBSTAT0_SPC, set according to ob_spc */
obstat0_reg &= ~FMC_OBSTAT0_MDF_SPC;
obstat0_reg |= ((uint32_t)ob_spc << OBSTAT0_SPC_OFFSET);
FMC_OBSTAT0_MDF = obstat0_reg;
}
}
return fmc_state;
}
/*!
\brief configure the option byte BOR threshold value (API_ID(0x0011U))
\param[in] ob_bor_th: option byte BOR threshold value
only one parameter can be selected which is shown as below:
\arg OB_BOR_TH_VALUE3: BOR threshold value 3
\arg OB_BOR_TH_VALUE2: BOR threshold value 2
\arg OB_BOR_TH_VALUE1: BOR threshold value 1
\arg OB_BOR_TH_OFF: no BOR function
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_bor_threshold_config(uint32_t ob_bor_th)
{
uint32_t obstat0_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_BOR_TH(ob_bor_th)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0011U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat0_reg = FMC_OBSTAT0_EFT;
/* set BOR threshold level */
obstat0_reg &= ~FMC_OBSTAT0_MDF_BOR_TH;
FMC_OBSTAT0_MDF = (uint32_t)(obstat0_reg | ob_bor_th);
}
}
return fmc_state;
}
/*!
\brief configure low power related option byte (API_ID(0x0012U))
\param[in] ob_fwdgt: option byte watchdog value
only one parameter can be selected which is shown as below:
\arg OB_FWDGT_SW: software free watchdog
\arg OB_FWDGT_HW: hardware free watchdog
\param[in] ob_deepsleep: option byte deepsleep reset value
only one parameter can be selected which is shown as below:
\arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
\arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
\param[in] ob_stdby:option byte standby reset value
only one parameter can be selected which is shown as below:
\arg OB_STDBY_NRST: no reset when entering standby mode
\arg OB_STDBY_RST: generate a reset instead of entering standby mode
\param[in] ob_fwdg_suspend_deepsleep: option byte FWDG suspend status in deep-sleep mode
only one parameter can be selected which is shown as below:
\arg OB_DPSLP_FWDGT_SUSPEND: free watchdog is suspended in deep-sleep mode
\arg OB_DPSLP_FWDGT_RUN: free watchdog is running in deep-sleep mode
\param[in] ob_fwdg_suspend_standby: option byte FWDG suspend status in standby mode
only one parameter can be selected which is shown as below:
\arg OB_STDBY_FWDGT_SUSPEND: free watchdog is suspended in standby mode
\arg OB_STDBY_FWDGT_RUN: free watchdog is running in standby mode
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_low_power_config(uint32_t ob_fwdgt, uint32_t ob_deepsleep, uint32_t ob_stdby, uint32_t ob_fwdg_suspend_deepsleep,
uint32_t ob_fwdg_suspend_standby)
{
uint32_t obstat0_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_FWDGT_VALUE(ob_fwdgt)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0012U), ERR_PARAM_INVALID);
} else if(NOT_FMC_DEEPSLEEP_VALUE(ob_deepsleep)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0012U), ERR_PARAM_INVALID);
} else if(NOT_FMC_STDBY_VALUE(ob_stdby)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0012U), ERR_PARAM_INVALID);
} else if(NOT_FMC_DPSLP_FWDGT_VALUE(ob_fwdg_suspend_deepsleep)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0012U), ERR_PARAM_INVALID);
} else if(NOT_FMC_STDBY_FWDGT_VALUE(ob_fwdg_suspend_standby)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0012U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat0_reg = FMC_OBSTAT0_EFT;
/* set according to ob_fwdgt, ob_deepsleep, ob_stdby, ob_fwdg_suspend_deepsleep, ob_fwdg_suspend_standby */
obstat0_reg &= ~(FMC_OBSTAT0_MDF_NWDG_HW | FMC_OBSTAT0_MDF_NRST_DPSLP | FMC_OBSTAT0_MDF_NRST_STDBY
| FMC_OBSTAT0_MDF_FWDGSPD_DPSLP | FMC_OBSTAT0_MDF_FWDGSPD_STDBY);
FMC_OBSTAT0_MDF = (uint32_t)(obstat0_reg | ob_fwdgt | ob_deepsleep | ob_stdby | ob_fwdg_suspend_deepsleep | ob_fwdg_suspend_standby);
}
}
return fmc_state;
}
/*!
\brief configure TCM ECC option byte (API_ID(0x0013U))
\param[in] ob_itcmecc: ITCM ECC function enable bit
only one parameter can be selected which is shown as below:
\arg OB_ITCMECCEN_DISABLE: disabled ITCM ECC function
\arg OB_ITCMECCEN_ENABLE: enabled ITCM ECC function
\param[in] ob_dtcm0ecc: DTCM0 ECC function enable bit
only one parameter can be selected which is shown as below:
\arg OB_DTCM0ECCEN_DISABLE: disabled DTCM0 ECC function
\arg OB_DTCM0ECCEN_ENABLE: enabled DTCM0 ECC function
\param[in] ob_dtcm1ecc: DTCM1 ECC function enable bit
only one parameter can be selected which is shown as below:
\arg OB_DTCM1ECCEN_DISABLE: disabled DTCM1 ECC function
\arg OB_DTCM1ECCEN_ENABLE: enabled DTCM1 ECC function
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_tcm_ecc_config(uint32_t ob_itcmecc, uint32_t ob_dtcm0ecc, uint32_t ob_dtcm1ecc)
{
uint32_t obstat0_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_ITCMECCEN_VALUE(ob_itcmecc)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0013U), ERR_PARAM_INVALID);
} else if(NOT_FMC_DTCM0ECCEN_VALUE(ob_dtcm0ecc)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0013U), ERR_PARAM_INVALID);
} else if(NOT_FMC_DTCM1ECCEN_VALUE(ob_dtcm1ecc)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0013U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat0_reg = FMC_OBSTAT0_EFT;
/* set according to ob_itcmecc, ob_dtcm0ecc, ob_stdby, ob_dtcm1ecc */
obstat0_reg &= ~(FMC_OBSTAT0_MDF_ITCMECCEN | FMC_OBSTAT0_MDF_DTCM0ECCEN | FMC_OBSTAT0_MDF_DTCM1ECCEN);
FMC_OBSTAT0_MDF = (uint32_t)(obstat0_reg | ob_itcmecc | ob_dtcm0ecc | ob_dtcm1ecc);
}
}
return fmc_state;
}
/*!
\brief configure I/O speed optimization option byte (API_ID(0x0014U))
\param[in] ob_iospeed_op: configure I/O speed optimization, high-speed at low-voltage enable bit
only one parameter can be selected which is shown as below:
\arg OB_IOSPDOPEN_DISABLE: disabled I/O speed optimization
\arg OB_IOSPDOPEN_ENABLE: enabled I/O speed optimization
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_iospeed_optimize_config(uint32_t ob_iospeed_op)
{
uint32_t obstat0_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_IOSPDOPEN_VALUE(ob_iospeed_op)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0014U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat0_reg = FMC_OBSTAT0_EFT;
/* set according to ob_iospeed_op */
obstat0_reg &= ~(FMC_OBSTAT0_MDF_IOSPDOPEN);
FMC_OBSTAT0_MDF = (uint32_t)(obstat0_reg | ob_iospeed_op);
}
}
return fmc_state;
}
/*!
\brief configure option byte TCM shared RAM size (API_ID(0x0015U))
ITCM RAM + DTCM RAM size should not exceed 512KB
\param[in] itcm_shared_ram_size: ITCM shared RAM size
only one parameter can be selected which is shown as below:
\arg OB_ITCM_SHARED_RAM_0KB: ITCM shared RAM size is 0KB
\arg OB_ITCM_SHARED_RAM_64KB: ITCM shared RAM size is 64KB
\arg OB_ITCM_SHARED_RAM_128KB: ITCM shared RAM size is 128KB
\arg OB_ITCM_SHARED_RAM_256KB: ITCM shared RAM size is 256KB
\arg OB_ITCM_SHARED_RAM_512KB: ITCM shared RAM size is 512KB
\param[in] dtcm_shared_ram_size: DTCM shared RAM size
only one parameter can be selected which is shown as below:
\arg OB_DTCM_SHARED_RAM_0KB: DTCM shared RAM size is 0KB
\arg OB_DTCM_SHARED_RAM_64KB: DTCM shared RAM size is 64KB
\arg OB_DTCM_SHARED_RAM_128KB: DTCM shared RAM size is 128KB
\arg OB_DTCM_SHARED_RAM_256KB: DTCM shared RAM size is 256KB
\arg OB_DTCM_SHARED_RAM_512KB: DTCM shared RAM size is 512KB
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_tcm_shared_ram_config(uint32_t itcm_shared_ram_size, uint32_t dtcm_shared_ram_size)
{
uint32_t obstat1_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_ITCM_SHARED_RAM_VALUE(itcm_shared_ram_size)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0015U), ERR_PARAM_INVALID);
} else if(NOT_FMC_DTCM_SHARED_RAM_VALUE(dtcm_shared_ram_size)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0015U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat1_reg = FMC_OBSTAT1_EFT;
/* set ITCM shared ram size according to itcm_shared_ram_size */
obstat1_reg &= ~FMC_OBSTAT1_MDF_ITCM_SZ_SHRRAM;
obstat1_reg |= itcm_shared_ram_size;
/* set DTCM shared ram size according to dtcm_shared_ram_size */
obstat1_reg &= ~FMC_OBSTAT1_MDF_DTCM_SZ_SHRRAM;
obstat1_reg |= dtcm_shared_ram_size;
FMC_OBSTAT1_MDF = obstat1_reg;
}
}
return fmc_state;
}
/*!
\brief modify option byte DATA (API_ID(0x0016U))
\param[in] ob_data: option bytes user data
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_data_program(uint16_t ob_data)
{
uint32_t obstat1_reg;
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
obstat1_reg = FMC_OBSTAT1_EFT;
/* modify user data according to ob_data */
obstat1_reg &= ~FMC_OBSTAT1_MDF_DATA;
obstat1_reg |= ((uint32_t)ob_data << OBSTAT1_DATA_OFFSET);
FMC_OBSTAT1_MDF = obstat1_reg;
}
return fmc_state;
}
/*!
\brief configure boot address (API_ID(0x0017U))
\param[in] boot_pin: boot pin configuration
only one parameter can be selected which is shown as below:
\arg BOOT_PIN_0: boot pin value is 0
\arg BOOT_PIN_1: boot pin value is 1
\param[in] boot_address: specify the MSB of boot address
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_boot_address_config(uint8_t boot_pin, uint16_t boot_address)
{
uint32_t btaddr_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_BOOT_PIN_VALUE(boot_pin)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0017U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
btaddr_reg = FMC_BTADDR_EFT;
if(BOOT_PIN_0 == boot_pin) {
/* set to boot address 0 */
btaddr_reg &= ~FMC_BTADDR_MDF_BOOT_ADDR0;
btaddr_reg |= (uint32_t)((uint32_t)boot_address << BTADDR_BOOT_ADDR0_OFFSET);
} else {
/* set to boot address 1 */
btaddr_reg &= ~FMC_BTADDR_MDF_BOOT_ADDR1;
btaddr_reg |= (uint32_t)((uint32_t)boot_address << BTADDR_BOOT_ADDR1_OFFSET);
}
FMC_BTADDR_MDF = btaddr_reg;
}
}
return fmc_state;
}
/*!
\brief configure DCRP area (API_ID(0x0018U))
\param[in] dcrp_eren: DCRP area erase enable bit
\arg OB_DCRP_AREA_ERASE_DISABLE: DCRP area erase disable
\arg OB_DCRP_AREA_ERASE_ENABLE: DCRP area erase enable
\param[in] dcrp_start: DCRP area start address, contain the first 4K-byte block of the DCRP area.(0 - 0x3BF)
\param[in] dcrp_end: DCRP area end address, contain the last 4K-byte block of the DCRP area.(0 - 0x3BF)
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_dcrp_area_config(uint32_t dcrp_eren, uint32_t dcrp_start, uint32_t dcrp_end)
{
uint32_t dcrpaddr_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_DCRP_AREA_ERASE_STATUS(dcrp_eren)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0018U), ERR_PARAM_INVALID);
} else if(NOT_FMC_DCRP_AREA_START(dcrp_start)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0018U), ERR_PARAM_INVALID);
} else if(NOT_FMC_DCRP_AREA_END(dcrp_end)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0018U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
dcrpaddr_reg = 0U;
dcrpaddr_reg |= dcrp_eren;
dcrpaddr_reg |= dcrp_start;
dcrpaddr_reg |= (uint32_t)(dcrp_end << DCRPADDR_DCRP_AREA_END_OFFSET);
FMC_DCRPADDR_MDF = dcrpaddr_reg;
}
}
return fmc_state;
}
/*!
\brief configure secure-access area (API_ID(0x0019U))
\param[in] scr_eren: secure-access area erase enable bit
\arg OB_SCR_AREA_ERASE_DISABLE: secure-access area erase disable
\arg OB_SCR_AREA_ERASE_ENABLE: secure-access area erase enable
\param[in] scr_start: secure-access area start address, contain the first 4K-byte block of the secure-access area.(0 - 0x3BF)
\param[in] scr_end: secure-access area end address, contain the last 4K-byte block of the secure-access area.(0 - 0x3BF)
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_secure_area_config(uint32_t scr_eren, uint32_t scr_start, uint32_t scr_end)
{
uint32_t scraddr_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_SCR_AREA_ERASE_STATUS(scr_eren)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0019U), ERR_PARAM_INVALID);
} else if(NOT_FMC_SCR_AREA_START(scr_start)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0019U), ERR_PARAM_INVALID);
} else if(NOT_FMC_SCR_AREA_END(scr_end)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0019U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
scraddr_reg = 0U;
scraddr_reg |= scr_eren;
scraddr_reg |= scr_start;
scraddr_reg |= (uint32_t)(scr_end << SCRADDR_SCR_AREA_END_OFFSET);
FMC_SCRADDR_MDF = scraddr_reg;
}
}
return fmc_state;
}
/*!
\brief enable erase/program protection (API_ID(0x001AU))
\param[in] ob_wp: specify sector to be erase/program protected
one or more parameters can be selected which are shown as below:
\arg OB_WP_0 erase/program protect sector 0 ~ sector 15
\arg OB_WP_1: erase/program protect sector 16 ~ sector 31
\arg OB_WP_2: erase/program protect sector 32 ~ sector 47
\arg OB_WP_3: erase/program protect sector 48 ~ sector 63
\arg OB_WP_4: erase/program protect sector 64 ~ sector 79
\arg OB_WP_5: erase/program protect sector 80 ~ sector 95
\arg OB_WP_6: erase/program protect sector 96 ~ sector 111
\arg OB_WP_7: erase/program protect sector 112 ~ sector 127
\arg OB_WP_8: erase/program protect sector 128 ~ sector 143
\arg OB_WP_9: erase/program protect sector 144 ~ sector 159
\arg OB_WP_10: erase/program protect sector 160 ~ sector 175
\arg OB_WP_11: erase/program protect sector 176 ~ sector 191
\arg OB_WP_12: erase/program protect sector 192 ~ sector 207
\arg OB_WP_13: erase/program protect sector 208 ~ sector 223
\arg OB_WP_14: erase/program protect sector 224 ~ sector 239
\arg OB_WP_15: erase/program protect sector 240 ~ sector 255
\arg OB_WP_16: erase/program protect sector 256 ~ sector 383
\arg OB_WP_17: erase/program protect sector 384 ~ sector 511
\arg OB_WP_18: erase/program protect sector 512 ~ sector 639
\arg OB_WP_19: erase/program protect sector 640 ~ sector 767
\arg OB_WP_20: erase/program protect sector 768 ~ sector 895
\arg OB_WP_21: erase/program protect sector 896 ~ sector 959
\arg OB_WP_ALL: all sectors
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
{
uint32_t wp_reg = FMC_WP_EFT;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_OB_WP_VALUE(ob_wp)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x001AU), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
wp_reg &= ~ob_wp;
FMC_WP_MDF = wp_reg;
}
}
return fmc_state;
}
/*!
\brief disable erase/program protection (API_ID(0x001BU))
\param[in] ob_wp: specify sector to be erase/program protected
one or more parameters can be selected which are shown as below:
\arg OB_WP_0 ee/program protect sector 0 ~ sector 15
\arg OB_WP_1: erase/program protect sector 16 ~ sector 31
\arg OB_WP_2: erase/program protect sector 32 ~ sector 47
\arg OB_WP_3: erase/program protect sector 48 ~ sector 63
\arg OB_WP_4: erase/program protect sector 64 ~ sector 79
\arg OB_WP_5: erase/program protect sector 80 ~ sector 95
\arg OB_WP_6: erase/program protect sector 96 ~ sector 111
\arg OB_WP_7: erase/program protect sector 112 ~ sector 127
\arg OB_WP_8: erase/program protect sector 128 ~ sector 143
\arg OB_WP_9: erase/program protect sector 144 ~ sector 159
\arg OB_WP_10: erase/program protect sector 160 ~ sector 175
\arg OB_WP_11: erase/program protect sector 176 ~ sector 191
\arg OB_WP_12: erase/program protect sector 192 ~ sector 207
\arg OB_WP_13: erase/program protect sector 208 ~ sector 223
\arg OB_WP_14: erase/program protect sector 224 ~ sector 239
\arg OB_WP_15: erase/program protect sector 240 ~ sector 255
\arg OB_WP_16: erase/program protect sector 256 ~ sector 383
\arg OB_WP_17: erase/program protect sector 384 ~ sector 511
\arg OB_WP_18: erase/program protect sector 512 ~ sector 639
\arg OB_WP_19: erase/program protect sector 640 ~ sector 767
\arg OB_WP_20: erase/program protect sector 768 ~ sector 895
\arg OB_WP_21: erase/program protect sector 896 ~ sector 959
\arg OB_WP_ALL: all sectors
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum ob_write_protection_disable(uint32_t ob_wp)
{
uint32_t wp_reg = FMC_WP_EFT;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_OB_WP_VALUE(ob_wp)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x001BU), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
wp_reg |= ob_wp;
FMC_WP_MDF = wp_reg;
}
}
return fmc_state;
}
/*!
\brief get the option byte secure access mode (API_ID(0x001CU))
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ob_secure_mode_get(void)
{
FlagStatus secure_mode_state = RESET;
if(OB_SECURE_MODE_ENABLE == (uint32_t)(FMC_OBSTAT0_EFT & FMC_OBSTAT0_EFT_SCR)) {
secure_mode_state = SET;
} else {
secure_mode_state = RESET;
}
return secure_mode_state;
}
/*!
\brief get the option byte security protection level (API_ID(0x001DU))
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ob_security_protection_flag_get(void)
{
FlagStatus spc_state = RESET;
if(((uint8_t)(FMC_OBSTAT0_EFT >> OBSTAT0_SPC_OFFSET)) != (uint8_t)FMC_NSPC) {
spc_state = SET;
} else {
spc_state = RESET;
}
return spc_state;
}
/*!
\brief get the option byte BOR threshold value (API_ID(0x001EU))
\param[in] none
\param[out] none
\retval the BOR threshold value:
\arg OB_BOR_TH_VALUE3: BOR threshold value 3
\arg OB_BOR_TH_VALUE2: BOR threshold value 2
\arg OB_BOR_TH_VALUE1: BOR threshold value 1
\arg OB_BOR_TH_OFF: no BOR function
*/
uint32_t ob_bor_threshold_get(void)
{
return (uint32_t)((uint32_t)FMC_OBSTAT0_EFT & FMC_OBSTAT0_EFT_BOR_TH);
}
/*!
\brief get low power related option byte (API_ID(0x001FU))
\param[in] none
\param[out] fwdgt: watchdog option
\arg OB_FWDGT_HW: hardware free watchdog
\arg OB_FWDGT_SW: software free watchdog
\param[out] deepsleep: deepsleep reset option
\arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
\arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
\param[out] standby: standby reset option
\arg OB_STDBY_RST: generate a reset instead of entering standby mode
\arg OB_STDBY_NRST: no reset when entering standby mode
\param[out] fwdg_suspend_deepsleep: FWDG suspend status in deepsleep mode option
\arg OB_DPSLP_FWDGT_SUSPEND: free watchdog is suspended in deepsleep mode
\arg OB_DPSLP_FWDGT_RUN: free watchdog is running in deepsleep mode
\param[out] fwdg_suspend_standby: FWDG suspend status in standby mode option
\arg OB_STDBY_FWDGT_SUSPEND: free watchdog is suspended in standby mode
\arg OB_STDBY_FWDGT_RUN: free watchdog is running in standby mode
\retval none
*/
void ob_low_power_get(uint32_t *fwdgt, uint32_t *deepsleep, uint32_t *standby, uint32_t *fwdg_suspend_deepsleep, uint32_t *fwdg_suspend_standby)
{
uint32_t obstat0_reg;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if((NOT_VALID_POINTER(fwdgt)) || (NOT_VALID_POINTER(deepsleep)) || (NOT_VALID_POINTER(standby)) || (NOT_VALID_POINTER(fwdg_suspend_deepsleep)) ||
(NOT_VALID_POINTER(fwdg_suspend_standby))) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x001FU), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
obstat0_reg = FMC_OBSTAT0_EFT;
*fwdgt = (uint32_t)(obstat0_reg & FMC_OBSTAT0_EFT_NWDG_HW);
*deepsleep = (uint32_t)(obstat0_reg & FMC_OBSTAT0_EFT_NRST_DPSLP);
*standby = (uint32_t)(obstat0_reg & FMC_OBSTAT0_EFT_NRST_STDBY);
*fwdg_suspend_deepsleep = (uint32_t)(obstat0_reg & FMC_OBSTAT0_EFT_FWDGSPD_DPSLP);
*fwdg_suspend_standby = (uint32_t)(obstat0_reg & FMC_OBSTAT0_EFT_FWDGSPD_STDBY);
}
}
/*!
\brief get TCM ECC configuration (API_ID(0x0020U))
\param[in] none
\param[out] itcmecc_option: CPU ITCM ECC function enable option
\arg OB_ITCMECCEN_DISABLE: ITCM ECC function disable
\arg OB_ITCMECCEN_ENABLE: ITCM ECC function enable
\param[out] dtcm0ecc_option: CPU DTCM0 ECC function enable option
\arg OB_DTCM0ECCEN_DISABLE: DTCM0 ECC function disable
\arg OB_DTCM0ECCEN_ENABLE: DTCM0 ECC function enable
\param[out] dtcm1ecc_option: CPU DTCM1 ECC function enable option
\arg OB_DTCM1ECCEN_DISABLE: DTCM1 ECC function disable
\arg OB_DTCM1ECCEN_ENABLE: DTCM1 ECC function enable
\retval none
*/
void ob_tcm_ecc_get(uint32_t *itcmecc_option, uint32_t *dtcm0ecc_option, uint32_t *dtcm1ecc_option)
{
uint32_t obstat0_reg;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if((NOT_VALID_POINTER(itcmecc_option)) || (NOT_VALID_POINTER(dtcm0ecc_option)) || (NOT_VALID_POINTER(dtcm1ecc_option))) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0020U), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
obstat0_reg = FMC_OBSTAT0_EFT;
*itcmecc_option = (uint32_t)(obstat0_reg & FMC_OBSTAT0_EFT_ITCMECCEN);
*dtcm0ecc_option = (uint32_t)(obstat0_reg & FMC_OBSTAT0_EFT_DTCM0ECCEN);
*dtcm1ecc_option = (uint32_t)(obstat0_reg & FMC_OBSTAT0_EFT_DTCM1ECCEN);
}
}
/*!
\brief get IO speed optimize configuration (API_ID(0x0021U))
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ob_iospeed_optimize_get(void)
{
FlagStatus iospeed_opt_state = RESET;
if(OB_IOSPDOPEN_ENABLE == (uint32_t)(FMC_OBSTAT0_EFT & FMC_OBSTAT0_EFT_IOSPDOPEN)) {
iospeed_opt_state = SET;
} else {
iospeed_opt_state = RESET;
}
return iospeed_opt_state;
}
/*!
\brief get the option byte ITCM shared RAM size (API_ID(0x0022U))
\param[in] none
\param[out] none
\retval ITCM shared RAM size in KB unit
*/
uint32_t ob_itcm_shared_ram_size_get(void)
{
uint32_t itcm_size_value;
uint32_t itcm_kb_size;
itcm_size_value = (uint32_t)((uint32_t)FMC_OBSTAT1_EFT & FMC_OBSTAT1_EFT_ITCM_SZ_SHRRAM);
switch(itcm_size_value) {
case OB_ITCM_SHARED_RAM_0KB:
/* ITCM shared RAM size is 0KB */
itcm_kb_size = 0U;
break;
case OB_ITCM_SHARED_RAM_64KB:
/* ITCM shared RAM size is 64KB */
itcm_kb_size = 64U;
break;
case OB_ITCM_SHARED_RAM_128KB:
/* ITCM shared RAM size is 128KB */
itcm_kb_size = 128U;
break;
case OB_ITCM_SHARED_RAM_256KB:
/* ITCM shared RAM size is 256KB */
itcm_kb_size = 256U;
break;
case OB_ITCM_SHARED_RAM_512KB:
/* ITCM shared RAM size is 512KB */
itcm_kb_size = 512U;
break;
default:
break;
}
return itcm_kb_size;
}
/*!
\brief get the option byte DTCM shared RAM size (API_ID(0x0023U))
\param[in] none
\param[out] none
\retval DTCM shared RAM size in KB unit
*/
uint32_t ob_dtcm_shared_ram_size_get(void)
{
uint32_t dtcm_size_value;
uint32_t dtcm_kb_size;
dtcm_size_value = (uint32_t)((uint32_t)FMC_OBSTAT1_EFT & FMC_OBSTAT1_EFT_DTCM_SZ_SHRRAM);
switch(dtcm_size_value) {
case OB_DTCM_SHARED_RAM_0KB:
/* DTCM shared RAM size is 0KB */
dtcm_kb_size = 0U;
break;
case OB_DTCM_SHARED_RAM_64KB:
/* DTCM shared RAM size is 64KB */
dtcm_kb_size = 64U;
break;
case OB_DTCM_SHARED_RAM_128KB:
/* DTCM shared RAM size is 128KB */
dtcm_kb_size = 128U;
break;
case OB_DTCM_SHARED_RAM_256KB:
/* DTCM shared RAM size is 256KB */
dtcm_kb_size = 256U;
break;
case OB_DTCM_SHARED_RAM_512KB:
/* DTCM shared RAM size is 512KB */
dtcm_kb_size = 512U;
break;
default:
break;
}
return dtcm_kb_size;
}
/*!
\brief get user data value (API_ID(0x0024U))
\param[in] none
\param[out] none
\retval option bytes user data
*/
uint16_t ob_data_get(void)
{
return (uint16_t)(FMC_OBSTAT1_EFT >> OBSTAT1_DATA_OFFSET);
}
/*!
\brief get boot address (API_ID(0x0025U))
\param[in] boot_pin: boot pin configuration
only one parameter can be selected which is shown as below:
\arg BOOT_PIN_0: boot pin value is 0
\arg BOOT_PIN_1: boot pin value is 1
\param[out] none
\retval boot_address: boot address
*/
uint32_t ob_boot_address_get(uint8_t boot_pin)
{
uint32_t boot_address;
uint32_t btaddr_reg = FMC_BTADDR_EFT;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_BOOT_PIN(boot_pin)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0025U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
if(BOOT_PIN_0 == boot_pin) {
/* get boot address 0 */
boot_address = (uint32_t)((btaddr_reg & FMC_BTADDR_EFT_BOOT_ADDR0) << 16U);
} else {
/* get boot address 1 */
boot_address = (uint32_t)((btaddr_reg & FMC_BTADDR_EFT_BOOT_ADDR1));
}
}
return boot_address;
}
/*!
\brief get DCRP area configuration (API_ID(0x0026U))
\param[in] none
\param[out] dcrp_erase_option: DCRP area erase option
\arg OB_DCRP_AREA_ERASE_DISABLE: DCRP area erase disable
\arg OB_DCRP_AREA_ERASE_ENABLE: DCRP area erase enable
\param[out] dcrp_start_addr: DCRP area start address, contain the first 4K-byte block of the DCRP area.(0 - 0x3BF)
\param[out] dcrp_end_addr: DCRP area end address, contain the last 4K-byte block of the DCRP area.(0 - 0x3BF)
\retval state of DCRP area address
\arg INVLD_AREA_ADDRESS: the area address is invalid
\arg VLD_AREA_ADDRESS: the area address is valid
*/
uint8_t ob_dcrp_area_get(uint32_t *dcrp_erase_option, uint32_t *dcrp_area_start_addr, uint32_t *dcrp_area_end_addr)
{
uint32_t dcrpaddr_reg;
uint32_t main_flash_size;
dcrpaddr_reg = FMC_DCRPADDR_EFT;
uint8_t reval = VLD_AREA_ADDRESS;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if((NOT_VALID_POINTER(dcrp_erase_option)) || (NOT_VALID_POINTER(dcrp_area_start_addr)) || (NOT_VALID_POINTER(dcrp_area_end_addr))) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0026U), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
main_flash_size = REG32(FLASH_DENSITY_ADDRESS) >> FLASH_DENSITY_OFFSET;
/* get DCRP area erase option */
*dcrp_erase_option = (uint32_t)(dcrpaddr_reg & FMC_DCRPADDR_EFT_DCRP_EREN);
*dcrp_area_start_addr = ((uint32_t)(dcrpaddr_reg & FMC_DCRPADDR_EFT_DCRP_AREA_START)) >> DCRPADDR_DCRP_AREA_START_OFFSET;
*dcrp_area_end_addr = ((uint32_t)(dcrpaddr_reg & FMC_DCRPADDR_EFT_DCRP_AREA_END)) >> DCRPADDR_DCRP_AREA_END_OFFSET;
if((*dcrp_area_start_addr) == (*dcrp_area_end_addr)) {
/* the whole main flash memory is DCRP area */
*dcrp_area_start_addr = MAIN_FLASH_BASE_ADDRESS;
*dcrp_area_end_addr = MAIN_FLASH_BASE_ADDRESS + main_flash_size - 1U;
reval = VLD_AREA_ADDRESS;
} else if((*dcrp_area_start_addr) < (*dcrp_area_end_addr)) {
/* get DCRP area start address */
*dcrp_area_start_addr = (*dcrp_area_start_addr) * DCRP_SIZE_UNIT;
*dcrp_area_start_addr += MAIN_FLASH_BASE_ADDRESS;
/* get DCRP area end address */
*dcrp_area_end_addr = ((*dcrp_area_end_addr) + 1U) * DCRP_SIZE_UNIT - 1U;
*dcrp_area_end_addr += MAIN_FLASH_BASE_ADDRESS;
reval = VLD_AREA_ADDRESS;
} else {
/* no valid DCRP area */
reval = INVLD_AREA_ADDRESS;
}
}
return reval;
}
/*!
\brief get secure-access area configuration (API_ID(0x0027U))
\param[in] none
\param[out] secure_erase_option: secure-access area erase option
\arg OB_SCR_AREA_ERASE_DISABLE: secure-access area erase disable
\arg OB_SCR_AREA_ERASE_ENABLE: secure-access area erase enable
\param[out] scr_area_start_addr: secure-access area start address, contain the first 4K-byte block of the secure-access area.(0 - 0x3BF)
\param[out] scr_area_end_addr: secure-access area end address, contain the last 4K-byte block of the secure-access area.(0 - 0x3BF)
\retval state of secure-access area address
\arg INVLD_AREA_ADDRESS: the area address is invalid
\arg VLD_AREA_ADDRESS: the area address is valid
*/
uint8_t ob_secure_area_get(uint32_t *secure_area_option, uint32_t *scr_area_start_addr, uint32_t *scr_area_end_addr)
{
uint32_t scraddr_reg;
uint32_t main_flash_size;
scraddr_reg = FMC_SCRADDR_EFT;
uint8_t reval = VLD_AREA_ADDRESS;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if((NOT_VALID_POINTER(secure_area_option)) || (NOT_VALID_POINTER(scr_area_start_addr)) || (NOT_VALID_POINTER(scr_area_end_addr))) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0027U), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
main_flash_size = REG32(FLASH_DENSITY_ADDRESS) >> FLASH_DENSITY_OFFSET;
/* get secure-access area erase option */
*secure_area_option = (uint32_t)(scraddr_reg & FMC_SCRADDR_EFT_SCR_EREN);
*scr_area_start_addr = ((uint32_t)(scraddr_reg & FMC_SCRADDR_EFT_SCR_AREA_START)) >> SCRADDR_SCR_AREA_START_OFFSET;
*scr_area_end_addr = ((uint32_t)(scraddr_reg & FMC_SCRADDR_EFT_SCR_AREA_END)) >> SCRADDR_SCR_AREA_END_OFFSET;
if((*scr_area_start_addr) == (*scr_area_end_addr)) {
/* the whole main flash memory is secure-access area */
*scr_area_start_addr = MAIN_FLASH_BASE_ADDRESS;
*scr_area_end_addr = MAIN_FLASH_BASE_ADDRESS + main_flash_size - 1U;
reval = VLD_AREA_ADDRESS;
} else if((*scr_area_start_addr) < (*scr_area_end_addr)) {
/* get secure-access area start address */
*scr_area_start_addr = (*scr_area_start_addr) * SCR_SIZE_UNIT;
*scr_area_start_addr += MAIN_FLASH_BASE_ADDRESS;
/* get secure-access area end address */
*scr_area_end_addr = ((*scr_area_end_addr) + 1U) * SCR_SIZE_UNIT - 1U;
*scr_area_end_addr += MAIN_FLASH_BASE_ADDRESS;
reval = VLD_AREA_ADDRESS;
} else {
/* no valid area */
reval = INVLD_AREA_ADDRESS;
}
}
return reval;
}
/*!
\brief get the option byte erase/program protection (API_ID(0x0028U))
\param[in] none
\param[out] none
\retval the FMC erase/program protection option byte value(0 - 0x3FFFFFFF)
*/
uint32_t ob_write_protection_get(void)
{
/* return the FMC erase/program protection option byte value */
return (uint32_t)(FMC_WP_EFT);
}
/*!
\brief configure NO-RTDEC area (API_ID(0x0029U))
\param[in] nodec_area_start: no rtdec area start address, contain the last 4K-byte block that reading main flash block without decryption.
\param[in] nodec_area_end: no rtdec area end address, contain the first 4K-byte block that reading main flash block without decryption.
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_no_rtdec_config(uint32_t nodec_area_start, uint32_t nodec_area_end)
{
uint32_t nodec_reg;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_FMC_NODEC_AREA_START(nodec_area_start)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0029U), ERR_PARAM_INVALID);
} else if(NOT_FMC_NODEC_AREA_END(nodec_area_end)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x0029U), ERR_PARAM_INVALID);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
fmc_unlock();
nodec_reg = 0U;
nodec_reg |= nodec_area_start;
nodec_reg |= (uint32_t)(nodec_area_end << NODEC_NODEC_AREA_END_OFFSET);
FMC_NODEC = nodec_reg;
fmc_lock();
}
}
return fmc_state;
}
/*!
\brief configure AES initialization vector (API_ID(0x002AU))
\param[in] aes_iv: high 96 bits of AES initialization vector
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_aes_iv_config(uint32_t *aes_iv)
{
uint32_t aes_iv_addr = (uint32_t)aes_iv;
fmc_state_enum fmc_state = FMC_READY;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_VALID_POINTER(aes_iv)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x002AU), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
fmc_unlock();
FMC_AESIV0_MDF = *(uint32_t *)(aes_iv_addr);
aes_iv_addr += 4U;
FMC_AESIV1_MDF = *(uint32_t *)(aes_iv_addr);
aes_iv_addr += 4U;
FMC_AESIV2_MDF = *(uint32_t *)(aes_iv_addr);
fmc_lock();
}
}
return fmc_state;
}
/*!
\brief get Flash ECC function enable flag (API_ID(0x002BU))
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_flash_ecc_get(void)
{
return fmc_flag_get((fmc_flag_enum)FMC_FLAG_FECC);
}
/*!
\brief get NO-RTDEC area (API_ID(0x002CU))
\param[in] none
\param[out] nodec_area_start: no rtdec area start address, contain the last 4K-byte block that reading main flash block without decryption.
\param[out] nodec_area_end: no rtdec area end address, contain the first 4K-byte block that reading main flash block without decryption.
\retval none
*/
void fmc_no_rtdec_get(uint32_t *nodec_area_start, uint32_t *nodec_area_end)
{
uint32_t nodec_reg;
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if((NOT_VALID_POINTER(nodec_area_start)) || (NOT_VALID_POINTER(nodec_area_end))) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x002CU), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
nodec_reg = FMC_NODEC;
*nodec_area_start = (uint32_t)(nodec_reg & FMC_NODEC_NODEC_AREA_START);
*nodec_area_end = (uint32_t)(nodec_reg & FMC_NODEC_NODEC_AREA_END);
}
}
/*!
\brief get AES initialization vector (API_ID(0x002DU))
\param[in] none
\param[out] aes_iv: high 96 bits of AES initialization vector
\retval none
*/
void fmc_aes_iv_get(uint32_t *aes_iv)
{
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_VALID_POINTER(aes_iv)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x002DU), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
uint32_t aes_iv_addr = (uint32_t)aes_iv;
*(uint32_t *)aes_iv_addr = (uint32_t)(FMC_AESIV0_EFT);
aes_iv_addr += 4U;
*(uint32_t *)aes_iv_addr = (uint32_t)(FMC_AESIV1_EFT);
aes_iv_addr += 4U;
*(uint32_t *)aes_iv_addr = (uint32_t)(FMC_AESIV2_EFT);
}
}
/*!
\brief get product ID (API_ID(0x002EU))
\param[in] none
\param[out] pid: product ID
\retval none
*/
void fmc_pid_get(uint32_t *pid)
{
#ifdef FW_DEBUG_ERR_REPORT
/* check parameter */
if(NOT_VALID_POINTER(pid)) {
fw_debug_report_err(FMC_MODULE_ID, API_ID(0x002EU), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
uint32_t pid_addr = (uint32_t)pid;
*(uint32_t *)pid_addr = (uint32_t)(FMC_PID0);
pid_addr += 4U;
*(uint32_t *)pid_addr = (uint32_t)(FMC_PID1);
}
}
/*!
\brief get FMC flag status (API_ID(0x002FU))
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_BUSY: flash busy flag bit
\arg FMC_FLAG_END: flash end of operation flag bit
\arg FMC_FLAG_WPERR: flash erase/program protection error flag bit
\arg FMC_FLAG_PGSERR: flash program sequence error flag bit
\arg FMC_FLAG_RPERR: flash read protection error flag bit
\arg FMC_FLAG_RSERR: flash read secure error flag bit
\arg FMC_FLAG_ECCCOR: flash one bit correct error flag bit
\arg FMC_FLAG_ECCDET: flash two bits detect error flag bit
\arg FMC_FLAG_OBMERR: flash option byte modify error flag bit
\arg FMC_FLAG_FECC: flash ECC function flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_flag_get(fmc_flag_enum flag)
{
if(RESET != (FMC_REG_VAL(flag) & BIT(FMC_BIT_POS(flag)))) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear FMC flag status (API_ID(0x0030U))
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_END: flash end of operation flag bit
\arg FMC_FLAG_WPERR: flash erase/program protection error flag bit
\arg FMC_FLAG_PGSERR: flash program sequence error flag bit
\arg FMC_FLAG_RPERR: flash read protection error flag bit
\arg FMC_FLAG_RSERR: flash read secure error flag bit
\arg FMC_FLAG_ECCCOR: flash one bit correct error flag bit
\arg FMC_FLAG_ECCDET: flash two bits detect error flag bit
\arg FMC_FLAG_OBMERR: flash option byte modify error flag bit
\param[out] none
\retval none
*/
void fmc_flag_clear(fmc_flag_enum flag)
{
/* clear the flags */
FMC_REG_VAL(flag) = BIT(FMC_BIT_POS(flag));
}
/*!
\brief enable FMC interrupt (API_ID(0x0031U))
\param[in] interrupt: the FMC interrupt source
only one parameter can be selected which is shown as below:
\arg FMC_INT_END : FMC end of program interrupt
\arg FMC_INT_WPERR: FMC erase/program protection error interrupt
\arg FMC_INT_PGSERR: FMC program sequence error interrupt
\arg FMC_INT_RPERR: FMC read protection error interrupt
\arg FMC_INT_RSERR: FMC read secure error interrupt
\arg FMC_INT_ECCCOR: FMC one bit correct error interrupt
\arg FMC_INT_ECCDET: FMC two bits detect error interrupt
\arg FMC_INT_OBMERR: FMC option byte modify error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_enable(fmc_interrupt_enum interrupt)
{
FMC_REG_VAL(interrupt) |= BIT(FMC_BIT_POS(interrupt));
}
/*!
\brief disable FMC interrupt (API_ID(0x0032U))
\param[in] interrupt: the FMC interrupt source
only one parameter can be selected which is shown as below:
\arg FMC_INT_END : FMC end of program interrupt
\arg FMC_INT_WPERR: FMC erase/program protection error interrupt
\arg FMC_INT_PGSERR: FMC program sequence error interrupt
\arg FMC_INT_RPERR: FMC read protection error interrupt
\arg FMC_INT_RSERR: FMC read secure error interrupt
\arg FMC_INT_ECCCOR: FMC one bit correct error interrupt
\arg FMC_INT_ECCDET: FMC two bits detect error interrupt
\arg FMC_INT_OBMERR: FMC option byte modify error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_disable(fmc_interrupt_enum interrupt)
{
FMC_REG_VAL(interrupt) &= ~BIT(FMC_BIT_POS(interrupt));
}
/*!
\brief get FMC interrupt flag status (API_ID(0x0033U))
\param[in] flag: FMC interrupt flag
only one parameter can be selected which is shown as below:
\arg FMC_INT_FLAG_END: flash end of operation interrupt flag
\arg FMC_INT_FLAG_WPERR: flash erase/program protection error interrupt flag
\arg FMC_INT_FLAG_PGSERR: flash program sequence error interrupt flag
\arg FMC_INT_FLAG_RPERR: flash read protection error interrupt flag
\arg FMC_INT_FLAG_RSERR: flash read secure error interrupt flag
\arg FMC_INT_FLAG_ECCCOR: flash one bit error detected and correct interrupt flag
\arg FMC_INT_FLAG_ECCDET: flash two bit errors detect interrupt flag
\arg FMC_INT_FLAG_OBMERR: option byte modify error flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_interrupt_flag_get(fmc_interrupt_flag_enum int_flag)
{
uint32_t intenable = 0U, flagstatus = 0U;
/* get the interrupt enable bit status */
intenable = (FMC_REG_VAL(int_flag) & BIT(FMC_BIT_POS(int_flag)));
/* get the corresponding flag bit status */
flagstatus = (FMC_REG_VAL2(int_flag) & BIT(FMC_BIT_POS2(int_flag)));
if(flagstatus && intenable) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear FMC interrupt flag status (API_ID(0x0034U))
\param[in] flag: FMC interrupt flag
only one parameter can be selected which is shown as below:
\arg FMC_INT_FLAG_END: flash end of operation interrupt flag
\arg FMC_INT_FLAG_WPERR: flash erase/program protection error interrupt flag
\arg FMC_INT_FLAG_PGSERR: flash program sequence error interrupt flag
\arg FMC_INT_FLAG_RPERR: flash read protection error interrupt flag
\arg FMC_INT_FLAG_RSERR: flash read secure error interrupt flag
\arg FMC_INT_FLAG_ECCCOR: flash one bit error detected and correct interrupt flag
\arg FMC_INT_FLAG_ECCDET: flash two bit errors detect interrupt flag
\arg FMC_INT_FLAG_OBMERR: option byte modify error flag
\param[out] none
\retval none
*/
void fmc_interrupt_flag_clear(fmc_interrupt_flag_enum int_flag)
{
/* clear the intrrupt flag */
FMC_REG_VAL2(int_flag) = BIT(FMC_BIT_POS2(int_flag));
}
/*!
\brief get FMC state (API_ID(0x0035U))
\param[in] none
\param[out] none
\retval state of FMC, refer to fmc_state_enum
\arg FMC_READY: operation has been completed
\arg FMC_BUSY: operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
*/
static fmc_state_enum fmc_state_get(void)
{
fmc_state_enum fmc_state = FMC_READY;
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)) {
fmc_state = FMC_BUSY;
} else {
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)) {
fmc_state = FMC_WPERR;
} else if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_PGSERR)) {
fmc_state = FMC_PGSERR;
} else if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_RPERR)) {
fmc_state = FMC_RPERR;
} else if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_RSERR)) {
fmc_state = FMC_RSERR;
} else if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_ECCCOR)) {
fmc_state = FMC_ECCCOR;
} else if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_ECCDET)) {
fmc_state = FMC_ECCDET;
} else if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_OBMERR)) {
fmc_state = FMC_OBMERR;
} else {
/* illegal parameters */
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief check whether FMC is ready or not (API_ID(0x0036U))
\param[in] timeout: timeout count
\param[out] none
\retval state of FMC, refer to fmc_state_enum
\arg FMC_READY: operation has been completed
\arg FMC_BUSY: operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
static fmc_state_enum fmc_ready_wait(uint32_t timeout)
{
fmc_state_enum fmc_state = FMC_BUSY;
/* wait for FMC ready */
do {
/* get FMC state */
fmc_state = fmc_state_get();
timeout--;
} while((FMC_BUSY == fmc_state) && (0U != timeout));
if(FMC_BUSY == fmc_state) {
fmc_state = FMC_TOERR;
}
/* return the FMC state */
return fmc_state;
}