/** ****************************************************************************** * @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; } /** * @} */ /** * @} */ /** * @} */ /** * @} */