SPI的概述(部分内容摘自百度百科)
SPI是英文Serial Peripheral Interface的缩写,中文意思是串行外围设备接口,SPI是Motorola公司推出的一种同步串行通讯方式,是一种三线同步总线,因其硬件功能很强,与SPI有关的软件就相当简单,使CPU有更多的时间处理其他事务。
SPI是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
SPI总线系统是一种同步串行外设接口,它可以使MCU与各种外围设备以串行方式进行通信以交换信息。该接口一般使用4条线:串行时钟线(SCLK)、主机输入/从机输出数据线MISO、主机输出/从机输入数据线MOSI和低电平有效的从机选择线SS(有的SPI接口芯片带有中断信号线INT或INT、有的SPI接口芯片没有主机输出/从机输入数据线MOSI)。
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)它们是SDI(数据输入),SDO(数据输出),SCLK(时钟),CS(片选信号)。
(1) SDO – 主设备数据输出,从设备数据输入
(2) SDI – 主设备数据输入,从设备数据输出
(3) SCLK – 时钟信号,主设备产生
(4) CS – 从设备使能信号,主设备控制
其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效。这就允许在同一总线上连接多个SPI设备成为可能。
SPI的工作方式
SPI 在CPU与外部设备之间传输1-bit串行数据,SPI允许CPU和DMA访问传输和接受FIFOs,并且支持两个方向的同时传输,即全双工。SPI有两个channel,TX channel和RX channel。TX channel从TX FIFO到外部设备,RX channel 从外部设备到RX FIFO。
CPU或DMA可以将数据写到SPI_TX_DATA寄存器上,再由寄存器自动的将数据移到TX FIFOs,如果从RX FIFOs中读数据的话,CPU或DMA可以访问SPI_RX_DATA, RX FIFOs中的数据会自动送到SPI_RX_DATA中。
SPI有两种工作模式,master和slave,在master方式下,SPICLK由主设备产生并传送到外部设备。SS(低电平有效)信号用来选择slave,在一对多的工作模式下,可以使能不同的slave设备。SPI支持DMA,中断和轮询工作方式。
SPI支持四种工作格式,根据CPOL(时钟极性)和CPHA(时钟相位)来定义四种格式。
SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设备时钟相位和极性应该一致。
结合datasheet,需要顺序的设置功能寄存器。
SPI驱动
由于SPI协议比较简单,所以驱动可以做成Build-in的流驱动,根据流驱动的规范,这样可以实现DllEntry ,SPI_Init,SPI_Open,SPI_Read,SPI_Write,SPI_IOControl,SPI_PowerDown,SPI_PowerUp,SPI_Deinit,SPI_Close,SPI_Seek等接口函数,其中SPI_Seek和SPI_Close可以不用实现。当驱动被加载的时候,就需要去初始化系统资源,创建一些线程,并且关联一些中断,如SPI中断,DMA中断等。在整个驱动里,支持DMA,中断和轮询等工作方式。创建多个初始化就运行的线程,如ThreadForTx,ThreadForRx,ThreadForSpi,ThreadForRxDmaDone,ThreadForTxDmaDone。通过与硬件中断关联的事件和软件中断来配合实现数据的收发。例如,应用程序可以通过CreateFile打开驱动句柄,并通过DeviceIoControl进行配置,此时SPI将被调用,当调用SPI_Read时,可以通过设置事件来使能ThreadForRx,使其被唤醒并根据所设置的工作方式进行读取数据,当 工作结束时,就可以通知SPI_Read,整个读取过程结束。
整个过程相对简单,但是如果要很好的工作,就需要slave与master设置一致。驱动尽可能做的与外部设备无关。因为工作中,时间有限,只要调试成功,能够正常工作,就很少再去考虑驱动的完善。这是目前自己比较欠缺的。希望在工作中不断加深认识,学习协议,多看源码。
点滴记录自己的成长历程,如有认识错误,敬请指出。