825 lines
23 KiB
C
825 lines
23 KiB
C
/*!
|
|
\file gd32f4xx_fmc.c
|
|
\brief FMC driver
|
|
*/
|
|
|
|
/*
|
|
Copyright (C) 2016 GigaDevice
|
|
|
|
2016-08-15, V1.0.0, firmware for GD32F4xx
|
|
*/
|
|
|
|
#include "gd32f4xx_fmc.h"
|
|
|
|
/*!
|
|
\brief set the wait state counter value
|
|
\param[in] wscnt£ºwait state counter value
|
|
\arg WS_WSCNT_0: FMC 0 wait
|
|
\arg WS_WSCNT_1: FMC 1 wait
|
|
\arg WS_WSCNT_2: FMC 2 wait
|
|
\arg WS_WSCNT_3: FMC 3 wait
|
|
\arg WS_WSCNT_4: FMC 4 wait
|
|
\arg WS_WSCNT_5: FMC 5 wait
|
|
\arg WS_WSCNT_6: FMC 6 wait
|
|
\arg WS_WSCNT_7: FMC 7 wait
|
|
\arg WS_WSCNT_8: FMC 8 wait
|
|
\arg WS_WSCNT_9: FMC 9 wait
|
|
\arg WS_WSCNT_10: FMC 10 wait
|
|
\arg WS_WSCNT_11: FMC 11 wait
|
|
\arg WS_WSCNT_12: FMC 12 wait
|
|
\arg WS_WSCNT_13: FMC 13 wait
|
|
\arg WS_WSCNT_14: FMC 14 wait
|
|
\arg WS_WSCNT_15: FMC 15 wait
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void fmc_wscnt_set(uint32_t wscnt)
|
|
{
|
|
uint32_t reg;
|
|
|
|
reg = FMC_WS;
|
|
/* set the wait state counter value */
|
|
reg &= ~FMC_WC_WSCNT;
|
|
FMC_WS = (reg | wscnt);
|
|
}
|
|
|
|
/*!
|
|
\brief unlock the main FMC operation
|
|
\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 the main FMC operation
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void fmc_lock(void)
|
|
{
|
|
/* set the LK bit*/
|
|
FMC_CTL |= FMC_CTL_LK;
|
|
}
|
|
|
|
/*!
|
|
\brief erase sector
|
|
\param[in] fmc_sector: select the sector to erase
|
|
\arg CTL_SECTOR_NUMBER_0: sector 0
|
|
\arg CTL_SECTOR_NUMBER_1: sector 1
|
|
\arg CTL_SECTOR_NUMBER_2: sector 2
|
|
\arg CTL_SECTOR_NUMBER_3: sector 3
|
|
\arg CTL_SECTOR_NUMBER_4: sector 4
|
|
\arg CTL_SECTOR_NUMBER_5: sector 5
|
|
\arg CTL_SECTOR_NUMBER_6: sector 6
|
|
\arg CTL_SECTOR_NUMBER_7: sector 7
|
|
\arg CTL_SECTOR_NUMBER_8: sector 8
|
|
\arg CTL_SECTOR_NUMBER_9: sector 9
|
|
\arg CTL_SECTOR_NUMBER_10: sector 10
|
|
\arg CTL_SECTOR_NUMBER_11: sector 11
|
|
\arg CTL_SECTOR_NUMBER_12: sector 12
|
|
\arg CTL_SECTOR_NUMBER_13: sector 13
|
|
\arg CTL_SECTOR_NUMBER_14: sector 14
|
|
\arg CTL_SECTOR_NUMBER_15: sector 15
|
|
\arg CTL_SECTOR_NUMBER_16: sector 16
|
|
\arg CTL_SECTOR_NUMBER_17: sector 17
|
|
\arg CTL_SECTOR_NUMBER_18: sector 18
|
|
\arg CTL_SECTOR_NUMBER_19: sector 19
|
|
\arg CTL_SECTOR_NUMBER_20: sector 20
|
|
\arg CTL_SECTOR_NUMBER_21: sector 21
|
|
\arg CTL_SECTOR_NUMBER_22: sector 22
|
|
\arg CTL_SECTOR_NUMBER_23: sector 23
|
|
\arg CTL_SECTOR_NUMBER_24: sector 24
|
|
\arg CTL_SECTOR_NUMBER_25: sector 25
|
|
\arg CTL_SECTOR_NUMBER_26: sector 26
|
|
\arg CTL_SECTOR_NUMBER_27: sector 27
|
|
\arg CTL_SECTOR_NUMBER_28: sector 28
|
|
\arg CTL_SECTOR_NUMBER_29: sector 29
|
|
\arg CTL_SECTOR_NUMBER_30: sector 30
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_sector_erase(uint32_t fmc_sector)
|
|
{
|
|
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){
|
|
/* start sector erase */
|
|
FMC_CTL &= ~FMC_CTL_SN;
|
|
FMC_CTL |= (FMC_CTL_SER | fmc_sector);
|
|
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);
|
|
FMC_CTL &= ~FMC_CTL_SN;
|
|
}
|
|
|
|
/* return the FMC state */
|
|
return fmc_state;
|
|
}
|
|
|
|
/*!
|
|
\brief erase whole chip
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_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){
|
|
/* start whole chip erase */
|
|
FMC_CTL |= (FMC_CTL_MER0 | FMC_CTL_MER1);
|
|
FMC_CTL |= FMC_CTL_START;
|
|
|
|
/* wait for the FMC ready */
|
|
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
|
|
|
/* reset the MER bits */
|
|
FMC_CTL &= ~(FMC_CTL_MER0 | FMC_CTL_MER1);
|
|
}
|
|
|
|
/* return the fmc state */
|
|
return fmc_state;
|
|
}
|
|
|
|
/*!
|
|
\brief erase all FMC sectors in bank0
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_bank0_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){
|
|
/* start FMC bank0 erase */
|
|
FMC_CTL |= FMC_CTL_MER0;
|
|
FMC_CTL |= FMC_CTL_START;
|
|
|
|
/* wait for the FMC ready */
|
|
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
|
|
|
/* reset the MER0 bit */
|
|
FMC_CTL &= (~FMC_CTL_MER0);
|
|
}
|
|
|
|
/* return the fmc state */
|
|
return fmc_state;
|
|
}
|
|
|
|
/*!
|
|
\brief erase all FMC sectors in bank1
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_bank1_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){
|
|
/* start FMC bank1 erase */
|
|
FMC_CTL |= FMC_CTL_MER1;
|
|
FMC_CTL |= FMC_CTL_START;
|
|
|
|
/* wait for the FMC ready */
|
|
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
|
|
|
|
/* reset the MER1 bit */
|
|
FMC_CTL &= (~FMC_CTL_MER1);
|
|
}
|
|
|
|
/* return the fmc state */
|
|
return fmc_state;
|
|
}
|
|
|
|
/*!
|
|
\brief program a word at the corresponding address
|
|
\param[in] address: address to program
|
|
\param[in] data: word to program
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
|
|
{
|
|
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){
|
|
/* set the PG bit to start program */
|
|
FMC_CTL &= ~FMC_CTL_PSZ;
|
|
FMC_CTL |= CTL_PSZ_WORD;
|
|
FMC_CTL |= FMC_CTL_PG;
|
|
|
|
REG32(address) = data;
|
|
|
|
/* 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 program a half word at the corresponding address
|
|
\param[in] address: address to program
|
|
\param[in] data: halfword to program
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data)
|
|
{
|
|
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){
|
|
/* set the PG bit to start program */
|
|
FMC_CTL &= ~FMC_CTL_PSZ;
|
|
FMC_CTL |= CTL_PSZ_HALF_WORD;
|
|
FMC_CTL |= FMC_CTL_PG;
|
|
|
|
REG16(address) = data;
|
|
|
|
/* 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 program a byte at the corresponding address
|
|
\param[in] address: address to program
|
|
\param[in] data: byte to program
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_byte_program(uint32_t address, uint8_t data)
|
|
{
|
|
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){
|
|
/* set the PG bit to start program */
|
|
FMC_CTL &= ~FMC_CTL_PSZ;
|
|
FMC_CTL |= CTL_PSZ_BYTE;
|
|
FMC_CTL |= FMC_CTL_PG;
|
|
|
|
REG8(address) = data;
|
|
|
|
/* 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 unlock the option byte operation
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_unlock(void)
|
|
{
|
|
if(RESET != (FMC_OBCTL0 & FMC_OBCTL0_OB_LK)){
|
|
/* write the FMC key */
|
|
FMC_OBKEY = OB_UNLOCK_KEY0;
|
|
FMC_OBKEY = OB_UNLOCK_KEY1;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief lock the option byte operation
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_lock(void)
|
|
{
|
|
/* reset the OB_LK bit */
|
|
FMC_OBCTL0 &= ~FMC_OBCTL0_OB_LK;
|
|
}
|
|
|
|
/*!
|
|
\brief send option byte change command
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_start(void)
|
|
{
|
|
/* set the OB_START bit in OBCTL0 register */
|
|
FMC_OBCTL0 |= FMC_OBCTL0_OB_START;
|
|
}
|
|
|
|
/*!
|
|
\brief enable write protection
|
|
\param[in] ob_wp: specify sector to be write protected
|
|
\arg OB_WPx(x=0..11): write protect specify sector
|
|
\arg OB_WP_ALL: write protect all sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_write_protection0_enable(uint32_t ob_wp)
|
|
{
|
|
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){
|
|
FMC_OBCTL0 &= (~((uint32_t)ob_wp << 16));
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief disable write protection
|
|
\param[in] ob_wp: specify sector to be write protected
|
|
\arg OB_WPx(x=0..11): write protect specify sector
|
|
\arg OB_WP_ALL: write protect all sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_write_protection0_disable(uint32_t ob_wp)
|
|
{
|
|
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){
|
|
FMC_OBCTL0 |= ((uint32_t)ob_wp << 16);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief enable write protection
|
|
\param[in] ob_wp: specify sector to be write protected
|
|
\arg OB_WPx(x=12..30): write protect specify sector
|
|
\arg OB_WP_ALL: write protect all sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_write_protection1_enable(uint32_t ob_wp)
|
|
{
|
|
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){
|
|
FMC_OBCTL1 &= (~((uint32_t)ob_wp << 16));
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief disable write protection
|
|
\param[in] ob_wp: specify sector to be write protected
|
|
\arg OB_WPx(x=12..30): write protect specify sector
|
|
\arg OB_WP_ALL: write protect all sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_write_protection1_disable(uint32_t ob_wp)
|
|
{
|
|
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){
|
|
FMC_OBCTL1 |= ((uint32_t)ob_wp << 16);
|
|
}
|
|
}
|
|
/*!
|
|
\brief configure the protection mode
|
|
\param[in] ob_drp: configure the protection mode of WPx bits
|
|
\arg OB_DRP_DISABLE: the WPx bits used as erase/program protection of each sector
|
|
\arg OB_DRP_ENABLE: the WPx bits used as erase/program protection and D-bus read protection of each sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_drp_config(uint32_t ob_drp)
|
|
{
|
|
FMC_OBCTL0 &= ~FMC_OBCTL0_DRP;
|
|
FMC_OBCTL0 |= ob_drp;
|
|
}
|
|
|
|
/*!
|
|
\brief enable erase/program protection and D-bus read protection
|
|
\param[in] ob_drp: enable the WPx bits used as erase/program protection and D-bus read protection of each sector
|
|
\arg OB_DRPx(x=0..11): erase/program protection and D-bus read protection of specify sector
|
|
\arg OB_DRP_ALL: erase/program protection and D-bus read protection of all sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_drp0_enable(uint32_t ob_drp)
|
|
{
|
|
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){
|
|
FMC_OBCTL0 |= ((uint32_t)ob_drp << 16);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief disable erase/program protection and D-bus read protection
|
|
\param[in] ob_drp: disable the WPx bits used as erase/program protection and D-bus read protection of each sector
|
|
\arg OB_DRPx(x=0..11): erase/program protection and D-bus read protection of specify sector
|
|
\arg OB_DRP_ALL: erase/program protection and D-bus read protection of all sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_drp0_disable(uint32_t ob_drp)
|
|
{
|
|
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){
|
|
FMC_OBCTL0 &= (~((uint32_t)ob_drp << 16));
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief enable erase/program protection and D-bus read protection
|
|
\param[in] ob_drp: enable the WPx bits used as erase/program protection and D-bus read protection of each sector
|
|
\arg OB_DRPx(x=12..30): erase/program protection and D-bus read protection of specify sector
|
|
\arg OB_DRP_ALL: erase/program protection and D-bus read protection of all sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_drp1_enable(uint32_t ob_drp)
|
|
{
|
|
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){
|
|
FMC_OBCTL1 |= ((uint32_t)ob_drp << 16);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief disable erase/program protection and D-bus read protection
|
|
\param[in] ob_drp: disable the WPx bits used as erase/program protection and D-bus read protection of each sector
|
|
\arg OB_DRPx(x=12..30): erase/program protection and D-bus read protection of specify sector
|
|
\arg OB_DRP_ALL: erase/program protection and D-bus read protection of all sector
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_drp1_disable(uint32_t ob_drp)
|
|
{
|
|
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){
|
|
FMC_OBCTL1 &= (~((uint32_t)ob_drp << 16));
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief configure security protection level
|
|
\param[in] ob_spc: specify security protection level
|
|
\arg FMC_NSPC: no security protection
|
|
\arg FMC_LSPC: low security protection
|
|
\arg FMC_HSPC: high security protection
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_security_protection_config(uint8_t ob_spc)
|
|
{
|
|
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){
|
|
uint32_t reg;
|
|
|
|
reg = FMC_OBCTL0;
|
|
/* reset the OBCTL0_SPC, set according to ob_spc */
|
|
reg &= ~FMC_OBCTL0_SPC;
|
|
FMC_OBCTL0 |= ((uint32_t)ob_spc << 8);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief program the FMC user option byte
|
|
\param[in] ob_fwdgt: option byte watchdog value
|
|
\arg OB_FWDGT_SW: software free watchdog
|
|
\arg OB_FWDGT_HW: hardware free watchdog
|
|
\param[in] ob_deepsleep: option byte deepsleep reset value
|
|
\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
|
|
\arg OB_STDBY_NRST: no reset when entering standby mode
|
|
\arg OB_STDBY_RST: generate a reset instead of entering standby mode
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_user_write(uint32_t ob_fwdgt, uint32_t ob_deepsleep, uint32_t ob_stdby)
|
|
{
|
|
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){
|
|
uint32_t reg;
|
|
|
|
reg = FMC_OBCTL0;
|
|
/* reset the OB_FWDGT, OB_DEEPSLEEP and OB_STDBY, set according to ob_fwdgt ,ob_deepsleep and ob_stdby */
|
|
reg &= ~(FMC_OBCTL0_NWDG_HW | FMC_OBCTL0_NRST_DPSLP | FMC_OBCTL0_NRST_STDBY);
|
|
FMC_OBCTL0 = (reg | ob_fwdgt | ob_deepsleep | ob_stdby);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief program the option byte BOR threshold value
|
|
\param[in] ob_bor_th: user option byte
|
|
\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 none
|
|
*/
|
|
void ob_user_bor_threshold(uint32_t ob_bor_th)
|
|
{
|
|
uint32_t reg;
|
|
|
|
reg = FMC_OBCTL0;
|
|
/* set the BOR level */
|
|
reg &= ~FMC_OBCTL0_BOR_TH;
|
|
FMC_OBCTL0 = (reg | ob_bor_th);
|
|
}
|
|
|
|
/*!
|
|
\brief configure the option byte boot bank value
|
|
\param[in] boot_mode: specifies the option byte boot bank value
|
|
\arg OB_BB_DISABLE: boot from bank0
|
|
\arg OB_BB_ENABLE: boot from bank1 or bank0 if bank1 is void
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void ob_boot_mode_config(uint32_t boot_mode)
|
|
{
|
|
uint32_t reg;
|
|
|
|
reg = FMC_OBCTL0;
|
|
/* set option byte boot bank value */
|
|
reg &= ~FMC_OBCTL0_BB;
|
|
FMC_OBCTL0 = (reg | boot_mode);
|
|
}
|
|
|
|
/*!
|
|
\brief get the FMC user option byte
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval the FMC user option byte values: ob_fwdgt(Bit0), ob_deepsleep(Bit1), ob_stdby(Bit2).
|
|
*/
|
|
uint8_t ob_user_get(void)
|
|
{
|
|
return (uint8_t)((uint8_t)(FMC_OBCTL0 >> 5) & (uint8_t)0x07);
|
|
}
|
|
|
|
/*!
|
|
\brief get the FMC option byte write protection
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval the FMC write protection option byte value
|
|
*/
|
|
uint16_t ob_write_protection0_get(void)
|
|
{
|
|
/* return the FMC write protection option byte value */
|
|
return (uint16_t)(((uint16_t)(FMC_OBCTL0 >> 16)) & (uint16_t)0x0FFF);
|
|
}
|
|
|
|
/*!
|
|
\brief get the FMC option byte write protection
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval the FMC write protection option byte value
|
|
*/
|
|
uint16_t ob_write_protection1_get(void)
|
|
{
|
|
/* return the the FMC write protection option byte value */
|
|
return (uint16_t)(((uint16_t)(FMC_OBCTL1 >> 16)) & (uint16_t)0x0FFF);
|
|
}
|
|
|
|
/*!
|
|
\brief get the FMC D-bus read protection protection
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval the FMC erase/program protection and D-bus read protection option bytes value
|
|
*/
|
|
uint16_t ob_drp0_get(void)
|
|
{
|
|
/* return the FMC erase/program protection and D-bus read protection option bytes value */
|
|
return (uint16_t)(((uint16_t)(FMC_OBCTL0 >> 16)) & (uint16_t)0x0FFF);
|
|
}
|
|
|
|
/*!
|
|
\brief get the FMC D-bus read protection protection
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval the FMC erase/program protection and D-bus read protection option bytes value
|
|
*/
|
|
uint16_t ob_drp1_get(void)
|
|
{
|
|
/* return the FMC erase/program protection and D-bus read protection option bytes value */
|
|
return (uint16_t)(((uint16_t)(FMC_OBCTL1 >> 16)) & (uint16_t)0x0FFF);
|
|
}
|
|
|
|
/*!
|
|
\brief get the FMC option byte security protection
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval FlagStatus: SET or RESET
|
|
*/
|
|
FlagStatus ob_spc_get(void)
|
|
{
|
|
FlagStatus spc_state = RESET;
|
|
|
|
if (((uint8_t)(FMC_OBCTL0 >> 8)) != (uint8_t)FMC_NSPC){
|
|
spc_state = SET;
|
|
}else{
|
|
spc_state = RESET;
|
|
}
|
|
return spc_state;
|
|
}
|
|
|
|
/*!
|
|
\brief get the FMC option byte BOR threshold value
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval the FMC BOR threshold value:OB_BOR_TH_OFF,OB_BOR_TH_VALUE1,OB_BOR_TH_VALUE2,OB_BOR_TH_VALUE3
|
|
*/
|
|
uint8_t ob_user_bor_threshold_get(void)
|
|
{
|
|
/* return the FMC BOR threshold value */
|
|
return (uint8_t)((uint8_t)FMC_OBCTL0 & (uint8_t)0x0C);
|
|
}
|
|
|
|
/*!
|
|
\brief enable FMC interrupt
|
|
\param[in] the FMC interrupt source
|
|
\arg FMC_INTEN_END: enable FMC end of program interrupt
|
|
\arg FMC_INTEN_ERR: enable FMC error interrupt
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void fmc_interrupt_enable(uint32_t fmc_int)
|
|
{
|
|
FMC_CTL |= fmc_int;
|
|
}
|
|
|
|
/*!
|
|
\brief disable FMC interrupt
|
|
\param[in] the FMC interrupt source
|
|
\arg FMC_INTEN_END: disable FMC end of program interrupt
|
|
\arg FMC_INTEN_ERR: disable FMC error interrupt
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void fmc_interrupt_disable(uint32_t fmc_int)
|
|
{
|
|
FMC_CTL &= ~(uint32_t)fmc_int;
|
|
}
|
|
|
|
/*!
|
|
\brief get flag set or reset
|
|
\param[in] fmc_flag: check FMC flag
|
|
\arg FMC_FLAG_BUSY: FMC busy flag
|
|
\arg FMC_FLAG_RDDERR: FMC read D-bus protection error flag bit
|
|
\arg FMC_FLAG_PGSERR: FMC program sequence error flag bit
|
|
\arg FMC_FLAG_PGMERR: FMC program size not match error flag bit
|
|
\arg FMC_FLAG_WPERR: FMC Erase/Program protection error flag bit
|
|
\arg FMC_FLAG_OPERR: FMC operation error flag bit
|
|
\arg FMC_FLAG_END: FMC end of operation flag bit
|
|
\param[out] none
|
|
\retval FlagStatus: SET or RESET
|
|
*/
|
|
FlagStatus fmc_flag_get(uint32_t fmc_flag)
|
|
{
|
|
if(FMC_STAT & fmc_flag){
|
|
return SET;
|
|
}
|
|
/* return the state of corresponding FMC flag */
|
|
return RESET;
|
|
}
|
|
|
|
/*!
|
|
\brief clear the FMC pending flag
|
|
\param[in] FMC_flag: clear FMC flag
|
|
\arg FMC_FLAG_RDDERR: FMC read D-bus protection error flag bit
|
|
\arg FMC_FLAG_PGSERR: FMC program sequence error flag bit
|
|
\arg FMC_FLAG_PGMERR: FMC program size not match error flag bit
|
|
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag bit
|
|
\arg FMC_FLAG_OPERR: FMC operation error flag bit
|
|
\arg FMC_FLAG_END: FMC end of operation flag bit
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void fmc_flag_clear(uint32_t fmc_flag)
|
|
{
|
|
/* clear the flags */
|
|
FMC_STAT = fmc_flag;
|
|
}
|
|
|
|
/*!
|
|
\brief get the FMC state
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_state_get(void)
|
|
{
|
|
fmc_state_enum fmc_state = FMC_READY;
|
|
|
|
if((FMC_STAT & FMC_FLAG_BUSY) == FMC_FLAG_BUSY){
|
|
fmc_state = FMC_BUSY;
|
|
}else{
|
|
if((FMC_STAT & FMC_FLAG_WPERR) != (uint32_t)0x00){
|
|
fmc_state = FMC_WPERR;
|
|
}else{
|
|
if((FMC_STAT & FMC_FLAG_RDDERR) != (uint32_t)0x00){
|
|
fmc_state = FMC_RDDERR;
|
|
}else{
|
|
if((FMC_STAT & (uint32_t)0xEF) != (uint32_t)0x00){
|
|
fmc_state = FMC_PGERR;
|
|
}else{
|
|
if((FMC_STAT & FMC_FLAG_OPERR) != (uint32_t)0x00){
|
|
fmc_state = FMC_OPERR;
|
|
}else{
|
|
fmc_state = FMC_READY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* return the FMC state */
|
|
return fmc_state;
|
|
}
|
|
|
|
/*!
|
|
\brief check whether FMC is ready or not
|
|
\param[in] count: FMC_TIMEOUT_COUNT
|
|
\param[out] none
|
|
\retval fmc_state_enum
|
|
*/
|
|
fmc_state_enum fmc_ready_wait(uint32_t count)
|
|
{
|
|
fmc_state_enum fmc_state = FMC_BUSY;
|
|
|
|
/* wait for FMC ready */
|
|
do{
|
|
/* get FMC state */
|
|
fmc_state = fmc_state_get();
|
|
count--;
|
|
}while((FMC_BUSY == fmc_state) && ((uint32_t)RESET != count));
|
|
|
|
if(FMC_BUSY == fmc_state){
|
|
fmc_state = FMC_TOERR;
|
|
}
|
|
/* return the FMC state */
|
|
return fmc_state;
|
|
}
|