有人反馈在产品项目中使用STM32H743II芯片,在对片内flash进行编程时遇到点问题。9 d( d9 V* P: d# f0 z 他将片内的第一、二扇区存放用户应用程序,第七扇区用来存储网络应用相关的一些配置信息。他写Flash的过程及有关现象是这样的:* Q6 l1 ~ S+ w8 q . l+ q! |5 C9 k9 Z* e1 r' V6 \ / v7 H, ~& }* T# {) w. x 关中断->解锁flash->擦除扇区->写入数据->上锁flash->开中断,写入的数据总共40个字节。可是写完之后再去读时,发现只能读取前面32个字节的数据,在调试过程经常莫名其妙地触发硬错中断。这是怎么回事呢?* p9 \' ]+ V! u% c( w 根据该STM32用户的反馈,基体情况就是对片内FLASH进行写操作不成功并衍生出相应问题。 我们通过查看数据手册,不难得知STM32H743II片内FLASH为2MB,分为2个BANK.. M$ L7 m7 Y. _7 Y* U& e ' p' F6 G& ]0 F$ b! b3 ~) w 片内FLASH布局如下: - _& z& l3 r( v 8 R i! O T5 v: [ 我们对STM32H743片内Flash布局有了大致的了解,再去看看有关flash编程的介绍,了解相关规则。" e9 B" f9 J6 I 6 K5 `. D0 T5 Q2 f5 m G( R4 }. ` 2 z( q, k5 a; ~) k) N3 J 从上面描述来看,在做Flash编程时要以256位即32字节为编程单位,或者说8个32位字为单位。硬件以256位做为一个Flash字,并进行读写ECC校验,以保障数据的安全可靠。 # q) @! q1 Y5 I8 t' k9 b 那结合前面STM32H7用户的反馈,它现在每次是写40个字节的数据,既不是32字节也不是64字节,应该是在这个地方出了问题。5 @) U. ^- H% V7 `$ ? 0 x0 }9 n: F9 c6 c* K3 B4 p$ _ 如果他使用下面Cube库函数实现的话,它默认每次就是写8个字的数据到指定的Flash空间。 $ W( O* o$ m* Q4 e) R. D ( J! A* g) ^) d; t/ c, N HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress,uint32_t DataAddress) 1 i# W/ j7 |. N. B2 \% D 即基于该函数做flash编程时,若每次待写的数据多于8个字也没用。如果少于8个字,它会默认地从所给的内存起始地址连续读取8个字的数据。这个时候往往就很危险,很可能发生越界非法访问导致异常,或者读到一些未知数据写进去了。7 g! I0 M# A: |4 C 5 z% j; T# y& F# n+ m# S5 b: V0 W; P 0 d) I: ]& A7 U6 r 如果我们不使用该函数,而是自己组织Flash编程函数,是否就可以按任意数据个数来写呢?显然也是不行的。每次改写Flash必须以256位为单位,如果少于256位的数据硬件就不会进行写动作的。. O$ ]/ V! D- M ) j" c7 v" w+ z 如果说像上面客户的40个字节数据怎么写呢?分两次,一次32字节,另一次8个字节实际数据外加其它24字节数据【比方24个0xff】凑成32字节再做编程,如下图所示。 8 T% J; o5 f$ e 另外,还有一个地方要注意,因为我们每次以256位Flash字为编程单元,那么在指定待改写的Flash区域的地址时一定要遵循32字节对齐,不然也是没法成功完成Flash编程的。比方说,结合上面实例,我们将FLASH编程的起始地址安排在0x080e0010或0x080e0030这些非32字节对齐的地方,是没法完成FLASH编程的。0 e8 U" o1 F- k: M! V5 G, b ' b, W, Q6 s# e1 j3 x0 n2 Z 最后,我们回过头来看看上面提到Cube库自带的那个flash编程函数的部分内容。 + C1 _* y$ K* }# W 红色方框内的代码就是实现8个字的赋值操作进而交给硬件完成flash内容的改写。两绿色方框内是两条汇编指令ISB和DSB。# Y( e, E8 a& x2 r9 S& A* q( u , M/ b& m% ~2 s2 \, U2 j ISB是指令同步隔离指令,ISB指令清除微处理器流水线的内容以确保ISB之前的所有指令得以彻底执行后才执行其后续指令。显然,ISB之后的指令需重新从内存或Cache提取。* d. s/ f* {" M , e. {4 _5 v4 S DSB是数据同步隔离指令,在该指令执行完成之前,该指令后面的程序指令不会得到执行。而DSB指令的执行又是建立在该指令之前的所有内存访问操作的完成动作。换言之,DSB前面的内存访问操作未完成前,DSB及后续指令不会得以执行。5 R. w" r7 q9 I+ _1 A! N9 }+ X5 E 如果我们不使用库函数而是自行组织Flash编程代码的话,也可以参考下库函数的写法,尤其有些汇编指令的使用,可以参考借鉴。顺便提醒下,不同STM32系列的片内Flash编程模式或规则并不都一样,这里谈的是基于STM32H7系列的,不可一概而论地套用到其它系列。 . @8 u# ]' i. O/ I; } 好,今天的话题就聊到这里,圣诞快乐! P. R0 M, ] f( `/ B |
【管管推荐】STM32经验分享篇
【经验分享】STM32_H7_ADC
STM32H7R/S高性能MCU:安全性,大存储和优异图显赋能更多应用创新
Stm32H7XX GCC下分散加载实现
【银杏科技ARM+FPGA双核心应用】STM32H7系列10——ADC
DIY-STM32H750核心板
[nucleo-H7A3ZI-Q]1-点亮一个皮皮灯
DIY-STM32H743核心板
【银杏科技ARM+FPGA双核心应用】STM32H7系列57——MDK_FLM
1月10日有奖直播 | 基于STM32 的CODESYS智能自动化解决方案