STM32L0擦写EEPROM 无法执行代码?

在stm32L071cb 这个型号的mcu带了6k的eeprom,项目中正好需要用到存储一些参数,借用现成的何乐而不为呢

在测试代码中运行写入再次读取数据保证是正确的,也没有其他副作用。但是到真正派上用场的时候却挂了。在一上电的初始化过程中我会存储一些参数,而从程序打印的log信息来看,百分之八九十的情况都会运行到写入eeprom的时候程序卡死。当然还有百分之十的情况就是程序正常的跑起来了。

这么看来这种死机肯定和写eeprom有关,但是并不是一定会发生的,有一定的概率性。

为什么会出现这种情况,可以先看下STM32L071的芯片内部架构图:

cortex M0+就是单片机中的CPU,memory interface就是连接存储控制器和总线之间的接口。而读写flash和eeprom就是通过NVM memory控制器来的。所以最终cpu读写flash或者eeprom的数据流如下所示红色线标注:

eeprom和flash是共用的NVM控制器。所以现在会出现一种情况,当正在写eeprom时NVM会处于繁忙状态,就导致了这个时候cpu再从NVM取指令取不到,所以CPU要处于挂起等待的状态。等到eeprom写完了,才可以继续往下执行。

这样来看写eeprom会造成cpu阻塞,代码无法执行。这时候再来一个中断,中断服务函数(也是代码指令)也无法执行。

到目前就可以解释我项目中一上电为什么卡死。因为在上电的时候我串口也会通过中断方式接收比较多的数据,而此刻在写eeprom,cpu阻塞在那无法执行串口接收中断进而产生了串口接收数据错误中断。在写完eeprom以后,cpu就进入串口接收中断,但是我没有清除错误中断标志就会一直卡死在中断服务函数中。实际上假如我清除串口接收错误中断,也会因为cpu阻塞导致的串口接收数据丢失。

解决思路肯定也有,如果想让写eeprom的时候串口数据不丢失,也可以使用DMA来处理。如果想让在写eeprom的时候同时可以响应中断也可以把中断向量表和中断服务函数放在ram中运行。

不过这些方法感觉都不够完美,感觉有点过于复杂。实则有更简便的方法。从上面分析导致cpu阻塞等待,中断无法响应的根本原因还在于NVM控制器在写的时候就无法读取了。

庆幸的是STM32L071CB设计之初可能已经考虑这个问题,它的NVM一共有两个,但是需要注意的是并不是所有L0系列都有两个NVM,具体这个型号有几个还是要看下数据手册。两个NVM的架构如下图:

每个NVM中都包含了一块flash和一块儿eeprom。根据手册里面描述NVM1和NVM2中各占一半。对应的flash和eeprom地址如下:

两个NVM好处呢就是可以实现一个NVM在写的时候,另一个NVM进行读取的时候不会受影响。而我的代码是放在NVM1的 flash中的,那么我就把要存的数据写入NVM2 的eeprom中。只要读写不同时在一个nvm中,这个问题就解决了。所以最终我只用把我存储参数的eeprom基地址修改到0x8080c00就可以了。

写eeprom的操作代码就很简单:

还有两个问题需要描述一下:

在写eeprom之前需不需要擦除?

根据参考手册描述,在写eeprom,控制器会自动检测写入的地址需不需要擦除,如果需要会自动进行。但是可以设定FIX位来强制在每一次写入之前都擦除。所以我们在写eeprom的时候完全没必要再手动擦写一遍,并且为了节省写的时间也不用设置FIX位。而设置FIX位可以保证每次写入数据时用的时间会相同(因为都会自动强制执行擦除再写入的动作)。

写eeprom的时候要不要关中断?

如果在写eeprom,你又需要同时用中断接收串口数据,或者用定时器中断来捕获电平时长。你关了还行不?串口数据不会丢?捕获的时间还准确?

如果你的型号只有一个NVM,写的时候又阻塞到了cpu,这时候默认中断到来也是不会执行的。也必须等到写完eeprom才能继续运行,实际上关中断的意义已经不大。

最好的解决办法就是还是用有两个nvm的型号,从根本上解决不会影响中断运行的问题。或者你不怕麻烦,把关键代码放进ram去运行了。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注