【Autosar】MCAL - SPI(NXP - S32K14x)

MCAL - SPI(NXP - S32K14x)

MCAL - 汇总

  • 配置工具:EB Tresos Studio
  • 芯片类型:S32K146

1. 概述

如果有大佬对此部分有比较深入的介绍文章,希望能分享给我再深入学习一下。

1.1 SPI框图(S32K146)

SPI基础知识点:传送门
在这里插入图片描述
数据发送:

用户将数据写入到TDR寄存器后,数据会被存入TX FIFO,数据将通过Shift Register(移位寄存器)按位从SOUT发送出去。TCR寄存器和CCR寄存器分别决定了数据传输(CPOL、CPHA等)和传输时序。CCR寄存器在lpspi使能后就无法修改,TCR寄存器被修改后会被写入到TX FIFO并且被标记,当该值处于TX FIFO的头部分时候,会根据当前的spi状态来决定后续执行动作如下图如所示:
在这里插入图片描述
数据接收:

数据从SIN输入,通过Shift Register(移位寄存器)存入RX FIFO

1.2 引脚

各引脚功能介绍如下图所示,(SCK / PCS / SIN / SOUT)就是SPI中对应的(SCK / CS / MISO / MOSI)引脚:

在这里插入图片描述

1.3 时钟

数据收发框图中对应的时钟介绍如下图所示:

在这里插入图片描述

2. API

函数描述
Spi_InitSPI模块初始化
Spi_DeInitSPI模块恢复至默认状态
Spi_WriteIB将数据写入内部缓存区
Spi_AsyncTransmit异步传输数据
Spi_ReadIB从内部缓存区读取数据
Spi_SetEB设备外部数据缓存区
Spi_GetStatus获取SPI模块状态
Spi_GetJobResult获取任务结果
Spi_GetSequenceResult获取序列结果
Spi_SyncTransmit同步传输数据
Spi_GetHWUnitStatus获取硬件单元状态
Spi_Cancel取消执行序列
Spi_SetAsyncMode设置异步模式(中断/轮询)
Spi_MainFunction_Handling轮询函数

3. 配置介绍

3.1 General

在这里插入图片描述

SpiChannelBuffersAllowed:通道缓存允许方式(0:Inner / 1:Extern / 2:Both)

SpiInterruptibleSeqAllowed:是否允许正在执行的序列能否被打断(挂起)

SpiLevelDelivered:同步/ 异步

SpiSupportConcurrentSyncTransmit:是否支持多个同步任务并行执行

SpiCPUClockRef:时钟参考点

SpiGlobalDmaEnable:传输方式(true:支持FIFO、DMA / false:支持FIFO)

SpiTransmitTimeout:传输超时时间

超时时间的设置必须大于数据传输的时间,数据传输时间计算有以下两种方式:

①Continue: true

在这里插入图片描述

②Continue:false

在这里插入图片描述

SpiOptimizeOneJobSequences:在同步模式下,提前缓存只有一个任务的Sequence信息,加快传输速度(待深入了解)

3.2 SpiPhyUnit

SpiPhyUnitMapping:SPI硬件单元选择

SpiPhyUnitMode:主从模式选择

SpiPhyUnitSync:传输模式(true :同步 / false:异步)

配置项关联:同步(SpiLevelDelivered = 0 or 2),异步(SpiLevelDelivered = 1 or 2)

SpiPhyUnitClockRef:参考时钟点

3.3 SpiChannel

SpiChannelType:通道类型(IB/EB)

SpiDataWidth:数据宽度

①数据宽度决定了底层访问TDRRDR寄存器是按照1/2/4字节访问

②FRAMESZ = SpiDataWidth - 1

SpiDefaultData:默认填充数据(在没有配置缓存区的时候,如果启动传输,则会传输默认的填充数据)

SpiIbNBuffers:内部缓存区大小

SpiEbMaxLength:外部缓存区最大长度

SpiTransferStart:MSB/LSB(数据大小端)

3.3 SpiSequence

在这里插入图片描述

SpiInterruptibleSequence:正在执行的序列能否被打断(挂起)

SpiSeqEndNotification:Sequence完成回调

在这里插入图片描述

SpiJobAssignment:任务关联

3.3 SpiJob

在这里插入图片描述

SpiHwUnitSynchronous:以同步或异步的方式驱动硬件单元

SpiJobEndNotification:任务结束回调

SpiJobStartNotification:任务开始回调

SpiJobPriority:任务优先级

SpiDeviceAssignment:关联外部设备

在这里插入图片描述

SpiChannelList:关联通道

3.4 SpiExternalDevice

在这里插入图片描述

SpiSlaveMode:主从模式

SpiBaudrate:波特率

SpiCsIdentifier:选择片选引脚

SpiCsPolarity:片选引脚有效电平

SpiCsSelection:当使用LPSPI时,选择CS_VIA_PERIPHERAL_ENGINE会配置TCR寄存器的PCS(关联SpiCsIdentifier)

SpiDataShiftEdge:CPHA选择(边沿选择)

SpiEnableCs:启用片选引脚

SpiHwUnit:硬件单元选择(序号对应的是SpiPhyUnit中第几个)

SpiShiftClockIdleLevel:CPOL选择(空闲电平)

SpiTimeClk2Cs:

在这里插入图片描述

SpiTimeCs2Clk:

在这里插入图片描述

SpiTimeCs2Cs:

在这里插入图片描述

SpiCsContinous:连续模式(发送完FRAMES长度的数据帧后CS是否保持)

SpiByteSwap:字节交换

SpiPinConfig:

在这里插入图片描述

