stm32l151读保护设置完,读保护生效了,但是主程序无法运行了。
void Flash_EnableReadProtection(void)
{
FLASH_Unlock();
FLASH_OB_Unlock();
if(FLASH_GetStatus() == FLASH_ERROR_WRP){
FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR \
| FLASH_FLAG_SIZERR | FLASH_FLAG_OPTVERR);
}
if(FLASH_OB_GetRDP() == RESET)
{
FLASH_OB_RDPConfig(OB_RDP_Level_1);
FLASH_OB_Launch();
}
FLASH_OB_Lock();
FLASH_Lock();
}
如果对你有启发和帮助,请采纳! 答案参考Chatgpt解答
Flash读保护功能可以保护Flash存储器中的程序代码不被读取或修改,这对于保护程序的机密性和完整性非常重要。然而,设置读保护后,如果没有正确配置保护级别或密钥,可能会导致无法正确运行程序。 在你的代码中,首先你需要确保已经正确解锁了Flash和Option Bytes区域。然后,你使用`FLASH_OB_GetRDP()`函数来检查读保护级别是否已设置为RESET(未保护)。如果已经设置为RESET,那么你通过调用`FLASH_OB_RDPConfig()`函数将读保护级别设置为`OB_RDP_Level_1`。最后,调用`FLASH_OB_Launch()`函数来将读保护配置应用于Flash存储器。 如果在设置读保护后无法正确运行主程序,可能是由于以下原因之一: 1. 读保护级别不正确:请确保你选择了适当的读保护级别。根据你的应用需求,可以选择不同的读保护级别(例如Level 1或Level 2)。 2. 密钥不正确:如果你选择了Level 2的读保护级别,需要提供正确的密钥来解锁Flash。确保密钥的正确性,并在设置读保护之前正确配置密钥。 3. 程序代码与读保护冲突:某些特殊情况下,读保护的设置可能会影响程序的运行。如果你的程序代码访问了被保护的Flash区域,可能会导致异常。请确保程序代码与读保护设置相兼容。 如果遇到主程序无法运行的问题,你可以尝试以下步骤: 1. 检查读保护级别和密钥的正确性,并确保其与你的应用需求一致。 2. 检查程序代码是否与读保护设置相兼容。如果可能的话,尝试将代码移动到未受保护的Flash区域。 3. 尝试在设置读保护之前备份和恢复原始的Option Bytes设置,确保其他设置没有冲突。 4. 如果问题仍然存在,建议通过调试工具(例如SWD调试器)来检查程序运行时的状态和任何异常情况,以帮助确定具体的问题。
FPEC
FPEC(FLASH Program/Erase controller 闪存编程/擦除控制器),STM32通过FPEC来擦除和编程FLASH。FPEC使用7个寄存器来操作闪存:
FPEC键寄存器(FLASH_KEYR) //写入键值解锁。
选项字节键寄存器(FLASH_OPTKEYR) //写入键值解锁选项字节操作。
闪存控制寄存器(FLASH_CR) //选择并启动闪存操作。
闪存状态寄存器(FLASH_SR) //查询闪存操作状态。
闪存地址寄存器(FLASH_AR) //存储闪存操作地址。
选项字节寄存器(FLASH_OBR) //选项字节中主要数据的映象。
写保护寄存器(FLASH_WRPR) //选项字节中写保护字节的映象。
键值
为了增强安全性,进行某项操作时,须要向某个位置写入特定的数值,来验证是否为安全的操作,这些数值称为键值。STM32的FLASH共有三个键值:
RDPRT键 = 0x000000A5 用于解除读保护
KEY1 = 0x45670123 用于解除闪存锁
KEY2 = 0xCDEF89AB 用于解除闪存锁
闪存锁
在FLASH_CR中,有一个LOCK位,该位为1时,不能写FLASH_CR寄存器,从而也就不能擦除和编程FLASH,这称为闪存锁。
当LOCK位为1时,闪存锁有效,只有向FLASH_KEYR依次写入KEY1、KEY2后,LOCK位才会被硬件清零,从而解除闪存锁。当LOCK位为1时,对
FLASH_KEYR的任何错误写操作(第一次不是KEY1,或第二次不是KEY2),都将会导致闪存锁的彻底锁死,一旦闪存锁彻底锁死,在下一次复位前,都无法解锁,只有复位后,闪存锁才恢复为一般锁住状态。
复位后,LOCK位默认为1,闪存锁有效,此时,可以进行解锁。解锁后,可进行FLASH的擦除编程工作。任何时候,都可以通过对LOCK位置1来软件加锁,软件加锁与复位加锁是一样的,都可以解锁。
关于主存储块擦除编程操作的一些疑问
1. 为什么每次都要检查BSY位是否为0?
因为BSY位为1时,不能对任何FPEC寄存器执行写操作,所以必须要等BSY位为0时,才能执行闪存操作。
2. 如果没有擦除就进行编程,会出现什么结果?
STM32在执行编程操作前,会先检查要编程的地址是否被擦除,如果没有,则不进行编程,并置FLASH_SR寄存器的PGERR位为1。唯一例外的是,当要编程的数据为0X0000时,即使未擦除,也会进行编程,因为0X0000即使擦除也可以正确编程。
3. 为什么操作后要读出数据并验证?
STM32在某些特殊情况下(例如FPEC被锁住),可能根本就没有执行所要的操作,仅通过寄存器无法判断操作是否成功。所以,保险起见,操作后都要读出所有数据检查。
4. 等待BSY位为1的时间以多少为合适?
请参考STM32固件库中的数据。 5. FLASH编程手册上说进行闪存操作(擦除或编程)时,必须打开内部的RC振荡器(HSI),是不是一定要用HIS进行闪存的擦除及编程操作?
对于这点,我的理解是,进行闪存操作时,必须要保证HIS没有被关闭,但是操作时的系统仍然可以是HSE时钟。STM32复位后,HIS默认是开的,只要你不为了低功耗去主动关闭它,则用什么时钟都可以进行闪存操作的。我所编的程序也验证了这一点。
选项字节
选项字节用于存储芯片使用者对芯片的配置信息。
目前,所有的STM32101xx、STM32102xx、STM32103xx、STM32105xx、STM32107xx产品,选项字节都是16字节。但是这16字节,每两个字节组成一个正反对,即,字节1是字节0的反码,字节3是字节2的反码,...,字节15是字节14的反码,所以,芯片使用者只要设置8个字节就行了,另外8个字节系统自动填充为反码。因此,有时候,也说STM32的选项字节是8个字节,但是占了16字节的空间。选项字节的8字节正码概述如下:
RDP 字节0。 读保护字节,存储对主存储块的读保护设置。
USER 字节2。 用户字节,配置看门狗、停机、待机。
Data0 字节4。 数据字节0,由芯片使用者自由使用。
Data1 字节6。 数据字节1,由芯片使用者自由使用。
WRP0 字节8。 写保护字节0,存储对主存储块的写保护设置。
WRP1 字节10。写保护字节1,存储对主存储块的写保护设置。
WRP2 字节12。写保护字节2,存储对主存储块的写保护设置。
WRP3 字节14。写保护字节3,存储对主存储块的写保护设置
选项字节写使能
在FLASH_CR中,有一个OPTWRE位,该位为0时,不允许进行选项字节操作(擦除、编程)。这称为选项字节写使能。只有该位为1时,才能进行选项字节操作。 该位不能软件置1,但可以软件清零。只有向FLASH_OPTKEYR依次写入KEY1和KEY2后,硬件会自动对该位置1,此时,才允许选项字节操作。这称为解锁(打开)选项字节写使能。该位为1后,可以由软件清零,关闭写使能。复位后,该位为0。错误操作不会永远关闭写使能,只要写入正确的键序列,则又可以打开写使能。写使能已打开时,再次打开,不会出错,并且依然是打开的。 很显然,进行选项字节操作前,先要解开闪存锁,然后打开选项字节写使能,之后,才能进行选项字节操作。
选项字节擦除
建议使用如下步骤对选项字节进行擦除:
1.检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作。
2.解锁FLASH_CR寄存器的OPTWRE位。即,打开写使能。
3.设置FLASH_CR寄存器的OPTER位为1。选择选项字节擦除操作。
4.设置FLASH_CR寄存器的STRT位为1。
5.等待FLASH_SR寄存器的BSY位变为0,表示操作完成。
6.查询FLASH_SR寄存器的EOP位,EOP为1时,表示操作成功。
7.读出选项字节并验证数据。
由于选项字节只有16字节,因此,擦除时是整个选项字节都被擦除了。
选项字节编程
建议使用如下步骤对选项字节进行编程:
1.检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的编程操作。
2.解锁FLASH_CR寄存器的OPTWRE位。即,打开写使能。
3.设置FLASH_CR寄存器的OPTPG位为1。选择编程操作。
4.写入要编程的半字到指定的地址。启动编程操作。
5.等待FLASH_SR寄存器的BSY位变为0,表示操作完成。
6.查询FLASH_SR寄存器的EOP位,EOP为1时,表示操作成功。
7.读出写入的选项字节并验证数据。 对选项字节编程时,FPEC使用半字中的低字节并自动地计算出高字节(高字节为低字节的反码),并开始编程操作,这将保证选项字节和它的反码始终是正确的。
主存储块的保护
可以对主存储块中的数据进行读保护、写保护。 读保护用于保护数据不被非法读出。防止程序泄密。
写保护用于保护数据不被非法改写,增强程序的健壮性。
读保护
主存储块启动读保护后,简单的说具有以下特性:
1.从主存储块启动的程序,可以对整个主存储块执行读操作,不允许对主存储块的前4KB进行擦除编程操作,可以对4KB之后的区域进行擦除编程操作。
2.从SRAM启动的程序,不能对主存储块进行读、页擦除、编程操作,但可以进行主存储块整片擦除操作。
3.使用调试接口不能访问主存储块。这些特性足以阻止主存储器数据的非法读出,又能保证程序的正常运行。
只有当RDP选项字节的值为RDPRT键值时,读保护才被关闭,否则,读保护就是启动的。因此,擦除选项字节的操作,将启动主存储块的读保护。如果要关闭读保护,必须将RDP选项字节编程为RDPRT键值。并且,如果编程选项字节,使RDP由非键值变为键值(即由保护变为非保护)时,STM32将会先擦除整个主存储块,再编程RDP。芯片出厂时,RDP会事先写入RDPRT键值,关闭写保护功能。
写保护
STM32主存储块可以分域进行写保护。如果试图对写保护的域进行擦除或编程操作,在闪存状态寄存器(FLASH_SR)中会返回一个写保护错误标志。STM32主存储块每个域4KB,WRP0-WRP3选项字节中的每一位对应一个域,位为0时,写保护有效。对于超过128KB的产品,WRP3.15保护了域31及之后的所有域。显然,擦除选项字节将导致解除主存储块的写保护。
选项字节与它的寄存器映象
我们知道,FPEC有两个寄存器存储了选项字节的映象。那么,选项字节本体(在FLASH中)与映象(在寄存器中)究竟有什么区别呢?
选项字节的本体只是个FLASH,它的作用只是掉电存储选项字节内容而以,真正起作用的是寄存器中的映象。即,一个配置是否有效,不是看本体,而是看映象。而映象是在复位后,用本体的值加载的,此后,除非复位,映象将不再改变。所以,更改本体的数据后,不会立即生效,只有复位加载到映象中后,才会生效。 有一点要注意的是,当更改本体的值,使主存储块读保护变为不保护时,会先擦除整片主存储块,然后再改变本体。这是唯一一个改变本体会引发的动作。但即使这样,读保护依然要等到复位后,加载到映象后,才会解除。
关于FLASH编程手册中文版的几处错误(不一定是,但是与我的理解不符)
1.选项字节编程一节中:
对FPEC解锁后,必须分别写入KEY1和KEY2(见2.3.1节)到FLASH_OPTKEYR寄存器,再设置FLASH_CR寄存器的OPTWRE位为’1’,此时可以对选项字节进行编程
实际上,对FLASH_OPTKEYR写入KEY1和KEY2后,OPTWRE位会被硬件置1,而不是用软件写1。这一点在后面的寄存器描述中也可以得到验证。
2.对读保护的描述中:
对读保护的数值对无法理解。正确的应该是,RDP为RDPRT键值时,解除读保护,为其它值时,读保护生效。
看了半天,原来只要几句就可以解决,当然是不考虑其他功能,只是简单的读写操作。
其中写操作如下:
FLASH_Unlock(); //解锁FLASH编程擦除控制器
FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除标志位
/*********************************************************************************
// FLASH_FLAG_BSY FLASH忙标志位
// FLASH_FLAG_EOP FLASH操作结束标志位
// FLASH_FLAG_PGERR FLASH编写错误标志位
// FLASH_FLAG_WRPRTERR FLASH页面写保护错误标净
**********************************************************************************/
FLASH_ErasePage(FLASH_START_ADDR); //擦除指定地址页
FLASH_ProgramHalfWord(FLASH_START_ADDR+(addr+i)*2,dat); //从指定页的addr地址开始写
FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除标志位
FLASH_Lock(); //锁定FLASH编程擦除控制器
从上面可以看出基本顺序是:解锁—>清除标志位(可以不要)—>擦除—>写半字—>清楚标志位(也可以不要)—>上锁。
其中FLASH_START_ADDR是宏定义的0x8000000+2048255,0x8000000是Flash的起始地址,2048是因为我用的是大容量芯片,根据上一笔记Flash地址可以看出芯片每页容量2K,即2048字节,255表示芯片的最后一页,这个根据不同芯片而定。之所以从后面页写起可以防止储存数据破坏用户程序。addr2是因为每个数据占用2字节(半字),虽然写入的是1字节数据,但是编程是2字节为单位,也就是说一个字节的数据也会占用两个字节地址。
读操作如下:
u16 value;
value = *(u16*)(FLASH_START_ADDR+(addr*2));//从指定页的addr地址开始读
参考链接:STM32 Flash做为存储器储存数据
参考资料:《STM32F10xxx闪存编程参考手册》
对于这个问题,需要找到原因才能解决。首先需要确认是不是读保护的问题导致的程序无法运行。可以先尝试关闭读保护,看看是否正常运行。如果关闭读保护后可以正常运行,则说明确实是读保护导致的问题。
解决读保护导致的程序无法运行问题,一种方法是在程序中进行编程来解除读保护。具体步骤如下:
在程序中使用FLASH解锁函数unLock,解锁Flash。
使用FLASH_ErasePage函数,将保护区擦除。
使用FLASH_WRPConfig函数,重新配置Flash写保护设置。
在程序中使用FLASH Lock函数,重新锁定Flash。
代码示例:
#include "stm32l1xx.h"
void disableReadProtect(void)
{
FLASH_Unlock(); // 解锁Flash
FLASH_ErasePage(PAGE_NUMBER); // 擦除保护区
FLASH_WRPConfig(WRPROT_PAGE_NUMBER, DISABLE); // 禁止对保护区进行写操作
FLASH_Lock(); // 锁定Flash
}
其中,PAGE_NUMBER和WRPROT_PAGE_NUMBER需要根据实际情况进行修改。
另外,需要注意的是,解除读保护并不安全,可能会导致安全问题。因此,在使用前需要仔细评估是否真的有必要解除读保护。
你好,你可以把这段代码屏蔽掉,然后刷芯片的时候把flash全擦除,这样解锁了,主程序代码就能运行和仿真了,祝好运
你好,你可以把这段代码屏蔽掉,然后刷芯片的时候把flash全擦除,这样解锁了,主程序代码就能运行和仿真了,祝好运