看起来SPI好像挺简单,连上四根线,设置好极性相位,速率等等就可以通信了,但实际上这不仅仅是SPI的通信,还有更多嵌入式所带来的问题,同样值得思考。

1.硬件连接的问题

1.1 逻辑分析仪

最开始收到12个FF的时候,没有多想,拿了一块F1的板子简单改了改代码又跑了一次,结果是一样的,然后问了导师,导师说他也不会SPI,我直接栓Q,后来有人建议用逻辑分析仪试一下,看看发送的指令是不是发出来了,然后就用来逻辑分析仪,得到的结果是这样的:
在这里插入图片描述

左边上面前七位是我发的指令,收到的是FF,这很正常,因为就是要把指令发完才会有应答,之前的数据无所谓,后面发送12个0用来接收应答,可以看出还是那熟悉的12个FF。

给人的感觉是这块芯片压根就没有工作嘛,在这期间真的是看了很几天的代码,觉得是代码出了问题,但这恰恰就是我第一次做项目的问题所在,在分析软件方面是否出现问题之前,一定要先检查硬件连接是否出了问题!
在分析软件方面是否出现问题之前,一定要先检查硬件连接是否出了问题!
在分析软件方面是否出现问题之前,一定要先检查硬件连接是否出了问题!

1.2 原理图

1.2.1 上拉电阻

硬件连接包括引脚之间的线是否连对了,线是否有损坏,还有就是电源供电是否正常,有没有共地,还有还有就是原理图是不是对的,在检查了前几个都没有问题后,我开始检查原理图是否正确:

Alt

从原理图中可以看出,SDA,SCL接了上拉电阻,于是我开始百度看看是否合理,因为之前画原理图的时候以为是用IIC通信,所以上拉了SDA和SCL,但这两根线也是SPI的MOSI和MISO,而实际上正常来讲,SPI的输入输出是不需要上拉电阻的,但是呢,接了上拉电阻只会增强信号,并没有什么问题,有益无害, 那么这个问题被排除了。

1.2.2 电容

在这里我看到电源和GND之间接了一个电容,思考再三想明白了,应该是用来滤波的,又查了一下,专业一点叫做“退藕”,作用是为高频信号提供通路,减小电源内阻,去除电源和地线在敷铜板上“走长线”的影响,防止公用电源的各部分电路之间的“有害交连”等等。

1.2.3 复位

复位这里就出现了问题,看了芯片的手册发现,芯片是低复位,而原理图中将复位引脚直接拉低,当成高复位了,这一发现让我重新燃起了希望,我将电阻取下来,在C38电容两端飞了一根线,结果还是12个FF,蚌埠住了。。。

但是至少硬件方面的没有问题了。

2.HAL库的使用

秉着先硬件后软件的思想,我又把矛头对准软件上的问题,我问了一个搞过SPI的师兄,他用的是HAL库驱动,在发数据和接收数据的时候是分开的,于是我又了CuBeMX生成了一个STM32F4的HAL库,在stm32f4xx_hal_spi.c中找到了分别发送和接收的SPI接口:

HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

但是HAL也有同时发送和接收数据的接口:

 HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)

然后我又都试过一遍,结果依然是12个FF,那为什么师兄会用HAL库分别发送和接收,我开始仔细研究这些接口有什么不同。

3.深入底层驱动

底层驱动说起来可能要说很多,但是抛开其他的不谈,只看接收和发送的过程可以看出:收发同步就是设置一个标志位,先将数据放进SPI_DR数据寄存器中发送,改变标志位,暂停发送,然后接收DR寄存器返回的值。
在这里插入图片描述

而单独发送(接收)则是设置要收到(发送)的字节大小和字节数为0,相当于发送之后就不管接收到的是什么,和之前标准库发送数据没有设置返回值是一样的。

看了很久之后发现,单独发送和接收之间的不同点就是,接收的时候需要发送Dummy数据在CLK上产生时钟,这让我对单独收发的时序产生了怀疑:

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