主要工作就是把HAL的超时用LL库延时替代,保留了中断擦写模式、轮询等待擦写,待验证哈。
笔者用的芯片为STM32G473CBT6 128KB Flash,开环环境为CUBEMX+MDK5.32,因为G4已经没有标准库了,笔者还是习惯使用标准库的开发方式,所以选择了LL库开发应用,但是LL库没有对Flash进行支持,所以笔者想通过修改HAL库的Flash驱动来使用。
介绍下Datasheet内容,STM32G473系列有支持 ECC 的 最大512 KB 闪存、两个边写边读的存储体、专有代码读出保护 (PCROP)、安全存储区域、1 KB OTP区域。
STM32G473xB/xC/xE 器件具有高达 512 KB 的嵌入式闪存,可用于存储程序和数据。
闪存接口特性:
????????– 单存储体或双存储体操作模式
????????– 双存储体模式下的边写边读 (RWW)
此功能允许在对另一存储体执行擦除或编程操作的同时从一个存储体执行读取操作。还支持双组启动。(双分区升级貌似很方便)
通过选项字节可以配置灵活的保护:
? 读出保护(RDP),用于保护整个存储器。提供三种保护级别:
????????– 0 级:无读出保护
????????– 1 级:存储器读出保护;如果连接了调试功能或选择了 RAM 启动或启动加载程序,则无法读取或写入闪存
????????– 第 2 级:芯片读出保护;调试功能(Cortex-M4 JTAG 和串行线)、RAM 中的引导和引导加载程序选择被禁用(JTAG 熔丝)。这种选择是不可逆转的。(产品定型之后)
? 写保护(WRP):保护区域不被擦除和编程。
? 专有代码读出保护(PCROP):可以保护闪存的一部分,防止第三方读写。该保护区是只执行的,只能由STM32 CPU作为指令代码访问,而严格禁止所有其他访问(DMA、调试和CPU数据读取、写入和擦除)。当 RDP 保护从级别 1 更改为级别 0 时,附加选项位 (PCROP_RDP) 允许选择是否擦除 PCROP 区域。
? 安全存储区域:闪存的一部分可以通过选项字节配置为安全的。复位后,该安全存储区域不受保护,其行为类似于主闪存的其余部分(执行、读取、写入访问)。当安全时,对该安全存储区域的任何访问都会产生相应的读/写错误。
安全内存区域的目的是保护敏感代码和数据(安全密钥存储),这些代码和数据只能在启动时执行一次,除非发生新的重置,否则永远不会再次执行。
闪存嵌入纠错码 (ECC) 功能,支持:
? 单错误检测和纠正(应该指字节)
? 双错误检测
? ECC 失败的地址可在 ECC 寄存器中读取
? 1 KB(128 个双字)OTP(单字节)时间可编程)用于用户数据。 OTP 区域仅在 Bank 1 中可用。 OTP 数据无法擦除且只能写入一次。(常用来写密钥)
Flash的相关特性
查看参考手册发现STM32G4系列芯片FLASH分成好几类
4类器件
? 高达512 KB 的闪存(单块)
? 64 位数据宽度的闪存读取操作
? 页擦除和批量擦除
2类设备
? 高达128 KB 的闪存(单块)
? 64 位数据宽度的闪存读取操作
? 页擦除和批量擦除
?3类器件
? 高达 512 KB 的闪存,采用双存储体架构,支持边写边读功能 (RWW)
? 支持两种数据宽度模式的闪存读取操作:
????????– 单存储体模式 DBANK=0:128 位读访问
????????– 双存储体模式 DBANK=1:64 位读访问
? 页擦除、存储体擦除和批量擦除(两个存储体)
根据描述,STM32G473应该是第3类器件
接着来看,闪存结构
该闪存具有以下主要特性:
? 容量高达 512 KB,单存储体模式(读取宽度为 128 位)或双存储体模式(读取宽度为 64 位)
? 通过 BFB2 选项支持双启动模式位(仅在双存储体模式下)
? 当 DBANK 位置 1 时,为双存储体模式:
????????– 512 KB 组织为 2 个存储体作为主存储器
????????– 页大小为 2 KB
????????– 72 位宽数据读取(64 位加 8 ECC 位)
????????– Bank和批量擦除
? DBANK 复位时,为单存储体模式:
????????– 512 KB 组织在一个存储体中作为主存储器
????????– 页大小为 4 KB
????????– 144 位宽数据读取(128 位加 2x8 ECC 位)
????????– 批量擦除
结构划分如下:
? 根据双存储体配置位划分的主存储器块结构:
????????– 当使能双存储体(DBANK 位置位)时,闪存分为 2 个 256 KB 的存储体,每个存储体的组织方式如下:
????????????????主存储器块包含 128 个 2 KB 页
????????????????每页由 8 行 256 字节组成
????????– 当禁用双存储体(DBANK 位复位)时,主存储器块被组织为一个 512 KB 的单存储体,如下所示:
????????????????主存储器包含 128 个 4 KB 页的块
????????????????每个页由 8 行 512 字节组成
? 信息块包含:
????????– 设备在系统内存引导模式下从其引导的系统内存。该区域保留供 STMicroElectronics 使用,包含引导加载程序,用于通过以下接口之一对闪存重新编程:USART、SPI、I2C、FDCAN、USB。它在设备制造时由意法半导体进行编程,并防止虚假写入/擦除操作。如需了解更多详细信息,请参阅 www.st.com 上提供的 AN2606。(就是ST的bootloader,如ISP下载等)
????????– 1 KB(128 个双字)OTP(一次性可编程)字节用于用户数据。 OTP 区域仅在 Bank 1 中可用。 OTP 数据无法擦除且只能写入一次。如果只有一位为 0,则即使值为 0x0000 0000 0000 0000,也无法再写入整个双字。
????????– 用户配置的选项字节。
存储器结构基于主区域和信息块,如表所示。
查看G473的配置文件,可以看大看到DBANK初始化置位,为双区模式,128KB划分两个64KB分区,每一个从页0到页31,32x2KBx2=128KB。后面为功能介绍,因为移植官方驱动,我决定现在去测试一下代码。
直接给代码。
/**
******************************************************************************
* @file flash.h
* @author Amos
* @brief Header for flash.c file.
* @version v1.0.0
******************************************************************************
* @attention
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef FLASH_H__
#define FLASH_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Exported constants --------------------------------------------------------*/
/**
* @brief FLASH_Error FLASH Error
*/
#define FLASH_ERROR_NONE 0x00000000U
#define FLASH_ERROR_OP FLASH_FLAG_OPERR
#define FLASH_ERROR_PROG FLASH_FLAG_PROGERR
#define FLASH_ERROR_WRP FLASH_FLAG_WRPERR
#define FLASH_ERROR_PGA FLASH_FLAG_PGAERR
#define FLASH_ERROR_SIZ FLASH_FLAG_SIZERR
#define FLASH_ERROR_PGS FLASH_FLAG_PGSERR
#define FLASH_ERROR_MIS FLASH_FLAG_MISERR
#define FLASH_ERROR_FAST FLASH_FLAG_FASTERR
#define FLASH_ERROR_RD FLASH_FLAG_RDERR
#define FLASH_ERROR_OPTV FLASH_FLAG_OPTVERR
#define FLASH_ERROR_ECCC FLASH_FLAG_ECCC
#define FLASH_ERROR_ECCD FLASH_FLAG_ECCD
#if defined (FLASH_OPTR_DBANK)
#define FLASH_ERROR_ECCC2 FLASH_FLAG_ECCC2
#define FLASH_ERROR_ECCD2 FLASH_FLAG_ECCD2
#endif
/**
* @brief FLASH_Type_Erase FLASH Erase Type
*/
#define FLASH_TYPEERASE_PAGES 0x00U /*!<Pages erase only*/
#define FLASH_TYPEERASE_MASSERASE 0x01U /*!<Flash mass erase activation*/
/**
* @brief FLASH_Banks FLASH Banks
*/
#define FLASH_BANK_1 0x00000001U /*!< Bank 1 */
#if defined (FLASH_OPTR_DBANK)
#define FLASH_BANK_2 0x00000002U /*!< Bank 2 */
#define FLASH_BANK_BOTH (FLASH_BANK_1 | FLASH_BANK_2) /*!< Bank1 and Bank2 */
#else
#define FLASH_BANK_BOTH FLASH_BANK_1 /*!< Bank 1 */
#endif
/**
* @brief FLASH_Type_Program FLASH Program Type
*/
#define FLASH_TYPEPROGRAM_DOUBLEWORD 0x00U /*!< Program a double-word (64-bit) at a specified address.*/
#define FLASH_TYPEPROGRAM_FAST 0x01U /*!< Fast program a 32 row double-word (64-bit) at a specified address.
And another 32 row double-word (64-bit) will be programmed */
#define FLASH_TYPEPROGRAM_FAST_AND_LAST 0x02U /*!< Fast program a 32 row double-word (64-bit) at a specified address.
And this is the last 32 row double-word (64-bit) programmed */
/**
* @brief FLASH_OB_Type FLASH Option Bytes Type
*/
#define OPTIONBYTE_WRP 0x01U /*!< WRP option byte configuration */
#define OPTIONBYTE_RDP 0x02U /*!< RDP option byte configuration */
#define OPTIONBYTE_USER 0x04U /*!< USER option byte configuration */
#define OPTIONBYTE_PCROP 0x08U /*!< PCROP option byte configuration */
#define OPTIONBYTE_BOOT_LOCK 0x10U /*!< Boot lock option byte configuration */
#define OPTIONBYTE_SEC 0x20U /*!< Securable memory option byte configuration */
/**
* @brief FLASH_OB_WRP_Area FLASH WRP Area
*/
#define OB_WRPAREA_BANK1_AREAA 0x00U /*!< Flash Bank 1 Area A */
#define OB_WRPAREA_BANK1_AREAB 0x01U /*!< Flash Bank 1 Area B */
#if defined (FLASH_OPTR_DBANK)
#define OB_WRPAREA_BANK2_AREAA 0x02U /*!< Flash Bank 2 Area A */
#define OB_WRPAREA_BANK2_AREAB 0x04U /*!< Flash Bank 2 Area B */
#endif
/**
* @brief FLASH_OB_Boot_Lock FLASH Boot Lock
*/
#define OB_BOOT_LOCK_DISABLE 0x00000000U /*!< Boot Lock Disable */
#define OB_BOOT_LOCK_ENABLE FLASH_SEC1R_BOOT_LOCK /*!< Boot Lock Enable */
/**
* @brief FLASH_OB_Read_Protection FLASH Option Bytes Read Protection
*/
#define OB_RDP_LEVEL_0 0xAAU
#define OB_RDP_LEVEL_1 0xBBU
#define OB_RDP_LEVEL_2 0xCCU /*!< Warning: When enabling read protection level 2
it's no more possible to go back to level 1 or 0 */
/**
* @brief FLASH_OB_USER_Type FLASH Option Bytes User Type
*/
#define OB_USER_BOR_LEV 0x00000001U /*!< BOR reset Level */
#define OB_USER_nRST_STOP 0x00000002U /*!< Reset generated when entering the stop mode */
#define OB_USER_nRST_STDBY 0x00000004U /*!< Reset generated when entering the standby mode */
#define OB_USER_IWDG_SW 0x00000008U /*!< Independent watchdog selection */
#define OB_USER_IWDG_STOP 0x00000010U /*!< Independent watchdog counter freeze in stop mode */
#define OB_USER_IWDG_STDBY 0x00000020U /*!< Independent watchdog counter freeze in standby mode */
#define OB_USER_WWDG_SW 0x00000040U /*!< Window watchdog selection */
#if defined (FLASH_OPTR_DBANK)
#define OB_USER_BFB2 0x00000080U /*!< Dual-bank boot */
#define OB_USER_DBANK 0x00000100U /*!< Single bank with 128-bits data or two banks with 64-bits data */
#endif
#if defined (FLASH_OPTR_PB4_PUPEN)
#define OB_USER_PB4_PUPEN 0x00000100U /*!< USB power delivery dead-battery/TDI pull-up */
#endif
#define OB_USER_nBOOT1 0x00000200U /*!< Boot configuration */
#define OB_USER_SRAM_PE 0x00000400U /*!< SRAM parity check enable (first 32kB of SRAM1 + CCM SRAM) */
#define OB_USER_CCMSRAM_RST 0x00000800U /*!< CCMSRAM Erase when system reset */
#define OB_USER_nRST_SHDW 0x00001000U /*!< Reset generated when entering the shutdown mode */
#define OB_USER_nSWBOOT0 0x00002000U /*!< Software BOOT0 */
#define OB_USER_nBOOT0 0x00004000U /*!< nBOOT0 option bit */
#define OB_USER_NRST_MODE 0x00008000U /*!< Reset pin configuration */
#define OB_USER_IRHEN 0x00010000U /*!< Internal Reset Holder enable */
/**
* @brief FLASH_OB_USER_BOR_LEVEL FLASH Option Bytes User BOR Level
*/
#define OB_BOR_LEVEL_0 FLASH_OPTR_BOR_LEV_0 /*!< Reset level threshold is around 1.7V */
#define OB_BOR_LEVEL_1 FLASH_OPTR_BOR_LEV_1 /*!< Reset level threshold is around 2.0V */
#define OB_BOR_LEVEL_2 FLASH_OPTR_BOR_LEV_2 /*!< Reset level threshold is around 2.2V */
#define OB_BOR_LEVEL_3 FLASH_OPTR_BOR_LEV_3 /*!< Reset level threshold is around 2.5V */
#define OB_BOR_LEVEL_4 FLASH_OPTR_BOR_LEV_4 /*!< Reset level threshold is around 2.8V */
/**
* @brief FLASH_OB_USER_nRST_STOP FLASH Option Bytes User Reset On Stop
*/
#define OB_STOP_RST 0x00000000U /*!< Reset generated when entering the stop mode */
#define OB_STOP_NORST FLASH_OPTR_nRST_STOP /*!< No reset generated when entering the stop mode */
/**
* @brief FLASH_OB_USER_nRST_STANDBY FLASH Option Bytes User Reset On Standby
*/
#define OB_STANDBY_RST 0x00000000U /*!< Reset generated when entering the standby mode */
#define OB_STANDBY_NORST FLASH_OPTR_nRST_STDBY /*!< No reset generated when entering the standby mode */
/**
* @brief FLASH_OB_USER_nRST_SHUTDOWN FLASH Option Bytes User Reset On Shutdown
*/
#define OB_SHUTDOWN_RST 0x00000000U /*!< Reset generated when entering the shutdown mode */
#define OB_SHUTDOWN_NORST FLASH_OPTR_nRST_SHDW /*!< No reset generated when entering the shutdown mode */
/**
* @brief FLASH_OB_USER_IWDG_SW FLASH Option Bytes User IWDG Type
*/
#define OB_IWDG_HW 0x00000000U /*!< Hardware independent watchdog */
#define OB_IWDG_SW FLASH_OPTR_IWDG_SW /*!< Software independent watchdog */
/**
* @brief FLASH_OB_USER_IWDG_STOP FLASH Option Bytes User IWDG Mode On Stop
*/
#define OB_IWDG_STOP_FREEZE 0x00000000U /*!< Independent watchdog counter is frozen in Stop mode */
#define OB_IWDG_STOP_RUN FLASH_OPTR_IWDG_STOP /*!< Independent watchdog counter is running in Stop mode */
/**
* @brief FLASH_OB_USER_IWDG_STANDBY FLASH Option Bytes User IWDG Mode On Standby
*/
#define OB_IWDG_STDBY_FREEZE 0x00000000U /*!< Independent watchdog counter is frozen in Standby mode */
#define OB_IWDG_STDBY_RUN FLASH_OPTR_IWDG_STDBY /*!< Independent watchdog counter is running in Standby mode */
/**
* @brief FLASH_OB_USER_WWDG_SW FLASH Option Bytes User WWDG Type
*/
#define OB_WWDG_HW 0x00000000U /*!< Hardware window watchdog */
#define OB_WWDG_SW FLASH_OPTR_WWDG_SW /*!< Software window watchdog */
#if defined (FLASH_OPTR_DBANK)
/**
* @brief FLASH_OB_USER_BFB2 FLASH Option Bytes User BFB2 Mode
*/
#define OB_BFB2_DISABLE 0x00000000U /*!< Dual-bank boot disable */
#define OB_BFB2_ENABLE FLASH_OPTR_BFB2 /*!< Dual-bank boot enable */
/**
* @brief FLASH_OB_USER_DBANK FLASH Option Bytes User DBANK Type
*/
#define OB_DBANK_128_BITS 0x00000000U /*!< Single-bank with 128-bits data */
#define OB_DBANK_64_BITS FLASH_OPTR_DBANK /*!< Dual-bank with 64-bits data */
#endif
#if defined (FLASH_OPTR_PB4_PUPEN)
/**
* @brief FLASH_OB_USER_PB4_PUPEN FLASH Option Bytes User PB4 PUPEN bit
*/
#define OB_PB4_PUPEN_DISABLE 0x00000000U /*!< USB power delivery dead-battery enabled/ TDI pull-up deactivated */
#define OB_PB4_PUPEN_ENABLE FLASH_OPTR_PB4_PUPEN /*!< USB power delivery dead-battery disabled/ TDI pull-up activated */
#endif
/**
* @brief FLASH_OB_USER_nBOOT1 FLASH Option Bytes User BOOT1 Type
*/
#define OB_BOOT1_SRAM 0x00000000U /*!< Embedded SRAM1 is selected as boot space (if BOOT0=1) */
#define OB_BOOT1_SYSTEM FLASH_OPTR_nBOOT1 /*!< System memory is selected as boot space (if BOOT0=1) */
/**
* @brief FLASH_OB_USER_SRAM_PE FLASH Option Bytes User SRAM Parity Check Type
*/
#define OB_SRAM_PARITY_ENABLE 0x00000000U /*!< SRAM parity check enable (first 32kB of SRAM1 + CCM SRAM) */
#define OB_SRAM_PARITY_DISABLE FLASH_OPTR_SRAM_PE /*!< SRAM parity check disable (first 32kB of SRAM1 + CCM SRAM) */
/**
* @brief FLASH_OB_USER_CCMSRAM_RST FLASH Option Bytes User CCMSRAM Erase On Reset Type
*/
#define OB_CCMSRAM_RST_ERASE 0x00000000U /*!< CCMSRAM erased when a system reset occurs */
#define OB_CCMSRAM_RST_NOT_ERASE FLASH_OPTR_CCMSRAM_RST /*!< CCMSRAM is not erased when a system reset occurs */
/**
* @brief FLASH_OB_USER_nSWBOOT0 FLASH Option Bytes User Software BOOT0
*/
#define OB_BOOT0_FROM_OB 0x00000000U /*!< BOOT0 taken from the option bit nBOOT0 */
#define OB_BOOT0_FROM_PIN FLASH_OPTR_nSWBOOT0 /*!< BOOT0 taken from PB8/BOOT0 pin */
/**
* @brief FLASH_OB_USER_nBOOT0 FLASH Option Bytes User nBOOT0 option bit
*/
#define OB_nBOOT0_RESET 0x00000000U /*!< nBOOT0 = 0 */
#define OB_nBOOT0_SET FLASH_OPTR_nBOOT0 /*!< nBOOT0 = 1 */
/**
* @brief FLASH_OB_USER_NRST_MODE FLASH Option Bytes User NRST mode bit
*/
#define OB_NRST_MODE_INPUT_ONLY FLASH_OPTR_NRST_MODE_0 /*!< Reset pin is in Reset input mode only */
#define OB_NRST_MODE_GPIO FLASH_OPTR_NRST_MODE_1 /*!< Reset pin is in GPIO mode only */
#define OB_NRST_MODE_INPUT_OUTPUT FLASH_OPTR_NRST_MODE /*!< Reset pin is in reset input and output mode */
/**
* @brief FLASH_OB_USER_INTERNAL_RESET_HOLDER FLASH Option Bytes User internal reset holder bit
*/
#define OB_IRH_DISABLE 0x00000000U /*!< Internal Reset holder disable */
#define OB_IRH_ENABLE FLASH_OPTR_IRHEN /*!< Internal Reset holder enable */
/**
* @brief FLASH_OB_PCROP_RDP FLASH Option Bytes PCROP On RDP Level Type
*/
#define OB_PCROP_RDP_NOT_ERASE 0x00000000U /*!< PCROP area is not erased when the RDP level
is decreased from Level 1 to Level 0 */
#define OB_PCROP_RDP_ERASE FLASH_PCROP1ER_PCROP_RDP /*!< PCROP area is erased when the RDP level is
decreased from Level 1 to Level 0 (full mass erase) */
/**
* @brief FLASH_Latency FLASH Latency
*/
#define FLASH_LATENCY_0 FLASH_ACR_LATENCY_0WS /*!< FLASH Zero wait state */
#define FLASH_LATENCY_1 FLASH_ACR_LATENCY_1WS /*!< FLASH One wait state */
#define FLASH_LATENCY_2 FLASH_ACR_LATENCY_2WS /*!< FLASH Two wait states */
#define FLASH_LATENCY_3 FLASH_ACR_LATENCY_3WS /*!< FLASH Three wait states */
#define FLASH_LATENCY_4 FLASH_ACR_LATENCY_4WS /*!< FLASH Four wait states */
#define FLASH_LATENCY_5 FLASH_ACR_LATENCY_5WS /*!< FLASH Five wait state */
#define FLASH_LATENCY_6 FLASH_ACR_LATENCY_6WS /*!< FLASH Six wait state */
#define FLASH_LATENCY_7 FLASH_ACR_LATENCY_7WS /*!< FLASH Seven wait states */
#define FLASH_LATENCY_8 FLASH_ACR_LATENCY_8WS /*!< FLASH Eight wait states */
#define FLASH_LATENCY_9 FLASH_ACR_LATENCY_9WS /*!< FLASH Nine wait states */
#define FLASH_LATENCY_10 FLASH_ACR_LATENCY_10WS /*!< FLASH Ten wait state */
#define FLASH_LATENCY_11 FLASH_ACR_LATENCY_11WS /*!< FLASH Eleven wait state */
#define FLASH_LATENCY_12 FLASH_ACR_LATENCY_12WS /*!< FLASH Twelve wait states */
#define FLASH_LATENCY_13 FLASH_ACR_LATENCY_13WS /*!< FLASH Thirteen wait states */
#define FLASH_LATENCY_14 FLASH_ACR_LATENCY_14WS /*!< FLASH Fourteen wait states */
#define FLASH_LATENCY_15 FLASH_ACR_LATENCY_15WS /*!< FLASH Fifteen wait states */
/**
* @brief FLASH_Keys FLASH Keys
*/
#define FLASH_KEY1 0x45670123U /*!< Flash key1 */
#define FLASH_KEY2 0xCDEF89ABU /*!< Flash key2: used with FLASH_KEY1
to unlock the FLASH registers access */
#define FLASH_PDKEY1 0x04152637U /*!< Flash power down key1 */
#define FLASH_PDKEY2 0xFAFBFCFDU /*!< Flash power down key2: used with FLASH_PDKEY1
to unlock the RUN_PD bit in FLASH_ACR */
#define FLASH_OPTKEY1 0x08192A3BU /*!< Flash option byte key1 */
#define FLASH_OPTKEY2 0x4C5D6E7FU /*!< Flash option byte key2: used with FLASH_OPTKEY1
to allow option bytes operations */
/**
* @brief FLASH_Flags FLASH Flags Definition
*/
#define FLASH_FLAG_EOP FLASH_SR_EOP /*!< FLASH End of operation flag */
#define FLASH_FLAG_OPERR FLASH_SR_OPERR /*!< FLASH Operation error flag */
#define FLASH_FLAG_PROGERR FLASH_SR_PROGERR /*!< FLASH Programming error flag */
#define FLASH_FLAG_WRPERR FLASH_SR_WRPERR /*!< FLASH Write protection error flag */
#define FLASH_FLAG_PGAERR FLASH_SR_PGAERR /*!< FLASH Programming alignment error flag */
#define FLASH_FLAG_SIZERR FLASH_SR_SIZERR /*!< FLASH Size error flag */
#define FLASH_FLAG_PGSERR FLASH_SR_PGSERR /*!< FLASH Programming sequence error flag */
#define FLASH_FLAG_MISERR FLASH_SR_MISERR /*!< FLASH Fast programming data miss error flag */
#define FLASH_FLAG_FASTERR FLASH_SR_FASTERR /*!< FLASH Fast programming error flag */
#define FLASH_FLAG_RDERR FLASH_SR_RDERR /*!< FLASH PCROP read error flag */
#define FLASH_FLAG_OPTVERR FLASH_SR_OPTVERR /*!< FLASH Option validity error flag */
#define FLASH_FLAG_BSY FLASH_SR_BSY /*!< FLASH Busy flag */
#define FLASH_FLAG_ECCC FLASH_ECCR_ECCC /*!< FLASH ECC correction in 64 LSB bits */
#define FLASH_FLAG_ECCD FLASH_ECCR_ECCD /*!< FLASH ECC detection in 64 LSB bits */
#if defined (FLASH_OPTR_DBANK)
#define FLASH_FLAG_ECCC2 FLASH_ECCR_ECCC2 /*!< FLASH ECC correction in 64 MSB bits (mode 128 bits only) */
#define FLASH_FLAG_ECCD2 FLASH_ECCR_ECCD2 /*!< FLASH ECC detection in 64 MSB bits (mode 128 bits only) */
#endif
#define FLASH_FLAG_SR_ERRORS (FLASH_FLAG_OPERR | FLASH_FLAG_PROGERR | FLASH_FLAG_WRPERR | \
FLASH_FLAG_PGAERR | FLASH_FLAG_SIZERR | FLASH_FLAG_PGSERR | \
FLASH_FLAG_MISERR | FLASH_FLAG_FASTERR | FLASH_FLAG_RDERR | \
FLASH_FLAG_OPTVERR)
#if defined (FLASH_OPTR_DBANK)
#define FLASH_FLAG_ECCR_ERRORS (FLASH_FLAG_ECCC | FLASH_FLAG_ECCD | FLASH_FLAG_ECCC2 | FLASH_FLAG_ECCD2)
#else
#define FLASH_FLAG_ECCR_ERRORS (FLASH_FLAG_ECCC | FLASH_FLAG_ECCD)
#endif
#define FLASH_FLAG_ALL_ERRORS (FLASH_FLAG_SR_ERRORS | FLASH_FLAG_ECCR_ERRORS)
/**
* @brief FLASH_Interrupt_definition FLASH Interrupts Definition
*/
#define FLASH_IT_EOP FLASH_CR_EOPIE /*!< End of FLASH Operation Interrupt source */
#define FLASH_IT_OPERR FLASH_CR_ERRIE /*!< Error Interrupt source */
#define FLASH_IT_RDERR FLASH_CR_RDERRIE /*!< PCROP Read Error Interrupt source*/
#define FLASH_IT_ECCC (FLASH_ECCR_ECCIE >> 24U) /*!< ECC Correction Interrupt source */
/* Exported types ------------------------------------------------------------*/
/**
* @brief FLASH Status structures definition
*/
typedef enum
{
FLASH_OK = 0x00U,
FLASH_ERROR = 0x01U,
FLASH_BUSY = 0x02U,
FLASH_TIMEOUT = 0x03U
} FLASH_StatusTypeDef;
/**
* @brief FLASH Lock structures definition
*/
typedef enum
{
UNLOCKED = 0x00U,
LOCKED = 0x01U
} FLASH_LockTypeDef;
/**
* @brief FLASH Erase structure definition
*/
typedef struct
{
uint32_t TypeErase; /*!< Mass erase or page erase.
This parameter can be a value of @ref FLASH_Type_Erase */
uint32_t Banks; /*!< Select bank to erase.
This parameter must be a value of @ref FLASH_Banks
(FLASH_BANK_BOTH should be used only for mass erase) */
uint32_t Page; /*!< Initial Flash page to erase when page erase is disabled.
This parameter must be a value between 0 and (max number of pages in the bank - 1)
(eg : 127 for 512KB dual bank) */
uint32_t NbPages; /*!< Number of pages to be erased.
This parameter must be a value between 1 and (max number of pages in the bank - value of initial page)*/
} FLASH_EraseInitTypeDef;
/**
* @brief FLASH Option Bytes Program structure definition
*/
typedef struct
{
uint32_t OptionType; /*!< Option byte to be configured.
This parameter can be a combination of the values of @ref FLASH_OB_Type */
uint32_t WRPArea; /*!< Write protection area to be programmed (used for OPTIONBYTE_WRP).
Only one WRP area could be programmed at the same time.
This parameter can be value of @ref FLASH_OB_WRP_Area */
uint32_t WRPStartOffset; /*!< Write protection start offset (used for OPTIONBYTE_WRP).
This parameter must be a value between 0 and (max number of pages in the bank - 1) */
uint32_t WRPEndOffset; /*!< Write protection end offset (used for OPTIONBYTE_WRP).
This parameter must be a value between WRPStartOffset and (max number of pages in the bank - 1) */
uint32_t RDPLevel; /*!< Set the read protection level.. (used for OPTIONBYTE_RDP).
This parameter can be a value of @ref FLASH_OB_Read_Protection */
uint32_t USERType; /*!< User option byte(s) to be configured (used for OPTIONBYTE_USER).
This parameter can be a combination of @ref FLASH_OB_USER_Type */
uint32_t USERConfig; /*!< Value of the user option byte (used for OPTIONBYTE_USER).
This parameter can be a combination of @ref FLASH_OB_USER_BOR_LEVEL,
@ref FLASH_OB_USER_nRST_STOP, @ref FLASH_OB_USER_nRST_STANDBY,
@ref FLASH_OB_USER_nRST_SHUTDOWN, @ref FLASH_OB_USER_IWDG_SW,
@ref FLASH_OB_USER_IWDG_STOP, @ref FLASH_OB_USER_IWDG_STANDBY,
@ref FLASH_OB_USER_WWDG_SW, @ref FLASH_OB_USER_BFB2 (*),
@ref FLASH_OB_USER_nBOOT1, @ref FLASH_OB_USER_SRAM_PE,
@ref FLASH_OB_USER_CCMSRAM_RST
@note (*) availability depends on devices */
uint32_t PCROPConfig; /*!< Configuration of the PCROP (used for OPTIONBYTE_PCROP).
This parameter must be a combination of @ref FLASH_Banks (except FLASH_BANK_BOTH)
and @ref FLASH_OB_PCROP_RDP */
uint32_t PCROPStartAddr; /*!< PCROP Start address (used for OPTIONBYTE_PCROP).
This parameter must be a value between begin and end of bank
=> Be careful of the bank swapping for the address */
uint32_t PCROPEndAddr; /*!< PCROP End address (used for OPTIONBYTE_PCROP).
This parameter must be a value between PCROP Start address and end of bank */
uint32_t BootEntryPoint; /*!< Set the Boot Lock (used for OPTIONBYTE_BOOT_LOCK).
This parameter can be a value of @ref FLASH_OB_Boot_Lock */
uint32_t SecBank; /*!< Bank of securable memory area to be programmed (used for OPTIONBYTE_SEC).
Only one securable memory area could be programmed at the same time.
This parameter can be one of the following values:
FLASH_BANK_1: Securable memory area to be programmed in bank 1
FLASH_BANK_2: Securable memory area to be programmed in bank 2 (*)
@note (*) availability depends on devices */
uint32_t SecSize; /*!< Size of securable memory area to be programmed (used for OPTIONBYTE_SEC),
in number of pages. Securable memory area is starting from first page of the bank.
Only one securable memory could be programmed at the same time.
This parameter must be a value between 0 and (max number of pages in the bank - 1) */
} FLASH_OBProgramInitTypeDef;
/**
* @brief FLASH Procedure structure definition
*/
typedef enum
{
FLASH_PROC_NONE = 0,
FLASH_PROC_PAGE_ERASE,
FLASH_PROC_MASS_ERASE,
FLASH_PROC_PROGRAM,
FLASH_PROC_PROGRAM_LAST
} FLASH_ProcedureTypeDef;
/**
* @brief FLASH Cache structure definition
*/
typedef enum
{
FLASH_CACHE_DISABLED = 0,
FLASH_CACHE_ICACHE_ENABLED,
FLASH_CACHE_DCACHE_ENABLED,
FLASH_CACHE_ICACHE_DCACHE_ENABLED
} FLASH_CacheTypeDef;
/**
* @brief FLASH handle Structure definition
*/
typedef struct
{
FLASH_LockTypeDef Lock; /* FLASH locking object */
__IO uint32_t ErrorCode; /* FLASH error code */
__IO FLASH_ProcedureTypeDef ProcedureOnGoing; /* Internal variable to indicate which procedure is ongoing or not in IT context */
__IO uint32_t Address; /* Internal variable to save address selected for program in IT context */
__IO uint32_t Bank; /* Internal variable to save current bank selected during erase in IT context */
__IO uint32_t Page; /* Internal variable to define the current page which is erasing in IT context */
__IO uint32_t NbPagesToErase; /* Internal variable to save the remaining pages to erase in IT context */
__IO FLASH_CacheTypeDef CacheToReactivate; /* Internal variable to indicate which caches should be reactivated */
} FLASH_ProcessTypeDef;
/* Exported macro ------------------------------------------------------------*/
/**
* @brief Set the FLASH Latency.
* @param __LATENCY__ FLASH Latency.
* This parameter can be one of the following values :
* @arg FLASH_LATENCY_0: FLASH Zero wait state
* @arg FLASH_LATENCY_1: FLASH One wait state
* @arg FLASH_LATENCY_2: FLASH Two wait states
* @arg FLASH_LATENCY_3: FLASH Three wait states
* @arg FLASH_LATENCY_4: FLASH Four wait states
* @arg FLASH_LATENCY_5: FLASH Five wait states
* @arg FLASH_LATENCY_6: FLASH Six wait states
* @arg FLASH_LATENCY_7: FLASH Seven wait states
* @arg FLASH_LATENCY_8: FLASH Eight wait states
* @arg FLASH_LATENCY_9: FLASH Nine wait states
* @arg FLASH_LATENCY_10: FLASH Ten wait state
* @arg FLASH_LATENCY_11: FLASH Eleven wait state
* @arg FLASH_LATENCY_12: FLASH Twelve wait states
* @arg FLASH_LATENCY_13: FLASH Thirteen wait states
* @arg FLASH_LATENCY_14: FLASH Fourteen wait states
* @arg FLASH_LATENCY_15: FLASH Fifteen wait states
* @retval None
*/
#define FLASH_SET_LATENCY(__LATENCY__) MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, (__LATENCY__))
/**
* @brief Get the FLASH Latency.
* @retval FLASH_Latency.
* This parameter can be one of the following values :
* @arg FLASH_LATENCY_0: FLASH Zero wait state
* @arg FLASH_LATENCY_1: FLASH One wait state
* @arg FLASH_LATENCY_2: FLASH Two wait states
* @arg FLASH_LATENCY_3: FLASH Three wait states
* @arg FLASH_LATENCY_4: FLASH Four wait states
* @arg FLASH_LATENCY_5: FLASH Five wait states
* @arg FLASH_LATENCY_6: FLASH Six wait states
* @arg FLASH_LATENCY_7: FLASH Seven wait states
* @arg FLASH_LATENCY_8: FLASH Eight wait states
* @arg FLASH_LATENCY_9: FLASH Nine wait states
* @arg FLASH_LATENCY_10: FLASH Ten wait state
* @arg FLASH_LATENCY_11: FLASH Eleven wait state
* @arg FLASH_LATENCY_12: FLASH Twelve wait states
* @arg FLASH_LATENCY_13: FLASH Thirteen wait states
* @arg FLASH_LATENCY_14: FLASH Fourteen wait states
* @arg FLASH_LATENCY_15: FLASH Fifteen wait states
*/
#define FLASH_GET_LATENCY() READ_BIT(FLASH->ACR, FLASH_ACR_LATENCY)
/**
* @brief Enable the FLASH prefetch buffer.
* @retval None
*/
#define FLASH_PREFETCH_BUFFER_ENABLE() SET_BIT(FLASH->ACR, FLASH_ACR_PRFTEN)
/**
* @brief Disable the FLASH prefetch buffer.
* @retval None
*/
#define FLASH_PREFETCH_BUFFER_DISABLE() CLEAR_BIT(FLASH->ACR, FLASH_ACR_PRFTEN)
/**
* @brief Enable the FLASH instruction cache.
* @retval none
*/
#define FLASH_INSTRUCTION_CACHE_ENABLE() SET_BIT(FLASH->ACR, FLASH_ACR_ICEN)
/**
* @brief Disable the FLASH instruction cache.
* @retval none
*/
#define FLASH_INSTRUCTION_CACHE_DISABLE() CLEAR_BIT(FLASH->ACR, FLASH_ACR_ICEN)
/**
* @brief Enable the FLASH data cache.
* @retval none
*/
#define FLASH_DATA_CACHE_ENABLE() SET_BIT(FLASH->ACR, FLASH_ACR_DCEN)
/**
* @brief Disable the FLASH data cache.
* @retval none
*/
#define FLASH_DATA_CACHE_DISABLE() CLEAR_BIT(FLASH->ACR, FLASH_ACR_DCEN)
/**
* @brief Reset the FLASH instruction Cache.
* @note This function must be used only when the Instruction Cache is disabled.
* @retval None
*/
#define FLASH_INSTRUCTION_CACHE_RESET() do { \
SET_BIT(FLASH->ACR, FLASH_ACR_ICRST); \
CLEAR_BIT(FLASH->ACR, FLASH_ACR_ICRST); \
} while (0)
/**
* @brief Reset the FLASH data Cache.
* @note This function must be used only when the data Cache is disabled.
* @retval None
*/
#define FLASH_DATA_CACHE_RESET() do { \
SET_BIT(FLASH->ACR, FLASH_ACR_DCRST); \
CLEAR_BIT(FLASH->ACR, FLASH_ACR_DCRST); \
} while (0)
/**
* @brief Enable the FLASH power down during Low-power run mode.
* @note Writing this bit to 1, automatically the keys are
* lost and a new unlock sequence is necessary to re-write it to 0.
*/
#define FLASH_POWER_DOWN_ENABLE() do { \
WRITE_REG(FLASH->PDKEYR, FLASH_PDKEY1); \
WRITE_REG(FLASH->PDKEYR, FLASH_PDKEY2); \
SET_BIT(FLASH->ACR, FLASH_ACR_RUN_PD); \
} while (0)
/**
* @brief Disable the FLASH power down during Low-power run mode.
* @note Writing this bit to 0, automatically the keys are
* lost and a new unlock sequence is necessary to re-write it to 1.
*/
#define FLASH_POWER_DOWN_DISABLE() do { \
WRITE_REG(FLASH->PDKEYR, FLASH_PDKEY1); \
WRITE_REG(FLASH->PDKEYR, FLASH_PDKEY2); \
CLEAR_BIT(FLASH->ACR, FLASH_ACR_RUN_PD); \
} while (0)
/**
* @brief Enable the FLASH power down during Low-Power sleep mode
* @retval none
*/
#define FLASH_SLEEP_POWERDOWN_ENABLE() SET_BIT(FLASH->ACR, FLASH_ACR_SLEEP_PD)
/**
* @brief Disable the FLASH power down during Low-Power sleep mode
* @retval none
*/
#define FLASH_SLEEP_POWERDOWN_DISABLE() CLEAR_BIT(FLASH->ACR, FLASH_ACR_SLEEP_PD)
/**
* @brief Enable the specified FLASH interrupt.
* @param __INTERRUPT__ FLASH interrupt
* This parameter can be any combination of the following values:
* @arg FLASH_IT_EOP: End of FLASH Operation Interrupt
* @arg FLASH_IT_OPERR: Error Interrupt
* @arg FLASH_IT_RDERR: PCROP Read Error Interrupt
* @arg FLASH_IT_ECCC: ECC Correction Interrupt
* @retval none
*/
#define FLASH_ENABLE_IT(__INTERRUPT__) do { \
if (((__INTERRUPT__) & FLASH_IT_ECCC) != 0U) \
{ \
SET_BIT(FLASH->ECCR, FLASH_ECCR_ECCIE); \
} \
if (((__INTERRUPT__) & (~FLASH_IT_ECCC)) != 0U) \
{ \
SET_BIT(FLASH->CR, ((__INTERRUPT__) & (~FLASH_IT_ECCC))); \
} \
} while (0)
/**
* @brief Disable the specified FLASH interrupt.
* @param __INTERRUPT__ FLASH interrupt
* This parameter can be any combination of the following values:
* @arg FLASH_IT_EOP: End of FLASH Operation Interrupt
* @arg FLASH_IT_OPERR: Error Interrupt
* @arg FLASH_IT_RDERR: PCROP Read Error Interrupt
* @arg FLASH_IT_ECCC: ECC Correction Interrupt
* @retval none
*/
#define FLASH_DISABLE_IT(__INTERRUPT__) do { \
if (((__INTERRUPT__) & FLASH_IT_ECCC) != 0U) \
{ \
CLEAR_BIT(FLASH->ECCR, FLASH_ECCR_ECCIE); \
} \
if (((__INTERRUPT__) & (~FLASH_IT_ECCC)) != 0U) \
{ \
CLEAR_BIT(FLASH->CR, ((__INTERRUPT__) & (~FLASH_IT_ECCC))); \
} \
} while (0)
/**
* @brief Check whether the specified FLASH flag is set or not.
* @param __FLAG__ specifies the FLASH flag to check.
* This parameter can be one of the following values:
* @arg FLASH_FLAG_EOP: FLASH End of Operation flag
* @arg FLASH_FLAG_OPERR: FLASH Operation error flag
* @arg FLASH_FLAG_PROGERR: FLASH Programming error flag
* @arg FLASH_FLAG_WRPERR: FLASH Write protection error flag
* @arg FLASH_FLAG_PGAERR: FLASH Programming alignment error flag
* @arg FLASH_FLAG_SIZERR: FLASH Size error flag
* @arg FLASH_FLAG_PGSERR: FLASH Programming sequence error flag
* @arg FLASH_FLAG_MISERR: FLASH Fast programming data miss error flag
* @arg FLASH_FLAG_FASTERR: FLASH Fast programming error flag
* @arg FLASH_FLAG_RDERR: FLASH PCROP read error flag
* @arg FLASH_FLAG_OPTVERR: FLASH Option validity error flag
* @arg FLASH_FLAG_BSY: FLASH write/erase operations in progress flag
* @arg FLASH_FLAG_ECCC: FLASH one ECC error has been detected and corrected in 64 LSB bits
* @arg FLASH_FLAG_ECCD: FLASH two ECC errors have been detected in 64 LSB bits
* @arg FLASH_FLAG_ECCC2(*): FLASH one ECC error has been detected and corrected in 64 MSB bits (mode 128 bits only)
* @arg FLASH_FLAG_ECCD2(*): FLASH two ECC errors have been detected in 64 MSB bits (mode 128 bits only)
* @note (*) availability depends on devices
* @retval The new state of FLASH_FLAG (SET or RESET).
*/
#define FLASH_GET_FLAG(__FLAG__) ((((__FLAG__) & FLASH_FLAG_ECCR_ERRORS) != 0U) ? \
(READ_BIT(FLASH->ECCR, (__FLAG__)) == (__FLAG__)) : \
(READ_BIT(FLASH->SR, (__FLAG__)) == (__FLAG__)))
/**
* @brief Clear the FLASH's pending flags.
* @param __FLAG__ specifies the FLASH flags to clear.
* This parameter can be any combination of the following values:
* @arg FLASH_FLAG_EOP: FLASH End of Operation flag
* @arg FLASH_FLAG_OPERR: FLASH Operation error flag
* @arg FLASH_FLAG_PROGERR: FLASH Programming error flag
* @arg FLASH_FLAG_WRPERR: FLASH Write protection error flag
* @arg FLASH_FLAG_PGAERR: FLASH Programming alignment error flag
* @arg FLASH_FLAG_SIZERR: FLASH Size error flag
* @arg FLASH_FLAG_PGSERR: FLASH Programming sequence error flag
* @arg FLASH_FLAG_MISERR: FLASH Fast programming data miss error flag
* @arg FLASH_FLAG_FASTERR: FLASH Fast programming error flag
* @arg FLASH_FLAG_RDERR: FLASH PCROP read error flag
* @arg FLASH_FLAG_OPTVERR: FLASH Option validity error flag
* @arg FLASH_FLAG_ECCC: FLASH one ECC error has been detected and corrected in 64 LSB bits
* @arg FLASH_FLAG_ECCD: FLASH two ECC errors have been detected in 64 LSB bits
* @arg FLASH_FLAG_ECCC2(*): FLASH one ECC error has been detected and corrected in 64 MSB bits (mode 128 bits only)
* @arg FLASH_FLAG_ECCD2(*): FLASH two ECC errors have been detected in 64 MSB bits (mode 128 bits only)
* @arg FLASH_FLAG_SR_ERRORS: FLASH All SR errors flags
* @arg FLASH_FLAG_ECCR_ERRORS: FLASH All ECCR errors flags
* @note (*) availability depends on devices
* @retval None
*/
#define FLASH_CLEAR_FLAG(__FLAG__) do { \
if (((__FLAG__) & FLASH_FLAG_ECCR_ERRORS) != 0U) \
{ \
SET_BIT(FLASH->ECCR, ((__FLAG__) & FLASH_FLAG_ECCR_ERRORS)); \
} \
if (((__FLAG__) & ~(FLASH_FLAG_ECCR_ERRORS)) != 0U) \
{ \
WRITE_REG(FLASH->SR, ((__FLAG__) & ~(FLASH_FLAG_ECCR_ERRORS))); \
} \
} while (0)
#define FLASH_LOCK(__HANDLE__) do { \
if((__HANDLE__)->Lock == LOCKED) \
{ \
return FLASH_BUSY; \
} \
else \
{ \
(__HANDLE__)->Lock = LOCKED; \
} \
} while (0)
#define FLASH_UNLOCK(__HANDLE__) do{ \
(__HANDLE__)->Lock = UNLOCKED; \
} while (0)
/**
* @brief __RAM_FUNC definition
*/
#if defined (__CC_ARM) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
/* ARM Compiler V4/V5 and V6
--------------------------
RAM functions are defined using the toolchain options.
Functions that are executed in RAM should reside in a separate source module.
Using the 'Options for File' dialog you can simply change the 'Code / Const'
area of a module to a memory space in physical RAM.
Available memory areas are declared in the 'Target' tab of the 'Options for Target'
dialog.
*/
#define __RAM_FUNC
#elif defined ( __ICCARM__ )
/* ICCARM Compiler
---------------
RAM functions are defined using a specific toolchain keyword "__ramfunc".
*/
#define __RAM_FUNC __ramfunc
#elif defined ( __GNUC__ )
/* GNU Compiler
------------
RAM functions are defined using a specific toolchain attribute
"__attribute__((section(".RamFunc")))".
*/
#define __RAM_FUNC __attribute__((section(".RamFunc")))
#endif /* __CC_ARM */
/* Exported variables --------------------------------------------------------*/
extern FLASH_ProcessTypeDef MCU_FLASH;
/* Exported functions prototypes ---------------------------------------------*/
FLASH_StatusTypeDef FLASH_Unlock(void);
FLASH_StatusTypeDef FLASH_Lock(void);
FLASH_StatusTypeDef FLASH_OB_Unlock(void);
FLASH_StatusTypeDef FLASH_OB_Lock(void);
FLASH_StatusTypeDef FLASH_OB_Launch(void);
FLASH_StatusTypeDef FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data);
FLASH_StatusTypeDef FLASH_Program_IT(uint32_t TypeProgram, uint32_t Address, uint64_t Data);
void FLASH_IRQHandler(void);
void FLASH_EndOfOperationCallback(uint32_t ReturnValue);
void FLASH_OperationErrorCallback(uint32_t ReturnValue);
FLASH_StatusTypeDef FLASH_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError);
FLASH_StatusTypeDef FLASH_OBProgram(FLASH_OBProgramInitTypeDef *pOBInit);
void FLASH_OBGetConfig(FLASH_OBProgramInitTypeDef *pOBInit);
__RAM_FUNC FLASH_StatusTypeDef FLASH_EnableRunPowerDown(void);
__RAM_FUNC FLASH_StatusTypeDef FLASH_DisableRunPowerDown(void);
#if defined (FLASH_OPTR_DBANK)
__RAM_FUNC FLASH_StatusTypeDef FLASH_OB_DBankConfig(uint32_t DBankConfig);
#endif
FLASH_StatusTypeDef FLASH_EnableSecMemProtection(uint32_t Bank);
void FLASH_EnableDebugger(void);
void FLASH_DisableDebugger(void);
uint32_t FLASH_GetError(void);
#ifdef __cplusplus
}
#endif
#endif /* FLASH_H__ */
/**
******************************************************************************
* @file flash.c
* @author Amos
* @brief MCU flash program body.
******************************************************************************
* @attention
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "flash.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
/* External variables declaration --------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define FLASH_SIZE_DATA_REGISTER FLASHSIZE_BASE
#if defined (FLASH_OPTR_DBANK)
#define FLASH_SIZE ((((*((uint16_t *)FLASH_SIZE_DATA_REGISTER)) == 0xFFFFU)) ? (0x200UL << 10U) : \
(((*((uint32_t *)FLASH_SIZE_DATA_REGISTER)) & 0xFFFFUL) << 10U))
#define FLASH_BANK_SIZE (FLASH_SIZE >> 1)
#define FLASH_PAGE_NB 128U
#define FLASH_PAGE_SIZE_128_BITS 0x1000U /* 4 KB */
#else
#define FLASH_SIZE ((((*((uint16_t *)FLASH_SIZE_DATA_REGISTER)) == 0xFFFFU)) ? (0x80UL << 10U) : \
(((*((uint32_t *)FLASH_SIZE_DATA_REGISTER)) & 0xFFFFUL) << 10U))
#define FLASH_BANK_SIZE (FLASH_SIZE)
#define FLASH_PAGE_NB ((FLASH_SIZE == 0x00080000U) ? 256U : \
((FLASH_SIZE == 0x00040000U) ? 128U : 64U))
#endif
#define FLASH_PAGE_SIZE 0x800U /* 2 KB */
#define FLASH_TIMEOUT_VALUE 1000U /* 1 s */
#define FLASH_NB_DOUBLE_WORDS_IN_ROW 32U
/* Private typedef -----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
FLASH_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout);
static FLASH_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout);
static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data);
static void FLASH_Program_Fast(uint32_t Address, uint32_t DataAddress);
static void FLASH_MassErase(uint32_t Banks);
static void FLASH_PageErase(uint32_t Page, uint32_t Banks);
static void FLASH_FlushCaches(void);
static FLASH_StatusTypeDef FLASH_OB_WRPConfig(uint32_t WRPArea, uint32_t WRPStartOffset, uint32_t WRDPEndOffset);
static FLASH_StatusTypeDef FLASH_OB_RDPConfig(uint32_t RDPLevel);
static FLASH_StatusTypeDef FLASH_OB_UserConfig(uint32_t UserType, uint32_t UserConfig);
static FLASH_StatusTypeDef FLASH_OB_PCROPConfig(uint32_t PCROPConfig, uint32_t PCROPStartAddr, uint32_t PCROPEndAddr);
static void FLASH_OB_GetWRP(uint32_t WRPArea, uint32_t *WRPStartOffset, uint32_t *WRDPEndOffset);
static uint32_t FLASH_OB_GetRDP(void);
static uint32_t FLASH_OB_GetUser(void);
static void FLASH_OB_GetPCROP(uint32_t *PCROPConfig, uint32_t *PCROPStartAddr, uint32_t *PCROPEndAddr);
static FLASH_StatusTypeDef FLASH_OB_SecMemConfig(uint32_t SecMemBank, uint32_t SecMemSize);
static void FLASH_OB_GetSecMem(uint32_t SecMemBank, uint32_t *SecMemSize);
static FLASH_StatusTypeDef FLASH_OB_BootLockConfig(uint32_t BootLockConfig);
static uint32_t FLASH_OB_GetBootLock(void);
/* Private macro -------------------------------------------------------------*/
#define IS_FLASH_TYPEERASE(VALUE) (((VALUE) == FLASH_TYPEERASE_PAGES) || \
((VALUE) == FLASH_TYPEERASE_MASSERASE))
#if defined (FLASH_OPTR_DBANK)
#define IS_FLASH_BANK(BANK) (((BANK) == FLASH_BANK_1) || \
((BANK) == FLASH_BANK_2) || \
((BANK) == FLASH_BANK_BOTH))
#define IS_FLASH_BANK_EXCLUSIVE(BANK) (((BANK) == FLASH_BANK_1) || ((BANK) == FLASH_BANK_2))
#else
#define IS_FLASH_BANK(BANK) ((BANK) == FLASH_BANK_1)
#define IS_FLASH_BANK_EXCLUSIVE(BANK) ((BANK) == FLASH_BANK_1)
#endif
#define IS_FLASH_TYPEPROGRAM(VALUE) (((VALUE) == FLASH_TYPEPROGRAM_DOUBLEWORD) || \
((VALUE) == FLASH_TYPEPROGRAM_FAST) || \
((VALUE) == FLASH_TYPEPROGRAM_FAST_AND_LAST))
#define IS_FLASH_MAIN_MEM_ADDRESS(ADDRESS) (((ADDRESS) >= FLASH_BASE) && ((ADDRESS) < (FLASH_BASE+FLASH_SIZE)))
#define IS_FLASH_OTP_ADDRESS(ADDRESS) (((ADDRESS) >= 0x1FFF7000U) && ((ADDRESS) <= 0x1FFF73FFU))
#define IS_FLASH_PROGRAM_ADDRESS(ADDRESS) (IS_FLASH_MAIN_MEM_ADDRESS(ADDRESS) || IS_FLASH_OTP_ADDRESS(ADDRESS))
#define IS_FLASH_PAGE(PAGE) ((PAGE) < FLASH_PAGE_NB)
#define IS_OPTIONBYTE(VALUE) (((VALUE) <= (OPTIONBYTE_WRP | OPTIONBYTE_RDP | OPTIONBYTE_USER | \
OPTIONBYTE_PCROP | OPTIONBYTE_BOOT_LOCK | OPTIONBYTE_SEC)))
#if defined (FLASH_OPTR_DBANK)
#define IS_OB_WRPAREA(VALUE) (((VALUE) == OB_WRPAREA_BANK1_AREAA) || ((VALUE) == OB_WRPAREA_BANK1_AREAB) || \
((VALUE) == OB_WRPAREA_BANK2_AREAA) || ((VALUE) == OB_WRPAREA_BANK2_AREAB))
#else
#define IS_OB_WRPAREA(VALUE) (((VALUE) == OB_WRPAREA_BANK1_AREAA) || ((VALUE) == OB_WRPAREA_BANK1_AREAB))
#endif
#define IS_OB_BOOT_LOCK(VALUE) (((VALUE) == OB_BOOT_LOCK_ENABLE) || ((VALUE) == OB_BOOT_LOCK_DISABLE))
#define IS_OB_RDP_LEVEL(LEVEL) (((LEVEL) == OB_RDP_LEVEL_0) || ((LEVEL) == OB_RDP_LEVEL_1) || \
((LEVEL) == OB_RDP_LEVEL_2))
#define IS_OB_USER_TYPE(TYPE) (((TYPE) <= 0x1FFFFU) && ((TYPE) != 0U))
#define IS_OB_USER_BOR_LEVEL(LEVEL) (((LEVEL) == OB_BOR_LEVEL_0) || ((LEVEL) == OB_BOR_LEVEL_1) || \
((LEVEL) == OB_BOR_LEVEL_2) || ((LEVEL) == OB_BOR_LEVEL_3) || \
((LEVEL) == OB_BOR_LEVEL_4))
#define IS_OB_USER_STOP(VALUE) (((VALUE) == OB_STOP_RST) || ((VALUE) == OB_STOP_NORST))
#define IS_OB_USER_STANDBY(VALUE) (((VALUE) == OB_STANDBY_RST) || ((VALUE) == OB_STANDBY_NORST))
#define IS_OB_USER_SHUTDOWN(VALUE) (((VALUE) == OB_SHUTDOWN_RST) || ((VALUE) == OB_SHUTDOWN_NORST))
#define IS_OB_USER_IWDG(VALUE) (((VALUE) == OB_IWDG_HW) || ((VALUE) == OB_IWDG_SW))
#define IS_OB_USER_IWDG_STOP(VALUE) (((VALUE) == OB_IWDG_STOP_FREEZE) || ((VALUE) == OB_IWDG_STOP_RUN))
#define IS_OB_USER_IWDG_STDBY(VALUE) (((VALUE) == OB_IWDG_STDBY_FREEZE) || ((VALUE) == OB_IWDG_STDBY_RUN))
#define IS_OB_USER_WWDG(VALUE) (((VALUE) == OB_WWDG_HW) || ((VALUE) == OB_WWDG_SW))
#if defined (FLASH_OPTR_DBANK)
#define IS_OB_USER_BFB2(VALUE) (((VALUE) == OB_BFB2_DISABLE) || ((VALUE) == OB_BFB2_ENABLE))
#define IS_OB_USER_DBANK(VALUE) (((VALUE) == OB_DBANK_128_BITS) || ((VALUE) == OB_DBANK_64_BITS))
#endif
#if defined (FLASH_OPTR_PB4_PUPEN)
#define IS_OB_USER_PB4_PUPEN(VALUE) (((VALUE) == OB_PB4_PUPEN_DISABLE) || ((VALUE) == OB_PB4_PUPEN_ENABLE))
#endif
#define IS_OB_USER_BOOT1(VALUE) (((VALUE) == OB_BOOT1_SRAM) || ((VALUE) == OB_BOOT1_SYSTEM))
#define IS_OB_USER_SRAM_PARITY(VALUE) (((VALUE) == OB_SRAM_PARITY_ENABLE) || ((VALUE) == OB_SRAM_PARITY_DISABLE))
#define IS_OB_USER_CCMSRAM_RST(VALUE) (((VALUE) == OB_CCMSRAM_RST_ERASE) || ((VALUE) == OB_CCMSRAM_RST_NOT_ERASE))
#define IS_OB_USER_SWBOOT0(VALUE) (((VALUE) == OB_BOOT0_FROM_OB) || ((VALUE) == OB_BOOT0_FROM_PIN))
#define IS_OB_USER_BOOT0(VALUE) (((VALUE) == OB_nBOOT0_RESET) || ((VALUE) == OB_nBOOT0_SET))
#define IS_OB_USER_NRST_MODE(VALUE) (((VALUE) == OB_NRST_MODE_GPIO) || ((VALUE) == OB_NRST_MODE_INPUT_ONLY) || \
((VALUE) == OB_NRST_MODE_INPUT_OUTPUT))
#define IS_OB_USER_IRHEN(VALUE) (((VALUE) == OB_IRH_ENABLE) || ((VALUE) == OB_IRH_DISABLE))
#define IS_OB_PCROP_RDP(VALUE) (((VALUE) == OB_PCROP_RDP_NOT_ERASE) || ((VALUE) == OB_PCROP_RDP_ERASE))
#define IS_OB_SECMEM_SIZE(VALUE) ((VALUE) <= FLASH_PAGE_NB)
#define IS_FLASH_LATENCY(LATENCY) (((LATENCY) == FLASH_LATENCY_0) || ((LATENCY) == FLASH_LATENCY_1) || \
((LATENCY) == FLASH_LATENCY_2) || ((LATENCY) == FLASH_LATENCY_3) || \
((LATENCY) == FLASH_LATENCY_4) || ((LATENCY) == FLASH_LATENCY_5) || \
((LATENCY) == FLASH_LATENCY_6) || ((LATENCY) == FLASH_LATENCY_7) || \
((LATENCY) == FLASH_LATENCY_8) || ((LATENCY) == FLASH_LATENCY_9) || \
((LATENCY) == FLASH_LATENCY_10) || ((LATENCY) == FLASH_LATENCY_11) || \
((LATENCY) == FLASH_LATENCY_12) || ((LATENCY) == FLASH_LATENCY_13) || \
((LATENCY) == FLASH_LATENCY_14) || ((LATENCY) == FLASH_LATENCY_15))
/* Exported variables --------------------------------------------------------*/
/**
* @brief Variable used for Program/Erase sectors under interruption
*/
FLASH_ProcessTypeDef MCU_FLASH =
{
.Lock = UNLOCKED,
.ErrorCode = FLASH_ERROR_NONE,
.ProcedureOnGoing = FLASH_PROC_NONE,
.Address = 0U,
.Bank = FLASH_BANK_1,
.Page = 0U,
.NbPagesToErase = 0U,
.CacheToReactivate = FLASH_CACHE_DISABLED
};
/* Exported functions --------------------------------------------------------*/
/**
* @brief Unlock the FLASH control register access.
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_Unlock(void)
{
FLASH_StatusTypeDef status = FLASH_OK;
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0U)
{
/* Authorize the FLASH Registers access */
WRITE_REG(FLASH->KEYR, FLASH_KEY1);
WRITE_REG(FLASH->KEYR, FLASH_KEY2);
/* verify Flash is unlocked */
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0U)
{
status = FLASH_ERROR;
}
}
return status;
}
/**
* @brief Lock the FLASH control register access.
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_Lock(void)
{
FLASH_StatusTypeDef status = FLASH_ERROR;
/* Set the LOCK Bit to lock the FLASH Registers access */
SET_BIT(FLASH->CR, FLASH_CR_LOCK);
/* verify Flash is locked */
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0U)
{
status = FLASH_OK;
}
return status;
}
/**
* @brief Unlock the FLASH Option Bytes Registers access.
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_OB_Unlock(void)
{
FLASH_StatusTypeDef status = FLASH_OK;
if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0U)
{
/* Authorizes the Option Byte register programming */
WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1);
WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2);
/* verify option bytes are unlocked */
if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0U)
{
status = FLASH_ERROR;
}
}
return status;
}
/**
* @brief Lock the FLASH Option Bytes Registers access.
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_OB_Lock(void)
{
FLASH_StatusTypeDef status = FLASH_ERROR;
/* Set the OPTLOCK Bit to lock the FLASH Option Byte Registers access */
SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK);
/* Verify option bytes are locked */
if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0U)
{
status = FLASH_OK;
}
return status;
}
/**
* @brief Launch the option byte loading.
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_OB_Launch(void)
{
/* Set the bit to force the option byte reloading */
SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);
/* Wait for last operation to be completed */
return (FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE));
}
/**
* @brief Program double word or fast program of a row at a specified address.
* @param TypeProgram Indicate the way to program at a specified address.
* This parameter can be a value of @ref FLASH_Type_Program.
* @param Address specifies the address to be programmed.
* @param Data specifies the data to be programmed.
* This parameter is the data for the double word program and the address where
* are stored the data for the row fast program.
*
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
FLASH_StatusTypeDef status;
uint32_t prog_bit = 0;
/* Check the parameters */
assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
/* Process Locked */
FLASH_LOCK(&MCU_FLASH);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == FLASH_OK)
{
MCU_FLASH.ErrorCode = FLASH_ERROR_NONE;
if (TypeProgram == FLASH_TYPEPROGRAM_DOUBLEWORD)
{
/* Program double-word (64-bit) at a specified address */
FLASH_Program_DoubleWord(Address, Data);
prog_bit = FLASH_CR_PG;
}
else if ((TypeProgram == FLASH_TYPEPROGRAM_FAST) || (TypeProgram == FLASH_TYPEPROGRAM_FAST_AND_LAST))
{
/* Fast program a 32 row double-word (64-bit) at a specified address */
FLASH_Program_Fast(Address, (uint32_t)Data);
/* If it is the last row, the bit will be cleared at the end of the operation */
if (TypeProgram == FLASH_TYPEPROGRAM_FAST_AND_LAST)
{
prog_bit = FLASH_CR_FSTPG;
}
}
else
{
/* Nothing to do */
}
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the program operation is completed, disable the PG or FSTPG Bit */
if (prog_bit != 0U)
{
CLEAR_BIT(FLASH->CR, prog_bit);
}
}
/* Process Unlocked */
FLASH_UNLOCK(&MCU_FLASH);
/* return status */
return status;
}
/**
* @brief Program double word or fast program of a row at a specified address with interrupt enabled.
* @param TypeProgram Indicate the way to program at a specified address.
* This parameter can be a value of @ref FLASH_Type_Program.
* @param Address specifies the address to be programmed.
* @param Data specifies the data to be programmed.
* This parameter is the data for the double word program and the address where
* are stored the data for the row fast program.
*
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_Program_IT(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
FLASH_StatusTypeDef status;
/* Check the parameters */
assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
/* Process Locked */
FLASH_LOCK(&MCU_FLASH);
/* Reset error code */
MCU_FLASH.ErrorCode = FLASH_ERROR_NONE;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if (status != FLASH_OK)
{
/* Process Unlocked */
FLASH_UNLOCK(&MCU_FLASH);
}
else
{
/* Set internal variables used by the IRQ handler */
if (TypeProgram == FLASH_TYPEPROGRAM_FAST_AND_LAST)
{
MCU_FLASH.ProcedureOnGoing = FLASH_PROC_PROGRAM_LAST;
}
else
{
MCU_FLASH.ProcedureOnGoing = FLASH_PROC_PROGRAM;
}
MCU_FLASH.Address = Address;
/* Enable End of Operation and Error interrupts */
FLASH_ENABLE_IT(FLASH_IT_EOP | FLASH_IT_OPERR);
if (TypeProgram == FLASH_TYPEPROGRAM_DOUBLEWORD)
{
/* Program double-word (64-bit) at a specified address */
FLASH_Program_DoubleWord(Address, Data);
}
else if ((TypeProgram == FLASH_TYPEPROGRAM_FAST) || (TypeProgram == FLASH_TYPEPROGRAM_FAST_AND_LAST))
{
/* Fast program a 32 row double-word (64-bit) at a specified address */
FLASH_Program_Fast(Address, (uint32_t)Data);
}
else
{
/* Nothing to do */
}
}
return status;
}
/**
* @brief Handle FLASH interrupt request.
* @retval None
*/
void FLASH_IRQHandler(void)
{
uint32_t tmp_page;
uint32_t error;
FLASH_ProcedureTypeDef procedure;
/* If the operation is completed, disable the PG, PNB, MER1, MER2 and PER Bit */
CLEAR_BIT(FLASH->CR, (FLASH_CR_PG | FLASH_CR_MER1 | FLASH_CR_PER | FLASH_CR_PNB));
#if defined (FLASH_OPTR_DBANK)
CLEAR_BIT(FLASH->CR, FLASH_CR_MER2);
#endif
/* Disable the FSTPG Bit only if it is the last row programmed */
if (MCU_FLASH.ProcedureOnGoing == FLASH_PROC_PROGRAM_LAST)
{
CLEAR_BIT(FLASH->CR, FLASH_CR_FSTPG);
}
/* Check FLASH operation error flags */
error = (FLASH->SR & FLASH_FLAG_SR_ERRORS);
if (error != 0U)
{
/* Save the error code */
MCU_FLASH.ErrorCode |= error;
/* Clear error programming flags */
FLASH_CLEAR_FLAG(error);
/* Flush the caches to be sure of the data consistency */
FLASH_FlushCaches() ;
/* FLASH error interrupt user callback */
procedure = MCU_FLASH.ProcedureOnGoing;
if (procedure == FLASH_PROC_PAGE_ERASE)
{
FLASH_OperationErrorCallback(MCU_FLASH.Page);
}
else if (procedure == FLASH_PROC_MASS_ERASE)
{
FLASH_OperationErrorCallback(MCU_FLASH.Bank);
}
else if ((procedure == FLASH_PROC_PROGRAM) ||
(procedure == FLASH_PROC_PROGRAM_LAST))
{
FLASH_OperationErrorCallback(MCU_FLASH.Address);
}
else
{
/* Nothing to do */
}
/*Stop the procedure ongoing*/
MCU_FLASH.ProcedureOnGoing = FLASH_PROC_NONE;
}
/* Check FLASH End of Operation flag */
if (FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
if (MCU_FLASH.ProcedureOnGoing == FLASH_PROC_PAGE_ERASE)
{
/* Nb of pages to erased can be decreased */
MCU_FLASH.NbPagesToErase--;
/* Check if there are still pages to erase*/
if (MCU_FLASH.NbPagesToErase != 0U)
{
/* Indicate user which page has been erased*/
FLASH_EndOfOperationCallback(MCU_FLASH.Page);
/* Increment page number */
MCU_FLASH.Page++;
tmp_page = MCU_FLASH.Page;
FLASH_PageErase(tmp_page, MCU_FLASH.Bank);
}
else
{
/* No more pages to Erase */
/* Reset Address and stop Erase pages procedure */
MCU_FLASH.Page = 0xFFFFFFFFU;
MCU_FLASH.ProcedureOnGoing = FLASH_PROC_NONE;
/* Flush the caches to be sure of the data consistency */
FLASH_FlushCaches() ;
/* FLASH EOP interrupt user callback */
FLASH_EndOfOperationCallback(MCU_FLASH.Page);
}
}
else
{
/* Flush the caches to be sure of the data consistency */
FLASH_FlushCaches() ;
procedure = MCU_FLASH.ProcedureOnGoing;
if (procedure == FLASH_PROC_MASS_ERASE)
{
/* MassErase ended. Return the selected bank */
/* FLASH EOP interrupt user callback */
FLASH_EndOfOperationCallback(MCU_FLASH.Bank);
}
else if ((procedure == FLASH_PROC_PROGRAM) ||
(procedure == FLASH_PROC_PROGRAM_LAST))
{
/* Program ended. Return the selected address */
/* FLASH EOP interrupt user callback */
FLASH_EndOfOperationCallback(MCU_FLASH.Address);
}
else
{
/* Nothing to do */
}
/*Clear the procedure ongoing*/
MCU_FLASH.ProcedureOnGoing = FLASH_PROC_NONE;
}
}
if (MCU_FLASH.ProcedureOnGoing == FLASH_PROC_NONE)
{
/* Disable End of Operation and Error interrupts */
FLASH_DISABLE_IT(FLASH_IT_EOP | FLASH_IT_OPERR);
/* Process Unlocked */
FLASH_UNLOCK(&MCU_FLASH);
}
}
/**
* @brief FLASH end of operation interrupt callback.
* @param ReturnValue The value saved in this parameter depends on the ongoing procedure:
* @arg Mass Erase: Bank number which has been requested to erase
* @arg Page Erase: Page which has been erased
* (if 0xFFFFFFFF, it means that all the selected pages have been erased)
* @arg Program: Address which was selected for data program
* @retval None
*/
__weak void FLASH_EndOfOperationCallback(uint32_t ReturnValue)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(ReturnValue);
/* NOTE : This function should not be modified, when the callback is needed,
the FLASH_EndOfOperationCallback could be implemented in the user file
*/
}
/**
* @brief FLASH operation error interrupt callback.
* @param ReturnValue The value saved in this parameter depends on the ongoing procedure:
* @arg Mass Erase: Bank number which has been requested to erase
* @arg Page Erase: Page number which returned an error
* @arg Program: Address which was selected for data program
* @retval None
*/
__weak void FLASH_OperationErrorCallback(uint32_t ReturnValue)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(ReturnValue);
/* NOTE : This function should not be modified, when the callback is needed,
the FLASH_OperationErrorCallback could be implemented in the user file
*/
}
/**
* @brief Perform a mass erase or erase the specified FLASH memory pages.
* @param[in] pEraseInit pointer to an FLASH_EraseInitTypeDef structure that
* contains the configuration information for the erasing.
* @param[out] PageError pointer to variable that contains the configuration
* information on faulty page in case of error (0xFFFFFFFF means that all
* the pages have been correctly erased).
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError)
{
FLASH_StatusTypeDef status;
uint32_t page_index;
/* Check the parameters */
assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
/* Process Locked */
FLASH_LOCK(&MCU_FLASH);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == FLASH_OK)
{
MCU_FLASH.ErrorCode = FLASH_ERROR_NONE;
/* Deactivate the cache if they are activated to avoid data misbehavior */
if (READ_BIT(FLASH->ACR, FLASH_ACR_ICEN) != 0U)
{
if (READ_BIT(FLASH->ACR, FLASH_ACR_DCEN) != 0U)
{
/* Disable data cache */
FLASH_DATA_CACHE_DISABLE();
MCU_FLASH.CacheToReactivate = FLASH_CACHE_ICACHE_DCACHE_ENABLED;
}
else
{
MCU_FLASH.CacheToReactivate = FLASH_CACHE_ICACHE_ENABLED;
}
}
else if (READ_BIT(FLASH->ACR, FLASH_ACR_DCEN) != 0U)
{
/* Disable data cache */
FLASH_DATA_CACHE_DISABLE();
MCU_FLASH.CacheToReactivate = FLASH_CACHE_DCACHE_ENABLED;
}
else
{
MCU_FLASH.CacheToReactivate = FLASH_CACHE_DISABLED;
}
if (pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
{
/* Mass erase to be done */
FLASH_MassErase(pEraseInit->Banks);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
#if defined (FLASH_OPTR_DBANK)
/* If the erase operation is completed, disable the MER1 and MER2 Bits */
CLEAR_BIT(FLASH->CR, (FLASH_CR_MER1 | FLASH_CR_MER2));
#else
/* If the erase operation is completed, disable the MER1 Bit */
CLEAR_BIT(FLASH->CR, (FLASH_CR_MER1));
#endif
}
else
{
/*Initialization of PageError variable*/
*PageError = 0xFFFFFFFFU;
for (page_index = pEraseInit->Page; page_index < (pEraseInit->Page + pEraseInit->NbPages); page_index++)
{
FLASH_PageErase(page_index, pEraseInit->Banks);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the PER Bit */
CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB));
if (status != FLASH_OK)
{
/* In case of error, stop erase procedure and return the faulty page */
*PageError = page_index;
break;
}
}
}
/* Flush the caches to be sure of the data consistency */
FLASH_FlushCaches();
}
/* Process Unlocked */
FLASH_UNLOCK(&MCU_FLASH);
return status;
}
/**
* @brief Program Option bytes.
* @param pOBInit pointer to an FLASH_OBInitStruct structure that
* contains the configuration information for the programming.
* @note To configure any option bytes, the option lock bit OPTLOCK must be
* cleared with the call of FLASH_OB_Unlock() function.
* @note New option bytes configuration will be taken into account in two cases:
* - after an option bytes launch through the call of FLASH_OB_Launch()
* - after a power reset (BOR reset or exit from Standby/Shutdown modes)
* @retval FLASH_Status
*/
FLASH_StatusTypeDef FLASH_OBProgram(FLASH_OBProgramInitTypeDef *pOBInit)
{
FLASH_StatusTypeDef status = FLASH_OK;
/* Check the parameters */
assert_param(IS_OPTIONBYTE(pOBInit->OptionType));
/* Process Locked */
FLASH_LOCK(&MCU_FLASH);
MCU_FLASH.ErrorCode = FLASH_ERROR_NONE;
/* Write protection configuration */
if ((pOBInit->OptionType & OPTIONBYTE_WRP) != 0U)
{
/* Configure of Write protection on the selected area */
if (FLASH_OB_WRPConfig(pOBInit->WRPArea, pOBInit->WRPStartOffset, pOBInit->WRPEndOffset) != FLASH_OK)
{
status = FLASH_ERROR;
}
}
/* Read protection configuration */
if ((pOBInit->OptionType & OPTIONBYTE_RDP) != 0U)
{
/* Configure the Read protection level */
if (FLASH_OB_RDPConfig(pOBInit->RDPLevel) != FLASH_OK)
{
status = FLASH_ERROR;
}
}
/* User Configuration */
if ((pOBInit->OptionType & OPTIONBYTE_USER) != 0U)
{
/* Configure the user option bytes */
if (FLASH_OB_UserConfig(pOBInit->USERType, pOBInit->USERConfig) != FLASH_OK)
{
status = FLASH_ERROR;
}
}
/* PCROP Configuration */
if ((pOBInit->OptionType & OPTIONBYTE_PCROP) != 0U)
{
if (pOBInit->PCROPStartAddr != pOBInit->PCROPEndAddr)
{
/* Configure the Proprietary code readout protection */
if (FLASH_OB_PCROPConfig(pOBInit->PCROPConfig, pOBInit->PCROPStartAddr, pOBInit->PCROPEndAddr) != FLASH_OK)
{
status = FLASH_ERROR;
}
}
}
/* Securable memory Configuration */
if ((pOBInit->OptionType & OPTIONBYTE_SEC) != 0U)
{
/* Configure the securable memory area */
if (FLASH_OB_SecMemConfig(pOBInit->SecBank, pOBInit->SecSize) != FLASH_OK)
{
status = FLASH_ERROR;
}
}
/* Boot Entry Point Configuration */
if ((pOBInit->OptionType & OPTIONBYTE_BOOT_LOCK) != 0U)
{
/* Configure the boot unique entry point option */
if (FLASH_OB_BootLockConfig(pOBInit->BootEntryPoint) != FLASH_OK)
{
status = FLASH_ERROR;
}
}
/* Process Unlocked */
FLASH_UNLOCK(&MCU_FLASH);
return status;
}
/**
* @brief Get the Option bytes configuration.
* @param pOBInit pointer to an FLASH_OBInitStruct structure that contains the
* configuration information.
* @note The fields pOBInit->WRPArea and pOBInit->PCROPConfig should indicate
* which area is requested for the WRP and PCROP, else no information will be returned.
* @retval None
*/
void FLASH_OBGetConfig(FLASH_OBProgramInitTypeDef *pOBInit)
{
pOBInit->OptionType = (OPTIONBYTE_RDP | OPTIONBYTE_USER);
#if defined (FLASH_OPTR_DBANK)
if ((pOBInit->WRPArea == OB_WRPAREA_BANK1_AREAA) || (pOBInit->WRPArea == OB_WRPAREA_BANK1_AREAB) ||
(pOBInit->WRPArea == OB_WRPAREA_BANK2_AREAA) || (pOBInit->WRPArea == OB_WRPAREA_BANK2_AREAB))
#else
if ((pOBInit->WRPArea == OB_WRPAREA_BANK1_AREAA) || (pOBInit->WRPArea == OB_WRPAREA_BANK1_AREAB))
#endif
{
pOBInit->OptionType |= OPTIONBYTE_WRP;
/* Get write protection on the selected area */
FLASH_OB_GetWRP(pOBInit->WRPArea, &(pOBInit->WRPStartOffset), &(pOBInit->WRPEndOffset));
}
/* Get Read protection level */
pOBInit->RDPLevel = FLASH_OB_GetRDP();
/* Get the user option bytes */
pOBInit->USERConfig = FLASH_OB_GetUser();
#if defined (FLASH_OPTR_DBANK)
if ((pOBInit->PCROPConfig == FLASH_BANK_1) || (pOBInit->PCROPConfig == FLASH_BANK_2))
#else
if (pOBInit->PCROPConfig == FLASH_BANK_1)
#endif
{
pOBInit->OptionType |= OPTIONBYTE_PCROP;
/* Get the Proprietary code readout protection */
FLASH_OB_GetPCROP(&(pOBInit->PCROPConfig), &(pOBInit->PCROPStartAddr), &(pOBInit->PCROPEndAddr));
}
pOBInit->OptionType |= OPTIONBYTE_BOOT_LOCK;
/* Get the boot entry point */
pOBInit->BootEntryPoint = FLASH_OB_GetBootLock();
/* Get the securable memory area configuration */
#if defined (FLASH_OPTR_DBANK)
if ((pOBInit->SecBank == FLASH_BANK_1) || (pOBInit->SecBank == FLASH_BANK_2))
#else
if (pOBInit->SecBank == FLASH_BANK_1)
#endif
{
pOBInit->OptionType |= OPTIONBYTE_SEC;
FLASH_OB_GetSecMem(pOBInit->SecBank, &(pOBInit->SecSize));
}
}
/**
* @brief Enable the Power down in Run Mode
* @note This function should be called and executed from SRAM memory.
* @retval None
*/
__RAM_FUNC FLASH_StatusTypeDef FLASH_EnableRunPowerDown(void)
{
/* Enable the Power Down in Run mode*/
FLASH_POWER_DOWN_ENABLE();
return FLASH_OK;
}
/**
* @brief Disable the Power down in Run Mode
* @note This function should be called and executed from SRAM memory.
* @retval None
*/
__RAM_FUNC FLASH_StatusTypeDef FLASH_DisableRunPowerDown(void)
{
/* Disable the Power Down in Run mode*/
FLASH_POWER_DOWN_DISABLE();
return FLASH_OK;
}
#if defined (FLASH_OPTR_DBANK)
/**
* @brief Program the FLASH DBANK User Option Byte.
*
* @note To configure the user option bytes, the option lock bit OPTLOCK must
* be cleared with the call of the FLASH_OB_Unlock() function.
* @note To modify the DBANK option byte, no PCROP region should be defined.
* To deactivate PCROP, user should perform RDP changing.
*
* @param DBankConfig The FLASH DBANK User Option Byte value.
* This parameter can be one of the following values:
* @arg OB_DBANK_128_BITS: Single-bank with 128-bits data
* @arg OB_DBANK_64_BITS: Dual-bank with 64-bits data
*
* @retval FLASH_Status
*/
__RAM_FUNC FLASH_StatusTypeDef FLASH_OB_DBankConfig(uint32_t DBankConfig)
{
uint32_t count, reg;
FLASH_StatusTypeDef status = FLASH_ERROR;
/* Process Locked */
FLASH_LOCK(&MCU_FLASH);
/* Check if the PCROP is disabled */
reg = FLASH->PCROP1SR;
if (reg > FLASH->PCROP1ER)
{
reg = FLASH->PCROP2SR;
if (reg > FLASH->PCROP2ER)
{
/* Disable Flash prefetch */
FLASH_PREFETCH_BUFFER_DISABLE();
if (READ_BIT(FLASH->ACR, FLASH_ACR_ICEN) != 0U)
{
/* Disable Flash instruction cache */
FLASH_INSTRUCTION_CACHE_DISABLE();
/* Flush Flash instruction cache */
FLASH_INSTRUCTION_CACHE_RESET();
}
if (READ_BIT(FLASH->ACR, FLASH_ACR_DCEN) != 0U)
{
/* Disable Flash data cache */
FLASH_DATA_CACHE_DISABLE();
/* Flush Flash data cache */
FLASH_DATA_CACHE_RESET();
}
/* Disable WRP zone A of 1st bank if needed */
reg = FLASH->WRP1AR;
if (((reg & FLASH_WRP1AR_WRP1A_STRT) >> FLASH_WRP1AR_WRP1A_STRT_Pos) <=
((reg & FLASH_WRP1AR_WRP1A_END) >> FLASH_WRP1AR_WRP1A_END_Pos))
{
MODIFY_REG(FLASH->WRP1AR, (FLASH_WRP1AR_WRP1A_STRT | FLASH_WRP1AR_WRP1A_END), FLASH_WRP1AR_WRP1A_STRT);
}
/* Disable WRP zone B of 1st bank if needed */
reg = FLASH->WRP1BR;
if (((reg & FLASH_WRP1BR_WRP1B_STRT) >> FLASH_WRP1BR_WRP1B_STRT_Pos) <=
((reg & FLASH_WRP1BR_WRP1B_END) >> FLASH_WRP1BR_WRP1B_END_Pos))
{
MODIFY_REG(FLASH->WRP1BR, (FLASH_WRP1BR_WRP1B_STRT | FLASH_WRP1BR_WRP1B_END), FLASH_WRP1BR_WRP1B_STRT);
}
/* Disable WRP zone A of 2nd bank if needed */
reg = FLASH->WRP2AR;
if (((reg & FLASH_WRP2AR_WRP2A_STRT) >> FLASH_WRP2AR_WRP2A_STRT_Pos) <=
((reg & FLASH_WRP2AR_WRP2A_END) >> FLASH_WRP2AR_WRP2A_END_Pos))
{
MODIFY_REG(FLASH->WRP2AR, (FLASH_WRP2AR_WRP2A_STRT | FLASH_WRP2AR_WRP2A_END), FLASH_WRP2AR_WRP2A_STRT);
}
/* Disable WRP zone B of 2nd bank if needed */
reg = FLASH->WRP2BR;
if (((reg & FLASH_WRP2BR_WRP2B_STRT) >> FLASH_WRP2BR_WRP2B_STRT_Pos) <=
((reg & FLASH_WRP2BR_WRP2B_END) >> FLASH_WRP2BR_WRP2B_END_Pos))
{
MODIFY_REG(FLASH->WRP2BR, (FLASH_WRP2BR_WRP2B_STRT | FLASH_WRP2BR_WRP2B_END), FLASH_WRP2BR_WRP2B_STRT);
}
/* Modify the DBANK user option byte */
MODIFY_REG(FLASH->OPTR, FLASH_OPTR_DBANK, DBankConfig);
/* Set OPTSTRT Bit */
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
/* Wait for last operation to be completed */
/* 8 is the number of required instruction cycles for the below loop statement (timeout expressed in ms) */
count = FLASH_TIMEOUT_VALUE * (SystemCoreClock / 8U / 1000U);
do
{
if (count == 0U)
{
break;
}
count--;
}
while (FLASH_GET_FLAG(FLASH_FLAG_BSY) != RESET);
/* If the option byte program operation is completed, disable the OPTSTRT Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
/* Set the bit to force the option byte reloading */
SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);
}
}
/* Process Unlocked */
FLASH_UNLOCK(&MCU_FLASH);
return status;
}
#endif
/**
* @brief Enable the FLASH Securable Memory protection.
* @param Bank: Bank to be protected
* This parameter can be one of the following values:
* @arg FLASH_BANK_1: Bank1 to be protected
* @arg FLASH_BANK_2: Bank2 to be protected (*)
* @arg FLASH_BANK_BOTH: Bank1 and Bank2 to be protected (*)
* @note (*) availability depends on devices
* @retval FLASH Status
*/
FLASH_StatusTypeDef FLASH_EnableSecMemProtection(uint32_t Bank)
{
#if defined (FLASH_OPTR_DBANK)
if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) != 0U)
{
/* Check the parameters */
assert_param(IS_FLASH_BANK(Bank));
/* Enable the Securable Memory Protection Bit for the bank 1 if requested */
if ((Bank & FLASH_BANK_1) != 0U)
{
SET_BIT(FLASH->CR, FLASH_CR_SEC_PROT1);
}
/* Enable the Securable Memory Protection Bit for the bank 2 if requested */
if ((Bank & FLASH_BANK_2) != 0U)
{
SET_BIT(FLASH->CR, FLASH_CR_SEC_PROT2);
}
}
else
#endif
{
SET_BIT(FLASH->CR, FLASH_CR_SEC_PROT1);
}
return FLASH_OK;
}
/**
* @brief Enable Debugger.
* @note After calling this API, flash interface allow debugger intrusion.
* @retval None
*/
void FLASH_EnableDebugger(void)
{
FLASH->ACR |= FLASH_ACR_DBG_SWEN;
}
/**
* @brief Disable Debugger.
* @note After calling this API, Debugger is disabled: it's no more possible to
* break, see CPU register, etc...
* @retval None
*/
void FLASH_DisableDebugger(void)
{
FLASH->ACR &= ~FLASH_ACR_DBG_SWEN;
}
/**
* @brief Get the specific FLASH error flag.
* @retval FLASH_ErrorCode. The returned value can be:
* @arg FLASH_ERROR_RD: FLASH Read Protection error flag (PCROP)
* @arg FLASH_ERROR_PGS: FLASH Programming Sequence error flag
* @arg FLASH_ERROR_PGP: FLASH Programming Parallelism error flag
* @arg FLASH_ERROR_PGA: FLASH Programming Alignment error flag
* @arg FLASH_ERROR_WRP: FLASH Write protected error flag
* @arg FLASH_ERROR_OPERATION: FLASH operation Error flag
* @arg FLASH_ERROR_NONE: No error set
* @arg FLASH_ERROR_OP: FLASH Operation error
* @arg FLASH_ERROR_PROG: FLASH Programming error
* @arg FLASH_ERROR_WRP: FLASH Write protection error
* @arg FLASH_ERROR_PGA: FLASH Programming alignment error
* @arg FLASH_ERROR_SIZ: FLASH Size error
* @arg FLASH_ERROR_PGS: FLASH Programming sequence error
* @arg FLASH_ERROR_MIS: FLASH Fast programming data miss error
* @arg FLASH_ERROR_FAST: FLASH Fast programming error
* @arg FLASH_ERROR_RD: FLASH PCROP read error
* @arg FLASH_ERROR_OPTV: FLASH Option validity error
*/
uint32_t FLASH_GetError(void)
{
return MCU_FLASH.ErrorCode;
}
/* Private functions ---------------------------------------------------------*/
/**
* @brief Wait for a FLASH operation to complete.
* @param Timeout maximum flash operation timeout.
* @retval FLASH_Status
*/
static FLASH_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout)
{
/* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
Even if the FLASH operation fails, the BUSY flag will be reset and an error
flag will be set */
uint32_t MsCnt = 0;
uint32_t ErrFlag;
while (FLASH_GET_FLAG(FLASH_FLAG_BSY))
{
if (MsCnt++ > Timeout)
{
return FLASH_TIMEOUT;
}
LL_mDelay(1);
}
/* Check FLASH operation error flags */
ErrFlag = (FLASH->SR & FLASH_FLAG_SR_ERRORS);
if (ErrFlag != 0u)
{
/* Save the error code */
MCU_FLASH.ErrorCode |= ErrFlag;
/* Clear error programming flags */
FLASH_CLEAR_FLAG(ErrFlag);
return FLASH_ERROR;
}
/* Check FLASH End of Operation flag */
if (FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* If there is an error flag set */
return FLASH_OK;
}
/**
* @brief Program double-word (64-bit) at a specified address.
* @param Address specifies the address to be programmed.
* @param Data specifies the data to be programmed.
* @retval None
*/
static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
{
/* Check the parameters */
assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));
/* Set PG bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program first word */
*(uint32_t *)Address = (uint32_t)Data;
/* Barrier to ensure programming is performed in 2 steps, in right order
(independently of compiler optimization behavior) */
__ISB();
/* Program second word */
*(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);
}
/**
* @brief Fast program a row double-word (64-bit) at a specified address.
* @param Address specifies the address to be programmed.
* @param DataAddress specifies the address where the data are stored.
* @retval None
*/
static void FLASH_Program_Fast(uint32_t Address, uint32_t DataAddress)
{
uint8_t row_index = (2 * FLASH_NB_DOUBLE_WORDS_IN_ROW);
uint32_t *dest_addr = (uint32_t *)Address;
uint32_t *src_addr = (uint32_t *)DataAddress;
uint32_t primask_bit;
/* Check the parameters */
assert_param(IS_FLASH_MAIN_MEM_ADDRESS(Address));
/* Set FSTPG bit */
SET_BIT(FLASH->CR, FLASH_CR_FSTPG);
/* Enter critical section: Disable interrupts to avoid any interruption during the loop */
primask_bit = __get_PRIMASK();
__disable_irq();
/* Program the double words of the row */
do
{
*dest_addr = *src_addr;
dest_addr++;
src_addr++;
row_index--;
}
while (row_index != 0U);
/* Exit critical section: restore previous priority mask */
__set_PRIMASK(primask_bit);
}
/**
* @brief Mass erase of FLASH memory.
* @param Banks Banks to be erased.
* This parameter can be one of the following values:
* @arg FLASH_BANK_1: Bank1 to be erased
* @arg FLASH_BANK_2: Bank2 to be erased (*)
* @arg FLASH_BANK_BOTH: Bank1 and Bank2 to be erased (*)
* @note (*) availability depends on devices
* @retval None
*/
static void FLASH_MassErase(uint32_t Banks)
{
#if defined (FLASH_OPTR_DBANK)
if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) != 0U)
#endif
{
/* Check the parameters */
assert_param(IS_FLASH_BANK(Banks));
/* Set the Mass Erase Bit for the bank 1 if requested */
if ((Banks & FLASH_BANK_1) != 0U)
{
SET_BIT(FLASH->CR, FLASH_CR_MER1);
}
#if defined (FLASH_OPTR_DBANK)
/* Set the Mass Erase Bit for the bank 2 if requested */
if ((Banks & FLASH_BANK_2) != 0U)
{
SET_BIT(FLASH->CR, FLASH_CR_MER2);
}
#endif
}
#if defined (FLASH_OPTR_DBANK)
else
{
SET_BIT(FLASH->CR, (FLASH_CR_MER1 | FLASH_CR_MER2));
}
#endif
/* Proceed to erase all sectors */
SET_BIT(FLASH->CR, FLASH_CR_STRT);
}
/**
* @brief Erase the specified FLASH memory page.
* @param Page FLASH page to erase.
* This parameter must be a value between 0 and (max number of pages in the bank - 1).
* @param Banks Bank where the page will be erased.
* This parameter can be one of the following values:
* @arg FLASH_BANK_1: Page in bank 1 to be erased
* @arg FLASH_BANK_2: Page in bank 2 to be erased (*)
* @note (*) availability depends on devices
* @retval None
*/
static void FLASH_PageErase(uint32_t Page, uint32_t Banks)
{
/* Check the parameters */
assert_param(IS_FLASH_PAGE(Page));
#if defined (FLASH_OPTR_DBANK)
if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) == 0U)
{
CLEAR_BIT(FLASH->CR, FLASH_CR_BKER);
}
else
{
assert_param(IS_FLASH_BANK_EXCLUSIVE(Banks));
if ((Banks & FLASH_BANK_1) != 0U)
{
CLEAR_BIT(FLASH->CR, FLASH_CR_BKER);
}
else
{
SET_BIT(FLASH->CR, FLASH_CR_BKER);
}
}
#endif
/* Proceed to erase the page */
MODIFY_REG(FLASH->CR, FLASH_CR_PNB, ((Page & 0xFFU) << FLASH_CR_PNB_Pos));
SET_BIT(FLASH->CR, FLASH_CR_PER);
SET_BIT(FLASH->CR, FLASH_CR_STRT);
}
/**
* @brief Flush the instruction and data caches.
* @retval None
*/
static void FLASH_FlushCaches(void)
{
FLASH_CacheTypeDef cache = MCU_FLASH.CacheToReactivate;
/* Flush instruction cache */
if ((cache == FLASH_CACHE_ICACHE_ENABLED) ||
(cache == FLASH_CACHE_ICACHE_DCACHE_ENABLED))
{
/* Disable instruction cache */
FLASH_INSTRUCTION_CACHE_DISABLE();
/* Reset instruction cache */
FLASH_INSTRUCTION_CACHE_RESET();
/* Enable instruction cache */
FLASH_INSTRUCTION_CACHE_ENABLE();
}
/* Flush data cache */
if ((cache == FLASH_CACHE_DCACHE_ENABLED) ||
(cache == FLASH_CACHE_ICACHE_DCACHE_ENABLED))
{
/* Reset data cache */
FLASH_DATA_CACHE_RESET();
/* Enable data cache */
FLASH_DATA_CACHE_ENABLE();
}
/* Reset internal variable */
MCU_FLASH.CacheToReactivate = FLASH_CACHE_DISABLED;
}
/**
* @brief Configure the write protection area into Option Bytes.
* @note When the memory read protection level is selected (RDP level = 1),
* it is not possible to program or erase Flash memory if the CPU debug
* features are connected (JTAG or single wire) or boot code is being
* executed from RAM or System flash, even if WRP is not activated.
* @note To configure any option bytes, the option lock bit OPTLOCK must be
* cleared with the call of FLASH_OB_Unlock() function.
* @note New option bytes configuration will be taken into account in two cases:
* - after an option bytes launch through the call of FLASH_OB_Launch()
* - after a power reset (BOR reset or exit from Standby/Shutdown modes)
* @param WRPArea specifies the area to be configured.
* This parameter can be one of the following values:
* @arg OB_WRPAREA_BANK1_AREAA: Flash Bank 1 Area A
* @arg OB_WRPAREA_BANK1_AREAB: Flash Bank 1 Area B
* @arg OB_WRPAREA_BANK2_AREAA: Flash Bank 2 Area A (*)
* @arg OB_WRPAREA_BANK2_AREAB: Flash Bank 2 Area B (*)
* @note (*) availability depends on devices
* @param WRPStartOffset specifies the start page of the write protected area.
* This parameter can be page number between 0 and (max number of pages in the bank - 1).
* @param WRDPEndOffset specifies the end page of the write protected area.
* This parameter can be page number between WRPStartOffset and (max number of pages in the bank - 1).
* @retval FLASH_Status
*/
static FLASH_StatusTypeDef FLASH_OB_WRPConfig(uint32_t WRPArea, uint32_t WRPStartOffset, uint32_t WRDPEndOffset)
{
FLASH_StatusTypeDef status;
/* Check the parameters */
assert_param(IS_OB_WRPAREA(WRPArea));
assert_param(IS_FLASH_PAGE(WRPStartOffset));
assert_param(IS_FLASH_PAGE(WRDPEndOffset));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == FLASH_OK)
{
/* Configure the write protected area */
if (WRPArea == OB_WRPAREA_BANK1_AREAA)
{
FLASH->WRP1AR = ((WRDPEndOffset << FLASH_WRP1AR_WRP1A_END_Pos) | WRPStartOffset);
}
else if (WRPArea == OB_WRPAREA_BANK1_AREAB)
{
FLASH->WRP1BR = ((WRDPEndOffset << FLASH_WRP1BR_WRP1B_END_Pos) | WRPStartOffset);
}
#if defined (FLASH_OPTR_DBANK)
else if (WRPArea == OB_WRPAREA_BANK2_AREAA)
{
FLASH->WRP2AR = ((WRDPEndOffset << FLASH_WRP2AR_WRP2A_END_Pos) | WRPStartOffset);
}
else if (WRPArea == OB_WRPAREA_BANK2_AREAB)
{
FLASH->WRP2BR = ((WRDPEndOffset << FLASH_WRP2BR_WRP2B_END_Pos) | WRPStartOffset);
}
#endif
else
{
/* Nothing to do */
}
/* Set OPTSTRT Bit */
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
return status;
}
/**
* @brief Set the read protection level into Option Bytes.
* @note To configure any option bytes, the option lock bit OPTLOCK must be
* cleared with the call of FLASH_OB_Unlock() function.
* @note New option bytes configuration will be taken into account in two cases:
* - after an option bytes launch through the call of FLASH_OB_Launch()
* - after a power reset (BOR reset or exit from Standby/Shutdown modes)
* @note !!! Warning : When enabling OB_RDP level 2 it's no more possible
* to go back to level 1 or 0 !!!
* @param RDPLevel specifies the read protection level.
* This parameter can be one of the following values:
* @arg OB_RDP_LEVEL_0: No protection
* @arg OB_RDP_LEVEL_1: Memory Read protection
* @arg OB_RDP_LEVEL_2: Full chip protection
*
* @retval FLASH_Status
*/
static FLASH_StatusTypeDef FLASH_OB_RDPConfig(uint32_t RDPLevel)
{
FLASH_StatusTypeDef status;
/* Check the parameters */
assert_param(IS_OB_RDP_LEVEL(RDPLevel));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == FLASH_OK)
{
/* Configure the RDP level in the option bytes register */
MODIFY_REG(FLASH->OPTR, FLASH_OPTR_RDP, RDPLevel);
/* Set OPTSTRT Bit */
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
return status;
}
/**
* @brief Program the FLASH User Option Bytes.
* @note To configure any option bytes, the option lock bit OPTLOCK must be
* cleared with the call of FLASH_OB_Unlock() function.
* @note New option bytes configuration will be taken into account in two cases:
* - after an option bytes launch through the call of FLASH_OB_Launch()
* - after a power reset (BOR reset or exit from Standby/Shutdown modes)
* @param UserType The FLASH User Option Bytes to be modified.
* This parameter can be a combination of @ref FLASH_OB_USER_Type.
* @param UserConfig The selected User Option Bytes values:
* This parameter can be a combination of @ref FLASH_OB_USER_BOR_LEVEL,
* @ref FLASH_OB_USER_nRST_STOP, @ref FLASH_OB_USER_nRST_STANDBY ,
* @ref FLASH_OB_USER_nRST_SHUTDOWN, @ref FLASH_OB_USER_IWDG_SW,
* @ref FLASH_OB_USER_IWDG_STOP, @ref FLASH_OB_USER_IWDG_STANDBY,
* @ref FLASH_OB_USER_WWDG_SW, @ref FLASH_OB_USER_WWDG_SW,
* @ref FLASH_OB_USER_BFB2 (*), @ref FLASH_OB_USER_nBOOT1,
* @ref FLASH_OB_USER_SRAM_PE, @ref FLASH_OB_USER_CCMSRAM_RST,
* @ref FLASH_OB_USER_nSWBOOT0, @ref FLASH_OB_USER_nBOOT0,
* @ref FLASH_OB_USER_NRST_MODE, @ref FLASH_OB_USER_INTERNAL_RESET_HOLDER
* @note (*) availability depends on devices
* @retval FLASH_Status
*/
static FLASH_StatusTypeDef FLASH_OB_UserConfig(uint32_t UserType, uint32_t UserConfig)
{
uint32_t optr_reg_val = 0;
uint32_t optr_reg_mask = 0;
FLASH_StatusTypeDef status;
/* Check the parameters */
assert_param(IS_OB_USER_TYPE(UserType));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == FLASH_OK)
{
if ((UserType & OB_USER_BOR_LEV) != 0U)
{
/* BOR level option byte should be modified */
assert_param(IS_OB_USER_BOR_LEVEL(UserConfig & FLASH_OPTR_BOR_LEV));
/* Set value and mask for BOR level option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_BOR_LEV);
optr_reg_mask |= FLASH_OPTR_BOR_LEV;
}
if ((UserType & OB_USER_nRST_STOP) != 0U)
{
/* nRST_STOP option byte should be modified */
assert_param(IS_OB_USER_STOP(UserConfig & FLASH_OPTR_nRST_STOP));
/* Set value and mask for nRST_STOP option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_nRST_STOP);
optr_reg_mask |= FLASH_OPTR_nRST_STOP;
}
if ((UserType & OB_USER_nRST_STDBY) != 0U)
{
/* nRST_STDBY option byte should be modified */
assert_param(IS_OB_USER_STANDBY(UserConfig & FLASH_OPTR_nRST_STDBY));
/* Set value and mask for nRST_STDBY option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_nRST_STDBY);
optr_reg_mask |= FLASH_OPTR_nRST_STDBY;
}
if ((UserType & OB_USER_nRST_SHDW) != 0U)
{
/* nRST_SHDW option byte should be modified */
assert_param(IS_OB_USER_SHUTDOWN(UserConfig & FLASH_OPTR_nRST_SHDW));
/* Set value and mask for nRST_SHDW option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_nRST_SHDW);
optr_reg_mask |= FLASH_OPTR_nRST_SHDW;
}
if ((UserType & OB_USER_IWDG_SW) != 0U)
{
/* IWDG_SW option byte should be modified */
assert_param(IS_OB_USER_IWDG(UserConfig & FLASH_OPTR_IWDG_SW));
/* Set value and mask for IWDG_SW option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_IWDG_SW);
optr_reg_mask |= FLASH_OPTR_IWDG_SW;
}
if ((UserType & OB_USER_IWDG_STOP) != 0U)
{
/* IWDG_STOP option byte should be modified */
assert_param(IS_OB_USER_IWDG_STOP(UserConfig & FLASH_OPTR_IWDG_STOP));
/* Set value and mask for IWDG_STOP option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_IWDG_STOP);
optr_reg_mask |= FLASH_OPTR_IWDG_STOP;
}
if ((UserType & OB_USER_IWDG_STDBY) != 0U)
{
/* IWDG_STDBY option byte should be modified */
assert_param(IS_OB_USER_IWDG_STDBY(UserConfig & FLASH_OPTR_IWDG_STDBY));
/* Set value and mask for IWDG_STDBY option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_IWDG_STDBY);
optr_reg_mask |= FLASH_OPTR_IWDG_STDBY;
}
if ((UserType & OB_USER_WWDG_SW) != 0U)
{
/* WWDG_SW option byte should be modified */
assert_param(IS_OB_USER_WWDG(UserConfig & FLASH_OPTR_WWDG_SW));
/* Set value and mask for WWDG_SW option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_WWDG_SW);
optr_reg_mask |= FLASH_OPTR_WWDG_SW;
}
#if defined (FLASH_OPTR_BFB2)
if ((UserType & OB_USER_BFB2) != 0U)
{
/* BFB2 option byte should be modified */
assert_param(IS_OB_USER_BFB2(UserConfig & FLASH_OPTR_BFB2));
/* Set value and mask for BFB2 option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_BFB2);
optr_reg_mask |= FLASH_OPTR_BFB2;
}
#endif
if ((UserType & OB_USER_nBOOT1) != 0U)
{
/* nBOOT1 option byte should be modified */
assert_param(IS_OB_USER_BOOT1(UserConfig & FLASH_OPTR_nBOOT1));
/* Set value and mask for nBOOT1 option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_nBOOT1);
optr_reg_mask |= FLASH_OPTR_nBOOT1;
}
if ((UserType & OB_USER_SRAM_PE) != 0U)
{
/* SRAM_PE option byte should be modified */
assert_param(IS_OB_USER_SRAM_PARITY(UserConfig & FLASH_OPTR_SRAM_PE));
/* Set value and mask for SRAM_PE option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_SRAM_PE);
optr_reg_mask |= FLASH_OPTR_SRAM_PE;
}
if ((UserType & OB_USER_CCMSRAM_RST) != 0U)
{
/* CCMSRAM_RST option byte should be modified */
assert_param(IS_OB_USER_CCMSRAM_RST(UserConfig & FLASH_OPTR_CCMSRAM_RST));
/* Set value and mask for CCMSRAM_RST option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_CCMSRAM_RST);
optr_reg_mask |= FLASH_OPTR_CCMSRAM_RST;
}
if ((UserType & OB_USER_nSWBOOT0) != 0U)
{
/* nSWBOOT0 option byte should be modified */
assert_param(IS_OB_USER_SWBOOT0(UserConfig & FLASH_OPTR_nSWBOOT0));
/* Set value and mask for nSWBOOT0 option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_nSWBOOT0);
optr_reg_mask |= FLASH_OPTR_nSWBOOT0;
}
if ((UserType & OB_USER_nBOOT0) != 0U)
{
/* nBOOT0 option byte should be modified */
assert_param(IS_OB_USER_BOOT0(UserConfig & FLASH_OPTR_nBOOT0));
/* Set value and mask for nBOOT0 option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_nBOOT0);
optr_reg_mask |= FLASH_OPTR_nBOOT0;
}
if ((UserType & OB_USER_NRST_MODE) != 0U)
{
/* Reset Configuration option byte should be modified */
assert_param(IS_OB_USER_NRST_MODE(UserConfig & FLASH_OPTR_NRST_MODE));
/* Set value and mask for Reset Configuration option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_NRST_MODE);
optr_reg_mask |= FLASH_OPTR_NRST_MODE;
}
if ((UserType & OB_USER_IRHEN) != 0U)
{
/* IRH option byte should be modified */
assert_param(IS_OB_USER_IRHEN(UserConfig & FLASH_OPTR_IRHEN));
/* Set value and mask for IRH option byte */
optr_reg_val |= (UserConfig & FLASH_OPTR_IRHEN);
optr_reg_mask |= FLASH_OPTR_IRHEN;
}
/* Configure the option bytes register */
MODIFY_REG(FLASH->OPTR, optr_reg_mask, optr_reg_val);
/* Set OPTSTRT Bit */
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
return status;
}
/**
* @brief Configure the Proprietary code readout protection area into Option Bytes.
* @note To configure any option bytes, the option lock bit OPTLOCK must be
* cleared with the call of FLASH_OB_Unlock() function.
* @note New option bytes configuration will be taken into account in two cases:
* - after an option bytes launch through the call of FLASH_OB_Launch()
* - after a power reset (BOR reset or exit from Standby/Shutdown modes)
* @param PCROPConfig specifies the configuration (Bank to be configured and PCROP_RDP option).
* This parameter must be a combination of FLASH_BANK_1 or FLASH_BANK_2 (*)
* with OB_PCROP_RDP_NOT_ERASE or OB_PCROP_RDP_ERASE.
* @note (*) availability depends on devices
* @param PCROPStartAddr specifies the start address of the Proprietary code readout protection.
* This parameter can be an address between begin and end of the bank.
* @param PCROPEndAddr specifies the end address of the Proprietary code readout protection.
* This parameter can be an address between PCROPStartAddr and end of the bank.
* @retval FLASH_Status
*/
static FLASH_StatusTypeDef FLASH_OB_PCROPConfig(uint32_t PCROPConfig, uint32_t PCROPStartAddr, uint32_t PCROPEndAddr)
{
FLASH_StatusTypeDef status;
uint32_t reg_value;
uint32_t bank1_addr;
#if defined (FLASH_OPTR_DBANK)
uint32_t bank2_addr;
#endif
/* Check the parameters */
assert_param(IS_FLASH_BANK_EXCLUSIVE(PCROPConfig & FLASH_BANK_BOTH));
assert_param(IS_OB_PCROP_RDP(PCROPConfig & FLASH_PCROP1ER_PCROP_RDP));
assert_param(IS_FLASH_MAIN_MEM_ADDRESS(PCROPStartAddr));
assert_param(IS_FLASH_MAIN_MEM_ADDRESS(PCROPEndAddr));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == FLASH_OK)
{
#if defined (FLASH_OPTR_DBANK)
/* Get the information about the bank swapping */
if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0U)
{
bank1_addr = FLASH_BASE;
bank2_addr = FLASH_BASE + FLASH_BANK_SIZE;
}
else
{
bank1_addr = FLASH_BASE + FLASH_BANK_SIZE;
bank2_addr = FLASH_BASE;
}
#else
bank1_addr = FLASH_BASE;
#endif
#if defined (FLASH_OPTR_DBANK)
if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) == 0U)
{
/* Configure the Proprietary code readout protection */
if ((PCROPConfig & FLASH_BANK_BOTH) == FLASH_BANK_1)
{
reg_value = ((PCROPStartAddr - FLASH_BASE) >> 4);
MODIFY_REG(FLASH->PCROP1SR, FLASH_PCROP1SR_PCROP1_STRT, reg_value);
reg_value = ((PCROPEndAddr - FLASH_BASE) >> 4);
MODIFY_REG(FLASH->PCROP1ER, FLASH_PCROP1ER_PCROP1_END, reg_value);
}
else if ((PCROPConfig & FLASH_BANK_BOTH) == FLASH_BANK_2)
{
reg_value = ((PCROPStartAddr - FLASH_BASE) >> 4);
MODIFY_REG(FLASH->PCROP2SR, FLASH_PCROP2SR_PCROP2_STRT, reg_value);
reg_value = ((PCROPEndAddr - FLASH_BASE) >> 4);
MODIFY_REG(FLASH->PCROP2ER, FLASH_PCROP2ER_PCROP2_END, reg_value);
}
else
{
/* Nothing to do */
}
}
else
#endif
{
/* Configure the Proprietary code readout protection */
if ((PCROPConfig & FLASH_BANK_BOTH) == FLASH_BANK_1)
{
reg_value = ((PCROPStartAddr - bank1_addr) >> 3);
MODIFY_REG(FLASH->PCROP1SR, FLASH_PCROP1SR_PCROP1_STRT, reg_value);
reg_value = ((PCROPEndAddr - bank1_addr) >> 3);
MODIFY_REG(FLASH->PCROP1ER, FLASH_PCROP1ER_PCROP1_END, reg_value);
}
#if defined (FLASH_OPTR_DBANK)
else if ((PCROPConfig & FLASH_BANK_BOTH) == FLASH_BANK_2)
{
reg_value = ((PCROPStartAddr - bank2_addr) >> 3);
MODIFY_REG(FLASH->PCROP2SR, FLASH_PCROP2SR_PCROP2_STRT, reg_value);
reg_value = ((PCROPEndAddr - bank2_addr) >> 3);
MODIFY_REG(FLASH->PCROP2ER, FLASH_PCROP2ER_PCROP2_END, reg_value);
}
#endif
else
{
/* Nothing to do */
}
}
MODIFY_REG(FLASH->PCROP1ER, FLASH_PCROP1ER_PCROP_RDP, (PCROPConfig & FLASH_PCROP1ER_PCROP_RDP));
/* Set OPTSTRT Bit */
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
return status;
}
/**
* @brief Configure the Securable memory area into Option Bytes.
* @note To configure any option bytes, the option lock bit OPTLOCK must be
* cleared with the call of FLASH_OB_Unlock() function.
* @note New option bytes configuration will be taken into account in two cases:
* - after an option bytes launch through the call of FLASH_OB_Launch()
* - after a power reset (BOR reset or exit from Standby/Shutdown modes)
* @param SecBank specifies bank of securable memory area to be configured.
* This parameter can be one of the following values:
* @arg FLASH_BANK_1: Securable memory in Bank1 to be configured
* @arg FLASH_BANK_2: Securable memory in Bank2 to be configured (*)
* @note (*) availability depends on devices
* @param SecSize specifies the number of pages of the Securable memory area,
* starting from first page of the bank.
* This parameter can be page number between 0 and (max number of pages in the bank - 1)
* @retval FLASH Status
*/
static FLASH_StatusTypeDef FLASH_OB_SecMemConfig(uint32_t SecBank, uint32_t SecSize)
{
FLASH_StatusTypeDef status;
/* Check the parameters */
assert_param(IS_FLASH_BANK_EXCLUSIVE(SecBank));
assert_param(IS_OB_SECMEM_SIZE(SecSize));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == FLASH_OK)
{
/* Configure the write protected area */
if (SecBank == FLASH_BANK_1)
{
MODIFY_REG(FLASH->SEC1R, FLASH_SEC1R_SEC_SIZE1, SecSize);
}
#if defined (FLASH_OPTR_DBANK)
else if (SecBank == FLASH_BANK_2)
{
MODIFY_REG(FLASH->SEC2R, FLASH_SEC2R_SEC_SIZE2, SecSize);
}
else
{
/* Nothing to do */
}
#endif
/* Set OPTSTRT Bit */
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
return status;
}
/**
* @brief Configure the Boot Lock into Option Bytes.
* @note To configure any option bytes, the option lock bit OPTLOCK must be
* cleared with the call of FLASH_OB_Unlock() function.
* @note New option bytes configuration will be taken into account in two cases:
* - after an option bytes launch through the call of FLASH_OB_Launch()
* - after a power reset (BOR reset or exit from Standby/Shutdown modes)
* @param BootLockConfig specifies the boot lock configuration.
* This parameter can be one of the following values:
* @arg OB_BOOT_LOCK_ENABLE: Enable Boot Lock
* @arg OB_BOOT_LOCK_DISABLE: Disable Boot Lock
*
* @retval FLASH_Status
*/
static FLASH_StatusTypeDef FLASH_OB_BootLockConfig(uint32_t BootLockConfig)
{
FLASH_StatusTypeDef status;
/* Check the parameters */
assert_param(IS_OB_BOOT_LOCK(BootLockConfig));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == FLASH_OK)
{
MODIFY_REG(FLASH->SEC1R, FLASH_SEC1R_BOOT_LOCK, BootLockConfig);
/* Set OPTSTRT Bit */
SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
return status;
}
/**
* @brief Return the Securable memory area configuration into Option Bytes.
* @param[in] SecBank specifies the bank where securable memory area is located.
* This parameter can be one of the following values:
* @arg FLASH_BANK_1: Securable memory in Bank1
* @arg FLASH_BANK_2: Securable memory in Bank2 (*)
* @note (*) availability depends on devices
* @param[out] SecSize specifies the number of pages used in the securable
memory area of the bank.
* @retval None
*/
static void FLASH_OB_GetSecMem(uint32_t SecBank, uint32_t *SecSize)
{
/* Get the configuration of the securable memory area */
if (SecBank == FLASH_BANK_1)
{
*SecSize = READ_BIT(FLASH->SEC1R, FLASH_SEC1R_SEC_SIZE1);
}
#if defined (FLASH_OPTR_DBANK)
else if (SecBank == FLASH_BANK_2)
{
*SecSize = READ_BIT(FLASH->SEC2R, FLASH_SEC2R_SEC_SIZE2);
}
else
{
/* Nothing to do */
}
#endif
}
/**
* @brief Return the Boot Lock configuration into Option Byte.
* @retval BootLockConfig.
* This return value can be one of the following values:
* @arg OB_BOOT_LOCK_ENABLE: Boot lock enabled
* @arg OB_BOOT_LOCK_DISABLE: Boot lock disabled
*/
static uint32_t FLASH_OB_GetBootLock(void)
{
return (READ_REG(FLASH->SEC1R) & FLASH_SEC1R_BOOT_LOCK);
}
/**
* @brief Return the Write Protection configuration into Option Bytes.
* @param[in] WRPArea specifies the area to be returned.
* This parameter can be one of the following values:
* @arg OB_WRPAREA_BANK1_AREAA: Flash Bank 1 Area A
* @arg OB_WRPAREA_BANK1_AREAB: Flash Bank 1 Area B
* @arg OB_WRPAREA_BANK2_AREAA: Flash Bank 2 Area A (don't apply to STM32G43x/STM32G44x devices)
* @arg OB_WRPAREA_BANK2_AREAB: Flash Bank 2 Area B (don't apply to STM32G43x/STM32G44x devices)
* @param[out] WRPStartOffset specifies the address where to copied the start page
* of the write protected area.
* @param[out] WRDPEndOffset specifies the address where to copied the end page of
* the write protected area.
* @retval None
*/
static void FLASH_OB_GetWRP(uint32_t WRPArea, uint32_t *WRPStartOffset, uint32_t *WRDPEndOffset)
{
/* Get the configuration of the write protected area */
if (WRPArea == OB_WRPAREA_BANK1_AREAA)
{
*WRPStartOffset = READ_BIT(FLASH->WRP1AR, FLASH_WRP1AR_WRP1A_STRT);
*WRDPEndOffset = (READ_BIT(FLASH->WRP1AR, FLASH_WRP1AR_WRP1A_END) >> FLASH_WRP1AR_WRP1A_END_Pos);
}
else if (WRPArea == OB_WRPAREA_BANK1_AREAB)
{
*WRPStartOffset = READ_BIT(FLASH->WRP1BR, FLASH_WRP1BR_WRP1B_STRT);
*WRDPEndOffset = (READ_BIT(FLASH->WRP1BR, FLASH_WRP1BR_WRP1B_END) >> FLASH_WRP1BR_WRP1B_END_Pos);
}
#if defined (FLASH_OPTR_DBANK)
else if (WRPArea == OB_WRPAREA_BANK2_AREAA)
{
*WRPStartOffset = READ_BIT(FLASH->WRP2AR, FLASH_WRP2AR_WRP2A_STRT);
*WRDPEndOffset = (READ_BIT(FLASH->WRP2AR, FLASH_WRP2AR_WRP2A_END) >> FLASH_WRP2AR_WRP2A_END_Pos);
}
else if (WRPArea == OB_WRPAREA_BANK2_AREAB)
{
*WRPStartOffset = READ_BIT(FLASH->WRP2BR, FLASH_WRP2BR_WRP2B_STRT);
*WRDPEndOffset = (READ_BIT(FLASH->WRP2BR, FLASH_WRP2BR_WRP2B_END) >> FLASH_WRP2BR_WRP2B_END_Pos);
}
#endif
else
{
/* Nothing to do */
}
}
/**
* @brief Return the FLASH Read Protection level into Option Bytes.
* @retval RDP_Level
* This return value can be one of the following values:
* @arg OB_RDP_LEVEL_0: No protection
* @arg OB_RDP_LEVEL_1: Read protection of the memory
* @arg OB_RDP_LEVEL_2: Full chip protection
*/
static uint32_t FLASH_OB_GetRDP(void)
{
uint32_t rdp_level = READ_BIT(FLASH->OPTR, FLASH_OPTR_RDP);
if ((rdp_level != OB_RDP_LEVEL_0) && (rdp_level != OB_RDP_LEVEL_2))
{
return (OB_RDP_LEVEL_1);
}
else
{
return rdp_level;
}
}
/**
* @brief Return the FLASH User Option Byte value.
* @retval OB_user_config
* This return value is a combination of @ref FLASH_OB_USER_BOR_LEVEL,
* @ref FLASH_OB_USER_nRST_STOP, @ref FLASH_OB_USER_nRST_STANDBY,
* @ref FLASH_OB_USER_nRST_SHUTDOWN, @ref FLASH_OB_USER_IWDG_SW,
* @ref FLASH_OB_USER_IWDG_STOP, @ref FLASH_OB_USER_IWDG_STANDBY,
* @ref FLASH_OB_USER_WWDG_SW, @ref FLASH_OB_USER_WWDG_SW,
* @ref FLASH_OB_USER_BFB2 (*), @ref FLASH_OB_USER_DBANK (*),
* @ref FLASH_OB_USER_nBOOT1, @ref FLASH_OB_USER_SRAM_PE,
* @ref FLASH_OB_USER_CCMSRAM_RST, @ref OB_USER_nSWBOOT0,@ref FLASH_OB_USER_nBOOT0,
* @ref FLASH_OB_USER_NRST_MODE, @ref FLASH_OB_USER_INTERNAL_RESET_HOLDER
* @note (*) availability depends on devices
*/
static uint32_t FLASH_OB_GetUser(void)
{
uint32_t user_config = READ_REG(FLASH->OPTR);
CLEAR_BIT(user_config, FLASH_OPTR_RDP);
return user_config;
}
/**
* @brief Return the FLASH PCROP configuration into Option Bytes.
* @param[in,out] PCROPConfig specifies the configuration (Bank to be configured and PCROP_RDP option).
* This parameter must be a combination of FLASH_BANK_1 or FLASH_BANK_2
* with OB_PCROP_RDP_NOT_ERASE or OB_PCROP_RDP_ERASE.
* @param[out] PCROPStartAddr specifies the address where to copied the start address
* of the Proprietary code readout protection.
* @param[out] PCROPEndAddr specifies the address where to copied the end address of
* the Proprietary code readout protection.
* @retval None
*/
static void FLASH_OB_GetPCROP(uint32_t *PCROPConfig, uint32_t *PCROPStartAddr, uint32_t *PCROPEndAddr)
{
uint32_t reg_value;
uint32_t bank1_addr;
#if defined (FLASH_OPTR_DBANK)
uint32_t bank2_addr;
/* Get the information about the bank swapping */
if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0U)
{
bank1_addr = FLASH_BASE;
bank2_addr = FLASH_BASE + FLASH_BANK_SIZE;
}
else
{
bank1_addr = FLASH_BASE + FLASH_BANK_SIZE;
bank2_addr = FLASH_BASE;
}
#else
bank1_addr = FLASH_BASE;
#endif
#if defined (FLASH_OPTR_DBANK)
if (READ_BIT(FLASH->OPTR, FLASH_OPTR_DBANK) == 0U)
{
if (((*PCROPConfig) & FLASH_BANK_BOTH) == FLASH_BANK_1)
{
reg_value = (READ_REG(FLASH->PCROP1SR) & FLASH_PCROP1SR_PCROP1_STRT);
*PCROPStartAddr = (reg_value << 4) + FLASH_BASE;
reg_value = (READ_REG(FLASH->PCROP1ER) & FLASH_PCROP1ER_PCROP1_END);
*PCROPEndAddr = (reg_value << 4) + FLASH_BASE;
}
else if (((*PCROPConfig) & FLASH_BANK_BOTH) == FLASH_BANK_2)
{
reg_value = (READ_REG(FLASH->PCROP2SR) & FLASH_PCROP2SR_PCROP2_STRT);
*PCROPStartAddr = (reg_value << 4) + FLASH_BASE;
reg_value = (READ_REG(FLASH->PCROP2ER) & FLASH_PCROP2ER_PCROP2_END);
*PCROPEndAddr = (reg_value << 4) + FLASH_BASE;
}
else
{
/* Nothing to do */
}
}
else
#endif
{
if (((*PCROPConfig) & FLASH_BANK_BOTH) == FLASH_BANK_1)
{
reg_value = (READ_REG(FLASH->PCROP1SR) & FLASH_PCROP1SR_PCROP1_STRT);
*PCROPStartAddr = (reg_value << 3) + bank1_addr;
reg_value = (READ_REG(FLASH->PCROP1ER) & FLASH_PCROP1ER_PCROP1_END);
*PCROPEndAddr = (reg_value << 3) + bank1_addr;
}
#if defined (FLASH_OPTR_DBANK)
else if (((*PCROPConfig) & FLASH_BANK_BOTH) == FLASH_BANK_2)
{
reg_value = (READ_REG(FLASH->PCROP2SR) & FLASH_PCROP2SR_PCROP2_STRT);
*PCROPStartAddr = (reg_value << 3) + bank2_addr;
reg_value = (READ_REG(FLASH->PCROP2ER) & FLASH_PCROP2ER_PCROP2_END);
*PCROPEndAddr = (reg_value << 3) + bank2_addr;
}
#endif
else
{
/* Nothing to do */
}
}
*PCROPConfig |= (READ_REG(FLASH->PCROP1ER) & FLASH_PCROP1ER_PCROP_RDP);
}