主要工作就是把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 --------------------------------------------------------*/
#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 */
/**
* @brief Base address of the Flash pages under dual bank mode for category 3 devices Bank 1
* Dual bank mode(2KB each page)
* For 256KB devices: from page 0 to page 63
* For 128KB devices: from page 0 to page 31
* Single bank mode(4KB each page)
* For 256KB devices: from page 0 to page 63
* For 128KB devices: from page 0 to page 31
*/
#define FLASH_ADDR_PAGE_0 ((uint32_t)0x08000000) /* Base @ of Page 0, 2 Kbytes */
#define FLASH_ADDR_PAGE_1 ((uint32_t)0x08000800) /* Base @ of Page 1, 2 Kbytes */
#define FLASH_ADDR_PAGE_2 ((uint32_t)0x08001000) /* Base @ of Page 2, 2 Kbytes */
#define FLASH_ADDR_PAGE_3 ((uint32_t)0x08001800) /* Base @ of Page 3, 2 Kbytes */
#define FLASH_ADDR_PAGE_4 ((uint32_t)0x08002000) /* Base @ of Page 4, 2 Kbytes */
#define FLASH_ADDR_PAGE_5 ((uint32_t)0x08002800) /* Base @ of Page 5, 2 Kbytes */
#define FLASH_ADDR_PAGE_6 ((uint32_t)0x08003000) /* Base @ of Page 6, 2 Kbytes */
#define FLASH_ADDR_PAGE_7 ((uint32_t)0x08003800) /* Base @ of Page 7, 2 Kbytes */
#define FLASH_ADDR_PAGE_8 ((uint32_t)0x08004000) /* Base @ of Page 8, 2 Kbytes */
#define FLASH_ADDR_PAGE_9 ((uint32_t)0x08004800) /* Base @ of Page 9, 2 Kbytes */
#define FLASH_ADDR_PAGE_10 ((uint32_t)0x08005000) /* Base @ of Page 10, 2 Kbytes */
#define FLASH_ADDR_PAGE_11 ((uint32_t)0x08005800) /* Base @ of Page 11, 2 Kbytes */
#define FLASH_ADDR_PAGE_12 ((uint32_t)0x08006000) /* Base @ of Page 12, 2 Kbytes */
#define FLASH_ADDR_PAGE_13 ((uint32_t)0x08006800) /* Base @ of Page 13, 2 Kbytes */
#define FLASH_ADDR_PAGE_14 ((uint32_t)0x08007000) /* Base @ of Page 14, 2 Kbytes */
#define FLASH_ADDR_PAGE_15 ((uint32_t)0x08007800) /* Base @ of Page 15, 2 Kbytes */
#define FLASH_ADDR_PAGE_16 ((uint32_t)0x08008000) /* Base @ of Page 16, 2 Kbytes */
#define FLASH_ADDR_PAGE_17 ((uint32_t)0x08008800) /* Base @ of Page 17, 2 Kbytes */
#define FLASH_ADDR_PAGE_18 ((uint32_t)0x08009000) /* Base @ of Page 18, 2 Kbytes */
#define FLASH_ADDR_PAGE_19 ((uint32_t)0x08009800) /* Base @ of Page 19, 2 Kbytes */
#define FLASH_ADDR_PAGE_20 ((uint32_t)0x0800A000) /* Base @ of Page 20, 2 Kbytes */
#define FLASH_ADDR_PAGE_21 ((uint32_t)0x0800A800) /* Base @ of Page 21, 2 Kbytes */
#define FLASH_ADDR_PAGE_22 ((uint32_t)0x0800B000) /* Base @ of Page 22, 2 Kbytes */
#define FLASH_ADDR_PAGE_23 ((uint32_t)0x0800B800) /* Base @ of Page 23, 2 Kbytes */
#define FLASH_ADDR_PAGE_24 ((uint32_t)0x0800C000) /* Base @ of Page 24, 2 Kbytes */
#define FLASH_ADDR_PAGE_25 ((uint32_t)0x0800C800) /* Base @ of Page 25, 2 Kbytes */
#define FLASH_ADDR_PAGE_26 ((uint32_t)0x0800D000) /* Base @ of Page 26, 2 Kbytes */
#define FLASH_ADDR_PAGE_27 ((uint32_t)0x0800D800) /* Base @ of Page 27, 2 Kbytes */
#define FLASH_ADDR_PAGE_28 ((uint32_t)0x0800E000) /* Base @ of Page 28, 2 Kbytes */
#define FLASH_ADDR_PAGE_29 ((uint32_t)0x0800E800) /* Base @ of Page 29, 2 Kbytes */
#define FLASH_ADDR_PAGE_30 ((uint32_t)0x0800F000) /* Base @ of Page 30, 2 Kbytes */
#define FLASH_ADDR_PAGE_31 ((uint32_t)0x0800F800) /* Base @ of Page 31, 2 Kbytes */
#define FLASH_ADDR_PAGE_32 ((uint32_t)0x08010000) /* Base @ of Page 32, 2 Kbytes */
#define FLASH_ADDR_PAGE_33 ((uint32_t)0x08010800) /* Base @ of Page 33, 2 Kbytes */
#define FLASH_ADDR_PAGE_34 ((uint32_t)0x08011000) /* Base @ of Page 34, 2 Kbytes */
#define FLASH_ADDR_PAGE_35 ((uint32_t)0x08011800) /* Base @ of Page 35, 2 Kbytes */
#define FLASH_ADDR_PAGE_36 ((uint32_t)0x08012000) /* Base @ of Page 36, 2 Kbytes */
#define FLASH_ADDR_PAGE_37 ((uint32_t)0x08012800) /* Base @ of Page 37, 2 Kbytes */
#define FLASH_ADDR_PAGE_38 ((uint32_t)0x08013000) /* Base @ of Page 38, 2 Kbytes */
#define FLASH_ADDR_PAGE_39 ((uint32_t)0x08013800) /* Base @ of Page 39, 2 Kbytes */
#define FLASH_ADDR_PAGE_40 ((uint32_t)0x08014000) /* Base @ of Page 40, 2 Kbytes */
#define FLASH_ADDR_PAGE_41 ((uint32_t)0x08014800) /* Base @ of Page 41, 2 Kbytes */
#define FLASH_ADDR_PAGE_42 ((uint32_t)0x08015000) /* Base @ of Page 42, 2 Kbytes */
#define FLASH_ADDR_PAGE_43 ((uint32_t)0x08015800) /* Base @ of Page 43, 2 Kbytes */
#define FLASH_ADDR_PAGE_44 ((uint32_t)0x08016000) /* Base @ of Page 44, 2 Kbytes */
#define FLASH_ADDR_PAGE_45 ((uint32_t)0x08016800) /* Base @ of Page 45, 2 Kbytes */
#define FLASH_ADDR_PAGE_46 ((uint32_t)0x08017000) /* Base @ of Page 46, 2 Kbytes */
#define FLASH_ADDR_PAGE_47 ((uint32_t)0x08017800) /* Base @ of Page 47, 2 Kbytes */
#define FLASH_ADDR_PAGE_48 ((uint32_t)0x08018000) /* Base @ of Page 48, 2 Kbytes */
#define FLASH_ADDR_PAGE_49 ((uint32_t)0x08018800) /* Base @ of Page 49, 2 Kbytes */
#define FLASH_ADDR_PAGE_50 ((uint32_t)0x08019000) /* Base @ of Page 50, 2 Kbytes */
#define FLASH_ADDR_PAGE_51 ((uint32_t)0x08019800) /* Base @ of Page 51, 2 Kbytes */
#define FLASH_ADDR_PAGE_52 ((uint32_t)0x0801A000) /* Base @ of Page 52, 2 Kbytes */
#define FLASH_ADDR_PAGE_53 ((uint32_t)0x0801A800) /* Base @ of Page 53, 2 Kbytes */
#define FLASH_ADDR_PAGE_54 ((uint32_t)0x0801B000) /* Base @ of Page 54, 2 Kbytes */
#define FLASH_ADDR_PAGE_55 ((uint32_t)0x0801B800) /* Base @ of Page 55, 2 Kbytes */
#define FLASH_ADDR_PAGE_56 ((uint32_t)0x0801C000) /* Base @ of Page 56, 2 Kbytes */
#define FLASH_ADDR_PAGE_57 ((uint32_t)0x0801C800) /* Base @ of Page 57, 2 Kbytes */
#define FLASH_ADDR_PAGE_58 ((uint32_t)0x0801D000) /* Base @ of Page 58, 2 Kbytes */
#define FLASH_ADDR_PAGE_59 ((uint32_t)0x0801D800) /* Base @ of Page 59, 2 Kbytes */
#define FLASH_ADDR_PAGE_60 ((uint32_t)0x0801E000) /* Base @ of Page 60, 2 Kbytes */
#define FLASH_ADDR_PAGE_61 ((uint32_t)0x0801E800) /* Base @ of Page 61, 2 Kbytes */
#define FLASH_ADDR_PAGE_62 ((uint32_t)0x0801F000) /* Base @ of Page 62, 2 Kbytes */
#define FLASH_ADDR_PAGE_63 ((uint32_t)0x0801F800) /* Base @ of Page 63, 2 Kbytes */
#define FLASH_ADDR_PAGE_64 ((uint32_t)0x08020000) /* Base @ of Page 64, 2 Kbytes */
#define FLASH_ADDR_PAGE_65 ((uint32_t)0x08020800) /* Base @ of Page 65, 2 Kbytes */
#define FLASH_ADDR_PAGE_66 ((uint32_t)0x08021000) /* Base @ of Page 66, 2 Kbytes */
#define FLASH_ADDR_PAGE_67 ((uint32_t)0x08021800) /* Base @ of Page 67, 2 Kbytes */
#define FLASH_ADDR_PAGE_68 ((uint32_t)0x08022000) /* Base @ of Page 68, 2 Kbytes */
#define FLASH_ADDR_PAGE_69 ((uint32_t)0x08022800) /* Base @ of Page 69, 2 Kbytes */
#define FLASH_ADDR_PAGE_70 ((uint32_t)0x08023000) /* Base @ of Page 70, 2 Kbytes */
#define FLASH_ADDR_PAGE_71 ((uint32_t)0x08023800) /* Base @ of Page 71, 2 Kbytes */
#define FLASH_ADDR_PAGE_72 ((uint32_t)0x08024000) /* Base @ of Page 72, 2 Kbytes */
#define FLASH_ADDR_PAGE_73 ((uint32_t)0x08024800) /* Base @ of Page 73, 2 Kbytes */
#define FLASH_ADDR_PAGE_74 ((uint32_t)0x08025000) /* Base @ of Page 74, 2 Kbytes */
#define FLASH_ADDR_PAGE_75 ((uint32_t)0x08025800) /* Base @ of Page 75, 2 Kbytes */
#define FLASH_ADDR_PAGE_76 ((uint32_t)0x08026000) /* Base @ of Page 76, 2 Kbytes */
#define FLASH_ADDR_PAGE_77 ((uint32_t)0x08026800) /* Base @ of Page 77, 2 Kbytes */
#define FLASH_ADDR_PAGE_78 ((uint32_t)0x08027000) /* Base @ of Page 78, 2 Kbytes */
#define FLASH_ADDR_PAGE_79 ((uint32_t)0x08027800) /* Base @ of Page 79, 2 Kbytes */
#define FLASH_ADDR_PAGE_80 ((uint32_t)0x08028000) /* Base @ of Page 80, 2 Kbytes */
#define FLASH_ADDR_PAGE_81 ((uint32_t)0x08028800) /* Base @ of Page 81, 2 Kbytes */
#define FLASH_ADDR_PAGE_82 ((uint32_t)0x08029000) /* Base @ of Page 82, 2 Kbytes */
#define FLASH_ADDR_PAGE_83 ((uint32_t)0x08029800) /* Base @ of Page 83, 2 Kbytes */
#define FLASH_ADDR_PAGE_84 ((uint32_t)0x0802A000) /* Base @ of Page 84, 2 Kbytes */
#define FLASH_ADDR_PAGE_85 ((uint32_t)0x0802A800) /* Base @ of Page 85, 2 Kbytes */
#define FLASH_ADDR_PAGE_86 ((uint32_t)0x0802B000) /* Base @ of Page 86, 2 Kbytes */
#define FLASH_ADDR_PAGE_87 ((uint32_t)0x0802B800) /* Base @ of Page 87, 2 Kbytes */
#define FLASH_ADDR_PAGE_88 ((uint32_t)0x0802C000) /* Base @ of Page 88, 2 Kbytes */
#define FLASH_ADDR_PAGE_89 ((uint32_t)0x0802C800) /* Base @ of Page 89, 2 Kbytes */
#define FLASH_ADDR_PAGE_90 ((uint32_t)0x0802D000) /* Base @ of Page 90, 2 Kbytes */
#define FLASH_ADDR_PAGE_91 ((uint32_t)0x0802D800) /* Base @ of Page 91, 2 Kbytes */
#define FLASH_ADDR_PAGE_92 ((uint32_t)0x0802E000) /* Base @ of Page 92, 2 Kbytes */
#define FLASH_ADDR_PAGE_93 ((uint32_t)0x0802E800) /* Base @ of Page 93, 2 Kbytes */
#define FLASH_ADDR_PAGE_94 ((uint32_t)0x0802F000) /* Base @ of Page 94, 2 Kbytes */
#define FLASH_ADDR_PAGE_95 ((uint32_t)0x0802F800) /* Base @ of Page 95, 2 Kbytes */
#define FLASH_ADDR_PAGE_96 ((uint32_t)0x08030000) /* Base @ of Page 96, 2 Kbytes */
#define FLASH_ADDR_PAGE_97 ((uint32_t)0x08030800) /* Base @ of Page 97, 2 Kbytes */
#define FLASH_ADDR_PAGE_98 ((uint32_t)0x08031000) /* Base @ of Page 98, 2 Kbytes */
#define FLASH_ADDR_PAGE_99 ((uint32_t)0x08031800) /* Base @ of Page 99, 2 Kbytes */
#define FLASH_ADDR_PAGE_100 ((uint32_t)0x08032000) /* Base @ of Page 100, 2 Kbytes */
#define FLASH_ADDR_PAGE_101 ((uint32_t)0x08032800) /* Base @ of Page 101, 2 Kbytes */
#define FLASH_ADDR_PAGE_102 ((uint32_t)0x08033000) /* Base @ of Page 102, 2 Kbytes */
#define FLASH_ADDR_PAGE_103 ((uint32_t)0x08033800) /* Base @ of Page 103, 2 Kbytes */
#define FLASH_ADDR_PAGE_104 ((uint32_t)0x08034000) /* Base @ of Page 104, 2 Kbytes */
#define FLASH_ADDR_PAGE_105 ((uint32_t)0x08034800) /* Base @ of Page 105, 2 Kbytes */
#define FLASH_ADDR_PAGE_106 ((uint32_t)0x08035000) /* Base @ of Page 106, 2 Kbytes */
#define FLASH_ADDR_PAGE_107 ((uint32_t)0x08035800) /* Base @ of Page 107, 2 Kbytes */
#define FLASH_ADDR_PAGE_108 ((uint32_t)0x08036000) /* Base @ of Page 108, 2 Kbytes */
#define FLASH_ADDR_PAGE_109 ((uint32_t)0x08036800) /* Base @ of Page 109, 2 Kbytes */
#define FLASH_ADDR_PAGE_110 ((uint32_t)0x08037000) /* Base @ of Page 110, 2 Kbytes */
#define FLASH_ADDR_PAGE_111 ((uint32_t)0x08037800) /* Base @ of Page 111, 2 Kbytes */
#define FLASH_ADDR_PAGE_112 ((uint32_t)0x08038000) /* Base @ of Page 112, 2 Kbytes */
#define FLASH_ADDR_PAGE_113 ((uint32_t)0x08038800) /* Base @ of Page 113, 2 Kbytes */
#define FLASH_ADDR_PAGE_114 ((uint32_t)0x08039000) /* Base @ of Page 114, 2 Kbytes */
#define FLASH_ADDR_PAGE_115 ((uint32_t)0x08039800) /* Base @ of Page 115, 2 Kbytes */
#define FLASH_ADDR_PAGE_116 ((uint32_t)0x0803A000) /* Base @ of Page 116, 2 Kbytes */
#define FLASH_ADDR_PAGE_117 ((uint32_t)0x0803A800) /* Base @ of Page 117, 2 Kbytes */
#define FLASH_ADDR_PAGE_118 ((uint32_t)0x0803B000) /* Base @ of Page 118, 2 Kbytes */
#define FLASH_ADDR_PAGE_119 ((uint32_t)0x0803B800) /* Base @ of Page 119, 2 Kbytes */
#define FLASH_ADDR_PAGE_120 ((uint32_t)0x0803C000) /* Base @ of Page 120, 2 Kbytes */
#define FLASH_ADDR_PAGE_121 ((uint32_t)0x0803C800) /* Base @ of Page 121, 2 Kbytes */
#define FLASH_ADDR_PAGE_122 ((uint32_t)0x0803D000) /* Base @ of Page 122, 2 Kbytes */
#define FLASH_ADDR_PAGE_123 ((uint32_t)0x0803D800) /* Base @ of Page 123, 2 Kbytes */
#define FLASH_ADDR_PAGE_124 ((uint32_t)0x0803E000) /* Base @ of Page 124, 2 Kbytes */
#define FLASH_ADDR_PAGE_125 ((uint32_t)0x0803E800) /* Base @ of Page 125, 2 Kbytes */
#define FLASH_ADDR_PAGE_126 ((uint32_t)0x0803F000) /* Base @ of Page 126, 2 Kbytes */
#define FLASH_ADDR_PAGE_127 ((uint32_t)0x0803F800) /* Base @ of Page 127, 2 Kbytes */
/**
* @brief Base address of the Flash pages under dual bank mode for category 3 devices Bank 2
* Dual bank mode(2KB each page)
* For 256KB devices: from page 0 to page 63
* For 128KB devices: from page 0 to page 31
* Single bank mode(4KB each page)
* For 256KB devices: from page 0 to page 63
* For 128KB devices: from page 0 to page 31
*/
#define FLASH_ADDR_PAGE_128 ((uint32_t)0x08040000) /* Base @ of Page 128, 2 Kbytes */
#define FLASH_ADDR_PAGE_129 ((uint32_t)0x08040800) /* Base @ of Page 129, 2 Kbytes */
#define FLASH_ADDR_PAGE_130 ((uint32_t)0x08041000) /* Base @ of Page 130, 2 Kbytes */
#define FLASH_ADDR_PAGE_131 ((uint32_t)0x08041800) /* Base @ of Page 131, 2 Kbytes */
#define FLASH_ADDR_PAGE_132 ((uint32_t)0x08042000) /* Base @ of Page 132, 2 Kbytes */
#define FLASH_ADDR_PAGE_133 ((uint32_t)0x08042800) /* Base @ of Page 133, 2 Kbytes */
#define FLASH_ADDR_PAGE_134 ((uint32_t)0x08043000) /* Base @ of Page 134, 2 Kbytes */
#define FLASH_ADDR_PAGE_135 ((uint32_t)0x08043800) /* Base @ of Page 135, 2 Kbytes */
#define FLASH_ADDR_PAGE_136 ((uint32_t)0x08044000) /* Base @ of Page 136, 2 Kbytes */
#define FLASH_ADDR_PAGE_137 ((uint32_t)0x08044800) /* Base @ of Page 137, 2 Kbytes */
#define FLASH_ADDR_PAGE_138 ((uint32_t)0x08045000) /* Base @ of Page 138, 2 Kbytes */
#define FLASH_ADDR_PAGE_139 ((uint32_t)0x08045800) /* Base @ of Page 139, 2 Kbytes */
#define FLASH_ADDR_PAGE_140 ((uint32_t)0x08046000) /* Base @ of Page 140, 2 Kbytes */
#define FLASH_ADDR_PAGE_141 ((uint32_t)0x08046800) /* Base @ of Page 141, 2 Kbytes */
#define FLASH_ADDR_PAGE_142 ((uint32_t)0x08047000) /* Base @ of Page 142, 2 Kbytes */
#define FLASH_ADDR_PAGE_143 ((uint32_t)0x08047800) /* Base @ of Page 143, 2 Kbytes */
#define FLASH_ADDR_PAGE_144 ((uint32_t)0x08048000) /* Base @ of Page 144, 2 Kbytes */
#define FLASH_ADDR_PAGE_145 ((uint32_t)0x08048800) /* Base @ of Page 145, 2 Kbytes */
#define FLASH_ADDR_PAGE_146 ((uint32_t)0x08049000) /* Base @ of Page 146, 2 Kbytes */
#define FLASH_ADDR_PAGE_147 ((uint32_t)0x08049800) /* Base @ of Page 147, 2 Kbytes */
#define FLASH_ADDR_PAGE_148 ((uint32_t)0x0804a000) /* Base @ of Page 148, 2 Kbytes */
#define FLASH_ADDR_PAGE_149 ((uint32_t)0x0804a800) /* Base @ of Page 149, 2 Kbytes */
#define FLASH_ADDR_PAGE_150 ((uint32_t)0x0804b000) /* Base @ of Page 150, 2 Kbytes */
#define FLASH_ADDR_PAGE_151 ((uint32_t)0x0804b800) /* Base @ of Page 151, 2 Kbytes */
#define FLASH_ADDR_PAGE_152 ((uint32_t)0x0804c000) /* Base @ of Page 152, 2 Kbytes */
#define FLASH_ADDR_PAGE_153 ((uint32_t)0x0804c800) /* Base @ of Page 153, 2 Kbytes */
#define FLASH_ADDR_PAGE_154 ((uint32_t)0x0804d000) /* Base @ of Page 154, 2 Kbytes */
#define FLASH_ADDR_PAGE_155 ((uint32_t)0x0804d800) /* Base @ of Page 155, 2 Kbytes */
#define FLASH_ADDR_PAGE_156 ((uint32_t)0x0804e000) /* Base @ of Page 156, 2 Kbytes */
#define FLASH_ADDR_PAGE_157 ((uint32_t)0x0804e800) /* Base @ of Page 157, 2 Kbytes */
#define FLASH_ADDR_PAGE_158 ((uint32_t)0x0804f000) /* Base @ of Page 158, 2 Kbytes */
#define FLASH_ADDR_PAGE_159 ((uint32_t)0x0804f800) /* Base @ of Page 159, 2 Kbytes */
#define FLASH_ADDR_PAGE_160 ((uint32_t)0x08050000) /* Base @ of Page 160, 2 Kbytes */
#define FLASH_ADDR_PAGE_161 ((uint32_t)0x08050800) /* Base @ of Page 161, 2 Kbytes */
#define FLASH_ADDR_PAGE_162 ((uint32_t)0x08051000) /* Base @ of Page 162, 2 Kbytes */
#define FLASH_ADDR_PAGE_163 ((uint32_t)0x08051800) /* Base @ of Page 163, 2 Kbytes */
#define FLASH_ADDR_PAGE_164 ((uint32_t)0x08052000) /* Base @ of Page 164, 2 Kbytes */
#define FLASH_ADDR_PAGE_165 ((uint32_t)0x08052800) /* Base @ of Page 165, 2 Kbytes */
#define FLASH_ADDR_PAGE_166 ((uint32_t)0x08053000) /* Base @ of Page 166, 2 Kbytes */
#define FLASH_ADDR_PAGE_167 ((uint32_t)0x08053800) /* Base @ of Page 167, 2 Kbytes */
#define FLASH_ADDR_PAGE_168 ((uint32_t)0x08054000) /* Base @ of Page 168, 2 Kbytes */
#define FLASH_ADDR_PAGE_169 ((uint32_t)0x08054800) /* Base @ of Page 169, 2 Kbytes */
#define FLASH_ADDR_PAGE_170 ((uint32_t)0x08055000) /* Base @ of Page 170, 2 Kbytes */
#define FLASH_ADDR_PAGE_171 ((uint32_t)0x08055800) /* Base @ of Page 171, 2 Kbytes */
#define FLASH_ADDR_PAGE_172 ((uint32_t)0x08056000) /* Base @ of Page 172, 2 Kbytes */
#define FLASH_ADDR_PAGE_173 ((uint32_t)0x08056800) /* Base @ of Page 173, 2 Kbytes */
#define FLASH_ADDR_PAGE_174 ((uint32_t)0x08057000) /* Base @ of Page 174, 2 Kbytes */
#define FLASH_ADDR_PAGE_175 ((uint32_t)0x08057800) /* Base @ of Page 175, 2 Kbytes */
#define FLASH_ADDR_PAGE_176 ((uint32_t)0x08058000) /* Base @ of Page 176, 2 Kbytes */
#define FLASH_ADDR_PAGE_177 ((uint32_t)0x08058800) /* Base @ of Page 177, 2 Kbytes */
#define FLASH_ADDR_PAGE_178 ((uint32_t)0x08059000) /* Base @ of Page 178, 2 Kbytes */
#define FLASH_ADDR_PAGE_179 ((uint32_t)0x08059800) /* Base @ of Page 179, 2 Kbytes */
#define FLASH_ADDR_PAGE_180 ((uint32_t)0x0805a000) /* Base @ of Page 180, 2 Kbytes */
#define FLASH_ADDR_PAGE_181 ((uint32_t)0x0805a800) /* Base @ of Page 181, 2 Kbytes */
#define FLASH_ADDR_PAGE_182 ((uint32_t)0x0805b000) /* Base @ of Page 182, 2 Kbytes */
#define FLASH_ADDR_PAGE_183 ((uint32_t)0x0805b800) /* Base @ of Page 183, 2 Kbytes */
#define FLASH_ADDR_PAGE_184 ((uint32_t)0x0805c000) /* Base @ of Page 184, 2 Kbytes */
#define FLASH_ADDR_PAGE_185 ((uint32_t)0x0805c800) /* Base @ of Page 185, 2 Kbytes */
#define FLASH_ADDR_PAGE_186 ((uint32_t)0x0805d000) /* Base @ of Page 186, 2 Kbytes */
#define FLASH_ADDR_PAGE_187 ((uint32_t)0x0805d800) /* Base @ of Page 187, 2 Kbytes */
#define FLASH_ADDR_PAGE_188 ((uint32_t)0x0805e000) /* Base @ of Page 188, 2 Kbytes */
#define FLASH_ADDR_PAGE_189 ((uint32_t)0x0805e800) /* Base @ of Page 189, 2 Kbytes */
#define FLASH_ADDR_PAGE_190 ((uint32_t)0x0805f000) /* Base @ of Page 190, 2 Kbytes */
#define FLASH_ADDR_PAGE_191 ((uint32_t)0x0805f800) /* Base @ of Page 191, 2 Kbytes */
#define FLASH_ADDR_PAGE_192 ((uint32_t)0x08060000) /* Base @ of Page 192, 2 Kbytes */
#define FLASH_ADDR_PAGE_193 ((uint32_t)0x08060800) /* Base @ of Page 193, 2 Kbytes */
#define FLASH_ADDR_PAGE_194 ((uint32_t)0x08061000) /* Base @ of Page 194, 2 Kbytes */
#define FLASH_ADDR_PAGE_195 ((uint32_t)0x08061800) /* Base @ of Page 195, 2 Kbytes */
#define FLASH_ADDR_PAGE_196 ((uint32_t)0x08062000) /* Base @ of Page 196, 2 Kbytes */
#define FLASH_ADDR_PAGE_197 ((uint32_t)0x08062800) /* Base @ of Page 197, 2 Kbytes */
#define FLASH_ADDR_PAGE_198 ((uint32_t)0x08063000) /* Base @ of Page 198, 2 Kbytes */
#define FLASH_ADDR_PAGE_199 ((uint32_t)0x08063800) /* Base @ of Page 199, 2 Kbytes */
#define FLASH_ADDR_PAGE_200 ((uint32_t)0x08064000) /* Base @ of Page 200, 2 Kbytes */
#define FLASH_ADDR_PAGE_201 ((uint32_t)0x08064800) /* Base @ of Page 201, 2 Kbytes */
#define FLASH_ADDR_PAGE_202 ((uint32_t)0x08065000) /* Base @ of Page 202, 2 Kbytes */
#define FLASH_ADDR_PAGE_203 ((uint32_t)0x08065800) /* Base @ of Page 203, 2 Kbytes */
#define FLASH_ADDR_PAGE_204 ((uint32_t)0x08066000) /* Base @ of Page 204, 2 Kbytes */
#define FLASH_ADDR_PAGE_205 ((uint32_t)0x08066800) /* Base @ of Page 205, 2 Kbytes */
#define FLASH_ADDR_PAGE_206 ((uint32_t)0x08067000) /* Base @ of Page 206, 2 Kbytes */
#define FLASH_ADDR_PAGE_207 ((uint32_t)0x08067800) /* Base @ of Page 207, 2 Kbytes */
#define FLASH_ADDR_PAGE_208 ((uint32_t)0x08068000) /* Base @ of Page 208, 2 Kbytes */
#define FLASH_ADDR_PAGE_209 ((uint32_t)0x08068800) /* Base @ of Page 209, 2 Kbytes */
#define FLASH_ADDR_PAGE_210 ((uint32_t)0x08069000) /* Base @ of Page 210, 2 Kbytes */
#define FLASH_ADDR_PAGE_211 ((uint32_t)0x08069800) /* Base @ of Page 211, 2 Kbytes */
#define FLASH_ADDR_PAGE_212 ((uint32_t)0x0806a000) /* Base @ of Page 212, 2 Kbytes */
#define FLASH_ADDR_PAGE_213 ((uint32_t)0x0806a800) /* Base @ of Page 213, 2 Kbytes */
#define FLASH_ADDR_PAGE_214 ((uint32_t)0x0806b000) /* Base @ of Page 214, 2 Kbytes */
#define FLASH_ADDR_PAGE_215 ((uint32_t)0x0806b800) /* Base @ of Page 215, 2 Kbytes */
#define FLASH_ADDR_PAGE_216 ((uint32_t)0x0806c000) /* Base @ of Page 216, 2 Kbytes */
#define FLASH_ADDR_PAGE_217 ((uint32_t)0x0806c800) /* Base @ of Page 217, 2 Kbytes */
#define FLASH_ADDR_PAGE_218 ((uint32_t)0x0806d000) /* Base @ of Page 218, 2 Kbytes */
#define FLASH_ADDR_PAGE_219 ((uint32_t)0x0806d800) /* Base @ of Page 219, 2 Kbytes */
#define FLASH_ADDR_PAGE_220 ((uint32_t)0x0806e000) /* Base @ of Page 220, 2 Kbytes */
#define FLASH_ADDR_PAGE_221 ((uint32_t)0x0806e800) /* Base @ of Page 221, 2 Kbytes */
#define FLASH_ADDR_PAGE_222 ((uint32_t)0x0806f000) /* Base @ of Page 222, 2 Kbytes */
#define FLASH_ADDR_PAGE_223 ((uint32_t)0x0806f800) /* Base @ of Page 223, 2 Kbytes */
#define FLASH_ADDR_PAGE_224 ((uint32_t)0x08070000) /* Base @ of Page 224, 2 Kbytes */
#define FLASH_ADDR_PAGE_225 ((uint32_t)0x08070800) /* Base @ of Page 225, 2 Kbytes */
#define FLASH_ADDR_PAGE_226 ((uint32_t)0x08071000) /* Base @ of Page 226, 2 Kbytes */
#define FLASH_ADDR_PAGE_227 ((uint32_t)0x08071800) /* Base @ of Page 227, 2 Kbytes */
#define FLASH_ADDR_PAGE_228 ((uint32_t)0x08072000) /* Base @ of Page 228, 2 Kbytes */
#define FLASH_ADDR_PAGE_229 ((uint32_t)0x08072800) /* Base @ of Page 229, 2 Kbytes */
#define FLASH_ADDR_PAGE_230 ((uint32_t)0x08073000) /* Base @ of Page 230, 2 Kbytes */
#define FLASH_ADDR_PAGE_231 ((uint32_t)0x08073800) /* Base @ of Page 231, 2 Kbytes */
#define FLASH_ADDR_PAGE_232 ((uint32_t)0x08074000) /* Base @ of Page 232, 2 Kbytes */
#define FLASH_ADDR_PAGE_233 ((uint32_t)0x08074800) /* Base @ of Page 233, 2 Kbytes */
#define FLASH_ADDR_PAGE_234 ((uint32_t)0x08075000) /* Base @ of Page 234, 2 Kbytes */
#define FLASH_ADDR_PAGE_235 ((uint32_t)0x08075800) /* Base @ of Page 235, 2 Kbytes */
#define FLASH_ADDR_PAGE_236 ((uint32_t)0x08076000) /* Base @ of Page 236, 2 Kbytes */
#define FLASH_ADDR_PAGE_237 ((uint32_t)0x08076800) /* Base @ of Page 237, 2 Kbytes */
#define FLASH_ADDR_PAGE_238 ((uint32_t)0x08077000) /* Base @ of Page 238, 2 Kbytes */
#define FLASH_ADDR_PAGE_239 ((uint32_t)0x08077800) /* Base @ of Page 239, 2 Kbytes */
#define FLASH_ADDR_PAGE_240 ((uint32_t)0x08078000) /* Base @ of Page 240, 2 Kbytes */
#define FLASH_ADDR_PAGE_241 ((uint32_t)0x08078800) /* Base @ of Page 241, 2 Kbytes */
#define FLASH_ADDR_PAGE_242 ((uint32_t)0x08079000) /* Base @ of Page 242, 2 Kbytes */
#define FLASH_ADDR_PAGE_243 ((uint32_t)0x08079800) /* Base @ of Page 243, 2 Kbytes */
#define FLASH_ADDR_PAGE_244 ((uint32_t)0x0807a000) /* Base @ of Page 244, 2 Kbytes */
#define FLASH_ADDR_PAGE_245 ((uint32_t)0x0807a800) /* Base @ of Page 245, 2 Kbytes */
#define FLASH_ADDR_PAGE_246 ((uint32_t)0x0807b000) /* Base @ of Page 246, 2 Kbytes */
#define FLASH_ADDR_PAGE_247 ((uint32_t)0x0807b800) /* Base @ of Page 247, 2 Kbytes */
#define FLASH_ADDR_PAGE_248 ((uint32_t)0x0807c000) /* Base @ of Page 248, 2 Kbytes */
#define FLASH_ADDR_PAGE_249 ((uint32_t)0x0807c800) /* Base @ of Page 249, 2 Kbytes */
#define FLASH_ADDR_PAGE_250 ((uint32_t)0x0807d000) /* Base @ of Page 250, 2 Kbytes */
#define FLASH_ADDR_PAGE_251 ((uint32_t)0x0807d800) /* Base @ of Page 251, 2 Kbytes */
#define FLASH_ADDR_PAGE_252 ((uint32_t)0x0807e000) /* Base @ of Page 252, 2 Kbytes */
#define FLASH_ADDR_PAGE_253 ((uint32_t)0x0807e800) /* Base @ of Page 253, 2 Kbytes */
#define FLASH_ADDR_PAGE_254 ((uint32_t)0x0807f000) /* Base @ of Page 254, 2 Kbytes */
#define FLASH_ADDR_PAGE_255 ((uint32_t)0x0807f800) /* Base @ of Page 255, 2 Kbytes */
/**
* @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 /*!> 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)
#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))
/**
* @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);
uint32_t FLASH_GetAddrPageIdx(uint32_t Addr);
uint32_t FLASH_GetAddrPageOffset(uint32_t StartAddr, uint32_t EndAddr);
uint32_t FLASH_GetAddrPageBank(uint32_t Addr);
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_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 -------------------------------------------------------------*/
/* 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 Gets the page index of a given address
* @param Addr: Address of the FLASH Memory
* @retval The page index of a given address
*/
uint32_t FLASH_GetAddrPageIdx(uint32_t Addr)
{
uint32_t PageIdx = 0;
if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))
{
/* Bank 1 */
PageIdx = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
}
else
{
/* Bank 2 */
PageIdx = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
}
return PageIdx;
}
/**
* @brief Gets the bank of a given address
* @param Addr: Address of the FLASH Memory
* @retval The bank of a given address
*/
uint32_t FLASH_GetAddrPageBank(uint32_t Addr)
{
if (Addr < (FLASH_BASE + FLASH_BANK_SIZE))
{
/* Bank 1 */
return FLASH_BANK_1;
}
else
{
/* Bank 2 */
return FLASH_BANK_2;
}
}
/**
* @brief Gets the page index offset of the given address
* @param StartAddr: Address of the FLASH Memory
* @param EndAddr: Address of the FLASH Memory
* @retval The page index offset of the given address
*/
uint32_t FLASH_GetAddrPageOffset(uint32_t StartAddr, uint32_t EndAddr)
{
uint32_t PageNum = 0;
PageNum = FLASH_GetAddrPageIdx(EndAddr) - FLASH_GetAddrPageIdx(StartAddr) + 1;
return PageNum;
}
/**
* @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);
}
上面是我修改的HAL库Flash驱动,大部分功能还没有验证,希望大家帮忙测试,提出问题,一起完善。
下面给出我的结构体读写程序,因为是项目里的,我就不全部放出来了,大家按需修改,我是参考官方flash擦除编程的DEMO,因为只支持双字写入,稍稍花了点时间。本着授人以鱼不如授人以渔的态度,希望大家自己修改,复制粘贴学不到啥东西,共勉。有错误,或者有更好的代码,希望大家也教教我,学无止境。就比如判断写入是否正常那里,我试了直接读取和比较内存空间2种方法,应该是都可以的,因为我读配置也是这样读上来的。我不喜欢设置粉丝可见,如果觉得有用,点个赞或者点个收藏,谢谢啦。
#define PID_CFG_FLASH_ADDR_START FLASH_ADDR_PAGE_31 // Page31 in DBANK mode
#define PID_CFG_FLASH_ADDR_END (FLASH_ADDR_PAGE_31 + FLASH_PAGE_SIZE - 1U) // 1Page 2KB
#define PID_CFG_FLASH_PAGE_IDX 31U
#define PID_CFG_FLASH_PAGE_NUM 1U
#define PID_CFG_STRUCT_SIZE64 (sizeof(PID_ObjectTypeDef) % 8U ? \
sizeof(PID_ObjectTypeDef) / 8U : \
sizeof(PID_ObjectTypeDef) / 8U + 1)
typedef struct
{
float P;
float I;
float D;
int ILimitMIN;
int ILimitMAX;
int ISeparate;
int Accuracy;
int Mode;
int Waveform;
int Enable;
int OutputMAX;
int OutputMED;
int OutputMIN;
int OutputInterval;
int OutputPolarity;
int SPInputMAX;
int SPInputMIN;
int FBInputMAX;
int FBInputMIN;
int FilterMethod;
int FilterSampleNum;
int AnalogInputCH1;
int AnalogInputCH2;
int AnalogOutput;
int DigitalInputCH1;
int DigitalInputCH2;
int DigitalOutputCH1;
int DigitalOutputCH2;
} PID_ObjectTypeDef;
int PID_CntlrConfigSave(void)
{
int Ret = ERROR;
uint8_t Idx = 0;
uint32_t PageErr = 0;
uint32_t WriteAddr = PID_CFG_FLASH_ADDR_START;
FLASH_EraseInitTypeDef FlashErase =
{
.TypeErase = FLASH_TYPEERASE_PAGES,
.Banks = FLASH_BANK_1,
.Page = PID_CFG_FLASH_PAGE_IDX,
.NbPages = PID_CFG_FLASH_PAGE_NUM,
// .Banks = FLASH_GetAddrPageBank(PID_CFG_FLASH_ADDR_START),
// .Page = FLASH_GetAddrPageIdx(PID_CFG_FLASH_ADDR_START),
// .NbPages = FLASH_GetAddrPageOffset(PID_CFG_FLASH_ADDR_START, PID_CFG_FLASH_ADDR_END),
};
/* Unlock the Flash to enable the flash control register access *************/
FLASH_Unlock();
/* Clear OPTVERR bit set on virgin samples */
FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
/* Erase the user Flash area
(area defined by PID_CFG_FLASH_ADDR_START and PID_CFG_FLASH_ADDR_END) *******/
/* Note: If an erase operation in Flash memory also concerns data in the data or instruction cache,
you have to make sure that these data are rewritten before they are accessed during code
execution. If this cannot be done safely, it is recommended to flush the caches by setting the
DCRST and ICRST bits in the FLASH_CR register. */
if (FLASH_Erase(&FlashErase, &PageErr) != FLASH_OK)
{
/*
Error occurred while page erase.
User can add here some code to deal with this error.
PageError will contain the faulty page and then to know the code error on this page,
user can call function 'FLASH_GetError()'
*/
PID_LOG_PRINT("Flash erase error code: %x, page: %x.\r\n", FLASH_GetError(), PageErr);
FLASH_Lock();
return Ret;
}
/* Program the user Flash area word by word
(area defined by PID_CFG_FLASH_ADDR_START and PID_CFG_FLASH_ADDR_END) *******/
for (Idx = 0; Idx < PID_CFG_STRUCT_SIZE64; Idx++)
{
if (FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, WriteAddr, *((uint64_t *)&PID + Idx)) != FLASH_OK)
{
/* Error occurred while writing data in Flash memory.
User can add here some code to deal with this error */
FLASH_Lock();
return Ret;
}
WriteAddr += 8; /* Increment to next double word*/
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
FLASH_Lock();
/* Check if the programmed data is OK*/
// PID_ObjectTypeDef PIDTmp = *(__IO PID_ObjectTypeDef *)ReadAddr;
if (!memcmp(&PID, (uint32_t *)PID_CFG_FLASH_ADDR_START, sizeof(PID_ObjectTypeDef)))
{
Ret = SUCCESS;
}
return Ret;
}