SylixOS NUC970平台SPI总线数据传输

  1. 概述

    本文档是对NUC970平台上的SylixOS SPI总线数据传输的详细分析。

  2. SPI总线数据传输流程

    NUC970平台上SPI总线数据传输流程如图 21所示。

    当一个消息准备传输时,第一步判断发送和接收缓存区是否为空,若为空,就没有要接收或发送的数据,直接返回。

    第二步,判断消息长度是否大于指定的值(可以改变,但要大于16个字节),若大于,以16字节为单位传输数据,否则以单字节为单位传输数据。

    图21 SPI数据传输流程图

  3. SPI总线的消息类型

    在SylixOS中,SPI总线的消息类型,如程序清单 21所示。

    程序清单 21 SPI总线消息类型

    /*********************************************************************************************************
      SPI 总线传输控制消息
    *********************************************************************************************************/
    
    typedef struct lw_spi_message {
        UINT16                   SPIMSG_usBitsPerOp;                        /*  操作单位bits数              */
        UINT16                   SPIMSG_usFlag;                             /*  传输控制参数                */
        
    #define LW_SPI_M_CPOL_0      0x0000                                     /*  CPOL 配置                   */
    #define LW_SPI_M_CPOL_1      0x0001
    #define LW_SPI_M_CPHA_0      0x0000                                     /*  CPHA 配置                   */
    #define LW_SPI_M_CPHA_1      0x0002
    
    #define LW_SPI_M_CPOL_EN     0x0004                                     /*  是否设置新的 CPOL 配置      */
                                                                            /*  否则 CPOL 配置与上次传输相同*/
    #define LW_SPI_M_CPHA_EN     0x0008                                     /*  是否设置新的 CPHA 配置      */
                                                                            /*  否则 CPHA 配置与上次传输相同*/
    
    #define LW_SPI_M_WRBUF_FIX   0x0010                                     /*  发送缓冲区仅发送第一个字符  */
    #define LW_SPI_M_RDBUF_FIX   0x0020                                     /*  接收缓冲区仅接收第一个字符  */
    
    #define LW_SPI_M_MSB         0x0040                                     /*  从高位到低位                */
    #define LW_SPI_M_LSB         0x0080                                     /*  从低位到高位                */
    
        UINT32                   SPIMSG_uiLen;                              /*  长度(缓冲区大小)            */
        
        UINT8                   *SPIMSG_pucWrBuffer;                        /*  发送缓冲区                  */
        UINT8                   *SPIMSG_pucRdBuffer;                        /*  接收缓冲区                  */
        
        VOIDFUNCPTR              SPIMSG_pfuncComplete;                      /*  传输结束后的回调函数        */
        PVOID                    SPIMSG_pvContext;                          /*  回调函数参数                */
    } LW_SPI_MESSAGE;
    typedef LW_SPI_MESSAGE      *PLW_SPI_MESSAGE;
  4. 技术实现

    SPI数据传输方式可分为两种:以单个字节为单位传输数据和以16个字节为单位传输数据。

    在SylixOS中SPI总线数据传输的代码实现,如程序清单 31所示。

    程序清单 31 SPI数据传输函数

    /*********************************************************************************************************
    ** 函数名称: __trySpiTransfer
    ** 功能描述: spi 传输函数
    ** 输 入  : pSpiChannel     spi 通道
    **           pSpiAdapter     spi 适配器
    **           pSpiMsg         spi 传输消息组
    ** 输 出  : ERROR_CODE
    *********************************************************************************************************/
    static INT  __trySpiTransfer (UINT              uiChannel,
                                  PLW_SPI_ADAPTER   pSpiadapter,
                                  PLW_SPI_MESSAGE   pSpimsg)
    {
        UINT          uiNum;
        UINT8        *pucTxBuf  = pSpimsg->SPIMSG_pucWrBuffer;              /*  发送缓存区                  */
        UINT8        *pucRxBuf  = pSpimsg->SPIMSG_pucRdBuffer;              /*  接收缓存区                  */
        UINT          uiByteLen = pSpimsg->SPIMSG_uiLen;                    /*  缓存区长度                  */
    
        if (!pucTxBuf && !pucRxBuf) {                                       /*  TxBuf和Rxbuf不能全为空      */
            SPI_DEBUG("transfer message is invalid\n");
            return (PX_ERROR);
        }
    
        if (uiByteLen > SPI_BIG_NUM) {
            /*
             *  大于SPI_BIG_NUM字节按16字节传输,否则按单字节传输
             */
            writel(readl(REG_SPI_CNTRL(uiChannel)) & SPI_TXNUM32,           /*  设置为32位传输单元          */
                   REG_SPI_CNTRL(uiChannel));
            writel(readl(REG_SPI_CNTRL(uiChannel)) | SPI_TX_FOUR,           /*  设置每次传输单元个数为4     */
                   REG_SPI_CNTRL(uiChannel));
            for (uiNum = 0; (uiNum + 16) <= uiByteLen; uiNum += 16) {
                if (pucTxBuf) {
                    writel_ESwap(*(UINT*)pucTxBuf,        REG_SPI_TX0(uiChannel));
                    writel_ESwap(*(UINT*)(pucTxBuf + 4),  REG_SPI_TX1(uiChannel));
                    writel_ESwap(*(UINT*)(pucTxBuf + 8),  REG_SPI_TX2(uiChannel));
                    writel_ESwap(*(UINT*)(pucTxBuf + 12), REG_SPI_TX3(uiChannel));
                    pucTxBuf += 16;                                         /*  将TxBuf指针偏移16个字节     */
                }
                writel(readl(REG_SPI_CNTRL(uiChannel)) | SPI_CNTRL_GOBUSY,  /*  使能开始传输位              */
                       REG_SPI_CNTRL(usheiChannel));
                API_SemaphoreBPend(__GspiChannels[uiChannel].hSignal,       /*  挂起,等待中断完成          */
                                   LW_OPTION_WAIT_INFINITE);
    
                if (pucRxBuf) {
                    *(UINT*)pucRxBuf        = readl_ESwap(REG_SPI_RX0(uiChannel));
                    *(UINT*)(pucRxBuf + 4)  = readl_ESwap(REG_SPI_RX1(uiChannel));
                    *(UINT*)(pucRxBuf + 8)  = readl_ESwap(REG_SPI_RX2(uiChannel));
                    *(UINT*)(pucRxBuf + 12) = readl_ESwap(REG_SPI_RX3(uiChannel));
                     pucRxBuf += 16;                                        /*  将RxBuf指针偏移16个字节     */
                }
            }
            if (uiNum < uiByteLen) {
                /*
                 *  将剩下的不足16字节的数据,按8位传输
                 */
                writel((readl(REG_SPI_CNTRL(uiChannel)) & SPI_TXNUM32) | SPI_TXNUM8,
                       REG_SPI_CNTRL(uiChannel));                           /*  设置8位传输单元             */
                writel(readl(REG_SPI_CNTRL(uiChannel)) & SPI_TX_ONE,        /*  设置每次传输单元个数为1     */
                       REG_SPI_CNTRL(uiChannel));
    
                for (; uiNum < uiByteLen; uiNum++) {
                    if (pucTxBuf) {
                        writel(*(pucTxBuf++), REG_SPI_TX0(uiChannel));
                    }
                    writel(readl(REG_SPI_CNTRL(uiChannel)) | SPI_CNTRL_GOBUSY,
                           REG_SPI_CNTRL(uiChannel));                       /*  使能开始传输位              */
                    API_SemaphoreBPend(__GspiChannels[uiChannel].hSignal,   /*  挂起,等待中断完成          */
                                       LW_OPTION_WAIT_INFINITE);
    
                    if (pucRxBuf) {
                        *(pucRxBuf++) = (UINT8)readl(REG_SPI_RX0(uiChannel));
                    }
                }
            }
        } else {
            /*
             *  小于16字节的数据,一直按8位传输
             */
            writel((readl(REG_SPI_CNTRL(uiChannel)) & SPI_TXNUM32) | SPI_TXNUM8,
                   REG_SPI_CNTRL(uiChannel));                               /*  设置8位传输单元             */
            writel(readl(REG_SPI_CNTRL(uiChannel)) & SPI_TX_ONE,            /*  设置每次传输单元个数为1     */
                   REG_SPI_CNTRL(uiChannel));
    
            for (uiNum = 0; uiNum < uiByteLen; uiNum++) {
                if (pucTxBuf) {
                    writel(*(pucTxBuf++), REG_SPI_TX0(uiChannel));
                }
                writel(readl(REG_SPI_CNTRL(uiChannel)) | SPI_CNTRL_GOBUSY,  /*  使能开始传输位              */
                       REG_SPI_CNTRL(uiChannel));
                API_SemaphoreBPend(__GspiChannels[uiChannel].hSignal,       /*  挂起,等待中断完成          */
                                   LW_OPTION_WAIT_INFINITE);
    
                if (pucRxBuf) {
                    *(pucRxBuf++) = (UINT8)readl(REG_SPI_RX0(uiChannel));
                }
            }
        }
        return  (ERROR_NONE);
    }
  5. 16字节数据传输流程

    在SPI总线的数据传输中,当缓存区长度大于指定的长度(指定的长度要大于16字节),会以16字节为单位进行数据传输,传输流程如图 31所示。

    图 31 16字节数据传输流程图

  6. 单字节数据传输流程

    在SPI总线的数据传输中,当缓存区长度小于指定的长度时,会以单字节为单位进行数据传输。如图 32所示。

    图 32单字节数据传输流程图

  7. 免责声明

    内部交流文档,仅针对NUC970相关平台,若发现相关错误或者建议,请及时联系文章档创建者进行修订和更新。

