写点什么

STM32L0 系列 EEPROM 读写,程序卡死?

作者:矜辰所致
  • 2022-10-16
    江苏
  • 本文字数:3471 字

    阅读完需:约 1 分钟

STM32L0 系列 EEPROM 读写,程序卡死?
STM32L0 系列EEPROM读写,使用过程必须注意到的问题,踩坑史 = =!......by 矜辰所致
复制代码


前言

因为芯片的涨价,使用 STM32L051 和 STM32L071 替换 STM32 有一年多了,替换完成以后还根据自己产品的需求写了几篇记录博文:


STM32L051 测试 (一、使用 CubeMX 生成工程文件 — ST 系列芯片通用)

https://xie.infoq.cn/article/fc5e31ea41e0b33f64b9ee537

STM32L051 测试 (二、开始添加需要的代码)

https://xie.infoq.cn/article/26e83bbc53646042a66e6fb8f

STM32L051 测试 (三、I2C 协议设备的添加测试)

https://xie.infoq.cn/article/76cbd45207fe8f4a6d2d9b99d

STM32L051 测试 (四、Flash 和 EEPROM 的读写)

https://xie.infoq.cn/article/8049c2e853c99348b66fc8c72

STM32L051 测试 (五、Enocean 模块串口通讯问题)

https://xie.infoq.cn/article/438fc48f0d1481e75e165863c


STM32L0 系列产品都自带了 EEPROM ,使用保存数据起来特别方便,因为写 EEPROM 并不需要删除一篇扇区,可以直接在指定地址写入。


但是最近有某个产品反馈,有时候会莫名其妙的“死机”,这是最直观的现象:


如果在初次配置完成(配置需要对 EEPROM 进行读写)后上电没问题,那么就一直没问题,如果断电重启,有可能遇到问题,遇到问题也是可以靠多重启几次解决(上电会读取 EEPROM 的数据)。


这个问题花了一些时间,其实就是 EEPROM 的读写问题,从以前的这篇文章


STM32L051 测试 (四、Flash 和 EEPROM 的读写)

https://xie.infoq.cn/article/8049c2e853c99348b66fc8c72


我更新了好多次可以看出来,EEPROM 不止出了一次的问题。


所以本文的目的就在于,把 STM32L0 系列 EEPROM 读写使用注意事项说明清楚,供大家参考!

一、写入地址问题

在 STM32L0 系列读取 EEPROM 的时候,需要注意:


字节操作,传入合理范围内的任何地址参数都可以;


半字操作,地址需要 2 字节对齐,就是 2 的倍数;


全字操作,地址需要 4 字节对齐,就是 4 的倍数;


这个在以前的测试文章《STM32L051 测试 (四、Flash 和 EEPROM 的读写)》中已经做过测试和总结。

二、写入时候容易死机问题

上面的地址写入问题,通过自己的测试可以很容的一发现,但是接下来的这个莫名其妙程序卡死的问题,花了好一阵子功夫。

2.1 问题的原因

这里我就不一步一步的说明我遇到的各种莫名其妙的程序卡死问题,当时虽然基本上猜测是 EEPROM 的写入有问题,因为读取直接取某个指针的值,速度快,也没有什么特别需要注意的,写 EEPROM 的时候需要时间,这个时间是必须等待的,所以基本上确定出问题就是在写入的时候。


虽然中间“优化”维护过程序好几次,但是莫名卡死的问题依然存在。。。。。


这里我直接说明最终原因,就是 在写入 EEPROM 的时候,如果发生了串口中断,那么就很容易出问题。


这里非常感谢 ST 社区一篇文章:STM32L0擦写EEPROM,然后宕机了?


我在自己有限的范围搜索这个问题,有且只有这一篇文章真正的说到了电子上,给了极大的参考价值:



出问题之后,我并没有单步调试,因为我虽然知道写 EEPROM 的时候会出问题,但也发现不是每次都会出这个问题,而且问题不一定能够复现,对于这个问题,上文说到:


2.2 问题的解决

2.2.1 不同的 Bank

在上面推荐文章中,给了一个很好的解决办法:

在有的芯片中,有 2 块 NVM (non-volatile memory 非易失性存储器),分为 Bank1 和 Bank2 ,两个区域都有 Flash 与 EEPROM 区域, 对 Bank1 的读写操作并不会影响对 Bank2 的读写操作,说直白点,就是 CPU 不用再挂起等待了。


那么我们我们可以做到使得对 EEPROM 的操作的地址区域 与 我们存放程序的 Flash 地址区域处于不同的 Bank 就可以。


那么这个怎么做到呢? 首先,你得明白我们程序存放于 Flash 中一般都是从 0x0800 0000 开始存放,也就是 Bank1,除非你自己修改了偏移地址。不明白这个,可以参考文章:


STM32 的启动过程 — startup_xxxx.s 文件解析(MDK 和 GCC 双环境)

https://xie.infoq.cn/article/bb7ca59b25e72f6e854e9e81f


那么我们只要保证我们的 EEPROM 的读写地址为 Bank2 即可:



于是,在程序中,我简单做了修改:


#define NVM2_EEPROM_START_ADDR     0x08080C00   //起始地址
/* EEPROM只有4页,每页512bytes,EEPROM使用方便,我们用它来保存数据 但是要注意,L051 falsh 和 eeprom没有数据的时候是 0,不是FFFFFFF L051C8 系列 和 L051R8 系列一样
L071
FALSH : bank1 0x0800 0000 - 0x0800 FFFF bank2 0x0801 0000 - 0x0801 FFFF EEPROM : bank1 0x0808 0000 - 0x0808 0BFF bank2 0x0808 0C00 - 0x0808 17FF*/

