[CortexM0--stm32f0308]Flash memory

问题描述

Flash在IC中用来存放code和const data,对于其中没有用到的Flash部分,可以使Application用来做data storage用。IC一般应用场景下都是会经常断电的,而有些数据需要记录之前的一些状态等内容,因此需要掉电保留的特质,Flash正是这样的设备。

stm32f0308的Flash

64K的Flash用page作为单位来划分,一共64个page,那每个page是1K byte,另外也可以用sector来划分,一个sector有4个page,那64K的Flash可以划分为16个sector。
下面的对用户Flash区域和option byte区域的描述都不适用于System Memory的,很显然,System Memory是类似于ROM的功能的,读/写保护都不会有这些机制,Read Only,总是能读的,而对于写和擦除,那是不可能的!

Flash读

Flash对于MCU而言是Read Only的,因此对于CPU而言,读Flash是很简单的事情,不需要通过Flash接口去读,M0 core直接通过AHB总线直接访问Flash的地址段,读取其中的指令或Read Only数据。有些memory段可能是Execution Only的,这就是由自己在设计程序时通过控制链接来实现的了,估计对Execution Only的Memory读是不能成功的,至于会不会产生什么错误,得尝试下才知道了。M0 core通过AHB访问Flash中Read Only数据,是通过指令fetch和latency来实现,这两个是由FLASH_ACR(Flash访问控制register)来管理。指令fetch的目的是为提高取指效率,通过使用一个prefetch buffer来实现的。latency是用来维持读Flash memory的控制信号,使高速读取Flash数据时不至于出错。

Flash写(编程与擦除)

Flash对于CPU而言Read Only,因此只能通过Flash peripheral接口来写入数据,如果像read操作一样直接写入地址,会导致hardfalt。从程序的宏观角度,stm32f0308的Flash编程分两种方式,ICP和IAP,ICP即是在系统编程,通过SWD和Flash download算法将整个Flash编程,IAP则是在应用编程,通过运行一小段App,实现其余的固件更新。
在对Flash进行编程/擦写时,这时候是不能进行Flash读取的。

Flash寄存器

  • Key register (FLASH_KEYR)
  • Option byte key regi ster (FLASH_OPTKEYR)
  • Flash control register (FLASH_CR)
  • Flash status register (FLASH_SR)
  • Flash address register (FLASH_AR)
  • Option byte register (FLASH_OBR)
  • Write protection register (FLASH_WRPR)

解锁Flash

这是编程/擦写需要做的第一步,因为IC reset后,Flash是被锁住不能被write和erase的,需要进行如下的解锁步骤:
[CortexM0--stm32f0308]Flash memory_第1张图片

编程Flash

对Flash编程,即写入数据到Flash的对应地址,只能以half-word(16 bit)的方式写入,而且对Flash的编程和擦除都必须按照规定的流程执行,否则会导致Flash数据修改不成功,而造成程序的异常。stm32f0308有说明,似乎在编程Flash之前需要先擦除Flash为0x00000000的,否则是没法编程Flash成功的。
编程Flash的标准步骤如下描述:

  1. 先要确保没有Flash memory相关操作正在进行,因此需要检查FLASH_SR register的BSY bit;
  2. 将FLASH_CR register的PG bit置1,表明是对Flash编程操作;
  3. 将half-word(16 bit)数据写入到Flash对应的地址;
  4. 由于进行了写入Flash的操作,需要等待直到FLASH_SR register的BSY bit被置位;
  5. 最后检查FLASH_SR register的EOP flag(EOP flag, End Of Procedure, 一次Flash操作成功完成,那该EOP flag就被置位),EOP flag被置位时,就说明这次Flash编程成功啦,需要在软件中将EOP flag清零,不然会影响后面的判断的。
    详细的流程图如下:
    [CortexM0--stm32f0308]Flash memory_第2张图片

擦除Flash

Flash擦除是将Flash数据恢复默认值的很快的方式,一般Flash的擦除是将Flash都变成0xFFFFFFFF,而这里stm32f0308好像是都变成0x00000000的,即清零了,这是根据stm32f0308的说明大概判断的,具体的得实验下看看~
stm32f0308的Flash擦除分为两种情况,Page Erase和Mass Erase,即分页擦除,或整个用户Flash区域都擦除。

Page Erase

即擦除Flash的某一页,Flash Page Erase的标准操作步骤如下描述:
1. 先要确保没有Flash memory相关操作正在进行,因此需要检查FLASH_SR register的BSY bit;
2. 将FLASH_CR register的PER bit置1,表明是对Flash的Page Erase操作;
3. 设置FLASH_AR register,选择要erase的page;
4. 将FLASH_CR register的STRT bit置1,开始对Flash的Page Erase操作;
5. 由于进行了写入Flash的操作,需要等待直到FLASH_SR register的BSY bit被置位;
5. 最后检查FLASH_SR register的EOP flag(EOP flag, End Of Procedure, 一次Flash操作成功完成,那该EOP flag就被置位),EOP flag被置位时,就说明这次Flash擦除成功啦,需要在软件中将EOP flag清零,不然会影响后面的判断的。
详细的流程图表示如下:
[CortexM0--stm32f0308]Flash memory_第3张图片