时间: 2024-07-31 14:31:27

SylixOS NUC970平台SPI总线数据传输的相关文章

SylixOS iMX6平台I2C总线驱动

原理概述 I2C总线驱动概述 I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和MasterXfer的实现函数.驱动程序包含初始化I2C总线控制器__i2cHwInit函数,操作函数集(总线传输__i2cTransfer函数,总线控制__i2cMasterCtl函数). Imx6ul控制器的硬件描述 imx6ul处理器内部集成了一个I2C控制器,通过五个寄存器来进行控制. I2Cx_IADR I2C地址寄存器 I2Cx_IFDR I2

I2C和SPI总线对比【转】

转自:http://blog.csdn.net/skyflying2012/article/details/8237881/ 最近2周一直在调试IIC和SPI总线设备,这里记录一下2种总线,以备后忘. 一 IIC总线 I2C--INTER-IC串行总线的缩写,是PHILIPS公司推出的芯片间串行传输总线.它以1根串行数据线(SDA)和1根串行时钟线(SCL)实 现了双工的同步数据传输.具有接口线少,控制方式简化,器件封装形式小,通信速率较高等优点.在主从通信中,可以有多个I2C总线器件同时接到I

I2C和SPI总线对比

1 iic总线不是全双工,2根线SCL SDA.spi总线实现全双工,4根线SCK CS MOSI MISO 2 iic总线是多主机总线,通过SDA上的地址信息来锁定从设备.spi总线只有一个主设备,主设备通过CS片选来确定从设备 3 iic总线传输速度在100kbps-4Mbps.spi总线传输速度更快,可以达到30MHZ以上. 4 iic总线空闲状态下SDA SCL都是高电平.spi总线空闲状态MOSI MISO也都是 SCK是有CPOL决定的 5 iic总线scl高电平时sda下降沿标志传

