Bootstrap

CP Autosar - Mcal - Spi

A picture is worth a thousand words --- 鲁迅

初来乍到,如有问题 请多指教。

overall

  • 主从模式操作

    全双工操作

    半双工操作

    自动从机选择控制

    四线和三线连接类型

  • 数据格式灵活

    可编程数据位数:2 ~ 32位数据位(加奇偶校验:3 ~ 33位)

    可编程切换方向:LSB或MSB先切换

    可编程时钟极性:空闲低或空闲高状态的移位时钟

    可编程时钟相位:用移位时钟的前或后边缘进行数据移位

  • 波特率生成

    由高精度锁相环时钟产生的波特率,异步到系统锁相环

  • 中断产生事件

    在发射机FIFO事件

    接收FIFO事件

    在一个错误条件(接收,波特率,发送错误,校验错误)

    报文传输过程(帧的开始,帧的结束…)

  • QSPI支持DMA控制器的控制和数据处理

  • 灵活的QSPI引脚配置

  • 硬件支持校验模式

    奇/偶/无奇偶性

  • 16个可编程从属选择输出SLSO[15:0]在主模式

    自动SLSO生成与可编程时间

    可编程激活和启用控制

    支持多路外部从设备输出

  • SPI的应用场景

- 多模式复位操作

  每个软件的状态机复位(只复位状态机)

  每个软件模块复位(包括fifo,所有寄存器和状态机)

  波特率错误后,从模式状态机自动停止选项

- 回环模式(上文提到的CAN 也有一样的机制)

- 在RxFIFO满时通信停止

  移位寄存器满和RxFIFO满可以暂停通信

  产生中断

QSPI模块的主要目的是使用时钟、数据输入、数据输出和从机选择信号提供与外部设备的同步串行通信。该模块的重点是快速和灵活的通信:点对点或主对多从服务器通信。从片上总线主服务器到模块的并行请求将通过片上总线系统依次执行。读-修改-写特性提供了一个原子的读/写序列,在此序列之间没有其他主程序可以访问模块。不支持模块硬件信号量

整个传输过程是 一个配置 加上一段数据,然后又是一个配置 加上一段数据。交替进行。Q的特点是 在RAM buffer 到FIFO 以及数据回读是 Qspi 和 DMA 的过程,在此期间释放了CPU,减少了CPU的负载,不需要CPU 进行参与。

上面我们对Qspi功能有了初步的认识,下面具体聊一聊不同模块。

原理分析

使用QSPI的两个设备之间的通信通常使用四种信号: (下图最右方)

  • 串行时钟SCLK

  • 数据在主从方向MTSR(主发送从接收)

  • 从到主的数据

  • 从节点片选信号

基础寄存器是制度寄存器,如果需要写需要写入FIFO,在读取过程中不需要,只需要移位寄存器。

上面说到的BACON 寄存器,基础寄存器。数据本身在RAM 空间时候就是队列的形式 通过DMA 想FIFO 进行传输,然后再FIFO 里面配置BACON 寄存器 和 移位寄存器。整个过程不需要CPU。

扩展配置寄存器ECON ,这个寄存器是静态的。只能在初始化的过程配置一次。

主要对最小时钟单元配置,时钟phase, idle时候的极性配置,大小端等SPI 通讯过程的属性配置。下面给一下mcal 配置界面和 寄存器的对照图(梨子)。

配置过程中需要仔细看芯片手册里面寄存器使用。然后对着工具进行配置。

那么数据是怎么使用这两个寄存器呢

  • 配置信息写到基础寄存器

  • 数据放到移位寄存器

  • 基础寄存器根据信息 来选择使用扩展寄存器信息,进而控制数据传输属性

举个梨子:

需求:

  • 有三个从节点

  • 节点一需要8个bit数据,MSB,偶校验;节点二需要16个bit LSB,奇校验;节点三需要32个bit MSB 偶校验

  • 使用短数据模式发送

看看怎么实现基本寄存器。

那么如果要发37位数据怎么办呢。

注意DL : Data Length Defines the data length in bits or bytes of one data block, depending on the setting of the bit field BYTE. For the maximum baud rate of 50 MBaud, the minimum data length possible is four. 00 H 2 bits if BYTE=0; XXL mode if BYTE=1 01 H 2 bits or bytes … 1F H 32 bits or bytes

最小的传输位2个bits 所以 我们可以采用16bits+17bits 来进行传输,只不过需要在前一个数据的LAST位填0 来表明这不是最后一组数。对应的就是

LAST:0, BYTE: 16; LAST:1, BYTE:17.

BACON 实例数据结构

uint32 IfxQspi_calculateBasicConfigurationValue(Ifx_QSPI *qspi, const IfxQspi_ChannelId channelId, const SpiIf_ChMode *chMode, const float baudrate)
{
    Ifx_QSPI_BACON bacon;
    bacon.U = 0;
​
    uint32         pre = IfxQspi_calculatePrescaler(qspi, baudrate);
​
    bacon.B.LAST   = 0;                       /* 1-bits Last Word in a Frame, will be set via recalcBasicConfiguration before transfer */
    bacon.B.IPRE   = pre;                     /* 3-bits Prescaler for the Idle Delay */
    bacon.B.IDLE   = chMode->csInactiveDelay; /* 3-bits Idle Delay Length */
    bacon.B.LPRE   = pre;                     /* 3-bits Prescaler for the Leading Delay */
    bacon.B.LEAD   = chMode->csLeadDelay;     /* 3-bits Leading Delay Length */
    bacon.B.TPRE   = pre;                     /* 3-bits Prescaler for the Trailing Delay */
    bacon.B.TRAIL  = chMode->csTrailDelay;    /* 2-bits Trailing Delay Length */
    bacon.B.PARTYP = (chMode->parityMode == Ifx_ParityMode_even) ? 0 : 1;
    bacon.B.UINT   = 0;                       /* 1-bits User Interrupt at the PT1 Event in the Subsequent Frames */
    bacon.B.MSB    = (chMode->dataHeading == SpiIf_DataHeading_lsbFirst) ? 0 : 1;
    bacon.B.BYTE   = 0;                       /* only support bitwise selection in B.DL */
    bacon.B.DL     = chMode->dataWidth - 1;
    bacon.B.CS     = channelId;
​
    return bacon.U;
}

