arm底层通讯协议之SPI通讯

发布者:清新天空最新更新时间:2019-07-11 来源: eefocus关键字:arm  底层通讯协议  SPI通讯 手机看文章 扫描二维码
随时随地手机看文章

1、基本概念区分


    (1)SPI和SSP区别


        可能很多人在其他的地方都多次到过SPI和SSP,比如爱NXP的LPC11XX系列的SOC手册中多次出现SSP,这里作统一区分:SSP(Synchronize Serial Port,同步串行口)和SPI(Serial Peripheral Interface,串行外设接口)。SSP是在SOC和一些串行外部设备通信的通信模块,他有两种工作模式:SPI和IIC。


    (2)SPI协议和代码关系


        我们在使用SPI接口进行数据通信的时候,之所以要了解SPI通信协议的原因是我们需要了解SPI通信协议原理。虽然实际硬件通讯硬件电路已经做好了,但是我们还是需要通过配置寄存器来实现SPI通讯时序,所以说还是要学会SPI通信原理的。


        了解SPI通信原理只是第一步,第二步是阅读硬件用户手册,根据手册指示编写配置寄存器代码,实现基本配置(时钟频率、数据帧格式、引脚功能等),第三步就是实际收发接口程序编写。


2、SPI硬件接口



    通过上图可以知道,首先SPI通信有4线:SCK(同步时钟信号)、MISO(主接收从发送)、MOSI(主发送从接收)、NSS(片选信号)。SPI通信最少3根线:SCK同步时钟、NSS(或者CS)片选信号、MISO或者MOSI。


    SCK:作为同步通信的时钟,指示什么时候开始/结束通讯,以及中间数据传输(主设备什么时候发送,从设备什么时候接收)。时钟由主设备发出,控制。


    MISO:SPI通信分为主设备(Master)和从设备(Slave),主设备intput,从设备output


    MOSI:主设备发送(output输出),从设备接收(intput输入)


    NSS:SPI通信分为一主多从,主设备要想从多个从设备中选中和哪个从设备通信,直接将和从设备连接的NSS引脚拉低即可。这个和IIC不一样,IIC直接发送从设备ID来选择从设备。


3、专业术语解释


    (1)空闲态


        指的是SPI总线上没有数据发送时候的状态。


    (2)时钟极性(CPOL)


        SCK时钟线,在SPI总线空闲时候,所处的电平状态(帧与帧之间的状态):


            CPOL = 0,SCK空闲时,主设备持续发送低电平


            CPOL = 1,SCK空闲时,主设备持续发送高电平


    (3)时钟相位(CPHA)


        时钟相位,实际指的就是发送和接受双方如何协调收发:


            CPHA = 0,无论收发方,在第一个边沿(上升沿还是下降沿看CPOL=0还是1)处采样(读取数据),在第二个边沿处发送数据


            CPHA = 1,在第二个边沿处(上升沿还是下降沿看CPOL=0还是1)处采样(读取数据),在第一个边沿处发送数据。


4、SPI通信协议


    SPI通信协议总结起来就是一句话,解决SPI通信问题:


    (1)数据发送高位在前还是低位在前:比如0x55(0101 0101),先发送第0位的1还是第7位的0?


        高位在前,先发送0(MSB),最后发送1(LSB)


    (2)怎么区分正在发送数据还是处在空闲,例如0xff(1111 1111):区分空闲和数据发送?


        在开始发送之前SCK处在空闲态(根据CPOL时钟极性设置规定,持续输出高电平(CPOL=1)或者低电平(CPOL=0)),开始发送时候,主设备会控制SCK发生变化(低电平转高电平,高电平转换低电平),知道数据发送完,SCK会继续回到空闲状态(持续输出高电平或者低电平)。


    (3)发送方什么时候发送?


        根据CPHA时钟相位设置,向数据线上放数据:CPHA=1,在第一个边沿处,向数据线上放数据(发送),CPHA=0,在第二个边沿处,向数据线上放数据(发送)


    (4)接收方什么时候接收?


        根据CPHA设置采样(读取数据):CPHA=1,在第二个边沿处,从数据线上采样(读取数据),CPHA=0,在第一个边沿处,从数据线上采样(读取数据)。


    (5)总结


        从上图可以看出SPI通信双方内部的基本结构,在主设备在发送的时候,从设备也在发送,只不过主设备发送的数据是我们(程序员)放进去的有效数据,但是从设备发送过来的数据确是不确定的(当然我们也可以自己指定垃圾数据,比如0xff或者0x00)。


        所以SPI通信的特点就是,发送方发送数据的时候,是将实现准备好的有效数据在CPHA规定的边沿发送出去的(比如MOSI上,主设备发送数据),同一时刻从设备也在CPHA规定的边沿发送数据(比如MISO上,从设备发送),然后在CPHA规定的采样边沿处,收发双方都会从MOSI或者MISO上去采样(读取数据)。总结起来就是一句话:发送方发送数据的同时,接收方也在发送数据,只不过发送方发的是实际有意义的数据,接收方发送的是无效垃圾数据(这是SPI通信方式所限定的)。


