声明:我是跟着B站江科大的视频的学习过程中记录下来作者的文案,记录下来是为了方便自己日后复习。如果你也是跟着江科大的视频学习的,可以一起学习。
我把其中一些白话进行了修改,并且添加了自己的一些理解。我只有一些pyhon基础,所以可能有错误,学起来也比较吃力,就把自己的一些理解加上去了,方便大家有和我一样没有基础的人进行学习,如果有不对的地方欢迎指正
接STM32--SPI通信外设(上)
https://blog.csdn.net/m0_61593113/article/details/141729739
波特率发生器,主要是用来产生SCK时钟的,他的内部就是一个分频器,输入时钟是PCLK,频率是72M或36M,经过分频器之后,输出到SCK引脚。这里产生的时钟是和移位寄存器同步的,每产生一个时钟,移入移出一个bit。
将以上无关的东西去掉,下面是简化后的框图。
移位寄存器是左移,高位先行,数据从高位移出去,通过GPIO,从MOSI输出,显然这是SPI的主机。同时,移入的数据通过MISO进来,通过GPIO进入移位寄存器的低位,这样循环8次,就可以交换一个字节。
另外,TDR寄存器的数据整体转入移位寄存器的时刻,TXE标志位置1,移位寄存器整体转入RDR的时刻,RXNE标志位置1,
数据控制器就是一个管理员,控制着整个电路的运行。开关控制就是SPI_Cmd(),初始化之后,给个ENABLE,使能整个外设。
此外,图上并没有画SS引脚,用普通的GPIO来模拟即可,因为可能有多个从机,STM32上的硬件资源可能不够,在一主多从的情况下,GPIO模拟的SS是最佳选择。
如何产生具体的时序,什么时间写DR,什么时间读DR?这是接下来的知识点。
这个图演示的是借助缓冲区,实现连续数据流的过程。但这个过程比较复杂,不太方便封装,实现起来比较困难。
如果对性能没有什么极致的要求,可以使用以下的非连续传输的示意图。,
实际用的话只需要4行代码就可以完成任务了。
看上图,SS置低电平,图上虽然没画但是要有。刚开始时,TXE为1,表示TDR为空,可以写入数据开始数据传输。第一步就是软件写入0xF1至SPI_DR,0xF1就是要发送的第一个数据,写入之后TDR变为0xF1,TXE变为0,表示TDR已经有数据了。此时,TDR是等候区,移位寄存器才是真正的发送区。移位寄存器刚开始没有数据,所以在等候区TDR里的F1,就会立刻转入移位寄存器开始发送,转入瞬间,置TXE标志位为1,表示发送寄存器为空。然后移位寄存器有数据了,波形就开始生成。
这里数据波形产生的时机可能有点早了,应该是在b1的时刻波形才开始产生,在这之前,数据还没有转入移位寄存器(添加一下我的理解,我也觉得有点早:TXE置0,说明TDR不为空,这时数据还在TDR中,还没有移入到移位寄存器中,然后TXE置1,说明TDR为空,数据就转移到移位寄存器中了,然后再开始产生波形移出数据,所以感觉b0出现的过早了)。然后,数据转入移位寄存器之后,数据F1的波形就开始产生了。在移位产生F1波形的同时,等候区TDR是空的,为了移位完成时,下一个数据能够不间断地跟随,就要提早把数据转到TDR里等着了,然后下一步指示软件等待TXE=1,一旦TDR空了,然后写入0xF2至SPI_DR,写入之后可以看到TDR的内容就变成0xF2了。之后的流程同理。
最后,如果我们只想发送3个数据,F3数据转入移位寄存器之后,TXE置1,我们就不需要继续写入了,TXE之后一直是1。注意,在最后一个TXE等于1之后,还需要等待一段时间,0xF3的波形才能完整发送。当完整发送之后,BUSY标志由硬件清除。
SPI是全双工,在发送一个字节完成后,接收一个字节也完成了。接收到的数据1是0xA1,这时移位寄存器的数据整体转入RDR,RDR随后存储的就是0xA1,转入的同时,RXNE置1,表示收到数据了。
注意,一个字节的波形收到后,移位寄存器的数据自动转入RDR,会覆盖原有的数据。所以,读取RDR要及时。
比如读A1,要在下一个字节A2移入RDR之前读出,否则下一个数据A2进来之后就会将A1覆盖掉,就不能实现连续数据流的接收了。
对于非连续传输,发送数据时,检测到TXE为1,TDR为空,此时移位寄存器也是空。就将第一个数据0xF1写入至SPI_DR,这时TDR的值变为0xF1,TXE为0。由于移位寄存器也是空,所以TDR的值会立刻转到移位寄存器进行发送,波形产生,并且TXE置回1,表示下一个数据就可以进入TDR进行等候发送了(这是对于连续传输)。对于非连续传输,当TXE等于1了,不着急将下一个数据写入TDR中,而是一直等待,等第一个字节时序结束,结束时意味着接收第一个字节也完成了,此时RXNE置1,然后先把接收到的第一个字节从RDR里读出来,之后再写入下一个字节的数据。也就是图中的软件等待TXE=1,但是较晚写入0xF2至SPI_DR,较晚写入TDR之后,数据2开始发送。
这样就比较容易封装成一个函数,调用一个函数就可以发送和接收一个字节。
但非连续传输问题是当上一个数据转移到移位寄存器之后,下一个数据没有及时把下一个数据写入TDR候着,所以等第一个时序结束后,下一个字节还没有送过来,那数据传输就会等着。所以时钟和数据的时序在字节与字节之间会产生间隙,拖慢了数据传输的速度。这个间隙在SCK频率低的时候影响不大,但是在SCK频率非常高得时候,间隙拖后腿得现象就比较严重了。
可以看一下下面几张图,是在不同分频系数下的波形。
首先是256分频,频率72M/256≈280k。上面是SCK信号,下面是SS信号,这个波形是SPI模式0,SPI非连续传输。这里连续交换了5个字节,但是看不出字节与字节之间的间隙。因为时钟频率比较慢,间隙时长也不大,所以间隙的影响可以忽略。
128分频,时钟频率大概在560kHz,就可以比较明显的看出来字节的间隙了。字节与字节之间并不是严丝合缝的,会降低整体字节的传输速度,但是看上去也可以忽略不计。
下图是64分频,频率大概是1M多点,因为时钟频率增大,时间尺度缩小,这样看来间隙比较明显。
以下是二分频,时钟频率是36MHz,
可以看出随着时钟频率增大,这个间隙影响越来越大,如果想要追求高性能,将时钟频率发挥到最大,可以采用连续传输的操作逻辑或使用DMA自动转运,
以下是软硬件波形对比,上面是软件,下面是硬件。
硬件波形数据线的变化是紧贴边沿的,而软件波形数据线的变化在边沿后有一些延迟,
后面手册时间我就没整理了,就是粗略地带着看了一遍,所以想要仔细了解的话可以自行查看手册。