1、概述
S32K3_低功耗LPSPI轮询、中断、同步、异步、DMA等传输方式。
所有的LPSPI支持最大15MHz数据波特率在增强型管脚上,最大7.5MHz在标准管脚上,高性能的SPI0在回环模式下支持20M速率,普通模式15M。K3系列MCU具有6个独立的SPI模块,序号为SPI0-5。所有SPI均支持DMA。一帧数据可以由一个字或多个字组成,一个字32bit,帧的最小传输长度为4bit,传输FIFO4个字,也就是128bit,发送也有128bit的FIFO。
可以在master模式下精细化调整SPI同步时钟脉冲的时频特征,如占空比,有效延迟时间。在半双工或者数据匹配功能上支持发送与接收掩码。支持半双工并行传输,允许1/2/4线并行传输, SPI0支持8线传输,可在一定程度上模拟QSPI;
LPSPI的时钟选择:LPSPI0时钟选择与其他模块不太一样。高型能的SPI0以外设桥平台时钟AIPS_PLAT_CLK为总线时钟源,其他SPI以外设桥时钟作为总线时钟源;总线时钟源输入SPI后,根据SPI预分频值得到用于度量时序参数的功能时钟,最后由功能时钟分频得到输出的SPI同步时钟信号SCK;根据时钟源的配置SPI0回环模式下支持20M波特率,普通引脚下15M;其他SPI模块回环模式下15M,普通模式下7.5M;
低功耗SPI模块硬件功能框图如右图所示,整个模块按功能可分为4部分;
1.控制逻辑:负责管理模块工作参数与通信参数,通过配置寄存器与TXFIFO写入参数;
2. 移位寄存器:将传输数据移出到总线与将数据移入RXFIFO;
3.FIFO:分为两类,发送FIFO与接收FIFO,总共4字深度。其中传输命令字也通过TXFIFO写入控制逻辑;
4.SPI外部接口:连接引脚与IO信号;
传输命令字
为在适应不同的应用场景并在传输中灵活的进行参数修改, K3_LPSPI使用传输命令寄存器TCR存储传输参数,也被称为命令字。该寄存器可为要传输的帧定义不同的属性,包括时钟相位和极性、 PCS引脚选择切换、帧长度等通信参数等。该寄存器的某些位字段可以在传输中动态更改,而无需重新配置所有SPI模块配置。这允许为不同的从机芯片重新配置通信参数,适应多变的应用场景。
值得注意的是,对传输命令寄存器TCR的修改需要执行32bit写操作,修改的命令字会被送入RX FIFO中,这可能与收到的数据混在一起。所以强烈建议在帧边界或者通信完成后(即模块处于空闲状态)再进行更新命令字的操作。
2、RTD-SDK配置
2.1、配置目标
整体框图如下
Master | 引脚 | 方向 | 作用 | 作用 | 方向 | 引脚 | Slave | |
SPI0 | PTD6 | OUT | PCS | PCS | IN | PTD6 | SPI0 | |
PTD11 | OUT | SCK | SCK | IN | PTD11 | |||
PTD10 | OUT | MOSI | MOSI | IN | PTD10 | |||
PTD12 | IN | MISO | MIS0 | OUT | PTD12 |
2.2、主、从机引脚配置
主机引脚配置如下:
从机引脚配置如下:
2.3、时钟配置
2.4、LPSPI配置
SpiDriver:
SpiBaudrate:SPI的波特率,这点没什么好说的
SpiCsldentifier:SPI的片选信号选择,这个地方与引脚配置处强相关。
SpiCsPolarity:片选信号的极性,高有效还是低有效。
SpiDataShiftEdge:数据转换在前沿还是后沿
SpiHwUnit:选择SPIx
SpiShiftClockldle:时钟空闲时是高电平还是低电平。
SpiDataWidth:数据传输宽度,单位是bit
SpiTransferStart:数据传输前沿还是后沿
SpiTimeCIk2Cs:传输时候第一次Clk到CS的时间,单位是秒。
SpiTimeCs2CIk:传输结束时候CS到CLK的时间
SpiTimeCs2Cs:两个片选时间的间隔,条件允许尽量大一些。
PSpiCsBehavior:多帧传输的时候片选保持到数据传输完还是每次传输配置的bit数之后就把CS拉到IDLE状态的选择。
SpiGeneral
SpiPhyUnit(使用DMA配置下面选项,不使用DMA不需要配置此处)
2.5、中断配置
此场景是不使用DMA的情况
使用DMA的时候不再配置SPI中断,使用DMA即可
2.6、DMA配置(使用DMA才会配置)
1、MclDma
2、dma Logic Instance
下面这个是不可配置的
3、dma Logic Channel
此处是配置DMA的用途
2.7、RM配置(使用DMA的情况下必须配置此选项)
RM:Resource Manager
3、代码实现
1、初始化
Siul2_Port_Ip_Init(NUM_OF_CONFIGURED_PINS0, g_pin_mux_InitConfigArr0);
IntCtrl_Ip_Init(&IntCtrlConfig_0);
IntCtrl_Ip_EnableIrq(DMATCD0_IRQn);
IntCtrl_Ip_EnableIrq(DMATCD1_IRQn);
Dma_Ip_Init(&Dma_Ip_xDmaInitPB);
Rm_Init(&Rm_Config);
Lpspi_Ip_Init(&Lpspi_Ip_PhyUnitConfig_SpiPhyUnit_0_Instance_0);
Lpspi_Ip_UpdateTransferMode(0, LPSPI_IP_INTERRUPT);(不使用DMA的时候调用这个)。
2、功能函数
此时注意一个陷阱:使用DMA的时候,需要将需要发送与接收的数据放在NO CACHE的区域内才可以,这一点也是FAE提醒才知道的。
主机调度函数如下:
#pragma GCC section bss ".no_cache"
__attribute__(( aligned(32) )) uint8 Txbuffer[16]
__attribute__(( aligned(32) )) uint8 Rxbuffer[16]
#pragma GCC section bss "default"
主机是一个主动的过程,此程序可以放置在周期调度任务里面。
Lpspi_Ip_AsyncTransmit(&Lpspi_Ip_DeviceAttributes_SpiExternalDevice_0_Instance_0,Txbuffer,Rxbuffer,16,Dma_Function);
Cache_Ip_InvalidateByAddr(CACHE_IP_CORE,CACHE_IP_DATA, (uint32)&Txbuffer[0U], 16);
Dma_Function是回调函数,在里面判断是发送时刻,清除接收Buff即可,也就是
Cache_Ip_InvalidateByAddr(CACHE_IP_CORE,CACHE_IP_DATA, (uint32)&Rxbuffer[0U], 16);
从机的调度有个注意点,必须在FIFO填满之后再接收主机信号,也就是从机的调度不是随意的,此时最佳时候就是在异步函数的回调里面当事件为LPSPI_IP_EVENT_END_TRANSFER再次调用Lpspi_Ip_AsyncTransmit函数以此防止数据错乱。
声明点:异步调用的时候使用DMA、同步时调用的函数为Lpspi_Ip_SyncTransmit,同步可以使用中断、轮询都行,但是异步实际测试下来尽量使用DMA,DMA在中断里面配置的其实不是中断而是DMA触发事件而已。