5、LPC11C14平台特点


    在开始在LPC11C14平台上编写SPI通信代码接口之前,将这几个问题搞明白就可以了:


    (1)既然SPI都是一位一位的传送的,那么我(程序员)发送或者接收的时候可是都以byte为单位的,怎么去界定已经发送完或者接收完一个byte?



        在LPC11C14的芯片手册中,可以知道,整个SPI的传输都是以8bit一个字节为单位的(一帧),当帧传输完成时,如果想要传输多个字节,在每个字节传输后,释放总线(还原SCK到空闲态,拉高NSS片选线),这样会将SPI标记寄存器中关于接受和发送标记置位。


    (2)发送和接受有没有FIFO?FIFO的大小是多少?


        LPC11C14上发送和接受的FIFO是公用一个的(环路收发),都是2字节(16bit)


    (3)发送和接受方式是轮训?还是中断?


        SPI的接收和发送均是轮训方式的,当然也可以设置成中断(SSP0IMSC寄存器,半满中断(FIFO收够1个字节)),建议不这么做,因为单个byte就产生一次中断,中断次数太频繁,容易打断CPU主程序执行


    (4)需要写几个接口?每个接口什么功能?


        需要至少2个接口:


            a、SPI初始化配置接口:void spi__0_config(void)


                完成相关引脚功能、时钟选择和分频、SPI通信帧格式、主从角色设置、时钟极性和时钟相位设置


/****************************************************

* 函数名称:spi_0_config

* 功能描述:配置SPI通讯接口:引脚功能、时钟频率、主从模式、数据帧格式

* 参数:无

* 返回值:无

*****************************************************/

void spi_0_config(void)

{

//1、spi引脚初始化:CLK-PIO0_6,MOSI0-PIO0_9,MISO-PIO0_8,C/S-PIO2_4

    LPC_IOCON->PIO0_9 &= ~(0x7<<0);

    LPC_IOCON->PIO0_9 |= (1<<0); //MOSI0

    LPC_IOCON->PIO0_8 &= ~(0x7<<0);

    LPC_IOCON->PIO0_8 |= (1<<0); //MISO0

    LPC_IOCON->PIO0_6 &= ~(0x7<<0);

    LPC_IOCON->PIO0_6 |= (2<<0); //SCK0

    

    //2、设置SCK0管脚时钟功能

    LPC_IOCON->SCK_LOC &= ~(0x3<<0);

    LPC_IOCON->SCK_LOC |= (2<<0);

    

    //3、设置SSP0总线时钟使能

    LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11);

    

    //4、SPI时钟分频设置

    LPC_SYSCON->SSP0CLKDIV &= ~(0xff<<0);

    LPC_SYSCON->SSP0CLKDIV |= 2<<0;

    

    //5、关闭SSP0复位

    LPC_SYSCON->PRESETCTRL |= (1<<0);

    

    

    //6、使能GPIO时钟输出功能:SPI的SCK输出

    LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);

    

    //7、设置SPI的偏选引脚为输出功能:PIO2_4

    LPC_IOCON->PIO2_4 &= ~(0x7<<0);

    LPC_GPIO2->DIR |= (1<<4); //设置PIO2_4引脚为输出功能

    LPC_GPIO2->DATA |= (1<<4); //设置PIO2_4引脚输出高电平(默认悬空不选中)

    

    

    //8、SPI通讯时钟选择、总线类型、数据长度设置

    LPC_SSP0->CR0 &= ~(0xf<<0);

    LPC_SSP0->CR0 |= (7<<0); //设置帧长度为8bit

    LPC_SSP0->CR0 &= ~(3<<4); //设置帧格式为SPI

    LPC_SSP0->CR0 &= ~(3<<6); //SPI时钟极性为低电平,在第一个边沿采样,第二个边沿输出

    

    LPC_SSP0->CR0 &= ~(0xf<<8);

    LPC_SSP0->CR0 |= (7<<8); //设置时钟分频因子7+1

    

    LPC_SSP0->CPSR = 2;//分频结果 = 48MHz/(2*(7+1)) = 3MHz

    

    //9、设置SPI通讯模式为主设备模式,使能SPI

    LPC_SSP0->CR1 &= ~(0xf<<0);

    LPC_SSP0->CR1 |= (1<<1);

}


            b、spi收发接口:unsigned short spi_put_get(unsigned short data)


                由于SPI发送和接受的特点:发送1个字节,必然会有一个字节数据交换接收回来,所以,如果是发送数据,对于返回自己不需要考虑(交换得来的垃圾数据);如果是接收数据,发送数据(垃圾无效数据),将交换得来的字节读取即可。