Mass Erase

将整个用户Flash都擦除掉,当然option byte和system memory部分是不受影响的。其操作步骤如下:
1. 先要确保没有Flash memory相关操作正在进行,因此需要检查FLASH_SR register的BSY bit;
2. 将FLASH_CR register的MER bit置1,表明是对Flash的Mass Erase操作;
3. 将FLASH_CR register的STRT bit置1,开始对Flash的Mass Erase操作;
4. 由于进行了写入Flash的操作,需要等待直到FLASH_SR register的BSY bit被置位;
5. 最后检查FLASH_SR register的EOP flag(EOP flag, End Of Procedure, 一次Flash操作成功完成,那该EOP flag就被置位),EOP flag被置位时,就说明这次Flash擦除成功啦,需要在软件中将EOP flag清零,不然会影响后面的判断的。
详细的流程图跟上:
[CortexM0--stm32f0308]Flash memory_第4张图片

option byte写和擦除

对option byte flash区域的编程和擦除与用户64 K byte Flash的操作还是有点不同的,因此上面介绍的写用户Flash区域的步骤并不能完全用来对option byte进行同样的操作,不过大体上还是差不多的。不过要执行option byte的编程或擦除之前,还是要对整个Flash进行解锁的操作的,不然FLASH_CR register并不能使用的。

option byte编程

和用户Flash区域一样,也是只能16 bit的写入,一般的步骤描述如下:
1. 先要确保没有Flash memory相关操作正在进行,因此需要检查FLASH_SR register的BSY bit;
2. 解锁FLASH_CR register的OPTWRE bit,具体的解锁方法和前面解锁整个Flash区域的方法类似,需要依次将KEY1和KEY2的值写入FLASH_OPTKEYR register即可;
3. 将FLASH_CR register的OPTPG bit置1,表明是对Option byte进行ProGram操作;
4. 将half-word(16 bit)数据写入到对应的option byte flash地址;
5. 由于进行了编程Flash的操作,需要等待直到FLASH_SR register的BSY bit被置位;
6. 最后检查FLASH_SR register的EOP flag(EOP flag, End Of Procedure, 一次Flash操作成功完成,那该EOP flag就被置位),EOP flag被置位时,就说明这次Flash擦除成功啦,需要在软件中将EOP flag清零,不然会影响后面的判断的。
另外,貌似option byte中要是将读保护的option byte从保护模式编程改写为了不保护模式,会导致对整个Flash的Mass Erase操作(数据都会丢失掉?),感觉这个比较危险啊。为什么要这样做呢,原因是,如果开始是读保护的,那此时只有Flash内部已编程好的code能访问Flash区域和option byte区域,此时从外面用Debug或者boot的模式是没法读和改写Flash中的代码的,这样就是当形成产品后,别人即使用调试器,或者用bootloader方式,都是不能改写和读取原有产品的代码的,这样就保护了自己的代码,防止被读出山寨,或者被非法写入使产品遭到破坏,引起安全问题。
但是,别人拆开了产品,看到了这颗IC是stm32f0308的,于是知道可以通过option byte来修改Flash读保护的级别的,不然,只要读保护级别不变,别人还是只能原封不动的使用它了。于是先通过某些方法(通过SWD协议是可以的哦),按照上面写option byte的步骤操作各个Flash的register,成功的将读保护级别修改成为无读保护,想想这时候要是IC没有自动的操作,那IC中的代码的读保护就被破解了,山寨就易如反掌了,因此,stm32f0308在这里会触发Mass Erase,呵呵,将所有代码都擦除掉,那还是只能拿到一颗IC而已,代码都被清除掉了。虽然这样有点危险,但是出于保护的目的,这种策略的确可以哇。其实这种加密和破解,是攻防不断对垒的,在复杂的保护机制,也还是存在破解的可能的……

option byte擦除

不多说,步骤如下:
1. 先要确保没有Flash memory相关操作正在进行,因此需要检查FLASH_SR register的BSY bit;
2. 解锁FLASH_CR register的OPTWRE bit,具体的解锁方法和前面解锁整个Flash区域的方法类似,需要依次将KEY1和KEY2的值写入FLASH_OPTKEYR register即可;
3. 将FLASH_CR register的OPTER bit置1,表明是对Option byte进行ERase操作;
4. 将FLASH_CR register的STRT bit置1,开始擦除;
5. 由于进行了擦除Flash的操作,需要等待直到FLASH_SR register的BSY bit被置位;
6. 最后检查FLASH_SR register的EOP flag(EOP flag, End Of Procedure, 一次Flash操作成功完成,那该EOP flag就被置位),EOP flag被置位时,就说明这次Flash擦除成功啦,需要在软件中将EOP flag清零,不然会影响后面的判断的。

Flash Memory保护

前面的Flash部分的操作都提到了Flash memory的读/写保护了,这部分主要是用于在某些情况下方式对用户Flash的非法的读写操作。不知道在防止产品山寨方面是否有用。

