觉得SPI很简单,所以从来没有去仔细去看就直接用了,这次在调一个芯片的时候出现了一个比较奇怪的问题,以为是程序逻辑的问题,浪费了好几天的时间都没有找到原因。今天乖乖查阅了一些手册,最后在《STM32不完全手册》里找到了线索,现在索性对SPI做个总结。首先说最近碰到的问题。
问题一:错以为SPI的读数据,直接读取SPIx->DR寄存器就可以完成。
这个问题我一直没注意,十分惭愧。原来SPI的时钟只有在往DR寄存器里面写数据的时候才会产生,读是不会产生的(暂时没有从哪个资料中得到确认,不过我猜就是这样)。所以要读取slave发过来的数据,master必须先发一个“DUMMY”数据,这个数据内容不重要,目的只是为了产生一组clock给 slave,slave的数据就沿着这一组clock给发了出来。
master给slave读写数据的过程是这样的:
写:master对DR写数据,产生clock,同时数据从MOSI管脚移位发送到slave的MOSI管脚;
读:master对DR写DUMMy,产生clock,同时DUMMy由MOSI发给slave(这个数据没有意义),同时读取的数据从slave的MISO管脚移位发送到master的MISO管脚。
问题二:在配置为双线全双工的时候,如上面所说,在master写数据的时候,其实stm32的SPI同时也往master的DR寄存器里面读进数据(读写虽然都是DR,其实是两个不同的寄存器)。对这点的忽略,就是这次问题产生的原因。
我在对采集芯片读取数据之前,需要向芯片发送一个读取数据的指令,在发送指令后,理论来说采集芯片会自动等待发送数据过来,只要我stm32这边发一个 DUMMy产生一组clock,然后就可以从DR中读取数据。但是由于在发送读取指令的时候,其实STM32也同时也把一个无用的数据读到DR里面去了,这个数据在没有被取走之前,是不会再接受新的数据的,所以在后来发送DUMMY的时候,读寄存器DR并没有更新,所以读到的数据自然是错的。
解决方法是,在发送指令之后,读一次数据,清除DR,以便接收下个数据。
下面对SPI其他要点做一些总结。
管脚定义:
MISO:主设备输入/从设备输出
MOSI:主设备输出/从设备输入
SCK:串口时钟,作为主设备的输出,从设备的输入
NSS:从设备选择
对于NSS,对于从设备,输入低电平表示选择该从设备,这个信号在硬件NSS模式时,由NSS管脚提供;在软件NSS模式时,由内部SSI位控制,NSS管脚可以用作普通IO使用。
对于主设备,如果NSS输出被使能,NSS会输出低电平,可以与从设备的NSS相连,当从设备为硬件NSS模式时,将自动变成从SPI设备(不允许多主环境);如果NSS输出被关闭:允许操作于多主环境。