/*****************************************************

* 函数名称:spi0_put_get

* 功能描述:收发一体接口,用来接收数据或者发送数据

* 参数:data,发送数据,

* 返回值: 接收的数据

***************************************************/

unsigned char spi0_put_get(unsigned char data)

{

    //等待spi空闲,并且发送FIFO不为满

    while((LPC_SSP0->SR & ((1<<1) | (1<<4))) != (1<<1))

    {

        ;

    }

    

    //发送数据

    LPC_SSP0->DR = data;

    

    //等待接收FIFO不为空

    while((LPC_SSP0->SR & (1<<2)) == 0)

    {

        ;

    }

    

    //返回接收数据

    return LPC_SSP0->DR;

    

}


            c、spi接收接口:void spi_receive(unsigned char *buf, unsigned int size)


                单独接收数据功能的接口


            d、spi发送接口:void spi_send(unsigned char *data, unsigned int size)


                单独发送数据功能的接口


/****************************************************

* 函数名称:ssp0_send

* 功能描述:spi发送数据接口

* 参数:data,发送的数据,size,发送字节数

* 返回值:无

*****************************************************/

void ssp0_send(unsigned char *data, unsigned int size)

{

    unsigned int ret = 0;

    unsigned int i = 0;

    unsigned char byte = 0;

    

    if(size <= 0)

        return ;

    

    for(i=size; i>0; i--) //循环发送

    {              

       //判断SPI是否繁忙、发送FIFO中是否已满

       while(((LPC_SSP0->SR & (1<<4)) != 0) && ((LPC_SSP0->SR & (1<<1)))) /*SPI处在繁忙状态 && 发送FIFO未满*/

       {

           ;

       }

       

       //开始发送数据

       LPC_SSP0->DR = *data;

       data++;

       

       //等待接收交换字节

       while((LPC_SSP0->SR & (1<<2)) == 0)//接收FIFO为空

       {

           ;

       }

       

       //读取接收FIFO

       byte = LPC_SSP0->DR ;

       

    }

         

}


    (5)使用SPI通信方式,SCK时钟频率设置多少?时钟极性和时钟相位该怎么设?


        首先在SPI通信过程中,LPC11C14控制器属于主设备角色,本次实验中的从设备通信对象是OLED显示屏,所以时钟频率具体怎么设置全看从设备OLED的SPI极限频率,只要主设备时钟频率设置的低于OLED时钟上线即可(这里OLED上限是3.3MHz),lpc11c14的外设总线频率是48MHz,根据此条件设置分频因子即可。


        时钟极性和时钟相位,在本实验中,主要是由从设备(OLED显示屏)决定,从OLED显示屏驱动芯片SSD1306芯片手册得到,SPI采样必须在上升沿,因此可以根据这个信息任意设置时钟极性和时钟相位,只要让采样发生在上升就可以了,这里使用时钟极性和时钟相位都设置为0(直接在第一个时钟边沿采样,也是在上升沿采样)


    以上内容就是针对LPC11C14平台上关于SPI通讯接口的实验内容


关键字:arm  底层通讯协议  SPI通讯 引用地址:arm底层通讯协议之SPI通讯

上一篇:DSP2808与ARM STM32F103的SPI通讯例程及详解
下一篇:STM32——SPI通信协议(W25Q128FLASH的通信)

推荐阅读最新更新时间:2024-11-11 12:33