读保护

读保护的启用

设置RDP option byte,reset IC使之复位再加载这个新的option byte,即可使用户Flash读保护生效。那么要将RDP option byte设置为什么样的值才可以呢?因为读保护还分为多种级别,当然就有不同的配置的值了,见接下来的内容咯。

读保护的级别

设置RDP option byte为对应的级别,那就将用户Flash区域启用了对应的保护级别了!见下表:
[CortexM0--stm32f0308]Flash memory_第5张图片
1. 级别0:读,写,擦除都可以进行,option byte也是同样的权限;
2. 级别1:代码运行模式下(User Mode),用户Flash和option byte都可以被读的;
3. 级别1:Debug/boot RAM/boot loader模式下,用户Flash不可读,不可写,不可擦除的,option byte呢?stm32f0308资料没有说,不过猜测option byte此时是可以写或擦除的才对,不然用户Flash就永远读保护了,看来stm32f0308是刻意不明说……那对读保护的清除的方法,就可以大概想到会怎么做了……
4. 级别2:no debug级别,首先,这个级别要慎用,级别1设置了读保护,还有办法补救,可以回退到级别0,只是用户Flash中的code都被清掉,级别2一旦设定,就没有办法解除读保护了,这个应当是Flash保护终极版了,产品中code应当没办法被山寨了,但是如果这个产品软件要做修改,也只能呵呵了。stm资料中也提到了意法半导体也没办法分析被保护的部分,意思估计就是说即使返厂都没法恢复的,自己搞的自己承担吧。
5. 级别2:代码运行模式下(User Execution Mode),对用户Flash memory各种操作都是可用的,毕竟不能影响代码正常运行嘛。而option byte而言,可以读,也可以写的(读保护的RDP option byte不能写),不能擦除,这也就断了从级别2修改读保护级别的可能了,因此说级别2不可逆的。
6. 级别2:Debug/boot RAM/boot loader模式下,用户Flash不可读,不可写,不可擦除的,而且Cortex-M0的debug也禁止了,即想通过SWD访问寄存器都成幻想,System memory boot也禁止了,因此此种级别下,只能从用户Flash boot。想一想,此时用户Flash通过任何手段都没法读/写/擦除,option byte的RDP option byte也没法读/写/擦除,其余option byte想办法修改了也无济于事的,System memory也沦陷,此时,只有SRAM能够读写一下,但是SRAM此时也已经没办法通过Cortex-M0间接去读写,一般手段上讲,Flash的代码没法往里做任何改变了。
所以,这个终极读保护,还是慎用,慎用。
最后,贴上读保护相关的,在各个级别,各种模式下各Flash区域的访问操作权限的表:
[CortexM0--stm32f0308]Flash memory_第6张图片

写保护

stm32f0308的写保护可以保护一个sector的Flash区域,即4个page,通过设置option byte中的WRPx option byte来实现写保护。貌似在使能了读保护时,stm32f0308会自动为page 0~3上写保护的,貌似为防止复位向量表的更改。

如何去除Flash写保护1-去除写保护之后去除读保护

  1. 使用FLASH_CR register的OPTER bit擦除整个option byte区域;
  2. 将option byte的RDP byte写0xAA,将Flash读保护变为级别0,(该动作将清除整个用户Flash的内容);
  3. 设置FLASH_CR register的OBL_LAUNCH bit来重新加载option byte的新内容,此时WRPx也已经被清掉,那写保护就被去除了。

如何去除Flash写保护2-只去除写保护而读保护还保留

这种方式适合与IAP(在应用编程)的方式使用,因为IAP在加载外部code时,需要将从外部获得的code搬到Flash当中制定区域段,如果此时该Flash区域是写保护的,那么就得去除写保护才行,此时使用的就是这第2种去除写保护的方式了。但是,产品维护者通过IAP写入的.bin的代码,仍然需要防山寨,因此还是要保留对Flash的读保护的限制的。这里去除Flash写保护的步骤如下:
1. 使用FLASH_CR register的OPTER bit擦除整个option byte区域;
2. 设置FLASH_CR register的OBL_LAUNCH bit来重新加载option byte的新内容,此时WRPx已经被清掉,那写保护就被去除了。
这里有点值得注意的,即比去除Flash写保护方法1少了中间一步,这是因为option byte被擦除后,RDP byte是0x00,是属于读保护级别1的,所以读保护还保留了。

option byte的写保护

用户Flash区域的写保护是通过option byte的WRPx byte部分来控制,而option byte自己的写保护,就是前面提到的写option byte之前的解锁步骤了,通过FLASH_CR register的OPTWRE bit来控制的,通过软件将该bit复位,貌似option byte就没有写保护,估计也不用去执行前面的解锁写保护的步骤了吧。

Flash中断

三个,用来表明一次Flash操作过程完成,以及可能引发的Flash操作错误。在中断处理中对这些异常处理好即可。
[CortexM0--stm32f0308]Flash memory_第7张图片

你可能感兴趣的:(Arch-ARM)