如果我们需要传输很大的数据,这时候可以使用长类型。长类型是以byte位单位进行传输。这里只需要把对应的 BYTE位 配置成1。 这时候DL 里面的意思就是n个byte.

ECON 实例代码:

uint32 IfxQspi_calculateExtendedConfigurationValue(Ifx_QSPI *qspi, const uint8 cs, const SpiIf_ChConfig *chConfig)
{
    Ifx_QSPI_ECON econ;
    econ.U = 0;
​
    float32       tQspi  = 1.0f / IfxQspi_getTimeQuantaFrequency(qspi);
    float32       tBaud  = 1.0f / chConfig->baudrate;
    int           abcMin = (2);
    int           abcMax = (4 + 0 + 4);
    int           q, bestQ = 0, abc, bestAbc = abcMax;
    float32       error, bestError;
    boolean       done = FALSE;
​
    bestError = 1e6;
​
    for (q = 1; q <= 64; q++)
    {
        for (abc = abcMax; abc >= abcMin; abc -= 2)
        {
            float32 tBaudTmp = tQspi * (q * abc);
            error = __absf(tBaudTmp - tBaud);
​
            if (__leqf(error, bestError) && ((q * abc) >= 4))
            {
                bestError = error;
                bestAbc   = abc;
                bestQ     = q;
​
                if (bestAbc > 5)
                {
                    done = (!__neqf(error, 0.0)) ? TRUE : FALSE;
​
                    if (done != FALSE)
                    {
                        break;
                    }
                }
            }
        }
​
        if (done != FALSE)
        {
            break;
        }
    }
​
    econ.B.Q     = bestQ - 1;
    econ.B.A     = (bestAbc / 2) - 1;
    econ.B.C     = __min(bestAbc / 2, 3);
    econ.B.B     = bestAbc - (econ.B.C + (econ.B.A + 1));
    econ.B.CPH   = (chConfig->mode.shiftClock == SpiIf_ShiftClock_shiftTransmitDataOnLeadingEdge) ? 1 : 0;
    econ.B.CPOL  = (chConfig->mode.clockPolarity == SpiIf_ClockPolarity_idleLow) ? 0 : 1;
    econ.B.PAREN = chConfig->mode.parityCheck;
​
    return econ.U;
}

但是Autosar对SPI 有个要求。上面提到BCON 和 数据是交叉存放在同一片ram. 但是autosar要求基础寄存器和数据必须存放在两个分开的ram空间内。这里工具供应商已经实现。

由于autosar 有 配置和数据需要在不同的独立的ram所以这里基础寄存器就需要用软件来进行配置,这一步是需要CPU的。DMA 无法独立完成。

Autosar接口

  • Spi_Init Spi_DeInit Spi_WriteIB Spi_AsyncTransmit Spi_ReadIB Spi_SetupEB Spi_GetStatus Spi_GetJobResult Spi_GetSequenceResult Spi_GetVersionInfo Spi_SyncTransmit Spi_GetHWUnitStatus Spi_Cancel Spi_SetAsyncMode

  • Setup/SyncTransmit (EB): Many Channels, many Jobs and one Sequence

首先说一下IB 和 EB 的区别,

IB:小型设备传输,最高10 Bytes

EB: 复杂的芯片传输,数据量大较大的数据流

Spi_SetupEB:

设置buffer(source和destination), 数据长度,channel定义)

**                   Channel - Channel ID of the respective EB channel        **
**                   SrcDataBufferPtr - This is the pointer to source buffer  **
**                                               for the EB channel           **
**                   DesDataBufferPtr - This is the pointer to destination    **
**                               buffer to where the received data is copied  **
**                   Length - Number of data elements to be transmitted.      **
**                            i.e.,                                           **
**                            for 8-bit channel, if length is 2, then         **
**                            2 * 8-bit = 16 bits will be transferred,        **
**                            for 16-bit channel, if length is 2, then        **
**                            2 * 16-bit = 32 bits will be transferred and    **
**                            for 32-bit channel, if length is 2, then        **
**                            2 * 32-bit = 64 bits will be transferred        **

Spi_SyncTransmit:

传输数据到SPI BUS

**                   This API transmits the sequence synchronously over the   **
**                   QSPI buses defined by the jobs associated with the       **
**                   sequence. This API is synchronous, which means the       **
**                   application invoking the API is blocked till the         **
**                   sequence is transmitted completely.                      **

作者:Z-ONE_00751242454
文章来源:上汽零束SOA开发者论坛 
原文链接:https://bbs.z-onesoft.com/omp/community/front/api/page/mainTz?articleId=7731

;