从之前的Watch窗口,知道flag1的地址为 0x2000000c,flag2的地址为0x2000000d。
现在对三句C语言测试语句的反汇编语句进行解析,如下:
可以看到,这段汇编是一点问题都没有的。
接下来,先分析第三种情况——也就是测试代码放在SPI初始化之前,但是使用直接操作寄存器的方式。其反汇编如图9所示。
图9.测试代码3的反汇编(位于SPI初始化之前,直接操作寄存器)
从之前的Watch窗口,知道flag1的地址为0x2000000c,flag2的地址为0x2000000d。
现在对三句C语言测试语句的反汇编语句进行解析,如下:
可以看到,这段汇编也是一点问题都没有的。
最后,再来分析一下有问题的第二种情况,也就是测试代码放在SPI初始化之前,但是使用_HAL_SPI_DISABLE()关闭SPI的情况。其反汇编如图10所示。
图10.测试代码2的反汇编(位于SPI初始化之前)
从之前的Watch窗口,知道flag1的地址为0x20000008,flag2的地址为0x20000009。
现在对三句C语言测试语句的反汇编语句进行解析,如下:
可以看到,问题出在哪了?问题就出在“STR R3,[R 2]”这个语句上,这个语句在0x00000000这个位置写值,而0x00000000此时映射的是Flash的地址0x08000000,也就是Stack Pointer的位置。如图11和图12所示。
图11.0x00000000地址的数据
图12.0x08000000地址的数据
首先,这个位置本来就不应该被修改。
第二,因为没有对Flash程序存储器进行解锁,就往里边写值,就会造成写保护错误,导致WRPERR标志位置位。所以,可以明白为什么WRPERR会被置位了。
可是关键的问题在哪儿呢?在执行“LDR R2,[R0,#4]”这条语句时,R2本来应该是SPI2_CR1的地址,但是它竟然是0x00000000!如图13所示。
[size=0.83em]微信图片_20230813140432_4.png (89.26 KB, 下载次数: 0) 下载附件 [color=rgb(153, 153, 153) !important]昨天 14:06 上传
图13.0x2000000c地址的数据
从Watch窗口来看一下SpiHandle的情况。如图14所示。
图14.SpiHandle(未初始化)
从图14可以看到,其实刚才的0x2000000c地址就是SpiHandle结构体的地址,也是SpiHandle.Instance的地址,而SpiHandle.Instance的值为0。SpiHandle.Ins tance.CR1的地址为0x0,导致显示它装载的值是Stack pointer的值0x20000468,这里本应该是SPI2_CR1的地址和SPI2_CR1的值。
也就是因为这里的问题,才会导致了后面的WRPERR错误。
2.4 代码分析
再回到代码这边来看一下,有问题的代码究竟是有什么情况。客户的代码主要就是一句关闭SPI的语句“_HAL_SPI_DISABLE(&SpiHandle);”。
这个语句是怎么解析的?它再stm32l0xx_hal_spi.h中解析,如图15所示。
图15._HAL_SPI_DISABLE函数
看到这个函数时,看到了重要的字眼——“Instance”!就明白是什么问题了,因为这个SpiHandle.Instance还没有被初始化呢!这也说明了为什么在图14中,看到的SpiHandle.Instance的值为0x0,而SpiHandle.Instance. CR2的值为0x20000468。关键就在于这个SpiHandle. Instance还没有初始化。
所以,把客户的测试代码放在SPI初始化代码之后没有问题,就是因为这个SpiHandle.Instance已经被初始化过了。所以,它不会有问题。
|