Appearance
读写内部Flash
内部Flash的结构
实际上就是一个内部存储器, 用于储存代码, 掉电不会丢失
下载过程: 读写内部flash的程序放在内存, 之后把程序写入flash
Cortex-M3使用ICode与Flash连接, 有三十二跟数据线与地址线, 所以读取比外部SPI-FLASH速度快
同时可以进行上锁, 防止程序被抄袭
系统存储区, 用户不可以访问, ISP支持, 以及芯片保护
选项字节, 存储的是芯片保护以及电压操作, 待机/停机复位, 软件/硬件看门狗功能, 共16字节, 可以修改
- 主存储器
一般说的Flash实际上就是这一个位置, 一共有256页, 在写入之前按照页进行擦除, 设置擦除用到的位置
参考文件: STM32F10xxx闪存编程手册
实际操作过程
- 写入
- 解锁, 为了防止误操作, 芯片复位之后会自动上锁, 这时候不允许设置FLASH的控制寄存器以及修改内容
解锁步骤: 向秘钥寄存器FLASH_KEYR写入KEY1=0x45670123
再向里面写入KEY2=0xCDEF89AB
通过CR寄存器的这一个位可以检查现在的状态
- 擦除扇区,
检查FLSH_SR寄存器中的忙标志
FLASH_CR寄存器的PER位置1
使用FLASH_AR寄存器选择要擦除的页
FLASR_CR的STRT设置为1
等待BUSY位清零
- 写入扇区
检查FLSH_SR寄存器中的忙标志
FLASH_CR寄存器的PG位置1
向指定的位置写入数据, 每一次16位
等待操作完成
- 读取
设置等待周期是通过寄存器进行的, 设置好以后就可以直接使用指针进行读取
没有读保护可以直接进行读取
由于FLASH本身存储有程序数据, 若不是有意的删除某段程序代码, 一般不修改程序的空间内容, 所以使用之前了解一下哪些空间被写入程序, 通过查询.map文件获取信息, 在Map of the image
Load Regina LR ROM1以及Execution Region ER_IROM1分别是程序加载以及执行的空间
实践
c
uint32_t *p;
//解锁
FLASH_Unlock();
//擦除第五页
FLASH_ErasePage(0x08000000 + 2*1024*5);
//写入
FLASH_ProgramWord(0x08000000 + 2*1024*5, 0x12345678);
printf("已经写入完成\r\n");
FLASH_Lock();
p = (uint32_t*)(0x08000000 + 2*1024*5);
printf("读取的值是0x%x\r\n", *p);
设置读写保护以及解除
实际发布的产品芯片中包含了程序, 但是J-Link等下载器可以获取, 所以有一个读写保护, 这样就会让程序非法读取
选项字节以及读写保护
需要更改Flash的选项字节, stm32会根据他的内容进行写保护配置
n=> 取反, 就是前一列的取反
- RDP读保护
设置为0xA5的时候是没有写保护的, 不是这个的时候就会处于保护的状态
- USER: 设置看门狗
- Datax: 这个地址留给用户使用
- WRPx, 用于用于进行写保护
这里的写保护是针对下载器以及仿真器, 或者是内部SRAM自举都不能对FLASH进行读写, 但是如果是从内部FLASH自举的时候就可以对Flash进行读
设置成读保护之后前4K字节会加上写保护, 也就是说Flash内部也不能进行读写, 利用这个特性可以编写IAP代码, 更新FLASH中的程序, 原理是通过通讯接口接收将要更新的程序内容, 然后利用内部的FLASH擦写操作把内容烧写到内部的FLASH中, 实现程序的更新, 类似于ISP程序下载
写保护会导致所有的方式都无法对代码进行更改, 解除之后不会丢失
解除保护
需要把RDP位重新设置为0xA5, 在解除保护之前芯片会擦除FLASH的所有的内容, 所有的代码丢失
解除写保护, 把对应的WRP设置为1
选项字节修改
复位之后的状态是可读但是进行写保护的, 因此FLASH_CR寄存器访问限制, 想要修改需要对FLASH_OPTKEYR寄存器写入解锁编码, 由于需要访问FLASH_CR, 所以要先解锁
- 解除FLASH_CR寄存器
- 解除选项字节的访问权限, 向FLASH_OPTKEYR写入KEY1=0x45670123, 以及KEY2=0xCDEF89AB
- 配置FLASH_CR的OPTPG位, 准备修改选项字节
- 使用指针修改
- 解除读保护之后确认FLASH的擦除操作完成
- 设置读保护以及解除需要给芯片重新上电, 配置选项字节生效, 写保护配置以及解除需要进行系统复位, 有专门的函数
c
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 */
在写入低字节高位设置为0的时候, stm32会自动进行设置高字节为补码
c
FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState)
{
FLASH_Status status = FLASH_COMPLETE;
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NewState));
status = FLASH_WaitForLastOperation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* Authorizes the small information block programming */
FLASH->OPTKEYR = FLASH_KEY1;
FLASH->OPTKEYR = FLASH_KEY2;
//恢复选项字节为出厂设置
FLASH->CR |= CR_OPTER_Set;
FLASH->CR |= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* if the erase operation is completed, disable the OPTER Bit */
FLASH->CR &= CR_OPTER_Reset;
/* Enable the Option Bytes Programming operation */
FLASH->CR |= CR_OPTPG_Set;
if(NewState != DISABLE)
{
//写入非0xA5的值设置为读保护
OB->RDP = 0x00;
}
else
{
OB->RDP = RDP_Key;
}
/* Wait for last operation to be completed 等待擦除完成*/
status = FLASH_WaitForLastOperation(EraseTimeout);
if(status != FLASH_TIMEOUT)
{
/* if the program operation is completed, disable the OPTPG Bit */
FLASH->CR &= CR_OPTPG_Reset;
}
}
else
{
if(status != FLASH_TIMEOUT)
{
/* Disable the OPTER Bit */
FLASH->CR &= CR_OPTER_Reset;
}
}
}
/* Return the protection operation Status */
return status;
}
在使用库函数去除读保护的时候, 会擦除之前设置的选项字节, 包括写保护
这里在使用RAM调试的时选择不进行擦除, 因为Flash被写保护了, 擦除不了
c
void Write_Protect(void)
{
FLASH_Unlock();
//擦除之前的选项, 这是由于flash的特性, 写入之前需要进行擦除
FLASH_EraseOptionBytes();
FLASH_EnableWriteProtection (FLASH_WRProt_AllPages );
NVIC_SystemReset();
}
void Write_Protect_Disable(void)
{
FLASH_Unlock();
FLASH_EraseOptionBytes();
FLASH_EnableWriteProtection (0x00000000 );
//进行一个系统的复位请求
NVIC_SystemReset();
}
void Read_Protect(void)
{
FLASH_Unlock();
FLASH_EraseOptionBytes();
FLASH_ReadOutProtection (ENABLE );
// NVIC_SystemReset();
}
void Read_Protect_Disable(void)
{
FLASH_Unlock();
FLASH_EraseOptionBytes();
FLASH_ReadOutProtection (DISABLE );
// NVIC_SystemReset();
}