STM32专题系列之二十九:Flash读写保护机制详解
设置Flash的读写保护,其实就是操作内部Flash的选项字节
RDP 读保护
修改选项字节的 RDP 位的值可设置内部 FLASH 为以下保护级别:
读保护的解除,必须要上电复位才可以。
WRP 写保护
1 设置写保护
写保护的配置一般以 4K 字节为单位,除 WRP3 的最后一位比较特殊外,每个WRP 选项字节的一位用于控制 4K 字节的写访问权限, 把对应 WRP 的位置 0 即可把它匹配的空间加入写保护。被设置成写保护后,主 FLASH 中的内容使用任何方式都不能被擦除和写入,写保护不会影响读访问权限,读访问权限完全由前面介绍的读保护设置限制。
2 解除写保护
解除写保护是逆过程,把对应 WRP 的位置 1 即可把它匹配的空间解除写保护。解除写保护后,主 FLASH 中的内容不会像解读保护那样丢失,它会被原样保留。
修改选项字节的过程
Flash_CR寄存器,操作选项字节的位描述:
操作选项字节的库函数:
结构体和宏定义:
/**
* @brief Option Bytes Registers
*/
typedef struct
{
__IO uint16_t RDP;
__IO uint16_t USER;
__IO uint16_t Data0;
__IO uint16_t Data1;
__IO uint16_t WRP0;
__IO uint16_t WRP1;
__IO uint16_t WRP2;
__IO uint16_t WRP3;
} OB_TypeDef;
#define OB ((OB_TypeDef *) OB_BASE)
#define OB_BASE ((uint32_t)0x1FFFF800) /*!< Flash Option Bytes base address */
设置Flash写保护使能函数:
/* 掩码 */
#define RDPRT_Mask ((uint32_t)0x00000002)
#define WRP0_Mask ((uint32_t)0x000000FF)
#define WRP1_Mask ((uint32_t)0x0000FF00)
#define WRP2_Mask ((uint32_t)0x00FF0000)
#define WRP3_Mask ((uint32_t)0xFF000000)
/* 大容量产品页保护的宏定义,每位控制 4K 字节(2 页) */
#define FLASH_WRProt_Pages0to1 ((uint32_t)0x00000001)
#define FLASH_WRProt_Pages2to3 ((uint32_t)0x00000002)
#define FLASH_WRProt_Pages4to5 ((uint32_t)0x00000004)
#define FLASH_WRProt_Pages6to7 ((uint32_t)0x00000008)
/*..部分省略*/
/*!< 特殊位,最后一位,页 62 至 511 */
#define FLASH_WRProt_Pages62to511 ((uint32_t)0x80000000)
/*保护所有页*/
#define FLASH_WRProt_AllPages ((uint32_t)0xFFFFFFFF)
/**
* @brief 对指定的页设置写保护
* @param FLASH_Pages: 指定要设置写保护的页.
* 可输入参数:
* STM32 大容量产品: FLASH_WRProt_Pages0to1 至 FLASH_WRProt_Pages60to61
* 或 FLASH_WRProt_Pages62to255 和 FLASH_WRProt_AllPages
* @retval FLASH Status:
* 可能的返回值: FLASH_ERROR_PG, FLASH_ERROR_WRP,
FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages)
{
uint16_t WRP0_Data = 0xFFFF, WRP1_Data = 0xFFFF,
P2_Data = 0xFFFF, WRP3_Data = 0xFFFF;
FLASH_Status status = FLASH_COMPLETE;
/* 检查参数 */
assert_param(IS_FLASH_WRPROT_PAGE(FLASH_Pages));
/*根据输入计算要设置的值*/
FLASH_Pages = (uint32_t)(~FLASH_Pages);
WRP0_Data = (uint16_t)(FLASH_Pages & WRP0_Mask);
WRP1_Data = (uint16_t)((FLASH_Pages & WRP1_Mask) >> 8);
WRP2_Data = (uint16_t)((FLASH_Pages & WRP2_Mask) >> 16);
WRP3_Data = (uint16_t)((FLASH_Pages & WRP3_Mask) >> 24);
/* 等待上一次操作完毕 */
status = FLASH_WaitForLastOperation(ProgramTimeout);
if (status == FLASH_COMPLETE) {
/* 对选项字节进行解锁 */
FLASH->OPTKEYR = FLASH_KEY1;
FLASH->OPTKEYR = FLASH_KEY2;
FLASH->CR |= CR_OPTPG_Set; //准备写入选项字节
if (WRP0_Data != 0xFF) {
OB->WRP0 = WRP0_Data;
/* 等待上一次操作完毕 */
status = FLASH_WaitForLastOperation(ProgramTimeout);
}
if ((status == FLASH_COMPLETE) && (WRP1_Data != 0xFF)) {
OB->WRP1 = WRP1_Data;
status = FLASH_WaitForLastOperation(ProgramTimeout);
}
if ((status == FLASH_COMPLETE) && (WRP2_Data != 0xFF)) {
OB->WRP2 = WRP2_Data;
status = FLASH_WaitForLastOperation(ProgramTimeout);
}
if ((status == FLASH_COMPLETE)&& (WRP3_Data != 0xFF)) {
OB->WRP3 = WRP3_Data;
status = FLASH_WaitForLastOperation(ProgramTimeout);
}
if (status != FLASH_TIMEOUT) {
/* 若写入完成, 对选项字节重新上锁 */
FLASH->CR &= CR_OPTPG_Reset;
}
}
/* 返回设置结果 */
return status;
}
设置读保护及解除
#define RDP_Key ((uint16_t)0x00A5)
/**
* @brief 使能或关闭读保护
* @note 若芯片本身有对选项字节进行其它操作,
请先读出然后再重新写入,因为本函数会擦除所有选项字节的内容
* @param Newstate: 使能(ENABLE)或关闭(DISABLE)
* @retval FLASH Status: 可能的返回值: FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState)
{
FLASH_Status status = FLASH_COMPLETE;
/* 检查参数 */
assert_param(IS_FUNCTIONAL_STATE(NewState));
status = FLASH_WaitForLastOperation(EraseTimeout);
if (status == FLASH_COMPLETE) {
/* 写入选项字节解锁码 */
FLASH->OPTKEYR = FLASH_KEY1;
FLASH->OPTKEYR = FLASH_KEY2;
FLASH->CR |= CR_OPTER_Set; //擦除选项字节
FLASH->CR |= CR_STRT_Set; //开始擦除
/* 等待上一次操作完毕 */
status = FLASH_WaitForLastOperation(EraseTimeout);
29 if (status == FLASH_COMPLETE) {
/* 若擦除操作完成,复位 OPTER 位 */
FLASH->CR &= CR_OPTER_Reset;
/* 准备写入选项字节 */
FLASH->CR |= CR_OPTPG_Set;
if (NewState != DISABLE) {
OB->RDP = 0x00;//写入非 0xA5 值,进行读保护
} else {
OB->RDP = RDP_Key; //写入 0xA5,解除读保护
}
/* 等待上一次操作完毕 */
status = FLASH_WaitForLastOperation(EraseTimeout);
if (status != FLASH_TIMEOUT) {
/* 若操作完毕,复位 OPTPG 位 */
FLASH->CR &= CR_OPTPG_Reset;
}
} else {
if (status != FLASH_TIMEOUT) {
/* 复位 OPTER 位 */
FLASH->CR &= CR_OPTER_Reset;
}
}
}
/* 返回设置结果 */
return status;
}
作者:旧梦m