打印
[应用相关]

实战经验 | 启用“实时观察窗口”导致通讯出错的案例分享

[复制链接]
204|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 STM新闻官 于 2024-9-13 11:18 编辑

01 前言
通常我们使用的 IDE 在调试时都支持在程序运行过程中实时观察窗口内容的功能,当启用这个功能后,实时观察窗口中包含的寄存器或变量的值会被周期性或重复性的进行采样,进而实现窗口内容的实时更新。但是这个功能使用不当的话可能会导致一些问题,下面我们介绍这样一个外设通讯出错的案例。

0
2 问题描述
客户在使用 STM32H723 的 SPI 外设进行通讯时,通过逻辑分析仪抓取到的总线数据是正确的,但是实际接收到的数据却为 0。这种情况每隔一段时间会出现一次,这个间隔时间不是固定的。客户的测试是使用 Keil MDK 在调试状态下进行的。
03 SPI 相关知识


图1. RM0468 的 SPI_SR_RXP 寄存器位


图 1 是 SPI_SR 寄存器中 RXP 位的描述。SPI_SR_RXP 寄存器位由硬件进行管理。当RxFIFO 包含至少一个完整的数据帧时,SPI_SR_RXP 位为 1,否则为 0。
▲ 图2. RM0468 的 SPI_RXDR 寄存器

图 2 是 SPI_RXDR 寄存器的描述,对 RxFIFO 的访问是通过读取 SPI_RXDR 寄存器进行的。并且不建议在 RxFIFO 中的数据少于一个数据帧时读取 SPI_RXDR 寄存器。
▲ 图3. RM0468 的55.4.11 SPI data transmission and reception procedures 章节


图 3 是 SPI 数据收发章节的相关描述。在进行数据读取时,当 RxFIFO 中数据不足一个完整的数据帧时,读取的值为 0;当 RxFIFO 中的数据包含至少一个数据帧时,则每次读取都会读取一个完整的数据帧,并将此数据帧从 RxFIFO 中弹出。
综上所述,当 SPI_SR_RXP 为 1 时,表示 RxFIFO 中包含至少一个完整的数据帧,可以通过 SPI_RXDR 寄存器读取接收到的数据,每次读取一个完整的数据帧,并且在读取后会将此数据帧从 RxFIFO 中弹出,也就是此数据帧只能通过 SPI_RXDR 读取一次。当SPI_SR_RXP 位为 0 时,表示 RxFIFO 中不足一个完整的数据帧,如果此时通过SPI_RXDR 寄存器进行读取的话,则读取得到的数据为 0,并且不建议这样做。

0
4 问题分析与测试
客户抓取 SPI 总线上的数据是正确的,但是读取到的数据为 0 的情况,这很可能是由于在 SPI_SR_RXP 为 0 的时候读取了 SPI_RXDR 寄存器。下面就这个推测对 SPI_SR_RXP进行测试。

4.1. 测试思路
使用 NUCLEO-H723 作为硬件平台,对 SPI1 进行自收发测试,也就是将 SPI1 的MISO 与 MOSI 引脚连接在一起。再使用 MCU 的其它两个引脚进行辅助测试,分别用来显示 SPI_SR_RXP 位的状态和定位程序执行的位置。将 PF0 设置为 GPIO_Output 模式来显示 SPI_SR_RXP 位的状态,因为 RXP 为 SPI_SR 的第 0 位,所以在代码中只要将SPI_SR 的值赋值给“GPIOF->ODR”,即可将 SPI_SR_RXP 位的状态值设置到 PF0 中,设置好之后即可通过 PF0 的 GPIO 电平来反映设置时的 SPI_SR_RXP 状态。将 PD0 设置为 EVENTOUT 模式来指示当前程序执行的位置,只要在代码中执行"SEV"的汇编指令,即可在 EVENTOUT 引脚上立即输出一个脉冲,速度很快。

4.2. 使用 CubeMX 进行配置
1. 设置数据长度为 8-bit,FIFO 阈值设为 1 个数据。
▲ 图4. 配置 SPI1 的参数

2. 这里将 PA6 设置为 SPI1_MISO,PB5 设置为 SPI1_MOSI。
▲ 图5. SPI1 引脚配置

3. 设置 PF0 为 GPIO_Output 模式,用来显示 SPI_SR_RXP 的状态。
▲ 图6. PF0 的配置

4. 设置 PD0 为 EVENTOUT 模式,通过发出脉冲来指示当前程序执行的位置。
图6. PD0 的配置

4.3. 硬件连接将 PA6 与 PB5 通过杜邦线等方式连接在一起即可。

4.4. 代码修改使用 CubeMX 生成代码后,对代码进行下面修改来进行测试。
1. 添加两个 buffer 分别用来作为 SPI 收发的 buffer