4. 功能介绍

4.1 关联图

在这里插入图片描述

4.1.1 HwUnit

硬件单元:S32K146可选择的有LPSPI0LPSPI1LPSPI2FLEXIOSPI0FLEXIOSPI1

4.1.2 ExternalDevice

外部设备:指的是SPI硬件单元的配置。

我们通过SPI外设与外部设备(FLASH、TJA1145)进行通讯,需要确定波特率、通讯模式(CPHA、CPOL)等信息,都在此处配置。

4.1.3 Channel

通道:数据缓存区,可以配置为IB / EB。

  • IB - Inner Buffer(模块内部)

    配置完成后,SPI模块会开辟2个数组作为通道的输入/输出缓存区指针,选择EB的时候则为NULL。

    看网上很多写内部缓存区是SPI内部的FIFO,其实是不对的,从软件上看,SPI底层始终都是从RAM中获取数据,再把数据写到TDR寄存区,SPI模块会将TDR寄存器里面的数据搬运到FIFO中,SPI内部的FIFO只有4字大小。所以从用户角度看,不管是内部还是外部Buffer,就是静态(自动生成)和动态(用户设置)的区别。

    /*  Buffers Descriptors for IB Channels (if any) */
    static VAR(Spi_BufferDescriptorType, SPI_VAR) Buffer_PBSpiChannel_0 =
    {
        BufferTX_PBSpiChannel_0,
        BufferRX_PBSpiChannel_0
    };
    
  • EB - External Buffer(模块外部)

    配置完成后,通道的输入/输出缓存区指针为NULL,且在SPI初始化的时候也会赋值为NULL且长度清0,配置为EB模式,需要用户调用SPI_SetupEB去设置输入/输出缓存区。

4.1.4 Job

任务:一个任务只能绑定一个外部设备,但是一个任务可以绑定多个通道,传输一个任务时,会先获取它绑定的外部设备信息,从外部设备信息中获取对应的硬件单元,将外部设备信息中定义的配置信息设置到对应的硬件单元的寄存器中,再按顺序将通道里面的数据进行传输。任务是可以设定优先级的,S32K146只能设置0/1/2/3这四个等级

4.1.5 Sequence

Sequence是数据传输的最小单位,一个Sequence可以包含多个Job。

当开始传输一个Sequence时,会按顺序获取绑定的Job,再以Job为单位依次进行传输。按我的理解这么设计是为了一次操作可以与多个外部设备进行数据交互。具体可以实现怎样花里胡哨的功能待探究~

4.2 异步 / 同步

等级支持模式
Level 0同步
Level 1异步(中断)
Level 2同步 / 异步(中断)/ 异步(轮询)

注意设置为Level2时,默认下使用的是轮询模式,需要用户自己调用Spi_SetAsyncMode切换到中断模式

4.2.1 同步

用户调用Spi_SyncTransmit开启数据传输,从下图可以看到,当发送数据和接收数据为空并且收/发FIFO为空的情况下才会退出,否则一直阻塞等待时间超时才退出。

while(
      ((Spi_LPspi_pSyncTransmitState->LPspi_LengthTX>0u) && (Spi_LPspi_pSyncTransmitState->LPspi_EndOfJobFlag==(uint8)FALSE)) ||
      ((Spi_LPspi_pSyncTransmitState->LPspi_EndOfJobFlag==(uint8)TRUE) && ((Spi_LPspi_pSyncTransmitState->LPspi_LengthTX>0u) || 
      (Spi_LPspi_pSyncTransmitState->LPspi_LengthRX>0u))) || 
      (LPspi_u32FSR_RX_TX_Status != 0u))
4.2.2 异步
#if (SPI_LEVEL_DELIVERED == LEVEL1)
                    /* handler uses interrupt mode only if LEVEL 1 is selected */
                    Spi_Ipw_IrqConfig(HWUnit, SPI_INTERRUPT_MODE);
#endif            
#if (SPI_LEVEL_DELIVERED == LEVEL2)
                    /* handler uses polling mode only if LEVEL 2 is selected */
                    Spi_Ipw_IrqConfig(HWUnit, SPI_POLLING_MODE);
#endif

异步模式配置:

SpiLevelDelivered:1 or 2

SpiHwUnitSynchronous:ASYNCHRONOUS

SpiPhyUnitSync:false

4.2.2.1 中断 / 轮询

轮询和中断的本质都是通过TDFRDF中断完成标志来通知用户,只不过中断模式下使能了中断,当中断标志置位后MCU内部主动调用中断服务函数执行后续操作(Job回调、Sequence回调、设置状态标志位、执行下一个任务等),轮询模式不使能中断,因此中断完成标志置位后,只能通过周期函数对中断完成标志进行轮询判断,这个周期函数就是Spi_MainFunction_Handling

4.2.2.2 HwUnit Queue

当执行3个Sequence,每个Sequence中都包含1个优先级为1的任务,任务的执行顺序如下图所示,当执行Job0的时候,会先将队列头尾都填充Job0,如果此时Job0还未被执行,Job1入队了,则将Job0的NextJob连接到Job1上,Job1填充队尾(模拟链表插入操作),当Job2入队的时候,Job1的NextJob连接Job2,队尾填充Job2。当Job0出队被执行时,将Job0的NextJob(也就是Job1)填充到队头,依次类推。当Job2出队以后,NextJob为NULL,此时将队尾填充为NULL,并去扫描低优先级的队列是否还有任务需要执行。


参考资料:

S32K-RM.pdf - NXP

AUTOSAR_MCAL_SPI_UM[1].pdf - NXP

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值