15/70 spi通信详解


layout: "post"
title: "SPI通信详解"
category: "嵌入式"
tags:
date: "2016-10-29 14:09"


SPI 相比其他协议算是比较简单的,本来是去年要总结的一篇文章,但由于偷懒只把部分参考链接放出来了,隔了很长时间,才下定决心将内容整理出来,之前写过 uart 还有其他一些内容,要完整的表述出来,还是相当占用篇幅的。

简述

SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的, 它允许 MCU 以全双工的同步串行方式, 与各种外围设备进行高速数据通信.SPI最大的特点是由主设备时钟信号的出现与否来确定主/从设备间的通信。一旦检测到主设备的时钟信号,数据开始传输。SPI 是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今越来越多的芯片集成了这种通信协议,比如 AT91RM9200,stm32,efm32等等。

SPI 主要应用在 EEPROM, Flash, 实时时钟(RTC), 数模转换器(ADC), 数字信号处理器(DSP) 以及数字信号解码器之间. 它在芯片中只占用四根管脚 (Pin) 用来控制以及数据传输, 节约了芯片的 pin 数目, 同时为 PCB 在布局上节省了空间. 正是出于这种简单易用的特性, 现在越来越多的芯片上都集成了 SPI技术.

接口定义

SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)。

  • SDO/MOSI:主设备数据输出,从设备数据输入
  • SDI/MISO:主设备数据输入,从设备数据输出
  • SCLK:时钟信号,由主设备产生(除非需要指定频率如: uart ,其他通讯一些一般都会配上一个时钟总线)
  • CS:从设备使能信号,由主设备控制,主设备可以通过 CS 来选择究竟读写哪个从设备

CS: 其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效,这就允许在同一总线上连接多个SPI设备成为可能。

SDI/SDO/SCLK: 通讯是通过数据交换完成的,这里先要知道SPI是串行通讯协议,也就是说数据是一位一位的传输的。这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。数据输出通过 SDO线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。完成一位数据传输,输入也使用同样原理。这样,在至少8次时钟信号的改变(上沿和下沿为一次),就可以完成8位数据的传输。

特性

采用主-从模式(Master-Slave) 的控制方式

SPI 规定了两个 SPI 设备之间通信必须由主设备 (Master) 来控制次设备 (Slave). 一个 Master 设备可以通过提供 Clock 以及对 Slave 设备进行片选 (Slave Select) 来控制多个 Slave 设备, SPI 协议还规定 Slave 设备的 Clock 由 Master 设备通过 SCK 管脚提供给 Slave 设备, Slave 设备本身不能产生或控制 Clock, 没有 Clock 则 Slave 设备不能正常工作。

采用同步方式(Synchronous)传输数据

Master 设备会根据将要交换的数据来产生相应的时钟脉冲(Clock Pulse), 时钟脉冲组成了时钟信号(Clock Signal) , 时钟信号通过时钟极性 (CPOL) 和 时钟相位 (CPHA) 控制着两个 SPI 设备间何时数据交换以及何时对接收到的数据进行采样, 来保证数据在两个设备之间是同步传输的。

数据交换(Data Exchanges)

SPI 设备间的数据传输之所以又被称为数据交换, 是因为 SPI 协议规定一个 SPI 设备不能在数据通信过程中仅仅只充当一个 "发送者(Transmitter)" 或者 "接收者(Receiver)". 在每个 Clock 周期内, SPI 设备都会发送并接收一个 bit 大小的数据, 相当于该设备有一个 bit 大小的数据被交换了。

一个 Slave 设备要想能够接收到 Master 发过来的控制信号, 必须在此之前能够被 Master 设备进行访问 (Access)。 所以, Master 设备必须首先通过 SS/CS pin 对 Slave 设备进行片选, 把想要访问的 Slave 设备选上。

模拟 SPI

SPI 并非芯片必须集成的功能,很多过去的芯片都没有集成该功能,但我们依然可以通过控制 IO 高低电平/输入输出,来模拟出芯片手册上面要求的信号,下面我以 FM25W256-G 为例做个简单说明。

/* 以下程序临时改写,未经过实验验证 */

/* SPI端口初始化 */  
void spi_init()  
{  
    set_gpio_direction(SS, OUTP);  
    set_gpio_direction(SCLK, OUTP);  
    set_gpio_direction(MOSI, OUTP);  
    set_gpio_direction(MISO, INP);  
    set_gpio_value(SCLK, 0);     //CPOL=0  
    set_gpio_value(MOSI, 0);  
}  

