第51章 设置FLASH的读写保护及解除
全套
200
集视频教程和
1000
页
PDF
教程请到秉火论坛下载:
www.firebbs.cn
野火视频教程优酷观看网址:
http://i.youku.com/firege
本章参考资料:《
STM32F4xx
中文参考手册》、《
STM32F4xx
规格书》、库说明文档《
stm32f4xx_dsp_stdperiph_lib_um.chm
》以及《
Proprietary code read-out protection on microcontrollers
》。
51.1 选项字节与读写保护
在实际发布的产品中,在
STM32
芯片的内部
FLASH
存储了控制程序,如果不作任何保护措施的话,可以使用下载器直接把内部
FLASH
的内容读取回来,得到
bin
或
hex
文件格式的代码拷贝,别有用心的厂商即可利用该代码文件山寨产品。为此,
STM32
芯片提供了多种方式保护内部
FLASH
的程序不被非法读取,但在默认情况下该保护功能是不开启的,若要开启该功能,需要改写内部
FLASH
选项字节
(Option Bytes)
中的配置。
51.1.1
选项字节的内容
选项字节是一段特殊的
FLASH
空间,
STM32
芯片会根据它的内容进行读写保护、复位电压等配置,选项字节的构成见表
511
。
表
511
选项字节的构成
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
选项字节具体的数据位配置说明见表
512
。
表
512
选项字节具体的数据位配置说明
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
我们主要讲解选项字节配置中的
RDP
位和
PCROP
位,它们分别用于配置读保护级别及代码读出保护。
51.1.2
RDP读保护级别
修改选项字节的
RDP
位的值可设置内部
FLASH
为以下保护级别:
0xAA
:级别
0
,无保护
这是
STM32
的默认保护级别,它没有任何读保护,读取内部
FLASH
及”备份
SRAM
“的内容都没有任何限制。
(
注意这里说的”备份
SRAM
“是指
STM32
备份域的
SRAM
空间,不是指主
SRAM
,下同
)
其它值:级别
1
,使能读保护
把
RDP
配置成除
0xAA
或
0xCC
外的任意数值,
都会使能级别
1
的读保护。在这种保护下,若使用调试功能
(
使用下载器、仿真器
)
或者从内部
SRAM
自举时都不能对内部
FLASH
及备份
SRAM
作任何访问
(
读写、擦除都被禁止
)
;而如果
STM32
是从内部
FLASH
自举时,它允许对内部
FLASH
及备份
SRAM
的任意访问。
也就是说,在级别
1
模式下,任何尝试从外部访问内部
FLASH
内容的操作都被禁止,例如无法通过下载器读取它的内容,或编写一个从内部
SRAM
启动的程序,若该程序读取内部
FLASH
,会被禁止。而如果是芯片自己访问内部
FLASH
,是完全没有问题的,例如前面的”读写内部
FLASH
“实验中的代码自己擦写内部
FLASH
空间的内容,即使处于级别
1
的读保护,也能正常擦写。
当芯片处于级别
1
的时候,可以把选项字节的
RDP
位重新设置为
0xAA
,恢复级别
0
。在恢复到级别
0
前,芯片会自动擦除内部
FLASH
及备份
SRAM
的内容,即降级后原内部
FLASH
的代码会丢失。在级别
1
时使用
SRAM
自举的程序也可以访问选项字节进行修改,所以如果原内部
FLASH
的代码没有解除读保护的操作时,可以给它加载一个
SRAM
自举的程序进行保护降级,后面我们将会进行这样的实验。
0xCC
:级别
2
,禁止调试
把
RDP
配置成
0xCC
值时,会进入最高级别的读保护,且设置后无法再降级,它会永久禁止用于调试的
JTAG
接口
(
相当于熔断
)
。在该级别中,除了具有级别
1
的所有保护功能外,进一步禁止了从
SRAM
或系统存储器的自举
(
即平时使用的串口
ISP
下载功能也失效
)
,
JTAG
调试相关的功能被禁止,选项字节也不能被修改。它仅支持从内部
FLASH
自举时对内部
FLASH
及
SRAM
的访问
(
读写、擦除
)
。
由于设置了级别
2
后无法降级,也无法通过
JTAG
、串口
ISP
等方式更新程序,所以使用这个级别的保护时一般会在程序中预留”后门”以更新应用程序,若程序中没有预留后门,芯片就无法再更新应用程序了。所谓的”后门”是一种
IAP
程序
(In Application Program)
,它通过某个通讯接口获取将要更新的程序内容,然后利用内部
FLASH
擦写操作把这些内容烧录到自己的内部
FLASH
中,实现应用程序的更新。
不同级别下的访问限制见图
511
。
图
511
不同级别下的访问限制
不同保护级别之间的状态转换见图
512
。
图
512
不同级别间的状态转换
51.1.3
PCROP代码读出保护
在
STM32F42xx
及
STM32F43xx
系列的芯片中,除了可使用
RDP
对整片
FLASH
进行读保护外,还有一个专用的代码读出保护功能(
Proprietary code readout protection
,下面简称
PCROP
),它可以为内部
FLASH
的某几个指定扇区提供保护功能,所以它可以用于保护一些
IP
代码,方便提供给另一方进行二次开发,见图
513
。
图
513 PCROP
保护功能
当
SPMOD
位设置为
0
时
(
默认值
)
,
nWRPi
位用于指定要进行写保护的扇区,这可以防止错误的指针操作导致
FLASH
内容的改变,若扇区被写保护,通过调试器也无法擦除该扇区的内容;当
SPMOD
位设置为
1
时,
nWRPi
位用于指定要进行
PCROP
保护的扇区。其中
PCROP
功能可以防止指定扇区的
FLASH
内容被读出,而写保护仅可以防止误写操作,不能被防止读出。
当要关闭
PCROP
功能时,必须要使芯片从读保护级别
1
降为级别
0
,同时对
SPMOD
位置
0
,才能正常关闭;若芯片原来的读保护为级别
0
,且使能了
PCROP
保护,要关闭
PCROP
时也要先把读保护级别设置为级别
1
,再在降级的同时设置
SPMOD
为
0
。
51.2 修改选项字节的过程
修改选项字节的内容可修改各种配置,但是,当应用程序运行时,无法直接通过选项字节的地址改写它们的内容,例如,接使用指针操作地址
0x1FFFC0000
的修改是无效的。要改写其内容时必须设置寄存器
FLASH_OPTCR
及
FLASH_OPTCR1
中的对应数据位,寄存器的与选项字节对应位置见图
514
及图
515
,详细说明请查阅《
STM32
参考手册》。
图
514 FLASH_OPTCR
寄存器说明
(nWRP
表示
0-11
扇区
)
图
515 FLASH_OPTCR1
寄存器说明
(nWRP
表示
12-23
扇区
)
默认情况下,
FLASH_OPTCR
寄存器中的第
0
位
OPTLOCK
值为
1
,它表示选项字节被上锁,需要解锁后才能进行修改,当寄存器的值设置完成后,对
FLASH_OPTCR
寄存器中的第
1
位
OPTSTRT
值设置为
1
,硬件就会擦除选项字节扇区的内容,并把
FLASH_OPTCR/1
寄存器中包含的值写入到选项字节。
所以,修改选项字节的配置步骤如下:
(1) 解锁,在 Flash 选项密钥寄存器 (FLASH_OPTKEYR) 中写入 OPTKEY1 = 0x0819 2A3B;接着在 Flash 选项密钥寄存器 (FLASH_OPTKEYR) 中写入 OPTKEY2 = 0x4C5D 6E7F。
(2) 检查 FLASH_SR 寄存器中的 BSY 位,以确认当前未执行其它Flash 操作。
(3) 在 FLASH_OPTCR 和/或 FLASH_OPTCR1 寄存器中写入选项字节值。
(4) 将 FLASH_OPTCR 寄存器中的选项启动位 (OPTSTRT) 置 1。
(5) 等待 BSY 位清零,即写入完成。
51.3 操作选项字节的库函数
为简化编程,
STM32
标准库提供了一些库函数,它们封装了修改选项字节时操作寄存器的过程。
1. 选项字节解锁、上锁函数
对选项字节解锁、上锁的函数见代码清单
511
。
代码清单
511
选项字节解锁、上锁
1
2
#define FLASH_OPT_KEY1 ((uint32_t)0x08192A3B)
3
#define FLASH_OPT_KEY2 ((uint32_t)0x4C5D6E7F)
4
5
/**
6
* @brief Unlocks the FLASH Option Control Registers access.
7
* @param None
8
* @retval None
9
*/
10
void
FLASH_OB_Unlock(
void
)
11
{
12
if
((FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) != RESET)
13
{
14
/* Authorizes the Option Byte register programming */
15
FLASH->OPTKEYR = FLASH_OPT_KEY1;
16
FLASH->OPTKEYR = FLASH_OPT_KEY2;
17
}
18
}
19
20
/**
21
* @brief Locks the FLASH Option Control Registers access.
22
* @param None
23
* @retval None
24
*/
25
void
FLASH_OB_Lock(
void
)
26
{
27
/* Set the OPTLOCK Bit to lock the FLASH Option Byte Registers access */
28
FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK;
29
}
解锁的时候,它对
FLASH_OPTCR
寄存器写入两个解锁参数,上锁的时候,对
FLASH_ OPTCR
寄存器的
FLASH_OPTCR_OPTLOCK
位置
1
。
2. 设置读保护级别
解锁后设置选项字节寄存器的
RDP
位可调用
FLASH_OB_RDPConfig
完成,见代码清单
512
。
代码清单
512
设置读保护级别
1
/**
2
* @brief Sets the read protection level.
3
* @param OB_RDP: specifies the read protection level.
4
* This parameter can be one of the following values:
5
* @arg OB_RDP_Level_0: No protection
6
* @arg OB_RDP_Level_1: Read protection of the memory
7
* @arg OB_RDP_Level_2: Full chip protection
8
*
9
* /!\
Warning /!\ When enabling OB_RDP level 2 it’s no more possible to go back to level 1 or 0
10
*
11
* @retval None
12
*/
13
void
FLASH_OB_RDPConfig(
uint8_t
OB_RDP)
14
{
15
FLASH_Status status = FLASH_COMPLETE;
16
17
/* Check the parameters */
18
assert_param(IS_OB_RDP(OB_RDP));
19
20
status = FLASH_WaitForLastOperation();
21
22
if
(status == FLASH_COMPLETE)
23
{
24
*(__IO
uint8_t
*)OPTCR_BYTE1_ADDRESS = OB_RDP;
25
26
}
27
}
该函数根据输入参数设置
RDP
寄存器位为相应的级别,其注释警告了若配置成
OB_RDP_Level_2
会无法恢复。类似地,配置其它选项时也有相应的库函数,如
FLASH_OB_PCROP1Config
、
FLASH_OB_WRP1Config
分别用于设置要进行
PCROP
保护或
WRP
保护
(
写保护
)
的扇区。
3. 写入选项字节
调用上一步骤中的函数配置寄存器后,还要调用代码清单
513
中的
FLASH_OB_Launch
函数把寄存器的内容写入到选项字节中。
代码清单
513
写入选项字节
1
/**
2
* @brief Launch the option byte loading.
3
* @param None
4
* @retval FLASH
Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PROGRAM,
5
* FLASH_ERROR_WRP, FLASH_ERROR_OPERATION or FLASH_COMPLETE.
6
*/
7
FLASH_Status FLASH_OB_Launch(
void
)
8
{
9
FLASH_Status status = FLASH_COMPLETE;
10
11
/* Set the OPTSTRT bit in OPTCR register */
12
*(__IO
uint8_t
*)OPTCR_BYTE0_ADDRESS |= FLASH_OPTCR_OPTSTRT;
13
14
/* Wait for last operation to be completed */
15
status = FLASH_WaitForLastOperation();
16
17
return
status;
18
}
该函数设置
FLASH_OPTCR_OPTSTRT
位后调用了
FLASH_WaitForLastOperation
函数等待写入完成,并返回写入状态,若操作正常,它会返回
FLASH_COMPLETE
。
51.4 实验:设置读写保护及解除
在本实验中我们将以实例讲解如何修改选项字节的配置,更改读保护级别、设置
PCROP
或写保护,最后把选项字节恢复默认值。
本实验要进行的操作比较特殊,在开发和调试的过程中都是在
SRAM
上进行的(使用
SRAM
启动方式)。例如,直接使用
FLASH
版本的程序进行调试时,如果该程序在运行后对扇区进行了写保护而没有解除的操作或者该解除操作不正常,此时将无法再给芯片的内部
FLASH
下载新程序,最终还是要使用
SRAM
自举的方式进行解除操作。所以在本实验中为便于修改选项字节的参数,我们统一使用
SRAM
版本的程序进行开发和学习,当
SRAM
版本调试正常后再改为
FLASH
版本。
关于在
SRAM
中调试代码的相关配置,请参考前面的章节。
注意:
若您在学习的过程中想亲自修改代码进行测试,请注意备份原工程代码。当芯片的
FLASH
被保护导致无法下载程序到
FLASH
时,可以下载本工程到芯片,并使用
SRAM
启动运行,即可恢复芯片至默认配置。但如果修改了读保护为级别
2
,采用任何方法都无法恢复!
(
除了这个配置,其它选项都可以大胆地修改测试。
)
51.4.1
硬件设计
本实验在
SRAM
中调试代码,因此把
BOOT0
和
BOOT1
引脚都使用跳线帽连接到
3.3V
,使芯片从
SRAM
中启动。
51.4.2
软件设计
本实验的工程名称为”设置读写保护与解除”,学习时请打开该工程配合阅读,它是从”
RAM
调试—多彩流水灯”工程改写而来的。为了方便展示及移植,我们把操作内部
FLASH
相关的代码都编写到”
internalFlash_reset.c
“及”
internalFlash_reset.h
“文件中,这些文件是我们自己编写的,不属于标准库的内容,可根据您的喜好命名文件。
1. 主要实验
(1) 学习配置扇区写保护;
(2) 学习配置PCROP保护;
(3) 学习配置读保护级别;
(4) 学习如何恢复选项字节到默认配置;
2. 代码分析
配置扇区写保护
我们先以代码清单
514
中的设置与解除写保护过程来学习如何配置选项字节。
代码清单
514
配置扇区写保护
1
2
#define FLASH_WRP_SECTORS (OB_WRP_Sector_0|OB_WRP_Sector_1)
3
__IO
uint32_t
SectorsWRPStatus = 0xFFF;
4
5
/**
6
* @brief WriteProtect_Test,
普通的写保护配置
7
* @param
运行本函数后会给扇区
FLASH_WRP_SECTORS
进行写保护,再重复一次会进行解写保护
8
* @retval None
9
*/
10
void
WriteProtect_Test(
void
)
11
{
12
FLASH_Status status = FLASH_COMPLETE;
13
{
14
/*
获取扇区的写保护状态
*/
15
SectorsWRPStatus = FLASH_OB_GetWRP() & FLASH_WRP_SECTORS;
16
17
if
(SectorsWRPStatus == 0x00)
18
{
19
/*
扇区已被写保护,执行解保护过程
*/
20
21
/*
使能访问
OPTCR
寄存器
*/
22
FLASH_OB_Unlock();
23
24
/*
设置对应的
nWRP
位,解除写保护
*/
25
FLASH_OB_WRPConfig(FLASH_WRP_SECTORS, DISABLE);
26
status=FLASH_OB_Launch();
27
/*
开始对选项字节进行编程
*/
28
if
(status != FLASH_COMPLETE)
29
{
30
FLASH_ERROR(
”
对选项字节编程出错,解除写保护失败,
status = %x”
,status);
31
/* User can add here some code to deal with this error */
32
while
(1)
33
{
34
}
35
}
36
/*
禁止访问
OPTCR
寄存器
*/
37
FLASH_OB_Lock();
38
39
/*
获取扇区的写保护状态
*/
40
SectorsWRPStatus = FLASH_OB_GetWRP() & FLASH_WRP_SECTORS;
41
42
/*
检查是否配置成功
*/
43
if
(SectorsWRPStatus == FLASH_WRP_SECTORS)
44
{
45
FLASH_INFO(
”
解除写保护成功!
”
);
46
}
47
else
48
{
49
FLASH_ERROR(
”
未解除写保护!
”
);
50
}
51
}
52
else
53
{
/*
若扇区未被写保护,开启写保护配置
*/
54
55
/*
使能访问
OPTCR
寄存器
*/
56
FLASH_OB_Unlock();
57
58
/*
使能
FLASH_WRP_SECTORS
扇区写保护
*/
59
FLASH_OB_WRPConfig(FLASH_WRP_SECTORS, ENABLE);
60
61
status=FLASH_OB_Launch();
62
/*
开始对选项字节进行编程
*/
63
if
(status != FLASH_COMPLETE)
64
{
65
FLASH_ERROR(
”
对选项字节编程出错,设置写保护失败,
status = %x”
,status);
66
while
(1)
67
{
68
}
69
}
70
/*
禁止访问
OPTCR
寄存器
*/
71
FLASH_OB_Lock();
72
73
/*
获取扇
区的写保护状态
*/
74
SectorsWRPStatus = FLASH_OB_GetWRP() & FLASH_WRP_SECTORS;
75
76
/*
检查是否配置成功
*/
77
if
(SectorsWRPStatus == 0x00)
78
{
79
FLASH_INFO(
”
设置写保护成功!
”
);
80
}
81
else
82
{
83
FLASH_ERROR(
”
设置写保护失败!
”
);
84
}
85
}
86
}
87
}
本函数分成了两个部分,它根据目标扇区的状态进行操作,若原来扇区为非保护状态时就进行写保护,若为保护状态就解除保护。其主要操作过程如下:
调用FLASH_OB_GetWRP函数获取目标扇区的保护状态若扇区被写保护,则开始解除保护过程,否则开始设置写保护过程;
调用FLASH_OB_Unlock解锁选项字节的编程;
调用FLASH_OB_WRPConfig函数配置目标扇区关闭或打开写保护;
调用FLASH_OB_Launch函数把寄存器的配置写入到选项字节;
调用FLASH_OB_GetWRP函数检查是否配置成功;
调用FLASH_OB_Lock禁止修改选项字节。
配置PCROP保护
配置
PCROP
保护的过程与配置写保护过程稍有区别,见代码清单
515
。
代码清单
515
配置
PCROP
保护
(internalFlash_reset.c
文件
)
1
2
/**
3
* @brief SetPCROP,
设置
PCROP
位,用于测试解锁
4
* @note
使用有问题的串口
ISP
下载软件,可能会导致
PCROP
位置
1
,
5
导致无法给芯片下载程序到
FLASH
,本函数用于把
PCROP
位置
1
,
6
模拟出无法下载程序到
FLASH
的环境,以便用于解锁的程序调试。
7
若不了解
PCROP
位的作用,请不要执行此函数!!
8
* @param None
9
* @retval None
10
*/
11
void
SetPCROP(
void
)
12
{
13
14
FLASH_Status status = FLASH_COMPLETE;
15
17
18
FLASH_INFO();
19
FLASH_INFO(
”
正在设置
PCROP
保护,请耐心等待
…”
);
20
//
选项字节解锁
21
FLASH_OB_Unlock();
22
23
//
设置为
PCROP
模式
24
FLASH_OB_PCROPSelectionConfig(OB_PcROP_Enable);
25
//
设置扇区
0
进行
PCROP
保护
26
FLASH_OB_PCROPConfig(OB_PCROP_Sector_10,ENABLE);
27
//
把寄存器设置写入到选项字节
28
status =FLASH_OB_Launch();
29
30
if
(status != FLASH_COMPLETE)
31
{
32
FLASH_INFO(
”
设置
PCROP
失败!
”
);
33
}
34
else
35
{
36
FLASH_INFO(
”
设置
PCROP
成功!
”
);
37
38
}
39
//
选项字节上锁
40
FLASH_OB_Lock();
41
}
该代码在解锁选项字节后,调用
FLASH_OB_PCROPSelectionConfig
函数把
SPMOD
寄存器位配置为
PCROP
模式,接着调用
FLASH_OB_PCROPConfig
函数配置目标保护扇区。
恢复选项字节为默认值
当芯片被设置为读写保护或
PCROP
保护时,这时给芯片的内部
FLASH
下载程序时,可能会出现图
516
和图
517
的擦除
FLASH
失败的错误提示。
图
516
擦除失败提示
图
517
擦除进度条卡在开始状态
只要不是把读保护配置成了级别
2
保护,都可以使用
SRAM
启动运行代码清单
516
中的函数恢复选项字节为默认状态,使得
FLASH
下载能正常进行。
代码清单
516
恢复选项字节为默认值
1
// @brief OPTCR register byte 0 (Bits[7:0]) base address
2
#define OPTCR_BYTE0_ADDRESS ((uint32_t)0x40023C14)
3
//@brief OPTCR register byte 1 (Bits[15:8]) base address
4
#define OPTCR_BYTE1_ADDRESS ((uint32_t)0x40023C15)
5
//@brief OPTCR register byte 2 (Bits[23:16]) base address
6
#define OPTCR_BYTE2_ADDRESS ((uint32_t)0x40023C16)
7
// @brief OPTCR register byte 3 (Bits[31:24]) base address
8
#define OPTCR_BYTE3_ADDRESS ((uint32_t)0x40023C17)
9
// @brief OPTCR1 register byte 0 (Bits[7:0]) base address
10
#define OPTCR1_BYTE2_ADDRESS ((uint32_t)0x40023C1A)
11
12
/**
13
* @brief InternalFlash_Reset,
恢复内部
FLASH
的默认配置
14
* @param None
15
* @retval None
16
*/
17
int
InternalFlash_Reset(
void
)
18
{
19
FLASH_Status status = FLASH_COMPLETE;
20
21
/*
使能访问选项字节寄存器
*/
22
FLASH_OB_Unlock();
23
24
/*
擦除用户区域
(
用户区域指程序本身没有使用的空间,可以自定义
)**/
25
/*
清除各种
FLASH
的标志位
*/
26
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
27
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
28
29
FLASH_INFO(
“\r\n”
);
30
FLASH_INFO(
”
正在准备恢复的条件,请耐心等待
…”
);
31
32
//
确保把读保护级别设置为
LEVEL1
,以便恢复
PCROP
寄存器位
33
//PCROP
寄存器位从设置为
0
时,必须是读保护级别由
LEVEL1
转为
LEVEL0
时才有效,
34
//
否则修改无效
35
FLASH_OB_RDPConfig(OB_RDP_Level_1);
36
37
status=FLASH_OB_Launch();
38
39
status = FLASH_WaitForLastOperation();
40
41
//
设置为
LEVEL0
并恢复
PCROP
位
42
43
FLASH_INFO(
“\r\n”
);
44
FLASH_INFO(
”
正在擦除内部
FLASH
的内容,请耐心等待
…”
);
45
46
//
关闭
PCROP
模式
47
FLASH_OB_PCROPSelectionConfig(OB_PcROP_Disable);
48
FLASH_OB_RDPConfig(OB_RDP_Level_0);
49
50
status =FLASH_OB_Launch();
51
52
//
设置其它位为默认值
53
(*(__IO
uint32_t
*)(OPTCR_BYTE0_ADDRESS))=0x0FFFAAE9;
54
(*(__IO uint16_t *)(OPTCR1_BYTE2_ADDRESS))=0x0FFF;
55
status =FLASH_OB_Launch();
56
if
(status != FLASH_COMPLETE)
57
{
58
FLASH_ERROR(
”
恢复选项字节默认值失败,错误代码:
status=%X”
,status);
59
}
60
else
61
{
62
FLASH_INFO(
”
恢复选项字节默认值成功!
”
);
63
}
64
//
禁止访问
65
FLASH_OB_Lock();
66
67
return
status;
68
}
这个函数进行了如下操作:
调用FLASH_OB_Unlock解锁选项字节的编程;
调用FLASH_ClearFlag函数清除所有FLASH异常状态标志;
调用FLASH_OB_RDPConfig函数设置为读保护级别1,以便后面能正常关闭PCROP模式;
调用FLASH_OB_Launch写入选项字节并等待读保护级别设置完毕;
调用FLASH_OB_PCROPSelectionConfig函数关闭PCROP模式;
调用FLASH_OB_RDPConfig函数把读保护级别降为0;
调用FLASH_OB_Launch定稿选项字节并等待降级完毕,由于这个过程需要擦除内部FLASH的内容,等待的时间会比较长;
直接操作寄存器,使用”(*(__IO uint32_t *)(OPTCR_BYTE0_ADDRESS))=0x0FFFAAE9;”和”(*(__IO uint16_t *)(OPTCR1_BYTE2_ADDRESS))=0x0FFF;”语句把OPTCR及OPTCR1寄存器与选项字节相关的位都恢复默认值;
调用FLASH_OB_Launch函数等待上述配置被写入到选项字节;
恢复选项字节为默认值操作完毕。
main函数
最后来看看本实验的
main
函数,见。代码清单
517
。
代码清单
517 main
函数
1
/**
2
* @brief
主函数
3
* @param
无
4
* @retval
无
5
*/
6
int
main(
void
)
7
{
8
/* LED
端口初始化
*/
9
LED_GPIO_Config();
10
Debug_USART_Config();
11
LED_BLUE;
12
13
FLASH_INFO(
”
本程序将会被下载到
STM32
的内部
SRAM
运行。
”
);
14
FLASH_INFO(
”
下载程序前,请确认把实验板的
BOOT0
和
BOOT1
引脚都接到
3.3V
电源处!!
”
);
15
16
FLASH_INFO(
“\r\n”
);
17
FLASH_INFO(
“—-
这是一个
STM32
芯片内部
FLASH
解锁程序
—-”
);
18
FLASH_INFO(
”
程序会把芯片的内部
FLASH
选项字节恢复为默认值
”
);
19
20
21
#if 0
//
工程调试、演示时使用,正常解除时不需要运行此函数
22
SetPCROP();
//
修改
PCROP
位,仿真芯片被锁无法下载程序到内部
FLASH
的环境
23
#endif
24
25
#if 0
//
工程调试、演示时使用,正常解除时不需要运行此函数
26
WriteProtect_Test();
//
修改写保护位,仿真芯片扇区被设置成写保护的的环境
27
#endif
28
30
31
/*
恢复选项字节到默认值,解除保护
*/
32
if
(
InternalFlash_Reset
()==FLASH_COMPLETE)
33
{
34
FLASH_INFO(
”
选项字节恢复成功,请把
BOOT0
和
BOOT1
引脚都连接到
GND
,
”
);
35
FLASH_INFO(
”
然后随便找一个普通的程序,下载程序到芯片的内部
FLASH
进行测试
”
);
36
LED_GREEN;
37
}
38
else
39
{
40
FLASH_INFO(
”
选项字节恢复成功失败,请复位重试
”
);
41
LED_RED;
42
}
43
45
46
while
(1);
47
}
在
main
函数中,主要是调用了
InternalFlash_Reset
函数把选项字节恢复成默认值,程序默认时没有调用
SetPCROP
和
WriteProtect_Test
函数设置写保护,若您想观察实验现象,可修改条件编译的宏,使它加入到编译中。
3. 下载测试
把开发板的BOOT0和BOOT1引脚都使用跳线帽连接到3.3V电源处,使它以SRAM方式启动,然后用USB线连接开发板”USB TO UART”接口跟电脑,在电脑端打开串口调试助手,把编译好的程序下载到开发板并复位运行,在串口调试助手可看到调试信息。程序运行后,请耐心等待至开发板亮绿灯或串口调试信息提示恢复完毕再给开发板断电,否则由于恢复过程被中断,芯片内部FLASH会处于保护状态。
芯片内部
FLASH
处于保护状态时,可重新下载本程序到开发板以
SRAM
运行恢复默认配置。
51.5 每课一问
1. 分别设置芯片为读保护级别1、写保护及PCROP保护,然后给芯片的内部FLASH下载程序,观察实验现象。