设置Flash的读写保护,其实就是操作内部Flash的选项字节。
选项字节在内部Flash的主存储页之后,由于是Flash,不能像内存RAM一样随意写入。由于Flash的写入特性,只能将 1 写成 0,而如果要确保写入数据的绝对正确,则需要先擦除再写入。如果直接对Flash写入,则只能确保写入 0 值是正确的。
选项字节,可以认为是掉电不会丢失的寄存器(Flash空间)。就是用Flash介质来存储配置,要修改选项字节,跟修改Flash一样。
RDP 读保护字节描述(可以通过j-link或st-link读Flash 加密等):
RDP配置方式:
2个数据字节 Data0 Data1
3 设置写保护
RDP 读保护
修改选项字节的 RDP 位的值可设置内部 FLASH 为以下保护级别:
读保护的解除,必须要上电复位才可以。
WRP 写保护
使用选项字节的 WRP0/1/2/3 可以设置主 FLASH 的写保护,防止它存储的程序内容被修改。
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 */
注意,这里的RDP定义成16位,但实际上的RDP只有8位。这里是把RDP和nRDP连续两个寄存器合起来。当向选项字节RDP写入时,stm32会把nRDP会自动取反并写入。
设置Flash写保护使能函数:
/* 宏定义,对应WRP寄存器的相应位 */
#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)
#define FLASH_WRProt_Pages8to9 ((uint32_t)0x00000010)
/* FLASH Mask 掩码,用于取出页码的对应位 */
#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)
/* 因为是 0 写保护,所以要对Flash页码来取反 */
FLASH_Pages = (uint32_t)(~FLASH_Pages);
/* 取出对应的WPR寄存器要写入的值,如果该页不写保护,则应该是0XFF */
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);
/* 没有先擦除选项字节,而是直接修改WRP寄存器的对应位,但是会存在一个问题,
Flash只能把1改写成0,因此写保护是能生效的。但是,如果想要解除某页的写保护,
无法使用这个函数,只能擦除选项字节 */
FLASH_EnableWriteProtection
/* 写保护所有页,直接0XFFFF FFFF,则取反后所有的位全为0,那么所有的WRP寄存器全部写入0 */
/* 解除写保护所有页,要先全部擦除选项字节,再0X0000 0000,取反后全为FFFF FFFF,那么所有
WPR寄存器全为1,都不设置写保护 */
注意,这里有对CR寄存器进行操作,因此要先对Flash进行解锁。
设置读保护FLASH_ReadOutProtection函数:
注意:在设置Flash读写保护时,一定要预留一个接口(串口 按键等都可以),来解除Flash的读写保护,不然很有可能导致芯片报废了。另外,由于Flash的特性,在操作Flash之前,最好先进行擦除操作,不然可能会设置出错。
示例:利用按键功能,来设置 / 解除 读写保护
写保护例程:
**
* @brief 反转写保护的配置,用于演示
若芯片处于写保护状态,则解除,
若不是写保护状态,则设置成写保护
* @param 无
* @retval 无
*/
void WriteProtect_Toggle(void)
{
/* 获取写保护寄存器的值进行判断,寄存器位为0表示有保护,为1表示无保护 */
/* 若不等于0xFFFFFFFF,则说明有部分页被写保护了 */
if(FLASH_GetWriteProtectionOptionByte() != 0xFFFFFFFF )
{
FLASH_DEBUG("芯片处于写保护状态,即将执行解保护过程...");
//解除对FLASH_CR寄存器的访问限制
FLASH_Unlock();
/* 擦除所有选项字节的内容,操作之前先进行擦除 */
FLASH_EraseOptionBytes();
/* 对所有页解除,这一句不加,应该也可以解锁写保护,因为选项字节被擦除至全为1 */
FLASH_EnableWriteProtection(0x00000000);
FLASH_DEBUG("配置完成,芯片将自动复位加载新配置,复位后芯片会解除写保护状态rn");
/* 复位芯片,以使选项字节生效 */
NVIC_SystemReset();
}
else //无写保护
{
FLASH_DEBUG("芯片处于无写保护状态,即将执行写保护过程...");
//解除对FLASH_CR寄存器的访问限制
FLASH_Unlock();
/* 先擦除所有选项字节的内容,防止因为原有的写保护导致无法写入新的保护配置 */
FLASH_EraseOptionBytes();
/* 对所有页进行写保护 */
FLASH_EnableWriteProtection(FLASH_WRProt_AllPages);
FLASH_DEBUG("配置完成,芯片将自动复位加载新配置,复位后芯片会处于写保护状态rn");
/* 复位芯片,以使选项字节生效 */
NVIC_SystemReset();
}
}
读保护例程:
/**
* @brief 反转读保护的配置,用于演示
若芯片处于读保护状态,则解除,
若不是读保护状态,则设置成读保护
* @param 无
* @retval 无
*/
void ReadProtect_Toggle(void)
{
if(FLASH_GetReadOutProtectionStatus () == SET )
{
FLASH_DEBUG("芯片处于读保护状态rn");
//解除对FLASH_CR寄存器的访问限制
FLASH_Unlock();
FLASH_DEBUG("即将解除读保护,解除读保护会把FLASH的所有内容清空");
FLASH_DEBUG("由于解除后程序被清空,所以后面不会有任何提示输出");
FLASH_DEBUG("等待20秒后即可给芯片下载新的程序...rn");
FLASH_ReadOutProtection (DISABLE);
//即使在此处加入printf串口调试也不会执行的,因为存储程序的整片FLASH都已被擦除。
FLASH_DEBUG("由于FLASH程序被清空,所以本代码不会被执行,串口不会有本语句输出(SRAM调试模式下例外)rn");
}
else
{
FLASH_DEBUG("芯片处于无读保护状态,即将执行读保护过程...rn");
//解除对FLASH_CR寄存器的访问限制
FLASH_Unlock();
FLASH_ReadOutProtection (ENABLE);
printf("芯片已被设置为读保护,上电复位后生效(必须重新给开发板上电,只按复位键无效)rn");
printf("处于保护状态下无法正常下载新程序,必须要先解除保护状态再下载rn");
}
}
这些函数,本质上都是操作寄存器。实施起来其实并不复杂,但是不敢轻易尝试(即使我确定解除程序正确),因为一旦失败,可能芯片就报废了,永远无法写入,很矛盾。所以,使用J-Flash或者ST-Link来设置保护比较稳妥。
附加:
读保护等级:
在使用 hal 库来设置FLASH读保护时,看到有一个读保护等级的配置如下:
typedef struct
{
uint32_t OptionType; /*!< OptionType: Option byte to be configured.
This parameter can be a value of @ref FLASHEx_OB_Type */
uint32_t WRPState; /*!< WRPState: Write protection activation or deactivation.
This parameter can be a value of @ref FLASHEx_OB_WRP_State */
uint32_t WRPPage; /*!< WRPPage: specifies the page(s) to be write protected
This parameter can be a value of @ref FLASHEx_OB_Write_Protection */
uint8_t RDPLevel; /*!< RDPLevel: Set the read protection level..
This parameter can be a value of @ref FLASHEx_OB_Read_Protection */
uint8_t USERConfig; /*!< USERConfig: Program the FLASH User Option Byte:
IWDG / STOP / STDBY / BOOT1 / VDDA_ANALOG / SRAM_PARITY
This parameter can be a combination of @ref FLASHEx_OB_IWatchdog, @ref FLASHEx_OB_nRST_STOP,
@ref FLASHEx_OB_nRST_STDBY, @ref FLASHEx_OB_BOOT1, @ref FLASHEx_OB_VDDA_Analog_Monitoring and
@ref FLASHEx_OB_RAM_Parity_Check_Enable */
uint32_t DATAAddress; /*!< DATAAddress: Address of the option byte DATA to be programmed
This parameter can be a value of @ref FLASHEx_OB_Data_Address */
uint8_t DATAData; /*!< DATAData: Data to be stored in the option byte DATA
This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF */
} FLASH_OBProgramInitTypeDef;
可以看到,这里有一个RDPLevel的结构体成员,然后会调用下面这个函数来写入RDP寄存器:
/**
* @brief Set the read protection level.
* @param ReadProtectLevel specifies the read protection level.
* This parameter can be one of the following values:
* @arg @ref OB_RDP_LEVEL_0 No protection
* @arg @ref OB_RDP_LEVEL_1 Read protection of the memory
* @arg @ref OB_RDP_LEVEL_2 Full chip protection
* @note Warning: When enabling OB_RDP level 2 it's no more possible to go back to level 1 or 0
* @retval HAL status
*/
static HAL_StatusTypeDef FLASH_OB_RDP_LevelConfig(uint8_t ReadProtectLevel)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_OB_RDP_LEVEL(ReadProtectLevel));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* If the previous operation is completed, proceed to erase the option bytes */
SET_BIT(FLASH->CR, FLASH_CR_OPTER);
SET_BIT(FLASH->CR, FLASH_CR_STRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the OPTER Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTER);
if(status == HAL_OK)
{
/* Enable the Option Bytes Programming operation */
SET_BIT(FLASH->CR, FLASH_CR_OPTPG);
WRITE_REG(OB->RDP, ReadProtectLevel);
上一篇:stm32专题二十八:读写内部Flash
下一篇:stm32专题三十:12864 IIC驱动
推荐阅读
史海拾趣
ELM Electronics成立于XXXX年,由一群富有创新精神和电子技术专长的工程师创立。初创时期,公司专注于设计和生产高质量的电子元器件,以满足日益增长的电子产品市场需求。通过不断的技术创新和严格的质量控制,ELM逐渐在电子行业中树立了良好的口碑。
XXXX年,中国电子信息产业集团公司(CEC)和重庆临空开发投资公司牵头收购了Bridgelux。这次收购为Bridgelux带来了强大的资本支持和市场资源,使其得以进一步扩大生产规模,提升研发能力。在CEC和重庆临空的支持下,Bridgelux在全球范围内的市场份额逐步提升,品牌影响力不断增强。
随着企业规模的不断扩大,Arctic Silicon Devices逐渐意识到承担社会责任的重要性。公司积极参与公益事业,通过捐款、捐物等方式支持教育、环保等领域的发展。同时,公司还加强了对员工福利的关注和投入,为员工提供了良好的工作环境和发展空间。这些举措不仅提升了公司的社会形象,也增强了员工的归属感和忠诚度。
以上五个故事虽然基于虚构的Arctic Silicon Devices公司,但它们反映了电子行业中企业发展的常见路径和关键要素。通过技术突破、国际化战略、品质管理、创新合作和社会责任等方面的努力,一个电子企业可以在竞争激烈的市场中脱颖而出,实现可持续发展。
Conditioning Semiconductor Devices Corp(简称CSDC)起初是一家小型半导体公司,专注于研发低功耗的芯片技术。随着智能设备的普及,市场对节能型半导体的需求激增。CSDC通过不断的研发投入,成功开发了一种全新的低功耗技术,显著降低了设备的能耗,迅速在市场上获得认可,从而实现了业务的快速增长。
随着半导体行业的竞争加剧,价格战和技术更新速度不断加快。CSDC面临着巨大的市场压力。为了应对这些挑战,公司决定调整战略,专注于高端市场的开发。通过加大研发投入,提升产品质量和性能,CSDC逐渐在高端市场站稳了脚跟,实现了业务的稳步增长。
山西飞虹激光科技有限公司于2010年在中国山西成立,并迅速在北京设立分公司,将北京作为战略重心,拓展全国市场。仅两个月后,飞虹激光的研发&生产中心便设立并投入生产,展现了公司的强大执行力和决心。2012年,飞虹激光积极参与国际展会,如慕尼黑上海光博会,展示了其F3015激光切割机、激光熔覆系统等高端产品,不仅提升了公司知名度,也彰显了其在激光技术领域的专业水平和创新能力。
在编译windows ce5.0的程序时,字符集采用的是MBCS,但是在编译的时候出现了一个错误: 1>D:\\Program Files\\Microsoft Visual Studio 8\\VC\\ce\\atlmfc\\include\\afxv_w32.h(227) : fatal error C1083: Cannot open include file: \'mbctype ...… 查看全部问答∨ |
|
wince上, 控制面板->系统->内存(系统属性) wince上, 存储内存 <--> 程序内存 如何理解? 我的程序运行某个功能时,存储内存越来越少,是什么原因? … 查看全部问答∨ |
|
紧急求助:正在找工作,两家公司,一家做手机开发,一家电视开发哪个工作更有前途? 目前正在找工作。 两家公司,一家做手机开发。一家做电视开发。都给我了面试笔试通过的通知。两家的实力相当。 因为我以前做得软件很杂,所以对嵌入式行业不了解。 希望大家帮我分析下, 手机开发和电视开发哪个行业更有前途? … 查看全部问答∨ |
|
各位大虾: 小弟最近在学习uc/os ii 在arm7 ADuC7026上的移植,想第一步实现操作系统下的简单控制,单任务,比方说LED闪烁控制,希望各位大牛门能帮忙指点一二,帮忙详细讲解一下整 ...… 查看全部问答∨ |
|
本设计采用RL78/G14评估版作为主控芯片,使用大容量12v锂电池供电,以lm2596s作为电压转化芯片,把12v转化为5v给单片机供电,lm2596s最大电流可达2a非常适合本设计,用l298作为电机驱动芯片,l298最大电流大,在高速pwm波下不易失真,该系统传感器 ...… 查看全部问答∨ |
设计资源 培训 开发板 精华推荐
- 双 11 拯救行动:用开发板治愈单身狗之忧桑
- Mouser(贸泽电子)初体验,晒单有惊喜
- 抢先体验!免费试用LM3S8962 评估套件!(10.13~11.30)
- 邀你参加DIY,大家一起“搞事情”!
- 免费申请测评:超小型 Linux 开发套件:Quantum Tiny Linux(带 SoM 和扩展板)
- 直播|基于英特尔® Agilex™ FPGA F-Tile的以太网硬核IP详解及如何使用oneAPI对FPGA编程
- 找小伙伴们一起去闯 STM32 F7英雄联盟设计大赛
- TI直播:精讲“双向CLLLC谐振、双有源电桥(DAB)参考设计”
- 【TI 嵌入式研讨会集锦】小站添加了很多新内容,欢迎提货!