2. 添加函数,用来比较收发 buffer 中数据是否完全相同。相同则返回 1,不相同则返回 0。


3. 在 main 函 数 中添 加下 面 的 操 作 进 行收 发测 试 , 清空 rxBuffer, 然 后使 用HAL_SPI_TransmitReceive()函数进行收据收发。


4. 在函数外添加了宏定义 SPI_TEST,在 HAL_SPI_TransmitReceive()函数内使用“#ifdef SPI_TEST”和“#endif”围起来的内容是新添加的内容。每次执行__SEV()的时候,都会在 PD0 中输出一个脉冲信号。每次执行“GPIOF->ODR = hspi->Instance->SR”的时候,PF0 的输出就会被更新为 SPI_SR_RXP 当前的状态。这部分主要是测试在 MCU 检测到 SPI_SR_RXP 为 1 到读取 SPI_RXDR 这一段时间内,SPI_SR_RXP 的值是否被改变(也就是 SPI_RXDR 中的值是否被读取)。




4.5. 测试与分析
将代码编译下载后进行调试。在调试状态下运行一段时间后复现了客户情况,可以看出 rxBuffer[19]的值,本来应该是 0x14,但是实际获取到的值却是 0x00。
▲ 图8. 使用 KEIL 调试时 SPI 接收到 0x00 数据

下图是在 rxBuffer[19]处抓取到的波形,可以看到在总线上的数据是正确的,解析出来是 0x14。为了更方便的进行说明,下面使用图中标签来说明执行的操作。
下面开始执行流程的分析:
  • 在图中波形的 RXP_1 处看到 PF0 的状态变高,也就是当前 SPI_SR_RXP 的值为1,也即 RxFIFO 中包含至少一个数据帧。
  • 然后执行程序的分支判断语句(用来判断 SPI_SR_RXP 是否为 1),由 STEP2 之后的波形可以看出,MCU 执行了程序 STEP_3 及之后的操作,也即这里 MCU 读取到的 SPI_SR_RXP 的值也为 1。
  • 在 STEP_3 和 STEP_4 之间执行了两个操作,一个是将 SPI_SR_RXP 的状态更新到PF0 上(RXP_2 位置处),另一个是读取 SPI_RXDR 的值。从图中波形可以看出,在RXP_2 位置处,波形由高变低,也即当前 SPI_SR_RXP 的值为 0。也就是说,在STEP_3 和 RXP_2 之间(包含这两个操作),SPI_SR_RXP 的值发生了从 1 变为 0 的变化,并且在 MCU 读取 SPI_RXDR 的时候 SPI_SR_RXP 的状态为 0。

▲ 图9. 在 rxBuffer[19]处抓取的波形与对应 SPI 进行接收的代码


但是在 STEP_3 和 RXP_2 之间(包含这两个操作),工程代码中并没有读取 SPI_RXDR寄存器的操作,所以到底什么操作读取了 SPI_RxDR 呢?通过查询《Getting started with MDK Version 5》文档发现,KEIL 在调试时有一个“Periodic Window Update”选项,当这个选项 Enable 时,调试窗口中的值会周期性的进行更新。如下图所示。
▲ 图10. Getting started with MDK Version 5 文档的 System Viewer 章节


至此,问题原因比较明显了。因为在 KEIL 调试时默认打开了"Periodic Window Update"这个选项,并且又由于在窗口中显示了 SPI_RXDR,导致调试器周期性的读取SPI_RXDR 的值,如果调试器恰好在 STEP_3 和 RXP_2 之间(包含这两个操作)读取了SPI_RXDR 寄存器的话,则会导致 MCU 读取 SPI_RXDR 的值为 0。下面对这个猜想进行验证,方法很简单,关闭"Periodic Window Update"这个选项做对比测试,如下图所示:
▲ 图11. 关闭 KEIL 的"Periodic Window Update"选项


关闭"Periodic Window Update"选项后运行了很长一段时间,并未复现读取数据为 0的情况。客户在关闭这个调试选项后,后续也并未再复现读取数据为 0 的情况。



05 小结

这个案例提醒我们,如果使用了可以通过读操作进行更新的寄存器时,最好在调试时慎用“实时观察窗口”来观察其值,因为这可能会影响程序的正常执行。这个“Periodic Window Update”的调试功能不是 Keil 独有的,在 IAR 中的"Live Watch"窗口以及CubeIDE 中的"Live Expressions"窗口都是“实时观察窗口”的功能,所以在使用时也要注意下。


使用特权

评论回复
沙发
STM新闻官|  楼主 | 2024-9-13 11:18 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:意法半导体(中国)投资有限公司
简介:您的嵌入式应用将得益于意法半导体领先的产品架构、技术、多源产地和全方位支持。意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器。

537

主题

697

帖子

17

粉丝