rt-thread/bsp/gd32103c-eval/Libraries/GD32F1xx_standard_peripheral/Source/gd32f10x_fmc.c

1167 lines
34 KiB
C

/**
******************************************************************************
* @brief FMC functions of the firmware library.
******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "gd32f10x_fmc.h"
/** @addtogroup GD32F10x_Firmware
* @{
*/
/** @defgroup FMC
* @brief FMC driver modules
* @{
*/
/** @defgroup FMC_Private_Functions
* @{
*/
/** @defgroup FMC_Group1 FMC Memory Programming functions
* @brief FMC Memory Programming functions
*
@verbatim
===============================================================================
##### FMC Memory Programming functions #####
===============================================================================
[..] The FMC Memory Programming functions, includes the following functions:
(+) void FMC_Unlock(void);
(+) void FMC_UnlockBank1(void);
(+) void FMC_UnlockBank2(void);
(+) void FMC_Lock(void);
(+) void FMC_LockBank1(void)
(+) void FMC_LockBank2(void)
(+) FMC_State FMC_ErasePage(uint32_t Page_Address);
(+) FMC_State FMC_MassErase(void);
(+) FMC_State FMC_MassBank1Erase(void)
(+) FMC_State FMC_MassBank2Erase(void)
(+) FMC_State FMC_ProgramWord(uint32_t Address, uint32_t Data);
[..] Any operation of erase or program should follow these steps:
(#) Call the FMC_Unlock() function to unlock the FMC operation
(#) Call erase or program data
(#) Call the FMC_Lock() to lock the FMC operation
@endverbatim
* @{
*/
/**
* @brief Unlock the main FMC operation.
* @param None
* @retval None
*/
void FMC_Unlock(void)
{
if ((FMC->CMR & FMC_CMR_LK) != RESET) {
/* Write the FMC key */
FMC->UKEYR = FMC_KEY1;
FMC->UKEYR = FMC_KEY2;
}
if (FMC_SIZE > FMC_BANK1_SIZE) {
/* Authorize the FPEC of Bank2 Access */
if ((FMC->CMR2 & FMC_CMR_LK) != RESET) {
FMC->UKEYR2 = FMC_KEY1;
FMC->UKEYR2 = FMC_KEY2;
}
}
}
/**
* @brief Unlocks the FMC Bank1 Program Erase Controller.
* @note This function can be used for all GD32F10x devices.
* - For GD32F10X_XD and GD32F10X_CL devices this function unlocks Bank1.
* - For all other devices it unlocks Bank1 and it is
* equivalent to FLASH_Unlock function.
* @param None
* @retval None
*/
void FMC_UnlockB1(void)
{
/* Authorize the FPEC of Bank1 Access */
if ((FMC->CMR & FMC_CMR_LK) != RESET) {
FMC->UKEYR = FMC_KEY1;
FMC->UKEYR = FMC_KEY2;
}
}
/**
* @brief Unlocks the FMC Bank2 Program Erase Controller.
* @note This function can be used for GD32F10X_XD and GD32F10X_CL density devices.
* @param None
* @retval None
*/
#if defined GD32F10X_XD || defined GD32F10X_CL
void FMC_UnlockB2(void)
{
/* Authorize the FPEC of Bank2 Access */
if ((FMC->CMR2 & FMC_CMR_LK) != RESET) {
FMC->UKEYR2 = FMC_KEY1;
FMC->UKEYR2 = FMC_KEY2;
}
}
#endif /* GD32F10X_XD and GD32F10X_CL */
/**
* @brief Lock the main FMC operation.
* @param None
* @retval None
*/
void FMC_Lock(void)
{
/* Set the LOCK bit*/
FMC->CMR |= FMC_CMR_LK;
if (FMC_SIZE > FMC_BANK1_SIZE) {
/* Set the Lock Bit to lock the FPEC and the CR of Bank2 */
FMC->CMR2 |= FMC_CMR_LK;
}
}
/**
* @brief Locks the FMC Bank1 Program Erase Controller.
* @note this function can be used for all GD32F10X devices.
* - For GD32F10X_XD and GD32F10X_CL devices this function Locks Bank1.
* - For all other devices it Locks Bank1 and it is equivalent
* to FMC_Lock function.
* @param None
* @retval None
*/
void FMC_LockB1(void)
{
/* Set the Lock Bit to lock the FPEC and the CMR of Bank1 */
FMC->CMR |= FMC_CMR_LK;
}
/**
* @brief Locks the FMC Bank2 Program Erase Controller.
* @note This function can be used for GD32F10X_XD and GD32F10X_CL density devices.
* @param None
* @retval None
*/
#if defined GD32F10X_XD || defined GD32F10X_CL
void FMC_LockB2(void)
{
/* Set the Lock Bit to lock the FPEC and the CMR of Bank2 */
FMC->CMR2 |= FMC_CMR_LK;
}
#endif
/**
* @brief Erase a page.
* @param Page_Address: The page address to be erased.
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_ErasePage(uint32_t Page_Address)
{
if (FMC_SIZE > FMC_BANK1_SIZE) {
FMC_State temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
if (Page_Address < FMC_B1_END_ADDRESS) {
/* Wait for last operation to be completed */
FMC_State temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
FMC->CMR |= FMC_CMR_PE;
FMC->AR = Page_Address;
FMC->CMR |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the PE bit */
FMC->CMR &= ~FMC_CMR_PE;
}
} else {
/* Wait for last operation to be completed */
FMC_State temp_state = FMC_B2_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
FMC->CMR2 |= FMC_CMR_PE;
FMC->AR2 = Page_Address;
if (FMC->OPTR & FMC_OPTR_PLEVEL1) {
FMC->AR = Page_Address;
}
FMC->CMR2 |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_B2_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the PE bit */
FMC->CMR2 &= ~FMC_CMR_PE;
}
}
/* Return the FMC state */
return temp_state;
}
else {
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Start page erase */
FMC->CMR |= FMC_CMR_PE;
FMC->AR = Page_Address;
FMC->CMR |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the PE bit */
FMC->CMR &= ~FMC_CMR_PE;
}
/* Return the FMC state */
return temp_state;
}
}
/**
* @brief Erase all main FMC.
* @param None
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_MassErase(void)
{
if (FMC_SIZE > FMC_BANK1_SIZE) {
/* Wait for last operation to be completed */
FMC_State temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Start chip erase */
FMC->CMR |= FMC_CMR_ME;
FMC->CMR |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the MER bit */
FMC->CMR &= ~FMC_CMR_ME;
}
temp_state = FMC_B2_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Start chip erase */
FMC->CMR2 |= FMC_CMR_ME;
FMC->CMR2 |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_B2_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the MER bit */
FMC->CMR2 &= ~FMC_CMR_ME;
}
/* Return the FMC state */
return temp_state;
} else {
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Start chip erase */
FMC->CMR |= FMC_CMR_ME;
FMC->CMR |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the MER bit */
FMC->CMR &= ~FMC_CMR_ME;
}
/* Return the FMC state */
return temp_state;
}
}
/**
* @brief Erases all Bank1 FMC pages.
* @note This function can be used for all GD32F10x devices.
* - For GD32F10X_XD and GD32F10X_CL devices this function erases all Bank1 pages.
* - For all other devices it erases all Bank1 pages and it is equivalent
* to FLASH_EraseAllPages function.
* @param None
* @retval FLASH Status: FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_MassB1Erase(void)
{
FMC_State temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Start chip erase */
FMC->CMR |= FMC_CMR_ME;
FMC->CMR |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the MER bit */
FMC->CMR &= ~FMC_CMR_ME;
}
/* Return the Erase Status */
return temp_state;
}
/**
* @brief Erases all Bank2 FMC pages.
* @note This function can be used for GD32F10X_XD and GD32F10X_CL density devices.
* @param None
* @retval FMC Status: FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_MassB2Erase(void)
{
FMC_State temp_state = FMC_B2_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Start chip erase */
FMC->CMR2 |= FMC_CMR_ME;
FMC->CMR2 |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_B2_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the MER bit */
FMC->CMR2 &= ~FMC_CMR_ME;
}
/* Return the Erase Status */
return temp_state;
}
/**
* @brief Program a word at the corresponding address.
* @param Address: The address to be programmed.
* @param Data: The data to be programmed.
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_ProgramWord(uint32_t Address, uint32_t Data)
{
if (FMC_SIZE > FMC_BANK1_SIZE) {
FMC_State temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
if (Address < FMC_B1_END_ADDRESS) {
FMC_State temp_state = FMC_B1_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Set the PG bit to start program */
FMC->CMR |= FMC_CMR_PG;
*(__IO uint32_t *)Address = Data;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the PG bit */
FMC->CMR &= ~FMC_CMR_PG;
}
} else {
FMC_State temp_state = FMC_B2_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Set the PG bit to start program */
FMC->CMR2 |= FMC_CMR_PG;
*(__IO uint32_t *)Address = Data;
/* Wait for the FMC ready */
temp_state = FMC_B2_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the PG bit */
FMC->CMR2 &= ~FMC_CMR_PG;
}
}
/* Return the FMC state */
return temp_state;
} else {
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Set the PG bit to start program */
FMC->CMR |= FMC_CMR_PG;
*(__IO uint32_t *)Address = Data;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
/* Reset the PG bit */
FMC->CMR &= ~FMC_CMR_PG;
}
/* Return the FMC state */
return temp_state;
}
}
/**
* @}
*/
/** @defgroup FMC_Group2 Option Bytes Programming functions
* @brief Option Bytes Programming functions
*
@verbatim
===============================================================================
##### Option Bytes Programming functions #####
===============================================================================
[..] The FMC_Option Bytes Programming_functions, includes the following functions:
(+) void FMC_OB_Unlock(void);
(+) void FMC_OB_Lock(void);
(+) void FMC_OB_Reset(void);
(+) FMC_State FMC_OB_Erase(void);
(+) FMC_State FMC_OB_WRPConfig(uint32_t OB_WRP);
(+) FMC_State FMC_OB_RDPConfig(uint8_t OB_RDP);
(+) FMC_State FMC_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_DEEPSLEEP, uint8_t OB_STDBY);
(+) FMC_State FMC_OB_BOOTConfig(uint8_t OB_BOOT);
(+) FMC_State FMC_OB_WriteUser(uint8_t OB_USER);
(+) FMC_ProgramOptionByteData(uint32_t Address, uint8_t Data);
(+) uint8_t FMC_OB_GetUser(void);
(+) uint32_t FMC_OB_GetWRP(void);
(+) FlagStatus FMC_OB_GetRDP(void);
[..] Any operation of erase or program should follow these steps:
(#) Call the FMC_OB_Unlock() function to enable the Option Bytes registers access
(#) Call one or several functions to program the desired option bytes
(++) FMC_State FMC_OB_RDPConfig(uint8_t OB_RDP) => to set the desired read Protection Level
(++) FMC_State FMC_OB_WRPConfig(uint32_t OB_WRP, FunctionalState NewState)
=> to Enable/Disable the desired sector write protection
(++) FMC_State FMC_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_DEEPSLEEP, uint8_t OB_STDBY)
=> to configure the user option Bytes: IWDG, DEEPSLEEP and the Standby.
(++) FMC_State FMC_OB_BOOTConfig(uint8_t OB_BOOT1)
=> to set or reset BOOT1
(++) FMC_State FMC_OB_VDDAConfig(uint8_t OB_VDDA_ANALOG)
=> to enable or disable the VDDA Analog Monitoring
(++) You can write all User Options bytes at once using a single function
by calling FMC_State FMC_OB_WriteUser(uint8_t OB_USER)
(++) FMC_ProgramOptionByteData(uint32_t Address, uint8_t Data) to program the
two half word in the option bytes
(#) Once all needed option bytes to be programmed are correctly written, call the
FMC_OB_Launch(void) function to launch the Option Bytes programming process.
(#) Call the FMC_OB_Lock() to disable the Option Bytes registers access (recommended
to protect the option Bytes against possible unwanted operations)
@endverbatim
* @{
*/
/**
* @brief Unlock the option byte operation
* @param None
* @retval None
*/
void FMC_OB_Unlock(void)
{
if ((FMC->CMR & FMC_CMR_OBWE) == RESET) {
/* Write the FMC key */
FMC->OBKEYR = FMC_KEY1;
FMC->OBKEYR = FMC_KEY2;
}
}
/**
* @brief Lock the option byte operation.
* @param None
* @retval None
*/
void FMC_OB_Lock(void)
{
/* Reset the OBWE bit */
FMC->CMR &= ~FMC_CMR_OBWE;
}
/**
* @brief Generate a system reset to reload the option byte.
* @param None
* @retval None
*/
void FMC_OB_Reset(void)
{
/* Set the OPTR bit */
FMC->CMR |= FMC_CMR_OPTR;
}
/**
* @brief Erase the FMC option byte.
* @param None
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_OB_Erase(void)
{
uint16_t temp_rdp = RDP_LEVEL_0;
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
/* Check the ReadOut Protection Option Byte */
if (FMC_OB_GetRDP() != RESET) {
temp_rdp = 0x00;
}
if (temp_state == FMC_READY) {
/* Start erase the option byte */
FMC->CMR |= FMC_CMR_OBER;
FMC->CMR |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Reset the OPER bit */
FMC->CMR &= ~FMC_CMR_OBER;
/* Set the OBPG bit */
FMC->CMR |= FMC_CMR_OBPG;
/* Set default RDP level */
OB->RDP = (uint16_t)temp_rdp;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OBPG bit */
FMC->CMR &= ~FMC_CMR_OBPG;
}
} else {
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OBPG bit */
FMC->CMR &= ~FMC_CMR_OBPG;
}
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Program Write protect Byte
* @param OB_WRP: specify the address of the pages to be write protected.
* The legal parameter can be:
* @arg WRP_SECTOR0 ... WRP_SECTOR31
* @arg WRP_ALLSECTORS
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_OB_EnableWRP(uint32_t OB_WRP)
{
uint16_t temp_WRP0, temp_WRP1, temp_WRP2, temp_WRP3;
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
OB_WRP = (uint32_t)(~OB_WRP);
temp_WRP0 = (uint16_t)(OB_WRP & OB_WRP0_WRP0);
temp_WRP1 = (uint16_t)((OB_WRP & OB_WRP0_nWRP0) >> 8);
temp_WRP2 = (uint16_t)((OB_WRP & OB_WRP1_WRP1) >> 16);
temp_WRP3 = (uint16_t)((OB_WRP & OB_WRP1_nWRP1) >> 24);
if (temp_state == FMC_READY) {
FMC->OBKEYR = FMC_KEY1;
FMC->OBKEYR = FMC_KEY2;
/* Set the OBPG bit*/
FMC->CMR |= FMC_CMR_OBPG;
if (temp_WRP0 != 0xFF) {
OB->WRP0 = temp_WRP0;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
}
if ((temp_state == FMC_READY) && (temp_WRP1 != 0xFF)) {
OB->WRP1 = temp_WRP1;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
}
if ((temp_state == FMC_READY) && (temp_WRP2 != 0xFF)) {
OB->WRP2 = temp_WRP2;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
}
if ((temp_state == FMC_READY) && (temp_WRP3 != 0xFF)) {
OB->WRP3 = temp_WRP3;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
}
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OBPG bit */
FMC->CMR &= ~FMC_CMR_OBPG;
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Enable or disable the read out protection,this function erases all option bytes.
* @param NewValue: ENABLE or DISABLE.
* @retval FMC state: FMC_READY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_ReadOutProtection(TypeState NewValue)
{
FMC_State temp_state = FMC_READY;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Unlock option bytes */
FMC->OBKEYR = FMC_KEY1;
FMC->OBKEYR = FMC_KEY2;
while ((FMC->CMR & FMC_CMR_OBWE) != FMC_CMR_OBWE)
{}
FMC->CMR |= FMC_CMR_OBER;
FMC->CMR |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Disable the OBER Bit */
FMC->CMR &= ~FMC_CMR_OBER ;
/* Enable the OBPG Bit */
FMC->CMR |= FMC_CMR_OBPG;
if (NewValue != DISABLE) {
OB->RDP = 0x00;
} else {
OB->RDP = RDP_LEVEL_0;
}
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state != FMC_TIMEOUT_ERR) {
/* Enable the OBPG Bit */
FMC->CMR &= ~FMC_CMR_OBPG ;
}
} else {
if (temp_state != FMC_TIMEOUT_ERR) {
/* Disable the OBER Bit */
FMC->CMR &= ~FMC_CMR_OBER ;
}
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Config the Read Out Protection bit.
* @param FMC_ReadProtection_Level: The Read Out Protection level.
* This parameter can be:
* @arg RDP_LEVEL_0: No protection
* @arg RDP_LEVEL_1: Read Outprotection of the memory
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_OB_RDPConfig(uint8_t OB_RDP)
{
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
FMC->CMR |= FMC_CMR_OBER;
FMC->CMR |= FMC_CMR_START;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Reset the OBER bit */
FMC->CMR &= ~FMC_CMR_OBER;
/* Start the Option Bytes Programming */
FMC->CMR |= FMC_CMR_OBPG;
OB->RDP = OB_RDP;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OBPG bit */
FMC->CMR &= ~FMC_CMR_OBPG;
}
} else {
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OBER Bit */
FMC->CMR &= ~FMC_CMR_OBER;
}
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Program the FMC User Option Byte: IWDG_SW / RST_DEEPSLEEP / RST_STDBY.
* @param OB_IWDG: Config the WDG mode
* @arg OB_IWDG_SW: Software WDG selected
* @arg OB_IWDG_HW: Hardware WDG selected
* @param OB_DEEPSLEEP: Config Reset event when entering DEEPSLEEP mode.
* @arg OB_DEEPSLEEP_NORST: No reset generated when entering in DEEPSLEEP
* @arg OB_DEEPSLEEP_RST: Reset generated when entering in DEEPSLEEP
* @param OB_STDBY: Config Reset event when entering Standby mode.
* @arg OB_STDBY_NORST: No reset generated when entering in STANDBY
* @arg OB_STDBY_RST: Reset generated when entering in STANDBY
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_DEEPSLEEP, uint8_t OB_STDBY)
{
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Set the OBPG bit*/
FMC->CMR |= FMC_CMR_OBPG;
OB->USER = (uint16_t)((uint16_t)(OB_IWDG | OB_DEEPSLEEP) | (uint16_t)(OB_STDBY | 0xF8));
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OBPG bit */
FMC->CMR &= ~FMC_CMR_OBPG;
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Program the BOOT option bit.
* @param OB_BOOT: The legal parameter can be one of the following value:
* @arg OB_BOOT_B1:Start up from Bank1
* @arg OB_BOOT_B2:Start up from Bank2
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_OB_BOOTConfig(uint8_t OB_BOOT)
{
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
FMC->OBKEYR = FMC_KEY1;
FMC->OBKEYR = FMC_KEY2;
if (temp_state == FMC_READY) {
/* Set the OBPG bit*/
FMC->CMR |= FMC_CMR_OBPG;
if (OB_BOOT == OB_BOOT_B1) {
OB->USER |= OB_USER_BFB2;
} else {
OB->USER &= (uint16_t)(~(uint16_t)(OB_USER_BFB2));
}
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OBPG bit */
FMC->CMR &= ~FMC_CMR_OBPG;
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Program the FMC User Option Byte.
* @param OB_USER: Select all user option byte
* The legal parameter is one of the following values:
* @arg OB_IWDG_SW
* @arg OB_IWDG_HW
* @arg OB_DEEPSLEEP_NORST
* @arg OB_DEEPSLEEP_RST
* @arg OB_STDBY_NORST
* @arg OB_STDBY_RST
* @arg OB_BOOT_B1
* @arg OB_BOOT_B2
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_OB_WriteUser(uint8_t OB_USER)
{
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* Set the OBPG bit */
FMC->CMR |= FMC_CMR_OBPG;
OB->USER = OB_USER | 0xf0;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OBPG bit */
FMC->CMR &= ~FMC_CMR_OBPG;
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Program Option Byte Data.
* @param Address: The Option Byte address to be programmed.
* The legal parameter can be 0x1FFFF804 or 0x1FFFF806.
* @param Data: The Byte to be programmed.
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_ProgramOptionByteData(uint32_t Address, uint8_t Data)
{
FMC_State temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state == FMC_READY) {
/* SET the OPTPG bit */
FMC->CMR |= FMC_CMR_OBPG;
*(__IO uint16_t *)Address = Data;
/* Wait for the FMC ready */
temp_state = FMC_WaitReady(FMC_TIMEOUT_COUNT);
if (temp_state != FMC_TIMEOUT_ERR) {
/* Reset the OPTPG bit */
FMC->CMR &= ~FMC_CMR_OBPG;
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Get the FMC User Option Byte.
* @param None
* @retval The FMC User Option Byte.
*/
uint8_t FMC_OB_GetUser(void)
{
return (uint8_t)(FMC->OPTR >> 8);
}
/**
* @brief Get the FMC Write Protection Option Byte.
* @param None
* @retval The FMC Write Protection Option Byte
*/
uint32_t FMC_OB_GetWRP(void)
{
return (uint32_t)(FMC->WPR);
}
/**
* @brief Check whether the FMC Read out Protection Status is SET or RESET.
* @param None
* @retval FMC ReadOut Protection state
*/
TypeState FMC_OB_GetRDP(void)
{
TypeState RDPState = RESET;
if ((uint8_t)(FMC->OPTR & (FMC_OPTR_PLEVEL1)) != RESET) {
RDPState = SET;
} else {
RDPState = RESET;
}
return RDPState;
}
/**
* @}
*/
/** @defgroup FMC_Group3 Interrupts and flags management functions
* @brief Interrupts and flags management functions
*
@verbatim
===============================================================================
##### Interrupts and flags management functions #####
===============================================================================
@endverbatim
* @{
*/
/**
* @brief Enable or disable the corresponding FMC interrupt source.
* @param FMC_INT: The FMC interrupt source to be enabled or disabled.
* This parameter can be any combination of the following values:
* @arg FMC_INT_EOP: FMC end of programming Interrupt
* @arg FMC_INT_ERR: FMC Error Interrupt
* @arg FMC_INT_B2_EOP: FMC end of programming Interrupt
* @arg FMC_INT_B2_ERR: FMC Error Interrupt
* @param NewValue: ENABLE or DISABLE.
* @retval None
*/
void FMC_INTConfig(uint32_t FMC_INT, TypeState NewValue)
{
if (FMC_SIZE > FMC_BANK1_SIZE) {
if ((FMC_INT & 0x80000000) != 0x0) {
if (NewValue != DISABLE) {
/* Enable the interrupt sources */
FMC->CMR2 |= (FMC_INT & 0x7fffffff);
} else {
/* Disable the interrupt sources */
FMC->CMR2 &= ~(uint32_t)(FMC_INT & 0x7fffffff);
}
} else {
if (NewValue != DISABLE) {
/* Enable the interrupt sources */
FMC->CMR |= FMC_INT;
} else {
/* Disable the interrupt sources */
FMC->CMR &= ~(uint32_t)FMC_INT;
}
}
} else {
if (NewValue != DISABLE) {
/* Enable the interrupt sources */
FMC->CMR |= FMC_INT;
} else {
/* Disable the interrupt sources */
FMC->CMR &= ~(uint32_t)FMC_INT;
}
}
}
/**
* @brief Checks whether the FMC flag is SET or RESET.
* @param FMC_FLAG: the corresponding FMC flag.
* the legal parameter can be:
* @arg FMC_FLAG_BSY: FMC BUSY flag
* @arg FMC_FLAG_PERR: FMC Programming error flag flag
* @arg FMC_FLAG_WERR: FMC Write protection error flag
* @arg FMC_FLAG_EOP: FMC End of Programming flag
* @arg FMC_FLAG_OPTER: FMC option byte error flag
* @retval The state of the FMC flag.
*/
TypeState FMC_GetBitState(uint32_t FMC_FLAG)
{
if (FMC_SIZE > FMC_BANK1_SIZE) {
/* Check the parameters */
if (FMC_FLAG == FMC_FLAG_OPTERR) {
if ((FMC->OPTR & FMC_FLAG_OPTERR) != (uint32_t)RESET) {
return SET;
} else {
return RESET;
}
} else {
if ((FMC_FLAG & 0x80000000) != 0x0) {
if ((FMC->CSR2 & FMC_FLAG) != (uint32_t)RESET) {
return SET;
} else {
return RESET;
}
} else {
if ((FMC->CSR & FMC_FLAG) != (uint32_t)RESET) {
return SET;
} else {
return RESET;
}
}
}
} else {
if (FMC_FLAG == FMC_FLAG_OPTERR) {
if ((FMC->OPTR & FMC_FLAG_OPTERR) != (uint32_t)RESET) {
return SET;
} else {
return RESET;
}
} else {
if ((FMC->CSR & FMC_FLAG) != (uint32_t)RESET) {
return SET;
}
/* Return the state of corresponding FMC flag */
else {
return RESET;
}
}
}
}
/**
* @brief Clear the FMC pending flag.
* @param FMC_FLAG: clear the corresponding FMC flag.
* @arg FMC_FLAG_PERR: Programming error flag flag
* @arg FMC_FLAG_WERR: Write protection error flag
* @arg FMC_FLAG_EOP: End of Programming flag
* @retval None
*/
void FMC_ClearBitState(uint32_t FMC_FLAG)
{
if (FMC_SIZE > FMC_BANK1_SIZE) {
if ((FMC_FLAG & 0x80000000) != 0x0) {
/* Clear the flags */
FMC->CSR2 = FMC_FLAG;
} else {
/* Clear the flags */
FMC->CSR = FMC_FLAG;
}
} else {
FMC->CSR = FMC_FLAG;
}
}
/**
* @brief Return the FMC state.
* @param None
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, or FMC_PGERR
*/
FMC_State FMC_GetState(void)
{
FMC_State temp_state = FMC_READY;
if ((FMC->CSR & FMC_CSR_BUSY) == FMC_CSR_BUSY) {
temp_state = FMC_BSY;
} else {
if ((FMC->CSR & (uint32_t)FMC_CSR_WPEF) != (uint32_t)0x00) {
temp_state = FMC_WRPERR;
} else {
if ((FMC->CSR & (uint32_t)(FMC_CSR_PGEF)) != (uint32_t)0x00) {
temp_state = FMC_PGERR;
} else {
temp_state = FMC_READY;
}
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Return the FMC bak1 state.
* @param None
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, or FMC_PGERR
*/
FMC_State FMC_GetB1State(void)
{
FMC_State temp_state = FMC_READY;
if ((FMC->CSR & FMC_CSR_BUSY) == FMC_CSR_BUSY) {
temp_state = FMC_BSY;
} else {
if ((FMC->CSR & (uint32_t)FMC_CSR_WPEF) != (uint32_t)0x00) {
temp_state = FMC_WRPERR;
} else {
if ((FMC->CSR & (uint32_t)(FMC_CSR_PGEF)) != (uint32_t)0x00) {
temp_state = FMC_PGERR;
} else {
temp_state = FMC_READY;
}
}
}
return temp_state;
}
/**
* @brief Return the FMC bak2 state.
* @param None
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, or FMC_PGERR
*/
FMC_State FMC_GetB2State(void)
{
FMC_State temp_state = FMC_READY;
if ((FMC->CSR2 & FMC_CSR2_BUSY & 0x7fffffff) == (FMC_CSR2_BUSY & 0x7fffffff)) {
temp_state = FMC_BSY;
} else {
if ((FMC->CSR2 & FMC_CSR2_WPEF & 0x7fffffff) != (uint32_t)0x00) {
temp_state = FMC_WRPERR;
} else {
if ((FMC->CSR2 & FMC_CSR2_PGEF & 0x7fffffff) != (uint32_t)0x00) {
temp_state = FMC_PGERR;
} else {
temp_state = FMC_READY;
}
}
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Check whether FMC is ready or not.
* @param Timeout: Count of loop
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_WaitReady(uint32_t uCount)
{
FMC_State temp_state = FMC_BSY;
/* Wait for FMC ready */
do {
/* Get FMC state */
temp_state = FMC_GetState();
uCount--;
} while ((temp_state == FMC_BSY) && (uCount != 0x00));
if (temp_state == FMC_BSY) {
temp_state = FMC_TIMEOUT_ERR;
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Check whether FMC Bank1 is ready or not.
* @param Timeout: Count of loop
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_B1_WaitReady(uint32_t uCount)
{
FMC_State temp_state = FMC_BSY;
/* Wait for FMC ready */
do {
/* Get FMC state */
temp_state = FMC_GetB1State();
uCount--;
} while ((temp_state == FMC_BSY) && (uCount != 0x00));
if (temp_state == FMC_BSY) {
temp_state = FMC_TIMEOUT_ERR;
}
/* Return the FMC state */
return temp_state;
}
/**
* @brief Check whether FMC Bank2 is ready or not.
* @param Timeout: Count of loop
* @retval FMC state: FMC_READY, FMC_BSY, FMC_WRPERR, FMC_PGERR or FMC_TIMEOUT_ERR.
*/
FMC_State FMC_B2_WaitReady(uint32_t uCount)
{
FMC_State temp_state = FMC_BSY;
/* Wait for FMC ready */
do {
/* Get FMC state */
temp_state = FMC_GetB2State();
uCount--;
} while ((temp_state == (FMC_BSY && 0x7FFFFFFF)) && (uCount != 0x00));
if (temp_state == FMC_BSY) {
temp_state = FMC_TIMEOUT_ERR;
}
/* Return the FMC state */
return temp_state;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/