本篇文章主要针对单片机FLASH编程和FLASH基本原理进行学习分享。以STM32单片机作为实例进行编程实训。
关于FLASH操作的相关寄存器及编程,大家可以参考下一篇文章:
单片机FLASH深度解析和编程实践(下)-CSDN博客
目录
一、STM32编程方式
二、闪存模块存储器组织(以STM32F767IGT为例)
1、主存储器
2、系统存储器
3、OPT区域
4、选项字节
三、FLASH闪存操作
(一)、FLASH闪存的读取
注意
(二)、FLASH闪存的编程(写)和擦除操作
(三)、FLASH编程注意事项
(四)、STM32的标准编程步骤
四、闪存擦除
(一)、扇区擦除的步骤
(二)、批量擦除的步骤
五、FLASH中断
六、结语
一、STM32编程方式
1在线编程(ICP,In-Circuit Programming):
通过JTAG/SWD协议或者系统加载程序(Bootloader)下载用户应用程序到微控制器中。
2在程序中编程(IAPIn Application Programming):通过任何一种通信接口(如IO端口,USB, CAN,UART,I2C,SPI等)下载程序或者应用数据到存储器中。也就是说,STM32允许用户在应用程序中重新烧写闪存存储器中的内容。然而,IAP需要至少有一部分程序已经使用ICP方式烧到闪存存储器中(Bootloader).
二、闪存模块存储器组织(以STM32F767IGT为例)
储器组织分为四个部分,分别是主存储器、系统存储器、OPT区域、选项字节。
1、主存储器
该部分用来存放代码和数据常数(如const类型的数据)。它可以分为1个Bank或者2个Bank,可以通过选项字节的nDBANK位来设置,默认是1个bank,也就是单Bank模式。
在单Bank模式下,STM32F767的主存储器被分为8个扇区,前4个扇区为32KB大小,第五个扇区是128KB大小,剩下的3个扇区都是256KB大小,总共1M字节。
因为STM32F7的FLASH访问路径有两条:AXIM和ITCM,对应不同的地址映射,表中我们列出了这两条不同访问路径下的扇区地址范围。我们一般选择AXIM接目访问FLASH,其主存储器的起始地址就是ox08000000。
B0、B1都接GND的时候,就是从OX08000000开始运行代码的。
2、系统存储器
这个主要用来存放STM32的bootloader代码,此代码是出厂的时候就固化在STM32里面了,专门来给主存储器下载代码的。当B0接V3.3,B1接GND的时候,从该存储器启动(即进入串口下载模式)。
3、OPT区域
OTP区域,即一次性可编程区域,共1056字节,被划分为16个64字节的OTP 数据块和1个16字节的OTP锁定块。OTP数据块和锁定块均无法擦除。锁定块中包含16字节的 LOCKBi (0 <= i <= 15),用于锁定相应的OTP数据块(块0到15)。每个OTP数据块均可编程,除非相应的OTP锁定字节编程为0x00。锁定字节的值只能是0x0和0xFF,否则这些OTP字节无法正确使用。
4、选项字节
用于配置读保护、BOR级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。
闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。
在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。
三、FLASH闪存操作
(一)、FLASH闪存的读取
STM32的FLASH读取是很简单的。例如,我们要从地址addr ,读取一个字(字节为8位,半字为16位,字为32位),可以通过如下的语句读取:
将addr强制转换为vu32指针,然后取该指针所指向的地址的值,即得到了addr地址的值。类似的,将上面的vu32改为vu16,即可读取指定地址的一个半字。相对FLASH读取来说,STM32 FLASH的写就复杂一点了,下面我们介绍STM32闪存的编程和擦除。
注意
为了准确读取 Flash数据,必须根据CPU时钟 (HCLK)频率和器件电源电压在 Flash存取控制寄存器(FLASH ACR)中正确地设置等待周期数(LKTENCY)。Flash等待周期与CPU时钟频率之间的对应关系:
等待周期通过FLASHAC寄存器的LATENCY[3:0]四三个位设置。系统复位后,CPU时钟频率为内部16MRC振荡器,LATENCY默认是0,即1个等待周期。供电电压,我们一般是3.3V,所以,在我们设置216Mhz频率作为CPU时钟之前,必须先设置LATENCY为7,即8个等待周期,否则FLASH读写可能出错,导致死机。
正常工作时(216Mhz),虽然FLASH需要8个CPU等待周期,但是由于STM32F767具有自适应实时存储器加速器(ARTAccelerator),通过指令缓存存储器,预取指令,实现相当于0 FLASH等待的运行速度。
(二)、FLASH闪存的编程(写)和擦除操作
在对 STM32的Flash执行写入或擦除操作期间,任何读取Flash的尝试都会导致总线阻塞。只有在完成编程操作后,才能正确处理读操作。这意味着,写/擦除操作进行期间不能从Flash中执行代码或数据获取操作。
STM32的闪存编程由7个32位寄存器控制。
(三)、FLASH编程注意事项
Step1:
STM32复位后,FLASH编程操作是被保护的,不能写入FLASH_CR寄存器;
通过写入特定的序列(0X45670123和OXCDEF89AB)到FLASH_KEYR寄存器才可解除写保护,只有在写保护被解除后,我们才能操作相关寄存器。FLASH_CR的解锁序列为:
1)写0X45670123 ( KEY1)到FLASH_ KEYR2)写OXCDEF89AB(KEY2)到FLASH_KEYR
通过这两个步骤,即可解锁FLASH_CR,如果写入错误,那么FLASH_CR将被锁定,直到下次复位后才可以再次解锁。Step2:
STM32闪存的编程位数可以通过FLASH_CR的PSIZE字段配置,PSIZE的设置必须和电源电压匹配,由于我的开发板用的电压是3.3V,所以PSIZE必须设置为10,即32位并行位数。擦除或者编程,都必须以32位为基础进行。
Step3:
STM32的FLASH在编程的时候,也必须要求其写入地址的FLASH是被擦除了的(也就是其值必须是0XFFFFFFFF ),否则无法写入。
(四)、STM32的标准编程步骤
按照以上四步操作,就可以完成一次FLASH编程。但是需要注意一下:
1、编程之前,必须确保要写入地址的FLASH已经擦除 ;
2、需要先解锁,否则不能操作FLASH;
3、编程操作对OPT区域也有效,方法一摸一样。
四、闪存擦除
我们在STM32的FLASH编程的时候,要先判断缩写地址是否被擦除了,所以,我们有必要再介绍-下STM32的闪存擦除,STM32的闪存擦除分为两种:
①扇区擦除②整片擦除。
(一)、扇区擦除的步骤
1、检查FLASH_CR的LOCK是否解锁,如果没有则先解锁
2、检查FLASH_SR寄存器中的BSY位,确保当前未执行任何FLASH操作
3、在FLASH_CR寄存器中,将SER位置1,并从主存储块的12个扇区中选择要擦除的扇区(SNB)
4、将FLASH_CR寄存器中的STRT位置1,触发擦除操作5、等待BSY位清零
经过以上五步,就可以擦除某个扇区!
(二)、批量擦除的步骤
1、检查FLASH_SR寄存器中的BSY位,确保当前未执行任何FLASH操作
2、在FLASH_CR寄存器中,将MER位置1(F767/F407)3、在FLASH_CR寄存器中,将MER和OMER1位置1(F429xx)
4、将FLASH_CR寄存器中的STRT位置1,触发擦除操作5等待BSY位清零
经过以上几个步骤,就可以批量擦除扇区。
五、FLASH中断
1、如果将FLASH_CR寄存器中的操作结束中断使能位(EOPIE)置1,则在擦除或者编程操作结束时,即FLASH_SR寄存器中的繁忙位BSY清零时,将产生中断。此时FLASH_SR寄存器中的操作结束(EOP)位置1。
2、如果在请求编程,擦除或读操作期间出现错误,则FLASH_SR寄存器中的以下错误标志位之一将置1:
PGAERR ,PGPERR ,ERSERR(编程错误标志)WRPERR(保护错误标志)
这种情况下,FLASH_CR的错误中断使能位(ERRIE)置1,并且如果FLASH_SR的操作错误位(OPERR)置1,则产生一个中断。
六、结语
有关FLASH操作的相关知识就分享至此了,下一篇文章将会带大家深度了解FLASH相关的寄存器和寄存器的配置。
单片机FLASH深度解析和编程实践(下)-CSDN博客