十四.SPI使用1——SPI基础和ICM20608的使用
在日常设备使用中,最常用通讯协议就是I2C和SPI了,前面过了一遍I2C,I2C接口速度最快能到400K,但是SPI能到几时兆。下面我们来实现SPI的使用。
SPI接口
SPI硬件定义
SPI和I2C一样属于一种串行通讯协议,但是I2C需要2根线实现通讯,这样就限制了传输的速度;SPI则需要4根线才能数据通信(如果是单向通讯的话可以只用3根线)这四根线的定义如下:
- CS/SS(Chip Select/Slave Select)片选信号,用来选择需要进行通讯的设备。I2C接口是通过主机发送从机地址来实现通讯的,SPI就不需要发送从机地址,通讯时直接将需要对设备对应的片选信号拉低就可以了。
- SCK(Serial Clock)串行时钟,和I2C的SCL一样用来提供通讯时钟。
- MOSI/SDO(Master Out Slave In/Serial Data Output)主机输出从机输入信号线,传输方向固定,用来从主机向从机发送数据。
- MISO/SDI(Master In Slave Out/Serial Data Input)和前面的信号线相反,由从机向主机发送数据。
SPI通信都是由主机发起,主机提供了通讯所需要的时钟,然后通过每个CS信号指定多个从机之间的某一个。硬件接口如下图
SPI工作模式
SPI有4种工作模式,通过串行时钟的极性(CPOL——Clock Polarity)和相位(CPHA——Clock Phase)的搭配来切换,主要就是描述了时钟在传输数据时的状态
CPOL=0:串行时钟空闲时为低电平
CPOL=1:串行时钟空闲时为高电平
CPHA=0:时钟的第一个跳变沿采集数据
CPHA=1:时钟的第二个跳变沿采集数据
不同模式下传输的时钟状态如下图(图截取自正点原子驱动开发指南)
我们一般使用,都是按照第4种状态——CPOL=0,CPHA=0。
数据时序
我们按照前面CPOL和CPHA都为0时的时序图分析一下:
因为SPI是全双工通讯的, 读和写可以同时完成,所以时序比区分读写时序的I2C要简单的多。上面的图中,由于,CPOL和CPHA都为0当CS信号拉低以后第一个时钟拉高的时候开始传输数据,MOSI数据线上数据为0b11010010,即主机发送0xD2给片选信号选中的设备,同时接收到MISO数据线上数据0b01100110(0x66)。整个数据传输过程就完成了。
IMX6ULL的SPI接口
I.MX6LL上的SPI全称叫做ECSPI(Enhanced Configureable Serial Perpheral Interface),具有64*32个接收FIFO(RXFIFO)和64*32个发送FIFO(TXFIFO)。整体架构如下:
具备如下特点:
- 一共具备4组SPI接口
- 全双工异步通讯
- 主从状态可配置
- 4个片选信号,支持多个从机
- 发送和接收数据都带有一个32位64的FIFO
- 时钟、片选信号及CPOL和CPHA可设置
- 支持DMA(Direct Memory Access)操作,直接操作寄存器
寄存器定义
I.MX6ULL提供了4组SPI接口,每组接口对应了10个寄存器来控制
我们一个个来看看这10个寄存器都是怎么用的
Receive Data Register(ECSPIx_RXDATA)
接收数据寄存器, 只读,由于我们每次传输数据都是一个一个字节进行的,所以一般情况只用到低8位。读取数据时要等到RR标志位有相应动作才能进行。
Transmit Data Register (ECSPIx_TXDATA)
发送数据寄存器,我们把数据写入到该寄存器,SPI控制器就会把数据发送出去。
Control Register (ECSPIx_CONREG)
控制寄存器。这是个重点,寄存器结构图如下
EN(bit[0])使能位,0时关闭SPI
HT(bit[1])Hardware Trigger 模式使能,IMX6UL不支持该功能,可以忽略
XCH(bit[2])master模式下起作用,为0时开启SPI突发访问
SMC(bit[3])开始模式控制,只能在master模式下起作用,设置为1时在我们向TXFIFO写入数据时马上开启SPI突发访问,发送数据。
CHANNEL_MODE(bit[7:4)设置SPI主从模式,由于有4个片选信号,每个接口可以接4个设备,4个bit对应4个接口,我们需要使用SS0片选,也就对应通道0,bit[4]要设置为1。
POST_DIVIDER(bit[11:8) 分频,SPI时钟第二步分频设置控制
PRE_DIVIDER(bit[15:12])SPI预分频,时钟分频设置第一步
DRCTL(bit[17:16])Data Ready Control信号控制,只在master模式下有用,主要用来确定突发访问的信号触发状态:00时不关心该信号,01时为边沿触发,10时为电平触发。
CHANNEL_SELECT(bit[19:18])选择通道,我们使用通道0,要将这两个bit设置为00。
BURST_LENGTH(bit[31:20])突发访问长度,12个bit,说明在一次SPI发送数据过程中最大可以发送2^12bit到数据,寄存器可以被设置0x0~0xFFF,如下表所示。
我们每次发送数据长度为1个字节,也就是8bit,可以将其设置为0x7。
Config Register (ECSPIx_CONFIGREG)
配置寄存器,结构如下表
每个控制单元都是4个bit,对应控制其下面对应的4个通道。
SCLK_PHA(bit[4:0]),时钟相位控制模式,4个bit控制4个通道,我们要将bit[0]设置为0,对应CPHA=0,即串行时钟第一个跳变沿开始采集数据
SCLK_POL(bit[7:4]),时钟极性控制模式,使用中要讲通道0的值设置为0(bit[4]=0),即空闲时为低电平
SS_CTL(bit[11:8]),片选信号控制,大概意思就是0时每次突发产生1个信号。我们设置为0。
SS_POL(bit[15:12]),片选信号极性设置,0时片选信号低电平有效,1时为高电平,设置为0
DATA_CTL(bit[19:16]) 数据空闲为状态,0时数据线为高电平
SCLK_CTL(bit[13:20]),时钟空闲状态,要和前面CPOL保持一致
HT_LENGTH(bit[21:28]),HT长度,我们不使用
Interrupt Control Register (ECSPIx_INTREG)
中断控制寄存器,只有低8位有效
我们暂时不使用,只把说明放在下面
主要就是几个中断相关的控制位。
Status Register (ECSPIx_STATREG)
状态寄存器,低8位有效
不论在读写的过程中都要判断状态寄存器的状态
TE(bit[0]) TXFIFO Empty,1时说明TXFIFO为空,发送数据前要等到FIFO空了以后才可以写入新的数据。要在发送数据前检查该位是否为1
TDR(bit[1])TXFIFO Data Request,1时说明FIFO中有数据需求,即有效数据数量低于指定值。
TF(bit[2])TXFIFO Full,1时说明FIFO数据满
RR(bit[3])RXFIFO Ready,1时说明有至少存在1个数据(32位)在FIFO中等待读取。所以在接收数据的时候要等待这个位为1
RDR(bit[4])RXFIFO Data Request,效果同TDR
RF(bit[5])RXFIFO Full,读FIFO数据满
RO(bit[6])RXFIFO Overflow,1时表明RXFIFO溢出,写1清除
TC(bit[7])Transfer Completed,1时表明传输完成,写1清除
bit[7:6]两个应该是和中断相关的标志位。
Sample Period Control Register (ECSPIx_PERIODREG)
采样周期,SPI设备在连续数据传输过程中在完成了8个bit的数据传输后,可以设置一个等待时间,
中间这个Wait State的时间就由这个寄存器控制
根据官方建议,bit[14:0]设置为0x2000,bit[15]设置为0,即SPI时钟,bit[20:16]表示片选信号延时,我们设置为0。
最后两个寄存器我们暂时用不到,先不关注了。以后如果用到了再来完善
时钟设置
SPI的时钟从时钟树上可以查到
最终来自pll3_sw_clk=480MHz,经过8分频以后为60MHz。但是要设置CSCDR2寄存器ECSPI_CLK_SEL(bit18)=0,分频器CAN_CLK_PODF(bit24:19)设置为0表示1分频,所以最终进入SPI的时钟源为60MHz。
但是ECSPI模块的Control Register(bit[15:8])还会将进入的时钟源进行2级分频,其中bit[15:12]为前几分频,值为0-0xf,表示1-16分频,bit[11:8]为2级分频,设置为2^0~2^15分频,一定要注意这个二级分频的分频器跟1级是不同的