摘要:在一个主机和多个从器件的典型SPI系统中,通常采用专门的片选信号来寻址从器件。随着从器件数量不断增加,片选线也随之增多。这种情况将给电路板布板带来很大的挑战。一个布板方法就是采用菊链结构。本文详细讲述了SPI系统的菊链配置,并展示如何使用软件向串联从器件发送命令。标准SPI™/QSPI™/MICROWIRE™兼容微控制器通过3线/4线串口与从器件通信。典型接口包括片选信号(/CS)、串行时钟(SCLK)和数据输入信号(DIN),有时还会有数据输出信号(DOUT)。如同I²C系统中一样,单独寻址的器件能轻易的和总线上的其它器件通信。基本串行通信接口很多SPI器件并不是单独寻址的。因此,这些器件和总线上其它单个器件通信时,就需要进行额外的硬件或者软件处理。图1所示是一个微控制器和多个从器件通信的系统。图1.带有多个从器件独立片选信号的微控制器。在上述系统中,微控制器通过一个串行时钟输出(SCLK)和一个主机输出/从机输入(MOSI)信号线向各从器件发送命令。主机为每个器件分配了一个独立的片选信号(/SS_),从而实现各个从器件的独立寻址。由于所有从器件共享同一个时钟和数据线,只有/CS输入变低的从器件才会应答串行时钟和数据线。当从器件数目较少时,该系统较易实现。如果系统中从器件数较多,微控制器需要提供和从器件一样多的/SS_输出,这种结构就增加了硬件和布板的复杂程度。菊链方法硬件空间方面的限制往往会使图1所示的电路无法实现或难以实现。可采用菊链法替代实现串行接口。图2是一个有N个从器件的菊链系统结构。图2.微控制器连接多个从器件采用一个/SS(或者/CS)信号控制所有从器件的/CS输入;所有从器件接收同一个时钟信号。只有链上的第一个从器件(SLAVE1)从微控制器直接接收命令。其他所有从器件都从链上前一个器件的DOUT输出获得其DIN数据。要保证菊链正常工作,每一个从器件就必须能在给定的命令周期内(定义为每一个命令所需的时钟数)从DIN引脚读入命令,而在下一个命令周期从DOUT引脚输出同样的命令。显然,从DIN到DOUT会有一个命令周期的延迟。另外,各个从器件只能在/CS的上升沿执行写入的命令。这意味着只要/CS保持低电平,从器件将不会执行命令,并且会在下一个命令周期将命令通过DOUT引脚输出。如果在给定命令周期之后/CS变高,所有从器件将立即执行写入DIN引脚的命令。如果/CS变高,数据将不会从DOUT输出,这就使得链上每个从器件可以执行不同的命令。只要菊链的这些要求能够满足,微控制器只需三个信号(/SS、SCK和MOSI)就能控制网络上的所有从器件。如何实现菊链在菊链系统中(图2),SLAVE1从微控制器直接接收数据。该数据在时钟驱动下进入SLAVE1的内部移位寄存器。只要/CS(或/SS)仍然保持低电平,该数据将通过SLAVE1的DOUT引脚输出。SLAVE1的DOUT引脚接至SLAVE2的DI引脚,因此当数据通过SLAVE1的DOUT引脚端输出时,同时也被同步移入SLAVE2的内部移位寄存器。同理,当SLAVE2接收来自SLAVE1的数据的时候,微控制器可同时向SLAVE1发送另一个命令。该新命令将覆盖SLAVE1移位寄存器中原来的数据。只要/CS保持为低,数据会在整条菊链上传递,直到每一个从器件都接收了相应的命令。存储在每一个从器件移位寄存器中的命令将在/CS的上升沿执行。下面例子使用MAX5233和MAX5290构成菊链。电路图范例#1图3给出的菊链结构中连接了3个MAX5233。MAX5233为双路、10位DAC(包含两个DAC通道,通道A和B)。将RSTV接至VDD,模拟输出的上电状态被设置到中点。图3.菊链电路#1图4给出了将IC1(A1和B1)、IC2(A2和B2)和IC3(A3和B3)的输出分别设为零点、中点和满刻度的命令序列图。在这个例子中,使用了以下的命令:0x7FF8—将满刻度数据加载到IC3DAC寄存器,并将两路输出(A3、B3)设置到满刻度0x7000—将满刻度数据加载到IC2DAC寄存器,并将两路输出(A2、B2)设置到中点0x6000—将满刻度数据加载到IC1DAC寄存器,并将两路输出(A1、B1)设置到零点图4.电路#1—命令时序A在第一个命令周期(16个SCLK脉冲序列),将0x7FF8载入IC1的移位寄存器。当/CS保持低电平,这一数据将在IC1内传递,并且在下一个命令周期内通过DOUT1输出。在第二个命令周期内,IC1输出端DOUT1上的数据输入到DIN2,将0x7FF8载入IC2的移位寄存器中。同时,新的命令0x7000将载入IC1移位寄存器,覆盖了前一个命令。第三个命令周期内,第一个命令0x7FF8将载入IC3的移位寄存器,而第二个命令0x7000将载入IC2的移位寄存器,同时IC1将接收到新的命令0x6000。此时,三个IC都从菊链上接收到命令并存储在他们的移位寄存器中。一旦/CS变高,将执行已存储的命令;A1和B1被设为零点、A2和B2被设为中点、A3和B3被设为满刻度。图5给出了更为复杂的命令序列。在这个例子中,使用以下的命令(更多详细信息,请参考MAX5233数据资料):0x3FF8—将满刻度数据加载到输入寄存器A,不改变DAC寄存器和输出0x3000—将中点数据加载到输入寄存器A,不改变DAC寄存器和输出0x2000—将零点数据加载到输入寄存器A,不改变DAC寄存器和输出0xBFF8—将满刻度数据加载到输入寄存器B,不改变DAC寄存器和输出0xB000—将中点数据加载到输入寄存器B,不改变DAC寄存器和输出0xA000—将零点数据加载到输入寄存器B,不改变DAC寄存器和输出0x0000—空操作图5.电路#1—命令序列B在第一个三命令周期内,菊链上三个IC中的各个器件的移位寄存器军接收到一条命令。IC1、IC2、IC3接收到的命令分别为0xB000、0xBFF8和0xBFF8。器件将在/CS的上升沿执行这些命令(第一次执行)。执行完之后,IC1、IC2、IC3的输入寄存器B中分别加载了中点、满刻度和满刻度的数据。此时,由于各IC的DAC寄存器B保持不变,因此B1、B2、B3均未改变。在接下来的三命令周期内,每个IC的移位寄存器中均写入了仅向输入寄存器A加载数据的命令。DAC寄存器A和输出保持不变。在/CS的上升沿,IC1、IC2、IC3的输入寄存器A分别加载了满刻度、零点和中点数据。此时,由于只更新了输入寄存器A而不是DAC寄存器A,因此A1、A2、A3均保持不变。在第二次执行命令之后,硬件/LDAC命令(驱动/LDAC为低)将输入寄存器中的数据加载到相应的DAC寄存器中。这样,DAC的输出就被刷新为相应的DAC寄存器中的数据。A1、B2和B3变为满刻度。A2变为零点而A3仍为中点状态。在第三个命令周期,IC2和IC3接收了空操作命令(0x0000),而IC1接收0xA000命令,将零点数据加载到IC1的输入寄存器B。第三次执行命令之后,所有的输出仍旧没有改变。在第四个命令周期内,IC1和IC2接收空操作命令,而IC3接收到0x3FF8命令。第四次执行命令之后,IC3的输入寄存器A加载满刻度数据。另一个硬件/LDAC命令将输入寄存器的数据加载到相应DAC寄存器。这将使B1从中点变为零点,A3从中点变为满刻度。其他的输出仍旧不变。表1.命令序列B中,上电后以及执行硬件/LDAC命令后,IC1、IC2和IC3的输出状态AnalogOutputNameStateofOutputAfterPower-Up(RSTV=VDD)FirstHardwareActive-LowLDACSecondHardwareActive-LowLDACIC1A1MidscaleFullscaleFullscaleB1MidscaleMidscaleZeroscaleIC2A2MidscaleZeroscaleZeroscaleB2MidscaleFullscaleFullscaleIC3A3MidscaleMidscaleFullscaleB3MidscaleFullscaleFullscale电路范例#2图6给出的菊链结构中有三个MAX5290(双路12位DAC)。将PU接至DVDD,则上电时模拟输出设置为满刻度。MAX5290没有专用于菊链的数字输出。因此,需通过串口将两个UPIO(用户可编程输入/输出)引脚中的任意一个编程设置为DOUTDC_模式。更多详细信息请见MAX5290数据资料。图6.菊链电路#2图7给出了命令序列示例,使用了以下的命令(更多详细信息请见MAX5290数据资料)。0xDFFF—将满刻度数据加载到所有输入寄存器和DAC寄存器,刷新DAC的A和B输出0xD800—将中点数据加载到所有输入寄存器和DAC寄存器,刷新DAC的A和B输出0xD000—将零点数据加载到所有输入寄存器和DAC寄存器,刷新DAC的A和B输出0xE400—将DAC的A和B输出置于关断模式0xE40F—使DAC的A和B输出跳出关断模式0xFFFF—空操作图7.电路#2命令时序示例器件在/CS上升沿时执行已经加载到每个器件移位寄存器中的命令。第一次执行命令后,所有DAC输出均刷新。IC1的DAC输出为零点,IC2的DAC输出为中点,而IC3的DAC输出为满刻度。第二个命令周期时,执行命令0xE400,IC2的DAC的A和B输出都进入关断模式。IC1和IC3由于执行空操作命令而不受影响。第三个命令周期后,IC1的输出变为满刻度,IC3的输出变为零点。而IC2的输出仍处于关断模式,其内部输入寄存器和DAC寄存器数据已被刷新。在最后的命令周期,IC2恢复正常工作模式,所有输出变为满刻度。表2.命令序列示例中,上电后和执行命令后,IC1、IC2、IC3的输出状态AnalogOutputNameStateofOutputAfterPower-Up(PU=VDD)AfterFirstExcutionAfterSecondExecutionAfterThirdExecutionAfterFourthExecutionIC1A1FullscaleZeroscaleZeroscaleFullscaleFullscaleB1FullscaleZeroscaleZeroscaleFullscaleFullscaleIC2A2FullscaleMidscaleShutdownShutdownFullscaleB2FullscaleMidscaleShutdownShutdownFullscaleIC3A3FullscaleFullscaleFullscaleZeroscaleZeroscaleB3FullscaleFullscaleFullscaleZeroscaleZeroscale