ARM学习笔记--初识uC/OS(一)
下面就直接进程序看吧,首先看mian函数 int main(void) { INT8U os_err;//OS error Bsp_init();//Embedded development board Initialization//开发板初始化 OSInit();//uC/OS initialization//系统初始化 os_err = OSTaskCreateExt((void (*)(void *)) App_Task_LCD,//创建任务 (void * ) 0, (OS_STK * )&App_TaskLCDStk , (INT8U ) APP_TASK_LCD_PRIO, (INT16U ) APP_TASK_
[单片机]
ARM指令解析
今天我来总结一下arm指令的学习,今天我不会对所有的arm指令进行一一的解析,在这里希望大家去看arm汇编手册,这个手册的中文版我放在了 http://download.csdn.net/detail/wrjvszq/8324589 大家先拿到这个文档,这个文档对arm指令的解析相当的全面,但是这里要注意的是文档是arm对标准的汇编写出的文档,但是我们要用的是gnu的汇编,这两个稍微有点区别,关于区别大家可以去看看这个博客http://www.cnblogs.com/hnrainll/archive/2011/05/17/2048315.html说完了这些,今天我的重点将会放在arm伪指令和arm协处理器访问指令进行解析。 l
[单片机]
<font color='red'>ARM</font>指令解析
ARM-Linux驱动--DM9000网卡驱动分析(三)
ARM-Linux驱动--DM9000网卡驱动分析(二)硬件平台:FL2440(s3c2440) 内核版本:2.6.35 主机平台:Ubuntu11.04 内核版本:2.6.39 交叉编译器:arm-linuc-gcc4.3.2 原创作品,转载请标明出处http://blog.csdn.net/yming0221/article/details/6615027 本文接上文 ARM-Linux驱动--DM9000网卡驱动分析(一) ARM-Linux驱动--DM9000网卡驱动分析(二) 下面开始看网卡设备的打开、关闭函数和操作函数 view plainprint? static const struct net_
[单片机]
<font color='red'>ARM</font>-Linux驱动--DM9000网卡驱动分析(三)
我与ARM的那些事儿1初识ARM
最近一直在研究ARM,说到ARM,我们首先想到了是三星、高通等公司,这些公司都制造CPU的,其实ARM也是一家公司,只不过它是提供最核心的逻辑电路,而且它的赚钱方式是与其他公司进行双赢的!你卖出多少芯片,我就收这些芯片的一点分红,真他么机智的公司! 微处理器说白一点就是 脑子 ,那么这个脑子它是咋么组成的呢?通常有3大部分 控制单元 算术逻辑单元 寄存器 那么ARM有哪些特点呢? 支持Thumb/ARM双指令集 采用3级流水线/5级流水线 采用哈弗结构,有指令cache和数据cache 寻址方式灵活简单、执行效率高 支持大端小端格式 支持byte\halfword\word三种数据类型 7种模式
[单片机]
我与<font color='red'>ARM</font>的那些事儿1初识<font color='red'>ARM</font>
ARM 链接地址和烧写地址
在ARM设计中,一般会涉及都一个链接地址,这个链接地址和烧写地址很容易混淆,会认为链接地址就是烧写地址,这个是错的,下面说的是个人的一些认识,可能会有一些错误,说的也可能不专业,但是对于初学者,可以帮助理解。 首先链接地址和烧写地址是两个范畴的东西,几乎是没有关系的,烧写地址,可以认为是物理地址,而链接地址可以认为是虚拟地址,对于程序员来说,看到的是虚拟地址,一般虚拟地址经过MMU映射成具体的物理地址,进而再去访问实际的物理地址。 链接地址也可以理解成是一个符号,因为一个可执行程序,一般要经过预编译,编译,汇编,链接三个过程,最后一个过程是链接,就是把前三部分产生的所有.o文件,串起来,形成一个整体的程序,所以每个.o
[单片机]
苹果靠iPad来定义PC未来?微软第一个不同意
至少到目前为止,只有 苹果 有再一次改变 PC 产业的能力,一起来看莫博士是怎么说的。    每一次 iPhone 更新迎来一代又一代更强的A处理器时,总会有人提出苹果也应该自己为 Mac 开发处理器,不应该被英特尔牵着鼻子走。实际上,每隔一段时间我们就会看到  ARM  版 Mac 即将发布的消息,有时候是分析报告,有时候则是业界人士的评论。其实在 Mac 发展史上,苹果已经历过几次更换处理器平台的事情。 第一次是 1994 年 3 月苹果 Mac 使用的处理器从 Motorola 680×0 系列变成新的 PowerPC 处理器架构;第二次是 PowerPC 换成英特尔芯片,苹果在 2005 年宣布了他们这个计划,并从 20
[嵌入式]
ARM7入门13,定时器控制LED灯闪烁
主程序: /******************************************************************************* *File: Main.c *功能: 使用定时器0实现1s定时,并打开IRQ中断,控制LED闪烁 * 同时使用定时器1实现比较匹配输出 *******************************************************************************/ #include config.h #define LEDCON 0x00002000 /*P0.13引脚控制LED,低电平点亮*/
[单片机]
<font color='red'>ARM</font>7入门13,定时器控制LED灯闪烁
Arm Tech Symposia 年度技术大会即将启幕,报名通道现已开启
享誉业界的Arm® Tech Symposia 年度技术大会将于 2024年 11 月 19 日在上海浦东丽思卡尔顿酒店拉开帷幕,并于 11 月 21 日移师深圳湾万丽酒店。 作为 Arm 一年一度最重要的技术盛会,本届Arm Tech Symposia以“让我们携手重塑未来”为主题,将汇聚多位全球顶尖的技术领袖、生态伙伴和开发者,共同展示和探讨AI时代下基于 Arm 技术的最新创新成果和未来发展趋势。 在人工智能的浪潮中,生成式AI、边缘AI、大语言模型、Chiplets、AI 基础设施、智能驾驶等前沿科技正不断突破,引领着应用场景创新。本次年度技术大会将聚焦这些激动人心的领域, 呈现六大精彩看点,敬请期待 : 1.4
[网络通信]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved