精华内容
下载资源
问答
  • SPI

    2015-07-02 08:17:46
    SPI 1、原理图   SPI芯片Al01790D(M95XXX) ...2440支持4中不同的SPI接口数据传输格式,也就是有四种时序图。 第一种: 读: 写: 第二种: 读: 写: 第三种: 读:
    SPI


    1、原理图
     
    SPI芯片Al01790D(M95XXX)
    2、挂载模型


    3、时序图
    硬件中可以接很多个SPI芯片,通过片选GPIO来选择跟哪个SPI芯片通信(激活哪个SPI芯片)。
    2440支持4中不同的SPI接口数据传输格式,也就是有四种时序图。
    第一种:
    读:


    写:


    第二种:
    读:


    写:


    第三种:
    读:


    写:


    第四种:
    读:


    写:
    4、程序要做的


    5、程序示例



    展开全文
  • SPI协议简单总结

    2021-03-19 15:32:55
    文章目录SPI接口---全双工 的 同步 串行通讯总线SPI的数据格式SPI的控制器举例s3c2440 spi控制器 SPI接口—全双工 的 同步 串行通讯总线 SPI(Serial Peripheral Interface)接口是全双工(同时发送接受)的同步...

    SPI接口—全双工 的 同步 串行通讯总线

    SPI(Serial Peripheral Interface)接口是全双工(同时发送接受)的同步(发送过程需要等待接受方响应)串行(数据按位连续发送)通讯总线,支持通过多个不同的片选信号来连接多个外设。外围设备包括Flash RAM,网络控制器、LCD显示驱动器、A/D转换器和MCU等。

    SPI 接口通常由四根线组成,分别是提供时钟的 SCLK提供数据输出的 MOSI(Master Out Slave In),提供数据输入的MISO(Master In Slave Out)和提供片选信号的 CS。同一时刻只能有一个SPI 设备处于工作状态,即多个 CS 信号中某时间只能有一个有效。为了适配不同的外设 ,SPI 支持通过寄存器来配置片选信号和时钟信号的极性和相位。

    在这里插入图片描述

    SPI的数据格式

    当片选信号拉低后,建立了连接,主设备开始发送时钟,然后同步开始数据传输。
    数据传输有4钟模式,由CPOL和CPHA两个配置相关(器件的datasheet有标明,mcu或soc可配置),如下:
    CPOL决定时钟初始极性(0表示默认 时钟为低电平)
    CPHA决定是采样位置,是第一个还是第二个电平变化沿(0表示在第一个,上升还是下降和CPOL相关)
    在这里插入图片描述

    SPI的控制器举例s3c2440 spi控制器

    S3C2440A 包含了 2 个 SPI,每个都有 2 个分别用于发送和接收的 8 位移位寄存器。一次 SPI 传输期间,同时发送(串行移出)和接收(串行移入)数据。由相应控制寄存器设置指定 8 位串行数据的频率。相关寄存器:
    SPCON0控制:配置查询/中断/dma模式,时钟使能,主从选择,CPOL CPHA配置。
    SPI状态:数据从图,多主机错误,数据就绪;
    SPPRE0波特率分频:配置分频决定SPI时钟;
    SPTDAT0 发送数据寄存器;
    SPRDAT0 接受数据寄存器;
    在这里插入图片描述
    伪代码流程(最简单的,不涉及DMA):
    SPI初始化:1、配置波特率 2、配置控制寄存器(查询模式、使能时钟、主机、CPOL CPHA);GPIO配置I2C模式;
    SPI发送数据:检查发送就绪REDY状态,就开始写入SPTDAT;
    SPI读取数据:写0xff到SPTDAT,检查就绪REDY状态,然后从读缓冲器读取数据。

    展开全文
  • SPI原理及控制器 包括以下内容 SPI总线协议简介 s3c2410SPI控制器 SPI接口在POD中的应用
  • S3C2410A的SPI支持的4种传输格式 SPI 的特殊功能寄存器 VxWorks开发板S3C2410A上SPI驱动DS1390 SPI驱动代码学习 外部接口 logMsgSPI —— 低电压串行外设接口 DS1390 —— 实时时钟(RTC)芯片DS1390先来简单介绍一下

    今天来继续学习S3C2410的SPI接口和DS1390实时时钟。

    SPI —— 低电压串行外设接口
    DS1390 —— 实时时钟(RTC)芯片

    DS1390

    先来简单介绍一下DS1390。

    低电压串行外设(SPI)实时时钟(RTC)芯片——DS1390——是能够提供百分之一秒、秒、分钟、小时、星期、日期、月份和年份等信息的时钟/日历芯片。少于31天的月份会自动调整月末日期,包括闰年日期调整。时钟可以工作在24小时格式下,也可以工作在带有AM/PM指示的12小时格式下。具有可编程的定时闹钟。可以通过SPI接口进行时间的设置和读取。

    先来看看官方datasheet怎么介绍的。

    这里写图片描述

    基本和前文一样。有温度补偿式的参考电压监视VCC的状态,一旦掉电,就自动禁用总线,并启用备用电源。另外在DS1390上还有一个单个的开漏输出给CPU提供中断或者方波信号(四种可选频率)。

    DS1390、DS1391、DS1394都是串行可编程的,SPI兼容、双向总线。

    DS1392、DS1393通过3-线式的串行总线通信,另外一个引脚 RST¯¯¯¯¯¯¯ 可用于中断或者复位输出/去抖动输入。

    特点:

    • 一 百分之一秒、秒、分、时、天、日期、星期、月份、年份到2100年
    • 二 输出引脚可以配置为中断模式或者方波输出(32.768kHz、8.192kHz、4.096kHz、1Hz)
    • 三 当日实时时钟
    • 四 掉电检测与切换电路
      (以上四个是最常用的,后针对各个不同的型号略有差异,可查看相应数据手册)

    再来看看DS1390的封装,常用接法,实物图

    封装图:
    这里写图片描述

    常用接法:
    这里写图片描述

    实物图:
    这里写图片描述

    DS1390的时序图就不再往上放了,那样就成了罗列手册了。自己写驱动的时候,也没必要一行一行自己对照时序图写,那样也很难调。网上有现成的驱动代码,拿过来,能调通,存入、读出时间就好了。

    SPI of S3C2410A

    再来说说S3C2410A的SPI。

    SPI—— Serial Peripheral Interface 串行外设接口

    S3C2410A有两个SPI接口,每个接口包含两个8位移位寄存器,分别用于发送和接收。SPI数据传输期间,数据同时的移出(发送)和移入(移位寄存器)。8-位串行数据由相应的控制寄存器决定。如果你在发送,则接收数据寄存器中的值无效;如果在接收,则应该发送假的数据 ‘1’.

    SPI的4个引脚信号:

    • SCK
    • MISO
    • MOSI
    • nSS0¯¯¯¯¯¯¯¯,nSS1¯¯¯¯¯¯¯¯

    来看其中一个SPI接口的框图:
    这里写图片描述

    另一个接口的框图和这里一模一样。

    SPI操作

    讲讲SPI的操作。SPI主控端提供时钟,可以向SPPREn 这个寄存器写入合适的值来改变传输波特率。对于一个SPI从设备,则由其他主设备提供时钟。双方时钟一定是同步的。向SPTDATn 寄存器写入数据则开始发送或接收数据。某些情况下nSS应该在写入数据到 SPTDATn前被激活。

    编程SPI模块的基本步骤:

    • 设置波特率 SPPREn
    • 配置控制寄存器 SPCONn
    • 写 0xFF 到 SPTDATn 10次来初始化MMC或者SD卡
    • 某个GPIO输入低拉低nSS来激活 MMC或者SD卡
    • 发送数据:检查 REDY=1并写数据到SPTDATn 进行发送
    • 接收数据:
      • SPCONn的TAGD位禁用=正常模式:写0xFF到SPTDATn,然后等REDY=1后从读缓存中读数据
      • SPCONn的TAGD位使能=Tx 自动清除数据模式:确认REDY=1即可直接读数据
    • 拉高GPIO,清除 nSS,deactivate MMC or SD card

    S3C2410A的SPI支持的4种传输格式

    SPCONn 控制寄存器中有两个功能位 CPOL 和 CPHA.

    CPOL控制IDLE状态下的时钟电平,0为低电平;
    CPHA控制数据和时钟之间的延迟,0——无延迟;1——数据相对时钟上升沿半个周期出现在总线上

    简单的看一下四种格式的波形图:

    这里写图片描述

    这里写图片描述

    这里写图片描述

    这里写图片描述

    对于几种格式就不再作解释了。更详细的可以直接查看 2410的datasheet.

    SPI 的特殊功能寄存器

    SPCON0
    SPCON1
    控制寄存器进行模式选择、SCK使能、主/从选择、时钟极性(CPOL)选择、时钟相位(CPHA)选择、TAGD使能(Tx Auto Garbage Data mode)

    SPSTA0
    SPSTA1
    状态寄存器只用了低三位作状态标志位,最常用的是最低位 (REDY)

    SPPIN0
    SPPIN1
    SPI的引脚控制寄存器,也只用了低三位。具体功能查手册。

    SPPRE0
    SPPRE1
    SPI的波特率预分频寄存器,共用低八位作为SPI时钟速率,计算工式为:

    Baudrate=PCLK/2/(Prescalervalue+1)

    由此,该寄存器的值设置应为:
    (volatileUINT8)rSPPRE0=freq/(PCLK/2)1;

    其中freq 为波特率值。注意:波特率值应该小于25MHz

    SPIDTA0
    SPIDAT1
    发送数据寄存器

    SPRDAT0
    SPRDAT1
    接收数据寄存器

    VxWorks开发板S3C2410A上SPI驱动DS1390

    在这之前,先来看看,DS1390与板子的连接。

    这里写图片描述

    S3C2410A的SPI1接口的4个引脚信号(GPG[5-8])
    SPIMISO
    SPIMOSI
    SPICLK
    SPICS
    分别与实时时钟芯片DS1390的 DOUT、DIN、SCLK、CS¯¯¯¯¯进行连接。

    SPI驱动代码学习

    先看几个功能性的常量和宏定义以及硬件访问寄存器。

    // 几个常用的数据类型
    typedef unsigned char       BYTE;
    typedef unsigned short      WORD;
    typedef unsigned int        UINT;
    typedef unsigned int        DWORD;      /* 32-bit CPU       */
    typedef unsigned char       BOOLEAN;
    
    // 收发寄存器和REDY位, 此处用到的 rSPTDAT1等 在头文件<2410addr.h>中找
    #define  rSPTDAT    (*(volatile unsigned int *)(rSPTDAT1))       
    #define  rSPRDAT    (*(volatile unsigned int *)(rSPRDAT1))       
    #define  rDATREAD  ((*(volatile unsigned int *)(rSPSTA1))&1)     
    
    #define CN_TIMEOUT_RW    10000
    
    typedef struct {                                // BCD码方式时标数据结构
        BYTE            byYear_L;                   // 年低位
        BYTE            byYear_H;                   // 年高位
        BYTE            byMonth;                    
        BYTE            byDay;                      
        BYTE            byHour;                     
        BYTE            byMinute;                   
        BYTE            bySecond;                   
        BYTE            byMS_L;                     // 毫秒 低位
        BYTE            byMS_H;                     // 毫秒 高位
        BYTE            byDate;                     // 星期
    }tagTimeBCD, *tagPTimeBCD;
    
    tagPTimeBCD    tTimeBcd;                 // 定义了一个全局的结构体指针变量

    由于相应的S3C2410用的GPIO口为GPG口,先来看一下GPG口有没有什么特别之处。

    上datasheet:
    这里写图片描述

    GPIOG口共16根口线,GPG[5-7]刚好有第二功能用来进行SPI口通信。

    这里写图片描述

    GPGCON[31:0] 控制寄存器共32位,每2-bit控制一根口线的功能模式。

    这里写图片描述

    这里写图片描述

    来看驱动代码:

    // 函数名称: SpiTimeInit
    // 函数功能: SPI口初始化
    static void SpiTimeInit()
    {
        DWORD   dwValReg;
    
        // 配置GPG[5-7]为利用的SPI功能、GPG[8]为普通输出
        M_CPU_REG_READ(  rGPGCON,  dwValReg );
        dwValReg = dwValReg & (~(3<<10)) & (~(3<<12)) & (~(3<<14)) & (~(3<<16));
        dwValReg = dwValReg | (3<<10) | (3<<12) | (3<<14) | (1<<16);
        M_CPU_REG_WRITE( rGPGCON,  dwValReg );
    
        SpiTimeDrv_En(FALSE);
    
        // SPPRE1
        dwValReg = 24;  // 设置波特率为 1Mbsp,需要用上面提到的公式提前计算好
        M_CPU_REG_WRITE( rSPPRE1,  dwValReg );
    
        // SPCON1
        dwValReg = 0|(1<<1)|(0<<2)|(1<<3)|(1<<4)|(0<<5);
        M_CPU_REG_WRITE( rSPCON1,  dwValReg );
    
        return;
    }

    //
    ///??? 没有搞懂这里返回值为什么要用 static 类型 ???
    //

    其中:

    // 不同类型数据的硬件访问(读写)方式
    #define M_CPU_REG_READ(r,result)     ((result)=*(volatile unsigned int *)(r))
    #define M_CPU_REG_WRITE(r,data)      (*((volatile unsigned int *)(r)) = (data))
    
    #define M_CPU_BYTE_READ(r,result)    ((result)=*(volatile unsigned char *)(r))
    #define M_CPU_BYTE_WRITE(r,data)     (*((volatile unsigned char *)(r)) =(data))
    
    #define M_CPU_REG_OR(r,result)       (*(volatile unsigned int *)(r) |= result))
    #define M_CPU_REG_AND(r,result)      (*(volatile unsigned int *)(r) &=result)
    #define M_CPU_REG_GET( r )           (*(volatile unsigned int *)(r))
    
    // GPG[8]普通输出实现的片选功能
    static void SpiTimeDrv_En( BOOLEAN bEn )
    {
        if( bEn )       // 拉低使能
        {
            M_CPU_REG_AND( rGPGDAT,  (~(1<<8)) );
        }
        else            // 拉高禁用
        {
            M_CPU_REG_OR ( rGPGDAT,  (1<<8) );
        }
        return;
    }
    // 函数名称:SpiTimeGet
    // 函数功能:获取时间
    static BOOLEAN SpiTimeGet( tagPTimeBCD ptTimeBcd )
    {
        WORD    wLoop,j;
        BYTE    byData[8];
        BOOLEAN bOk = TRUE;
    
        memset(ptTimeBcd,0,sizeof(tagTimeBCD)); // 清空结构体指针指向的内存
        SpiTimeDrv_En(TRUE);                    // 片选DS1390实时时钟芯片
    
        rSPTDAT = 0x00;          // 写入的第一个字节高位表示读写(0读,1写)后续位为地址
        for(wLoop=0;wLoop<CN_TIMEOUT_RW;wLoop++)     // 超时判断
        {
            if( rDATREAD ) break;
        }
        if( wLoop ==CN_TIMEOUT_RW ) bOk = FALSE;  // 参照SPI时序修改CN_TIMEOUT_RW
    
        // 写0xFF到SPTDAT,并读回来。实际的读操作,循环移位寄存器
        // 有一次超时,则返回 FALSE
        for(j=0;j<8;j++)
        {
            if( bOk == FALSE ) break;
            rSPTDAT = 0xFF;                         // 从2410写数据到DS1390
            for(wLoop=0;wLoop<CN_TIMEOUT_RW;wLoop++)
            {
                if( rDATREAD ) break;
            }
            if( wLoop ==CN_TIMEOUT_RW ) bOk = FALSE;
            else byData[j] = rSPRDAT;               // 读回时间数据
        }
    
        if( bOk )
        {
            ptTimeBcd->byYear_H = 0x20;
            ptTimeBcd->byMS_L = (byData[0]&0x0F)<<4; // 毫秒低位
            ptTimeBcd->byMS_H = (byData[0]&0xF0)>>4; // 毫秒高位
            ptTimeBcd->bySecond = byData[1];           
            ptTimeBcd->byMinute = byData[2];           
            ptTimeBcd->byHour   = byData[3];           
            ptTimeBcd->byDate   = byData[4];         // 星期   
            ptTimeBcd->byDay    = byData[5];           
            ptTimeBcd->byMonth  = byData[6];           
            ptTimeBcd->byYear_L = byData[7];           
        }   
        // 从这里可以看出 DS1390 的存储格式:
        // 毫秒低---毫秒高,秒,分,时,星期,日,月,年低位 共8个unsigned char的数据
    
        SpiTimeDrv_En(FALSE);     // 读完一次实时时间就不再操作DS1390,即片选禁用
        return(bOk);              // 与VxWorks的函数保持统一的返回状态形式
    }

    有了获取时间,那设置时间就是一样的了,只不过方向反过来。

    // 函数名称:SpiTimeSet
    // 函数功能:设置 DS1390 实时时钟芯片的当前时刻时间
    static BOOLEAN SpiTimeSet( tagPTimeBCD ptTimeBcd )
    {
        WORD    wLoop,j;
        BYTE    byData[8];
        BOOLEAN bOk = TRUE;
    
        SpiTimeDrv_En(TRUE);         // 片选DS1390芯片
    
        byData[0] = 0x81;   // 写入的第一个字节高位表示读写(0读,1写)后续位为地址
        byData[1] = ptTimeBcd->bySecond;    
        byData[2] = ptTimeBcd->byMinute;    
        byData[3] = ptTimeBcd->byHour;      
        byData[4] = 0x00;                   // 星期,信息无效,随便写入
        byData[5] = ptTimeBcd->byDay;       // 日
        byData[6] = ptTimeBcd->byMonth;     
        byData[7] = ptTimeBcd->byYear_L;    // 年低位
    
        for(j=0;j<8;j++)
        {
            rSPTDAT = byData[j];            // 注意写入DS1390顺序和读出顺序比较
            for(wLoop=0;wLoop<CN_TIMEOUT_RW;wLoop++)
            {
                if( rDATREAD ) break;
            }
            if( wLoop ==CN_TIMEOUT_RW )     // 一次写入超时则直接返回失败
            {
                bOk = FALSE;
                break;
            }
        }
    
        SpiTimeDrv_En(FALSE);                // 禁用片选 DS1390
        return bOk;
    }

    外部接口

    同前面的KEY一样,SPI驱动程序也要为其他任务提供接口函数。这里主要是针对DS1390写的几个操作函数。

    // 函数名称:timeget
    // 函数功能:获取并输出DS1390的当前时间
    STATUS timeget(void)
    {
        tagPTimeBCD pTime= (UINT8 *)malloc(10);   // 把10改成 sizeof(tagTimeBCD) 可读性会更强些
    
        SpiTimeGet(pTime);
    
        // 要注意 logMsg 和 printf 的区别
        logMsg( "现在时间20%x年%x月%x日%x时%x分%x秒\n",
            pTime->byYear_L,pTime->byMonth, pTime->byDay,
            pTime->byHour,pTime->byMinute,pTime->bySecond);
    
        return OK;
    }

    logMsg

    此处来讲讲 logMsg 函数。在VxWorks API Reference 的 OS Libraries 里面按字母序排好了所有的库函数。其中L打头的有

    • ledLib —— line-editing library
    • loadLib —— object module loader
    • loginLib —— user login/password subroutine library
    • logLib —— message logging library
    • lstLib —— doubly linked list subroutine library

    先直接来看 logLib,帮助文件地址为X:/Tornado2.2/docs/vxworks/ref/logLib.html#top
    其中X为Tornado开发环境安装目录。

    每一个库的帮助信息中包含 NAME, ROUTINES, DESCRIPTION, … , INCLUDE FILES, SEE ALSO等项,基本和MATLAB等的帮助信息类似,容易学习使用。

    5.5版本的VxWorks的logLib库包含了六个函数,分别是:

    logInit( ) - initialize message logging library
    logMsg( ) - log a formatted error message
    logFdSet( ) - set the primary logging file descriptor
    logFdAdd( ) - add a logging file descriptor
    logFdDelete( ) - delete a logging file descriptor
    logTask( ) - message-logging support task

    可以看到其中 logMsg()函数主要作用是用来日志记录一个格式化的错误消息。看一下logMsg的具体描述:

    logMsg()
    int logMsg
        (
        char * fmt,               /* format string for print */
        int    arg1,              /* first of six required args for fmt */
        int    arg2,
        int    arg3,
        int    arg4,
        int    arg5,
        int    arg6
        )
    
    DESCRIPTIOIN
    This routine logs a specified message via the logging task. This routine's syntax is similar to printf( ) -- a format string is followed by arguments to format. However, the logMsg( ) routine takes a char * rather than a const char * and requires a fixed number of arguments (6).
    
    The task ID of the caller is prepended to the specified message.
    
    // 此处可以看到了,logMsg 的语法和 printf 的语法很相似。但 logMsg 以 char* 为参数,而 printf 以 const char* 为参数,并且 logMsg 要求固定的6个参数,调用者任务的ID也被注入到指定的消息中。

    还应该注意的是,logMsg()并不直接产生输出到 logging stream,而是输出到 logging task 的消息队列,因此 logMsg() 可以用到中断函数中。

    同时,logTask() 并不在调用 logMsg()函数的时候 解释参数,而是在实际 logging 的时刻解释参数,因此,logMsg() 的参数不应当指向 volatile 实体对象。

    非常重要的是, logMsg() 会检测自身是否是运行在中断上下文。如果是在中断环境中,则继续运行;如果是在某个任务中调用了 logMsg() ,则该任务会被阻塞在 logMsg() 函数中。logMsg 用于中断环境中输出字符串消息

    作为对比的是IO函数 printf 则不可以在中断函数中使用, printf 输出到一个串口(经重定向)。

    printf()是将信息输出到标准输出设备(STDIN/STDOUT)中,如果此时设备正在工作,那么就会发生阻塞.

    logMsg()是使用消息队列的方式,它将信息地址发送到队列,由专门的任务将信息打印出来.

    EXAMPLE
    If the following code were executed by task 20:

    {
    name = "GRONK";
    num = 123;
    
    logMsg ("ERROR - name = %s, num = %d.\n", name, num, 0, 0, 0, 0);
    }
    

    the following error message would appear on the system log:
    0x180400 (t20): ERROR - name = GRONK, num = 123.

    可以看到,当调用logMsg时实际的参数不足6个时,即可用 0 代入。

    RETURN
    The number of bytes written to the log queue, or EOF if the routine is unable to write a message.
    返回信息几乎和 printf 一致。

    这里再加一小段他人的使用经验小结:

    LogMsg 利用消息队列将用户所发的消息传送给LogTask,然后由LogTask将其显示在屏幕或者其他输出设备上。而VxWorks默认的LogTask的任务优先级很高,这就直接导致了任务的切换。
    切换是这样发生的,假设用户任务usrTask的优先级是51级(通常要低于网络任务50级,一般在100级以后),而我记忆中的LogTask是1级任务,仅次于中断响应。当usrTask调用LogMsg的时候,LogTask解除阻塞状态,获得CPU资源,而usrTask则排队到就绪任务队列去了。LogTask释放CPU资源后,就绪队列中的第一个任务开始执行,usrTask则继续在就绪队列里等待,呵呵。
    所以在通常情况下,在中断处理函数中使用LogMsg就可以了,在任务中使用LogMsg是近乎画蛇添足的举动。

    再来看看第二个接口函数 timeset :

    STATUS timeset(UINT8 year,UINT8 month,UINT8 day,UINT8 hour,UINT8 minute,UINT8 second)
    {
        tagPTimeBCD pTime = (UINT8 *)malloc(10);   // malloc(sizeof(tagTimeBCD))
        logMsg("DrvTime_SetTime!\n",0,0,0,0,0,0);  // 格式串后面没有实际参数,6个全0即可
    
        pTime->bySecond     = second;
        pTime->byMinute     = minute;
        pTime->byHour       = hour;
        pTime->byDay        = day;
        pTime->byMonth      = month;
        //pTime->byWeek       = 0x00;              // byDate 星期 信息不用写入
        pTime->byYear_L     = year; 
    
        logMsg("输入时间20%x年%x月%x日%x时%x分%x秒\n",
            pTime->byYear_L,pTime->byMonth,pTime->byDay,
            pTime->byHour,pTime->byMinute,pTime->bySecond);
    
        SpiTimeSet(pTime);
        return OK;
    }

    /
    /// 按照上面的说法,这里两个接口函数中的 logMsg 是不是都应该换成 printf 更合适一些,现在还不懂,后续搞明白了再做说明
    /

    两个接口函数完了,再来看看SPI时钟任务主函数:

    // 函数功能:SPI时钟任务主函数
    void Time_Main( void )
    {
        tTimeBcd =(UINT8 *)malloc(10);   // malloc(sizeof(tagTimeBCD));
        SpiTimeInit();
        while(1)
        {
            SpiTimeGet(tTimeBcd);        // 获取时间后存到全局指针 tTimeBcd 指向的内存中
            taskDelay(6);                // 任务主动延时,让出CPU
        }
    }

    好了,SPI驱动DS1390就暂时讲到这里。

    展开全文
  • 串行数据总线由于占用较少的管脚被广泛应用在MCU和外设的连接中,在过去的几十年里,有三种最常用的多线串行数据传输格式SPI、I2C和UART。这3种串行总线的主要区别: SPI - Serial Peripheral Interface...

    串行数据总线由于占用较少的管脚被广泛应用在MCU和外设的连接中,在过去的几十年里,有三种最常用的多线串行数据传输格式SPI、I2C和UART。这3种串行总线的主要区别:

    • SPI - Serial Peripheral Interface(串行外设接口),突出了外设,也就有了主(Master - 控制器)和从(Slave - 外设)之分,在总线中也就只有一个“主人”,其它都是处于服从的位置,也就是Slave,它是一种有时钟信号的同步串行总线,从器件的寻址是靠专用的片选信号线SS来实现的;

    • I2C - Inter-Integrated Circuits(集成电路之间的连接),没有突出主次,也就是所有挂在总线上的器件都是平等的,它也是一种有时钟信号的同步串行总线,每个器件都有自己的地址,两根信号线都需要通过电阻上拉;

    • UART - universal asynchronous receiver/transmitter(通用异步收/发),顾名思义,它是异步串行总线,传输的信号中没有专用的时钟信号线。

    由于很多MCU、外设芯片为了节省管脚,都采用了管脚功能复用的方式,同一个管脚既可以用于SPI,也可以用于I2C,根据具体的器件连接方式进行选用。当器件的管脚配置为I2C的时候,要记住在I2C的两根信号线(SCL、SDA)上一定要有上拉电阻,SPI则不需要。

    今天我们就先来说说SPI:

    SPI(Serial Peripheral Interface - 串行外设接口)是一种用于短距离通信(主要是嵌入式系统中)的同步串行通信接口规范,这种接口由Motorola发明,已经成了一种事实标准。广泛用于各种MCU处理器中,同传感器,串行ADC、DAC、存储器、SD卡以及LCD等进行数据连接。

    几乎所有的微处理器/微控制器都有SPI/I2C和UART接口,而且不止一个

    SPI和I2C也被广泛用于传感器的数字接口连接

    即便FPGA也将SPI和I2C做成了硬化的IP在芯片内

    主要的信号线:

    SPI总线由4根主要的信号线组成以实现数据在主设备(Master)和从设备(Slave)之间的全双工(收、发同时执行)同步(由时钟同步)通信:

    • SCLK:串行时钟(由主设备输出),每个时钟周期将会移出一个新的数据位;

    • MOSI:主设备输出⇒从设备输入,数据由主设备进入从设备,器件A上的MOSI线连接到器件B上的MOSI线。

    • MISO:主设备输入⇐ 从设备输出,数据由从设备送到主设备(或其它从设备,采用菊花链配置),器件A上的MISO线连接到器件B上的MISO线。

    • SS(或SSN): 从设备选中(低电平有效),用于主设备控制从设备用,当该从选择信号线有效的时候表示主设备正在向相应的从设备发送数据或从相应的从设备请求数据。

    SPI端口管脚的名字也有其它的叫法,不同的芯片公司叫法不同,比如:

    • 串行输出: SCLK : SCK, CLK.

    • 主输出 –> 从输入: MOSI:SIMO、SDI(for slave devices)、DI、DIN、SI、MTST.

    • 主输入 ← 从输出: MISO:SOMI、SDO (for slave devices )、DO、DOUT、SO、MRSR.

    • 从选择: SS: SSN、nCS、CS、CSB、CSN、EN、nSS、STE、SYNC.

    主从器件之间的连接及数据传输方式

    基本的主从配置

    SPI允许将数据位从主设备移出到从设备,同时,可以将从设备的位移出到主设备中。

    动画1显示数据从器件A移出到器件B,从器件B移出到器件 A.

    动画2显示了通过一个虚拟的4通道示波器捕捉的两个器件之间SPI的转换 

    由于SPI未标准化,不同厂商的器件具体的定义不同,有的首先传输最高有效位(MSb),有的则是最低有效位(LSb),这需要我们认真阅读用到的相应器件的数据手册,以确定正确的数据处理方式。

    4种传输模式:

    每次数据传输都是先将SSN(有的器件命名为SS,从选择线)被驱动为逻辑低电平时开始。由时钟的极性(CPOL)和相位(CPHA)构成了4种不同的数据传输模式(0,1,2,3),分别对应四种可能的时钟配置。

    • CPOL: 时钟的极性,它控制着时钟信号的初始逻辑状态。

    • CPHA: 时钟相位,它控制了数据转换和时钟转换之间的关系。

    时钟的极性和相位构成了4种不同的可能,也就有4种模式

    在时钟周期的上升沿采样的位在时钟周期的下降沿移出,反之亦然。

    具有非反相时钟极性(即,当从器件选择转换为逻辑低时,时钟处于逻辑低电平):

    • 模式0:配置时钟相位使得数据在时钟脉冲的上升沿采样,并在时钟脉冲的下降沿移出。 这对应于上图中的第一个蓝色时钟轨迹。 请注意,数据必须在时钟的第一个上升沿之前可用。

    • 模式1:配置时钟相位使得数据在时钟脉冲的下降沿采样,并在时钟脉冲的上升沿移出。 这对应于上图中的第二个蓝色时钟轨迹。

    使用反相时钟极性(即,当从器件选择转换为逻辑低时,时钟处于逻辑高电平):

    • 模式2:配置时钟相位,使得数据在时钟脉冲的下降沿采样,并在时钟脉冲的上升沿移出。 这对应于上图中的第一个橙色时钟轨迹。 请注意,数据必须在时钟的第一个下降沿之前可用。

    • 模式3:配置时钟相位,使得数据在时钟脉冲的上升沿采样,并在时钟脉冲的下降沿移出。 这对应于上图中的第二个橙色时钟轨迹。

    由于主设备一般为可以编程各种模式的控制器/处理器或者可以灵活编程的FPGA,因此在使用SPI连接的时候要认真阅读自己选用的从设备的工作模式,以便在时许上满足传输的要求。

    主、从器件连接方式 

    通过多个从片选信号(SSN)配置

    在标准的SPI配置中,主设备可以通过使能相应的从设备,即通过将相应设备的从选择线(SSN或SS)设置为逻辑低电平,通过共享的公共数据线将数据写入各个从设备或由各个从设备中读取数据。 应注意不要同时使能多个从设备,因为返回到主设备的数据将在MISO线路之间的驱动器上产生竞争导致无法进行数据的判读。 在某些应用中不需要将数据返回给主设备,在这种情况下,如果主设备想要将相同的数据发送到多个从设备,则可以同时寻址多个从设备。

    在多从设备选择配置中,每个从设备都需要来自主设备的唯一从设备选择线(SS、SSN或CSn)。如果主设备没有足够的I/O引脚用于所需数量的从设备,则使用解码/解复用器(例如74HC(T)238(3到8线)来实现I/O扩展)。

    菊花链配置

    在这种配置中,数据从一个设备移动到下一个设备, 最终的从设备可以将数据返回给主设备(给FPGA编程的JTAG在给多个器件编程的时候也常用这种方式)。

    在菊花链配置中,所有从设备共享一条公共的从选择线(SS)。 数据从主设备传输到第一个从设备,然后从第一个从设备传输到第二个从设备,依此下去,数据沿着线路级联,直到系列中的最后一个从设备,最后的一个从设备使用其MISO线路将数据传送到主设备。

    这种配置非常适合于主设备的信号引脚有限的场景。

    SPI的优缺点:

    优点:

    • 支持全双工通信

    • 推挽驱动(跟漏极开路正相反)提供了比较好的信号完整性和较高的速度

    • 比I²C或SMBus吞吐率更高

    • 协议非常灵活支持“位”传输

      <ul><li>
      	<p>不仅限于8-bit一个字节的传输</p>
      	</li>
      	<li>
      	<p>可任意选择的信息大小、内容、以及用途</p>
      	</li>
      </ul></li>
      <li>
      <p>异常简单的硬件接口:</p>
      
      <ul><li>
      	<p>一般来讲比I²C或SMBus需要的功耗更低,因为需要更少的电路(包括上拉电阻)</p>
      	</li>
      	<li>
      	<p>没有仲裁机制或相关的失效模式</p>
      	</li>
      	<li>
      	<p>“从设备”采用的是“主设备”的时钟,不需要精确的晶振</p>
      	</li>
      	<li>
      	<p>“从设备”不需要一个单独的地址 — 这点不像I²C或GPIB或SCSI</p>
      	</li>
      	<li>
      	<p>不需要收/发器</p>
      	</li>
      </ul></li>
      <li>
      <p>在一个器件上只用了4个管脚, 板上走线和布局连接都比并行接口简单很多</p>
      </li>
      <li>
      <p>每个设备最多只有一个单独的从设备选择信号(SS、SSN、CSn);其它的都是共享的</p>
      </li>
      <li>
      <p>信号都是单方向的,非常容易进行电流隔离</p>
      </li>
      <li>
      <p>对于时钟的速度没有上限,有进一步提高速度的潜力,很多MCU的SPI传输速率可以高达50Msps,可用于数据采集以及图像的传输。</p>
      </li>
      

    缺点:

    • 相比于I²C总线需要更多的管脚, 即便是只用到3根线的情况下

    • 没有寻址机制,在共享的总线连接时需要通过片选信号支持多个设备的访问

    • 在从设备侧没有硬件流控机制(主设备一侧可以通过延迟到下一个时钟沿以降低传输的速率)

    • 从设备无法进行硬件“应答”(主设备传送的信息无法确定传递到哪里,是否传递成功)

    • 一般只支持一个主设备(取决于设备的硬件构成)

    • 没有查错机制

    • 没有一个正式的标准规范,无法验证一致性

    • 相对于RS-232, RS-485, 或CAN-总线,只能近距离传输

    • 存在很多的变种,很难能够找到开发工具(例如主适配卡)支持这所有的变种

    • SPI不支持热交换(动态地增加一个节点).

    • 如果想使用“中断”,只有通过SPI信号以外的其它信号线,或者采用类似USB1.1或2.0中的周期性查询的欺骗方式

    应用举例:

    小脚丫FPGA学习主板上的DAC、ADC、以及用于图形显示的液晶屏都是通过SPI接口连接的。

    小脚丫FPGA主板的实物照片,外设基本都是通过SPI、I2C以及UART进行连接的

    小脚丫FPGA主板的功能框图

    鉴于此,我们硬件工程师很有必要深入了解SPI、I2C以及UART的技术细节,尤其是传输信号线的连接以及传输的时序要求,争取能够自己通过FPGA来编程实现各种传输总线。

     

    转载 -- 电路设计技能公众号

    展开全文
  • SPI通信

    2018-11-08 08:45:00
    SPI接口由CPOL和CPHA设置四种不同传输格式的时序。其中: CPOL(Clock Polarity)时钟极性 CPHA(Clock Phase)时钟相位 CPOL决定时钟信号SCK的有效脉冲方式 0:表示空闲状态时,SCK保持低电平;1:表示空...
  • SPI实验

    2020-02-19 19:30:00
    一、简介 关于SPI的特征: ... 关于4根线中除了数据线与时钟线的片选信号,从选择脚管理: ...SPI_CR的CPOL和CPHA位确定了数据在第几个边沿以及是上边沿还是下边沿触发,并且将数据...之后就是传输数据的格式...
  • SPI协议学习

    2021-02-07 20:30:15
    SPI协议学习背景SPI协议时序SPI接口SPI时序SPI协议封装USB-SPI模块SPI数据格式定义FLASH数据格式参考数据格式定义 背景 家里有一块ZYNQ开发板,经常想去写一写模块学习总线之类的东西,但是由于本人软件能力比较弱,...
  • SPI理解

    2018-11-15 20:52:25
    四线变三线 是指将MISO MOSI 合并为一根线 然后就变成了两根传送数据的线路 然后在数据的前面加一位来决定是输入还是输出 数据格式有变化 (2) 下面是重新再网络上理解SPI协议 3.2.3 CPOL极性 先说什么是SCLK时钟的...
  • SPI学习(三):SPI协议波形

    千次阅读 2020-11-28 18:29:46
    写在前面:上一小节介绍了SPI的基本工作...一共有三种帧格式可选:TI/SPI/NSM,一般用SPI很多(这里不关注NSM),简单介绍一下TI模式: SSI(Synchronous Serial Interface)由TI公司定义的接口协议标准 SPI(Serial Perip
  • STM32_HAL SPI通信思考
  • FAT文件系统中标准的虚拟扇区是512bytes的数据,而SPI flash的扇区的真实大小是4096。 主要思想: 在内存中申请4096的buffer,每次写入数据,要把真实扇区的数据读出来,然后在写入内存中在填充512bytes的数据,请...
  • SPI通讯

    千次阅读 2018-11-08 11:35:45
    特点:全双工,单主机多从机,数据格式为8bit,数据传输高位在前,低位在后 SPI一共四根引脚,分别为 (1)CS:片选信号,固定使用的话可以硬件上直接拉低 (2)SCK:时钟信号,因为SCK时钟线由主控设备控制,当...
  • SPI总线协议

    千次阅读 2018-06-22 10:50:12
    SPI最初由Motorola在2000年提出,Motorola所定义的SPI标准为业界广泛引用,但不同半导体公司的实施细节可能有所不同,这些区别体现在寄存器设置、信号定义、数据格式等。业界没有统一的SPI标准,具体应用...
  • mp3spi1.9.4

    2010-12-18 23:38:05
    mp3spi1.9.4 让java支持播放mp3等格式的第三方支持
  • NRF51822 SPI 模拟

    2018-03-18 11:49:10
    NRF51822 SPI 模拟,只包含了官方库,仿照官方i2c格式编写,宏定义接口
  • 您可以尝试以下不同的(数据源和格式)方法: 基于IMERG netCDF的SPI() 基于CHIRPS netCDF的SPI() 基于CHIRPS GeoTIFF的SPI() 参考文献 古特曼,NB,1999年:接受标准化降水指数:一种计算算法。 J.阿米尔...
  • 详细记录了基于ISE14.7进行SPI Flash MCS文件格式转化和加载SPI Flash的全过程。
  • STM32库函数SPI学习笔记 SPI原理 SPI接口使用4线通信: MISO:主设备输入,从设备输出...主从机的移位寄存器组成环形,每个时钟周期移动一位,每8或16个周期,两寄存器数据完全交换(帧格式可选8或16位)。 ...
  • Saleae16、Kingst LA1016等逻辑分析仪SPI协议转换工具能够将竖向显示数据转换成横向显示数据,以方便使用者查看。使用说明:解压后:将要转换的文件放到软件的目录下,双击AutoConvert.bat就会自动转换数据输出到o-...
  • 1. SPI介绍 ...SPI最初由Motorola在2000年提出,Motorola所定义的SPI标准为业界广泛引用,但不同半导体公司的实施细节可能有所不同,这些区别体现在寄存器设置、信号定义、数据格式等。业界没有统一的SP...
  • spi FLASH 问答

    千次阅读 2019-01-08 09:47:22
    A:Fatfs文件系统只是一种Fat32/16文件格式的实现方式,可以应用于任何介质(NorFlash、NandFlash等)上,但应用前需要按照文件系统的格式进行处理。 2、如果能使用应该做哪些特殊设置 A:由于NorFlash本身就是线性...
  • STM32F103 SPI

    千次阅读 2018-09-30 13:54:03
     8或16位传输帧格式选择  主或从操作  支持多主模式  8个主模式波特率预分频系数(最大为fPCLK/2)  从模式频率 (最大为fPCLK/2)  主模式和从模式的快速通信  主模式和从模式下均可以由软件或硬...
  • MSP430 SPI 入门学习

    2019-05-14 17:44:47
    基本简介 MSP430 User Guide 学习 23.1 增强型通用串行通信接口(eUSCI_A, eUSCI_B) 概要 23.2 eUSCI 介绍 - SPI模式 ...23.3.2 字符格式 23.3.3 主模式 23.3.3.1 4线制 SPI 主模式(UCSTEM = 0) 23.3.3.2 ...
  • 【学习笔记】SPI详解

    2020-02-21 19:59:20
    文章目录SPI协议介绍相关介绍硬件原理图数据格式与四种模式OLED显示方法怎么把数据写到显存里面去 SPI协议介绍 相关介绍 SPI(Serial Peripheral Interface),串行外设接口 SPI,是一种高速的,全双工,同步的串行...
  • stm32 SPI学习

    2017-11-29 15:26:21
    串行外设接口(SPI) 允许芯片与外部设备以半/全双工、同步、串行方式通信。...● 8或16位传输帧格式选择 ● 主或从操作 ● 支持多主模式 ● 8个主模式波特率预分频系数(最大为fPCLK/2) ● 从模式频率 (最大为fPCLK

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 712
精华内容 284
关键字:

格式spi