SylixOS基于Nuc970平台的SD驱动移植

1. 适用范围 本文档为实现Nuc970平台的SD驱动总结,提供一些SylixOS SD驱动移植方法的参考. 2. 原理概述 2.1 控制器类型 SD控制器有两种类型,分为SD标准控制器(SDHCI)和SD非标准控制器. SylixOS Base代码中实现了SDHCI的驱动,但Nuc970的SD控制器是非标准控制器,其功能都需要在BSP中单独实现. 2.2  命令.应答.数据 SD传输过程中会有命令.应答和数据三个概念存在. 命令和应答都是在CMD线上传输的,数据在DAT线上进行传输. 2.2.

Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化

我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返回.而异步方式则正好相反,数据传输的发起者无需等待传输的结束,数据传输期间还可以做其它事情,用代码来解释就是,调用传输的函数后,函数会立刻返回而不用等待数据传输完成,我们只需设置一个回调函数,传输完成后,该回调函数会被调用以通知发起者数据传送已经完成.同步方式简单易用,很适合处理那些少量数据的单次传

SylixOS SPI 总线框架浅析

修订历史版本 日期 原因V1.00 2018/8/18 创建文档 目 录1 SPI总线关键结构体 11.1 总线传输控制消息块 11.2 SPI总线适配器 21.3 SPI设备 32 SPI各个结构体之间的联系 32.1 总线链表 32.2 总线与设备 33 参考资料 4 1 SPI总线关键结构体1.1 总线传输控制消息块传输控制消息包括操作单位bits数.传输控制参数(时钟极性.相位和字节序等配置).发送和接收缓冲区及其长度.传输结束的回调函数.如程序清单 1.1所示.程序清单 1.1 typ

SPI总线小结

串行外设接口(Serial Peripheral Interface,SPI)的缩写.是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线.Motorola首先在其MC68HCXX系列处理器上定义的.SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间. SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时).也是所有基于SPI的设备共有的,它们是

SPI总线

一.SPI总线简介 串行外围设备接口SPI(serial peripheral interface)总线技术是Motorola公司推出的一种同步串行接口.SPI 用 于CPU与各种外围器件进行全双工.同步串行通讯.它只需四条线就可以完成MCU与各种外围器件的通讯,这四条线是:串行时钟线(CSK).主机输入/从 机输出数据线(MISO).主机输出/从机输入数据线(MOSI).低电平有效从机选择线CS.当SPI工作时,在移位寄存器中的数据逐位从输出引脚 (MOSI)输出(高位在前),同时从输入引脚(

SPI总线协议及SPI时序图详解

SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议.SPI是一个环形总线结构,由ss(cs).sck.sdi.sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换. 上升沿发送.下降沿接收.高位先发送.上升沿到来