/* 
从设备使能 enable:为1时,使能信号有效,SS低电平为0时,使能信号无效,SS高电平
*/  
void ss_enable(int enable)  
{  
    if (enable)  
        set_gpio_value(SS, 0);     //SS低电平,从设备使能有效  
    else  
        set_gpio_value(SS, 1);     //SS高电平,从设备使能无效  
}  
 /* SPI字节写 */  
void spi_write_byte(unsigned char b)  
{  
    int i;  
    for (i=7; i>=0; i--) {  
        set_gpio_value(SCLK, 0);  
        set_gpio_value(MOSI, b&(1<<i));   //从高位7到低位0进行串行写入  
        delay();       //延时  
        set_gpio_value(SCLK, 1);    // CPHA=1,在时钟的第一个跳变沿采样  
        delay();   
    }  
}  
/* SPI字节读 */  
unsigned char spi_read_byte(void)  
{  
    int i;  
    unsigned char r = 0;  
    for (i=0; i<8; i++) {  
        set_gpio_value(SCLK, 0);  
        delay();       //延时  
        set_gpio_value(SCLK, 1);    // CPHA=1,在时钟的第一个跳变沿采样  
        r = (r <<1) | get_gpio_value(MISO);   //从高位7到低位0进行串行读出  
        delay();  
    }  
}  

/* 
 SPI写操作  buf:写缓冲区  len:写入字节的长度 
*/  
void spi_write (unsigned int add, unsigned char date)  
{  
    spi_init();       //初始化GPIO接口  
    ss_enable(1);       //从设备使能有效,通信开始  
    delay();        //延时  
    spi_write_byte(0x06);   // 写使能指令
    delay();        //延时  
    ss_enable(0);       
    delay();        //延时  
    
    ss_enable(1);       //从设备使能有效,通信开始  
    delay();        //延时  
    spi_write_byte(0x02);   // 写指令
    spi_write_byte((add&0xff00)>>8);    // 写高地址
    spi_write_byte(add&0xff);   // 写低地址
    spi_write_byte(date);  // 写数据
    delay();  
    ss_enable(0);       //从设备使能无效,通信结束  
}  
/* 
SPI读操作 buf:读缓冲区 len:读入字节的长度 
*/  
unsigned char spi_read(unsigned char* buf, int len)  
{  
    unsigned char res;
    spi_init();       //初始化GPIO接口  
    ss_enable(1);       //从设备使能有效,通信开始  
    delay();        //延时  
    spi_write_byte(0x03);   // 写指令
    spi_write_byte((add&0xff00)>>8);    // 写高地址
    spi_write_byte(add&0xff);   // 写低地址
    res = spi_read_byte();  // 写数据
    delay();  
    ss_enable(0);       //从设备使能无效,通信结束  
}  

int main(void)
{
    unsigned int tmp = 0;
    spi_init();
    spi_write_byte(0xaa, 0x22);
    tmp = spi_read_byte(0xaa);
}

通过上述代码我们不难发现,在使用模拟 SPI 时,可以方便我们移植,且不会增加特定寄存器的配置难度,但同时也以为着会增加代码量,且时钟要控制的比较精准才可以读取成功。

寄存器操作 SPI

使用寄存器配置 SPI,每个芯片厂家都不尽相同,会有自己的独家配置,这边为了文章的完整性,以 stm32 为例举个简答的例子。

注意点

相比 IIC 等其他协议而言,SPI 操作比较简单,但会占用更多的资源。同任何其他协议一样,在使用 SPI 进行通信时,也需要仔细阅读芯片手册,以下介绍一些可以会引起读写失败,容易忽视的问题:

时钟生效

在看芯片手册时,往往不同的 SPI 通讯设备,会存在不同的时钟周期,有效,如上面 FM25W256-G 就是在上升沿时有效,而少数芯片却可能会是下降沿有效,在使用 SPI 控制芯片时首先第一步就是该仔细看时钟周期,如果你在配置寄存器时,忽略了这点往往会读写失败。

大小端

同样芯片手册会详细指定是 MSB 还是 LSB 这点也要仔细阅读,不然容易造成数据错误。

指令操作顺序

操作指令的顺序很重要,FM25W256-G 这款芯片就仅指定了每次写时需要先使能,我们需要仔细阅读手册的时序图,查看使能时是否作为一个完整的执行周期。

小结


写作时间:20:30-22:30

To be continued...

参考链接:
http://wenku.baidu.com/view/2a0a7f9869dc5022abea001d.html
http://baike.baidu.com/item/SPI
https://my.oschina.net/freeblues/blog/67400
http://www.cnblogs.com/hello2mhb/p/3518974.html
http://www.cnblogs.com/aaronLinux/p/6219146.html
http://blog.csdn.net/special_lin/article/details/12835863
http://blog.csdn.net/zyboy2000/article/details/11861329

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容