#define CH1_ID_ADDR NVM2_EEPROM_START_ADDR + 0 #define CH2_ID_ADDR NVM2_EEPROM_START_ADDR + 4#define CH3_ID_ADDR NVM2_EEPROM_START_ADDR + 8#define CH4_ID_ADDR NVM2_EEPROM_START_ADDR + 12#define CH5_ID_ADDR NVM2_EEPROM_START_ADDR + 16#define CH6_ID_ADDR NVM2_EEPROM_START_ADDR + 20#define CH7_ID_ADDR NVM2_EEPROM_START_ADDR + 24 #define CH8_ID_ADDR NVM2_EEPROM_START_ADDR + 28 #define CH9_ID_ADDR NVM2_EEPROM_START_ADDR + 32 #define CH10_ID_ADDR NVM2_EEPROM_START_ADDR + 36
复制代码


那么有的小伙伴会说,如果我的程序特别大,超过了 Bank1 怎么办?


程序大小怎么算,可查看文章:


STM32 的内存管理相关(内存架构,内存管理,map 文件分析)

https://xie.infoq.cn/article/625b2009e810086435349be30


1、首先如果是使用的有 2 个 Bank 的芯片, Bank1 有 64k 大小,一般来说程序足够了;


2、个人认为,对于中断程序来说,他们存在的位置一定是程序的前面,即便程序超过大小,存放在 Bank2 中的也是用户自己的一些程序,不可能回事中断响应程序。即便中断发生了,也是在 Bank1 中运行,无影响;


3、再者,即便不分 Bank ,我们可以屏蔽中断。下面我将介绍在没有两个 Bank 的芯片上的处理方式。

2.2.2 临界区的保护

临界区的保护,是不是特别熟悉了, 我们在讲 FreeRTOS 或者 RT-Thread 的时候都讲到过 临界区保护。


上面我们介绍了直接把 EEPROM 的操作地址与程序地址区分开的解决方式,但是对于大部分产品上我使用的 STM32L051C8 来说,没有两块 NVM ,那么只能是做临界区保护了。


查看自己的 STM32L0 系列芯片有没有两块 NVM, 可以通过 J-Flash 工具查看他们的内存情况:



那知道了原因,我们只要在程序有 EEPROM 写的位置加上临界区保护即可,比如:



如果使用裸机操作,我们可以直接在写 EEPROM 的时候屏蔽中断,使用下面 2 个函数:


__enable_irq(void);__disable_irq(void);
复制代码


如图:



虽然写需要花时间,但是该等还是得等。


因为我使用的串口通讯是收无线的报文,虽然在屏蔽中断的时候有一定的概率丢数据,但是偶尔丢数据是可以接收的,至少比写数据的时候发生中断程序卡死来得好。


而且,EEPROM 虽然写方便,也不建议频繁的写入,往往需要写的时候都是第一次设置或者特殊情况设置的时候才用到。

2.2.3 关键程序放到 RAM 中执行

除了上面 2 种比较简单的解决办法,还有一种。


在网上看到有提问者说过,官方曾有过建议,把关键程序 放到 RAM 中执行,避免冲突。


把程序放到 RAM 中执行,如果有时间,我会单独写一篇博文说明,这里只是提一下解决这种问题的可行办法。

三、官方文档

这个问题告诉我们,要想真正用好一个芯片不出问题,还是得了解好对应的芯片文档。


即便我们已经很熟悉同类型的 STM32F103 系列,使用 STM32CUbeMX 可以快速简单的上手类似系列的芯片产品,但是在有些细节问题的处理上还是容易存在问题,此时官方的文档应该是首要想到的参考文档


那么文档资料哪里下载,在 ST 社区可以通过站内搜索,关于 STM32L0 系列(后缀 1 ,3 在这里应该都可以)有关的文档:RM0377 文档,关如下图:



在文档中有一整个章节单独介绍存储设备 Flash 和 EEPROM:



其实对于产品遇到的这些问题,文档里面其实有详细的说明以及解决方式,当然,即便是到现在,我也没有 详细的全部看完,因为知道了一些注意事项,还是偷懒,文档没看那么仔细= =!


但是这里比必须强调一次官方文档的重要性。


因为在网上我找了很久这个问题,在 ST 社区也找了很久,除了上面给出的链接那篇文章,再也没有第二篇 有问题也有解决办法的文章,那么这时候,我们就只能自己去啃官方文档了!

结语

一个简单的芯片,一个方便使用的 EEPROM ,前前后后出了这么多问题,也不得不感叹,细节问题还真是不能偷一点懒 = =!


做事情不要想当然,要想产品无 bug ,该看的资料还是得看到位,希望 EEPROM 这个问题是产品更换后最后的问题。ヾ(◍°∇°◍)ノ゙


本文就到这里,谢谢大家!

发布于: 2022-10-16阅读数: 16
用户头像

矜辰所致

关注

CSDN、知乎、微信公众号: 矜辰所致 2022-08-02 加入

不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开! 为了活下去的嵌入式工程师,画画板子,敲敲代码,玩玩RTOS,搞搞Linux ...

评论

发布
暂无评论
STM32L0 系列 EEPROM 读写,程序卡死?_EEPROM_矜辰所致_InfoQ写作社区