目录
2.3.2 SPI Channel Job Sequence
3.6.1 直接内存模式--Direct Memory Mode
3.6.2 固定缓冲内存模式--Fixed Buffer Memory Mode
3.6.3 固定缓冲队列内存模式--Fixed FIFO Memory Mode
MCAL处于AUTOSAR架构的最底层,和具体的芯片强绑定,且不同的芯片使用不同的MCAL配置工具,例如英飞凌芯片系列使用EB配置MCAL,瑞萨芯片系列使用Davince配置MCAL。所以,除了AUTOSAR标准定义好的配置项及标准接口外,不同厂商的MCAL还会有独立于MCAL标准之外的配置,所以MCAL的学习最好是结合具体的工具和芯片来学习。本系列MCAL分享,将基于瑞萨RH850芯片来讲解。
车载外设控制芯片(TLE92108,L9369,9301等高低边驱动)基本都是使用SPI通信。本文为SPI(Serial Peripheral Interface)模块详解。
SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。具体可以参考下面这篇文章:
SPI处理程序/驱动程序提供了从设备上读取和写入通过SPI总线连接的设备的服务。它为多个用户(例如,EEPROM、看门狗、I/OASIC)提供了对SPI通信的访问。它还提供了配置芯片SPI外设所需的机制。位于微控制器抽象层(MCAL)中。
AUTOSAR架构下的SPI模块的主要目标是充分利用每个微控制器的最佳特性,并允许根据静态配置进行实现优化,以尽可能多地适应ECU的需求。通过可选择的功能级别和可配置的特性,以允许设计一个利用微控制器特性的高可伸缩的模块。
要配置SPI处理程序/驱动程序,应遵循以下步骤:
. 应选择SPI处理程序/驱动程序功能级别,并配置可选功能
. SPI通道(Channel)应根据数据使用情况进行定义,它们可在SPI处理程序/驱动程序(IB)内进行缓冲,或由用户(EB)提供。
. SPI作业(Job)应根据HW属性(CS)进行定义,它们将包含使用这些属性的通道列表。
. 作为最后一步,应定义作业的顺序(Sequences),以便以一种排序的方式(优先级排序)传输数据。
根据所选择的功能级别,SPI处理程序/驱动程序的一般行为可以是异步的或同步的。
SPI模块涵盖了在一个单一模块中组合的Handler/Driver功能。一个是SPI处理(Handing)部分,它处理对可能位于ECU抽象层中的总线的多次访问。另一部分是SPI驱动(Driver),它直接访问可以位于微控制器抽象层中的微控制器硬件。
1个Channel对应1个发送缓冲区和1接收缓冲区;1个Job对应着1次SPI通讯发送的内容(既SPI一次片选过程所传输的内容)。1个Sequence?对应着1个SPI通讯序列(job序列)。多个Job可以分配给一个Sequence。SPI通讯是基于Sequence触发的,即使发送1个Job也要将该Job分配给1个队列,然后通过触发Sequence来实现Job的传输。
EB: 外部缓冲通道。包含要传输的数据的缓冲区在SPI处理程序/驱动程序之外。
IB: 内部缓冲通道。包含要传输的数据的缓冲区位于SPI处理程序/驱动程序中。一般都是配置为Internally Buffer。
AUTOSAR架构设计者基于以前的规范经验,总结设计了一个可伸缩性的SPI处理程序/驱动程序模块,同时也是一个适合增强需求的智能软件模块。
SPI处理程序/驱动程序指定了以下3级可扩展功能:
. LEVEL 0, Simple Synchronous SPI Handler/Driver:通信是基于与FIFO策略的同步处理来处理多次访问。缓冲区使用可配置,以优化和/或利用HW功能。
. LEVEL 1, Basic Asynchronous SPI Handler/Driver:该通信基于异步行为,并具有优先级策略来处理多次访问。缓冲区的使用是可配置为“简单同步”级别的。
. LEVEL 2, Enhanced (Synchronous/Asynchronous) SPI Handler/Driver: 该通信基于异步行为或同步处理,使用在执行期间可选择的中断或轮询机制,并使用优先级策略来处理多次访问。与其他级别一样配置。
SPI处理程序/驱动程序的可伸缩功能级别应始终是可静态配置的,即在预编译时进行配置,以允许最佳的源代码优化。
SpiLevelDelivered参数用来配置可扩展功能等级。
1个Channel对应1个发送缓冲区和1接收缓冲区;1个Job对应着1次SPI通讯发送的内容(既SPI一次片选过程所传输的内容)。1个Sequence?对应着1个SPI通讯序列(job序列)。多个Job可以分配给一个Sequence。SPI通讯是基于Sequence触发的,即使发送1个Job也要将该Job分配给1个队列,然后通过触发Sequence来实现Job的传输。
配置SPI,最主要的就是根据实际需求定义Channel Job Sequence。一个Job对应一个CS片选,多个Job可以对应同一个片选。Channel可以理解为两个主从SPI设备间的协议数据帧,每个Channel都有公共的属性(Data Width Channel ID),而这个IB/EB(缓存)里面的内容就是两个SPI设备交互的协议数据,每个Channel都绑定到一个Job上。Sequence就是几个相同内容的Job的组合。
为了允许利用所有微控制器的能力,但也允许从专用存储器位置发送/接收数据,所有级别都具有关于通道缓冲区位置的可选特性。
有两种通道缓存(Channel buffer)可以配置:
.Internally buffered Channels (IB):用于传输/接收数据的缓冲区由处理程序/驱动程序提供。
.Externally buffered Channels (EB): 要传输/接收的缓冲区由用户提供(静态和/或动态)。
通过SpiChannelBuffersAllowed参数可以配置只使用IB、只使用EB、同时使用IB和EB。
内部缓冲通道的目的是利用微控制器,包括这一特性的硬件(硬件寄存器缓存数据)。否则,该特性应该由软件进行模拟。
对于IB通道,处理程序/驱动程序应提供缓冲区,但它不能在传输期间考虑缓冲区中数据的一致性。通道缓冲区的大小是固定的。
外部缓冲区通道的目的是重用位于外部的现有缓冲区。这意味着SPI处理程序/驱动程序不监视它们。
AUTOSAR 为SPI 提供了两种方式通信的接口:
同步调用 Spi_SyncTransmit
异步调用 Spi_AsyncTransmit
同步调用,是需要等待返回调用结果,而异步调用这是发起任务,一般可以通过回调函数来告知调用结果。
对于同步调用接口 Spi_SyncTransmit() Sequence状态的切换都是在接口函数中完成的。开始将Sequence 状态置为PENDING,Sequence处理完成 立即置为OK。
?????????????
对于异步接口Spi_AsyncTransmit(),会把Sequence中的Job按照顺序加载到Job的调度表中,同时将Sequence的状态置为PENDING。由Spi_ScheduleJob函数通过DMA加载到硬件。从机返回数据通过DMA加载到对应的Channel的DestBuf中,此时Sequence并没有置为OK,而是通过Spi_Dspi_IsrDmaRx 函数去查询DMA是否传输完成,然后在重新将Sequence的状态置为OK。
这里有两种方式来调用Spi_Dspi_IsrDmaRx()。一种是在SPI的Rx中断中,一种是在MainFunction中。因此只要使用异步调用接口就没有办法直接通过接口返回值来判断数据是否发生完成,也无法判断Slave是否有返回数据。
这里有三种方式来解决这个问题。
. 将同步调用接口增加Sequence等待检查,抽象成同步方式;即等待中断服务函数将Sequence的状态切换为OK。
. 调用异步接口之后不管,在下一次发送相同Sequence时检查Sequence的状态,如果是非OK 就调用Spi_Cancel 函数取消上次Sequence的发送。
. 使能DMA Rx的Notificaion 功能,通过Call Back函数来告知调用方已经完成传输 ??
一般使用第二种办法。第三种方式使用于大量数据传输,菊花链的数据量并不是很大。
Channel配置包含:
.?EB/IB buffer的使用情况
. 传输位宽 (1~32bits)
. 传输数据个数
. 传输字节序LSB/MSB
. 传输的默认值
Job配置包含:
. 使用哪个SPI硬件实例
. 使用该实例的哪个片选引脚cs
. 片选功能是否启用
. 片选高/低有效
. 波特率
. ?clock 和 chip select之间的时间
. 时钟在空闲时是高/低
. 数据传输在上升沿/下降沿
. 优先级(低0~3高)
. Job完成的通知函数
. MCU相关的属性(可选)
. Channels(至少1个)
sequence配置包含:
. Jobs (至少1个)
. 在每个Job完成后是否产生中断
. Sequence完成的通知函数
此类型定义了SPI处理程序/驱动程序的特定状态范围。
类型Spi_StatusType为SPI处理程序/驱动程序定义了一个特定的状态范围。通过Spi_GetStatus可以获知SPI处理程序/驱动程序状态或指定的SPI硬件微控制器外设SPI通信状态。
类型Spi_JobResultType为SPI处理程序/驱动程序定义了一系列特定的Job状态。
它通知的类型Spi_JobResultType关于SPI处理程序/驱动程序作业状态,可以用作业ID调用API服务Spi_GetJobResult。
该类型的Spi_SeqResultType为SPI处理程序/驱动程序定义了一系列特定的序列状态,并可以通过调用API服务Spi_GetSequenceResult来获得。
类型Spi_AsyncModeType指定了在级别2中以异步方式处理并由Spi_SetAsyncMode获得的SPI总线的异步机制模式。
void Spi_Init( const Spi_ConfigType* ConfigPtr )
. 初始化所有ConfigPtr相关寄存器
. 定义ConfigPtr相关的默认值
. 设置SPI状态为“IDLE”,job、sequence的状态设为“ok”
. 对于Level2,异步模式设为polling,禁用spi相关中断
Std_ReturnType Spi_DeInit( void )
. 如果驱动状态不是BUSY,将spi外设置为复位上电后的状态
. 如果驱动状态是BUSY,请求被拒绝
. 去初始化后,模块的状态是UINIT
Std_ReturnType Spi_WriteIB( Spi_ChannelType Channel, const Spi_DataBufferType* DataBufferPtr )
. 返回值:E_OK:该命令被接受,E_NOT_OK:该命令被拒绝。
. 将入参数据写入对应channel的内部缓存
. 如果入参DataBufferPtr为NULL,将传输默认值
Std_ReturnType Spi_AsyncTransmit(Spi_SequenceType Sequence)
. 返回值:E_OK:该命令被接受,E_NOT_OK:该命令被拒绝。
. 在SPI总线上传输数据
. 驱动状态设为“BUSY”,Sequence状态设为“PENDING”后函数返回
. Job状态设为SPI_JOB_QUEUED
Std_ReturnType Spi_ReadIB( Spi_ChannelType Channel, Spi_DataBufferType* DataBufferPointer )
. 返回值:E_OK:该命令被接受,E_NOT_OK:该命令被拒绝。
. 同步读取一条或多条数据
. 应该在Transmit后调用,以获取相关数据
Std_ReturnType Spi_SyncTransmit( Spi_SequenceType Sequence )
. 返回值:E_OK:该命令被接受,E_NOT_OK:该命令被拒绝。
. 在SPI总线上传输数据
. 驱动状态设为“BUSY”
. Sequence、Job状态设为“PENDING”
. 此时如果有其他Sequence正在传输,应该返回 E_NOT_OK,并上报错误。
Spi_StatusType Spi_GetStatus( void )
. 获取驱动状态
本节为AUTOSAR架构下的SPI概念的理解和梳理,着重应理解Channel,Job,Sequence的概念。SPI模块是MCAL配置的难点和重点,几乎所有复杂的CDD都是通过SPI来通信的。而不同的外设,我们就需要更具外设芯片手册来配置MCU端SPI模块,除了AUTOSA架构下的哪些SPI参数的配置,还会涉及到时序的控制,独立于AUTOSAR架构之外的芯片特有的参数的配置。这些才是重点和难点。后面基于RH850芯片及L9301底边驱动的SPI模块将详细介绍SPI的实际配置,请关注本公众号后续的文章。
介绍完AUTOSAR架构下的SPI模块后,如果我们要进行配置实践,就要结合具体的主控制芯片MCU的SPI硬件模块特性以及外设芯片(这里以低边驱动芯片L9301为例)的特性来进行配置。本节将介绍RH850-U2A芯片的SPI模块。
以RH850-U22A16芯片为例,MCU内部集成了10个SPI Uinit(MSPI0-MSPI9),其中MSPI0-MSPI4每个SPI Unit有8个Channel(也就是片选通道,一个主SPI设备可以外挂8个从设备),MSPI5-MSPI8每个SPI Unit有4个Channel。也就是说RH850-U2A16理论上可以接60个SPI从设备。
RH850-U2A16芯片的SPI模块可以选用PCLK和MSPInCLK两个时钟,这两个时钟是在MCAL_MCU模块进行配置,详情请参考AUTOSAR-MCAL--MCU模块详解一文。这里我们假设选用了MSPInCLK时钟,且时钟频率配置为80MHz。后面SPI模块和外设芯片间的SPI时钟配置和数据方位时序配置都基于这个80MHz的时钟源。
每个SPI Unit的每个Channel都可以配置产生4个中断,数据发送中断,数据接收中断,错误中断以及最后一帧结束中断(Last frame end)。
每个SPI Unit的每个通道(Channel)都可以配置使用DMA进行数据传输,需要注意的是,如果一个用于SPI DMA数据传输的触发源被SPI的一个通道选定后就不能用于其他通道了。
比如触发源DMAMSPI0/DMAMSPI1可以用于MSPI0|0或者MSPI0|4,如果我们MSPI0|0选用了DMAMSPI0/DMAMSPI1,则MSPI0|4就不能使用DMA数据传输了。
RH850-U2A16的SPI数据链路层配置非常多而复杂,这里仅仅列出在配置AUTOSAR_SPI模块是需要涉及的知识点,具体的详细说明请参考芯片手册。?
1)通过设置MSPInCTL1寄存器的MSPInMSSEL位域等于0来启用主模式。
2)在主模式下,所有的通道都可以被使用。
3)可以为每个通道分别指定串行通信时钟频率和有源芯片选择。
4)通过配置MSPInCFGm3.MSPInPRCSm[1:0] 和MSPInCFGm3.MSPInCDIVm[4:0]这两个寄存器的两个位域可以分配SPI的时钟源MSPInSCK,从而得到我们想要的SPI同学波特率。
5)一个或多个芯片选择信号可以通过MSPInSSELm.MSPInCSRm[7:0]被选择。
Note: 对于RH850-U2A16 MCU端,一般都配置为Master节点,这里Slaver模式就不在赘述。
1)MSPIn的通信通过预设的帧长度和帧数来执行。
2)帧长由MSPInCFGm2.MSPInFLENm[7:0]设置,帧计数由MSPInCFSETm设置。
1) MSPInCS[7:0]位域代表SPIn的8个片选通道激活状态
2) MSPInCSRm[7:0]位域控制SPIn的8个片选通道
3)一个片选一般外接到一个SPI外挂设备上,所以一般情况下某一个时间段只片选一个外部设备(只和一个外部设备通信)。
4)如果想同时方位多个设备(多个片选信号Active激活),那么一下寄存器的参数值(设置SPI通信时序)必须设置为一样。
1)MSPInSEUPm、MSPInHOLDm的空闲时间、MSPInIDLEm、MSPInINDAm可以分别独立设置MSPInCS的设置时间(Setup time)、保持时间(Hold time)、空闲时间(Hold time)和每个CS的数据间时间(inter-data-time)。
2)通过将MSPInFIDLm设置为1,可以在两个连续的通信之间插入一个空闲时间。
Note: 配置不同SPI外挂设备,除了SPI通信波特率不一样外,就是上诉这些时隙时间配置不一样了。
1) MSPInCKR配置时钟默认状态(Low Level or High Level)
2) MSPInCFGm1. MSPInCPOLm配置时钟极性
3) MSPInCFGm1.MSPInCPHAm配置数据相位
1)MSPInCFGmMSPInPRIOm[2:0]可以为每个通道独立设置优先级。通道优先级可以设置为0到7,0为最高级别,7为最低级别。
2)如果多个通道的优先级设置相同,则最低的中断通道号具有优先级。
如果我们在AUTOSAR_MCU模块中SPI的时钟配置为80MHz。
MSPInCDIVm = 7
MSPInPRCSm=0
MSPInSCK=80 000000/(4^0 * 7 * 2) = 5714285 Hz
1)MSPI有一个可配置的RAM,可用于缓冲I/O。
2)MSPI?RAM由每个通道共享。每个通道都有一个寄存器,用来设置要使用的RAM区域。
3)MSPI有三种内存模式,而MSPI的可配置RAM用于两种内存模式。
4)可以为每个通道设置内存模式。
5)MSPI?RAM可以通过CPU/DMA直接访问。
1)在直接访问存储器模式下,通道不使用RAM,通信使用MSPInTXDAm0寄存器传输数据,使用MSPInRXDAm0寄存器接收接收数据。
2)每个传输和接收都输出中断,通信由CPU/DMA控制。
1)在固定的缓冲区内存模式下,通道使用MSPI?RAM。使用直接写入MSPI?RAM的数据作为传输数据,接收到的数据存储在MSPI?RAM中。
2)在开始通信之前,必须写入所有的传输数据。在所有通信完成后,必须读取所有接收数据。
1)在固定的FIFO内存模式下,通道使用MSPIRAM
2)从CPU/DMA写入到MSPInTXDAm0寄存器的传输数据将自动存储在MSPIRAM中。接收数据自动存储在MSPIRAM中,CPU/DMA可以使用MSPInRXDAm0读取接收到的数据。
3)当MSPInSIZEm[1:0]设置的FIFO级数的一半的缓冲区为空时,输出传输中断;当MSPInSInSIZEm[1:0]设置的FIFO级数的一半的缓冲区充满接收数据时,输出接收中断。
RH850-U2A16芯片的SPI资源非常丰富配置也非常复杂。在具体使用时需要结合具体的外设芯片的datasheet来具体配置,根据个人使用经验,其中最主要的就是配置SPI时钟及时序配置。下一篇先会介绍具体的一块SPI通信的外设芯片,后面基于RH850芯片及L9301底边驱动的SPI模块将详细介绍SPI的实际配置,请关注本公众号后续的文章。
L9301是ST(意法半导体)公司生产的专用于汽车高低边驱动的芯片。L9301芯片具有以下特点:
. 最高可配置12路输出,其中有8路可以配置为PWM输出,4路可以配置为高边驱动?
. 通过SPI接口命令可以配置L9301的转换速率(Slew-rate),过流保持(Overcurrent threshold),发送驱动命令(Drivers commands),回读诊断数据(Read baco the diagnosis results)
. 常见硬件保护:过温保护,过流保护(短路到底,短路到电源),开路保护
. 常见诊断信息:过流,过温,开路,短路诊断
. 通过配置SR寄存器(State Register)可提高EMC性能
我们主要关注芯片IC的主要输入输出引脚:
. EN使能脚(Enable),芯片正常工作时必须使能EN脚
. RES复位脚,芯片复位引脚(低电平有效)
. MOSI,MISO,SCK,CS也就是SPI硬件通信引脚,具体参考:
. DRn/SRn(n等于1,2,3,4)可配置为高边输出或者底边输出
. INn(n等于1~8),与OUTn(n等于1~8)对于,可以通过INn直接控制OUTn,INn可以为DIO输入或者PWM输入
. 其他引脚都是电源或低引脚,硬件工程师比较关注,但是我们在查问题的时候,首先应该保证芯片的电源和地的电平是正常的
通过配置L9301的CR0寄存器(后面详细介绍)的 output_conf[0:1]位域可以配置L9301的输出类型及输出通道数目。
L9301的输出配置有4种类型,配置1-3都是8路底边输出,配置4为8路底边输出加上4路高低变可配的输出。
Note:
域控项目中一般使用配置4(充分利用L9301的输出功能),这里仅介绍L9301的配置4。
1) IN1-8(MCU端的输入)或者Cmd1-8(SPI命令写寄存器) 控制 OUT1-8
2)OUT1-8只能输出低边驱动
3)DRN1-4和SRC1-4只能通过SPI命令(写寄存器)来控制
4)Cmd9同时控制DRN1 && SRC1 ....Cmd10-12以此类推
5)DRN1-4和SRC1-4可通过配置(通道配置寄存器)输出低边LS或者高边HS驱动
1)L9301的SPI协议帧长度(输入输出)固定为32Bit(4字节)
2)MOSI帧由读写寄存器位域W/R[0],寄存器地址ADD[24-30],复位请问位域RES[23],数据位域DATA[3-22],循环冗余校验CRC[0-2]组成。
3)MISO帧由SPI通信错误标志位域SPIErr[[29-31], 通道异常标志位域CHExcp[23-28],数据位域DATA[3-22],循环冗余校验CRC[0-2]组成。
对于外设芯片寄存器一般也是配置寄存器、控制寄存器、状态寄存器。
配置寄存器:配置芯片全局状态,比如CR0寄存器配置L9301的输出通道和通道高低边类型。
控制寄存器:控制芯片的输出状态,比如CR13寄存器控制L9301的12输出通道的打开和关闭。
状态寄存器:回读L9301的输出状态和诊断数据,比如SR0寄存器回读L9301的全局状态信息,SR1-SR12回读每个通道的开路、短路、过流、过温状态。
每个芯片寄存器的详细信息参考L9301的芯片手册。
MCAL的SPI标准模块中的SpiExternalDevices配置容器就是配置外设芯片的时序等信息,而SpiExternalDevices的配置就是需要结合具体芯片(L9301)的DataSheet数据手册来配置。
其他时序参数类似。
也就是根据L9301的时序图配置RH850-U2A的下述时序寄存器:
SPI通信的芯片手册的我们需要关注以下信息:
AUTOSAR架构下的MCAL_SPI的具体配置就需要结合意思外设芯片的具体信息来配置:
关注本公众号,后面具体项目实战会详细介绍。
个人认为AUTOSAR架构下的MCAL_SPI模块是整个MCAL层中最复杂的模块,我们要掌握好MCAL_SPI模块就需要详细掌握以下三个方面的基础知识:
熟练掌握好以上基础知识后,就需要结合具体的项目要求详细设计基于SPI通信的CDD_xxx复杂驱动(主要包括输入输出配置及控制,诊断信息回读及错误状态处理)。