20 Star 82 Fork 22

黑胡桃实验室 BlackWalnut Labs. / Waffle NanoV1 Python API Doc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 15.67 KB
一键复制 编辑 原始数据 按行查看 历史
HerculesHu 提交于 2021-07-20 09:30 . !37修改SPI图的地址错误

SPI总线协议

概要

​ 本节详细讲解SPI总线协议。

什么是SPI

  • SPI是串行外设接口(Serial Peripheral Interface)的缩写。是 Motorola 公司推出的一 种同步串行接口技术,是一种高速的,全双工,同步的通信总线。

  • SPI用于在主设备和从设备之间进行通信,常用于与闪存、实时时钟、传感器以及模数转换器等进行通信。

  • SPI协议主要用于短距离的通信系统中,特别是嵌入式系统,很多芯片的外围设备,比如LED显示驱动器、I/O接口芯片、UART收发器等都广泛的采用SPI总线协议。

通信原理

​ SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多 ​ 个从设备。在英文中,通常把主设备称作为 Master, 从设备称作为 Slave.

物理接线

​ SPI理论上需要4根线才能进行双向数据传输,3根线可以进行单向传输: ​ SPI理论上的4根接线分别是以下四种:

功能编号 缩写含义 中文含义
SDO 或者叫 MOSI Master Output Slave Input 主设备数据输出,从设备数据输入
SDI 或者叫 MISO Master Input Slave Output 主设备数据输入,从设备数据输出
SCLK serial clock 时钟信号, 由主设备产生
CS 或者叫SS chip select 片选信号, 从设备使能信号,由主设备控制。

​ 一个主设备和两个从设备的连接示意图如图1所示,Device A和Device B共享主设备的SCLK、MISO和MOSI三根引脚,Device A的片选CS0连接主设备的CS0,Device B的片选CS1连接主设备的CS1。

img

图 1 SPI主从设备连接示意图
  • SPI通信通常由主设备发起,通过以下步骤完成一次通信:
  1. 通过CS选中要通信的从设备,在任意时刻,一个主设备上最多只能有一个从设备被选中。
  2. 通过SCLK给选中的从设备提供时钟信号。
  3. 基于SCLK时钟信号,主设备数据通过MOSI发送给从设备,同时通过MISO接收从设备发送的数据,完成通信。

起始、停止信号

img

​ 如上图,红色编号1和6即为起始和停止信号的发生区域。

CS片选信号(图中的NSS)电平由高变低,则产生起始信号;

CS片选信号电平由低变高,则产生停止信号。

​ 从机检测到自己的CS片选信号线电平被置低,则开始与主机进行通讯;

​ 反之,检测到NSS电平被拉高,则停止通讯。

数据有效性

​ MOSI和MISO线在SCK的每个时钟周期传输一位数据,开发者可以自行设置MSB或LSB先行,不过需要保证两个通讯设备都使用同样的协定。

​ 从以下的时序图可以看出,在SCK时钟周期的上升沿和下降沿时进行触发和采样。

img

​ 这里的触发和采样其实是两个特殊的时间节点,分别对应了SCK时钟周期的上升沿和下降沿。

​ SPI有四种通讯模式,在SCK上升沿触发,下降沿采样只是其中一种模式。四种模式的主要区别便是总线空闲时SCK的状态及数据采样时刻。这涉及到“时钟极性CPOL”和“时钟相位CPHA”,由CPOL和CPHA的组合而产生了四种的通讯模式。

  • CPOL:即在没有数据传输时,时钟的空闲状态的电平。上面的两幅图示中,无数据传输时的时钟空闲状态为低电平。

  • CPHA:即数据的采样时刻,可以是SCK的上升沿,也可以是SCK的下降沿。

    ​ 将CPOL和CPHA的两种状态分别用0,1表示,因此由这两种方式排列组合,便可以产生四种模式的SPI:

SPI模式 CPOL 空闲时SCK时钟 CPHA 采样时刻
0 0 低电平 0 SCK下降沿
1 0 低电平 1 SCK上升沿
2 1 高电平 0 SCK下降沿
3 1 高电平 1 SCK上升沿

​ 配合下图理解:

img

很重要的一点是,主机和从机需要工作在相同的模式下才能正常通讯

操作SPI设备通用方法集合

​ SPI接口定义了操作SPI设备的通用方法集合,包括:

  • SPI设备句柄获取和释放。
  • SPI读写: 从SPI设备读取或写入指定长度数据。
  • SPI自定义传输:通过消息传输结构体执行任意读写组合过程。
  • SPI设备配置:获取和设置SPI设备属性。

SPI优点

  • 支持全双工通信,发送数据和接收数据可以同时进行。
  • 通信简单
  • 数据传输速率快

SPI缺点

  • 接线繁杂,需要至少四根接线
  • 在多个从机的情况下,每个从机都需要接入一根CS片选信号线,这是十分的浪费芯片的IO资源

SPI 引脚定义

 有10个引脚可以用作SPI

SPI组号 SCK MOSI MSIO
SPI 1 pin 0 pin 2 pin 1
SPI 0 pin 6、pin 10 pin 8、pin 9 pin 7

  除此两组SPI硬件资源外,其余的GPIO理论上也可以配置成SPI总线的输入输出管脚,只要满足该管脚既能够作为输入也能够作为输出。因此,

在MicroPython中,拥有两种模式的SPI总线:

  • 硬件SPI:
  • 软件SPI (GPIO模拟):

machine.SPI API详解

硬件SPI构造machine.spi

  硬件SPI:由SPI 0或SPI1组成

  使用from machine import SPI导入machine模块的类SPI

  再使用TAB 按键来查看SPI中所包含的内容:

>>>from machine import SPI
>>>SPI.
read            readinto        write           LSB
MSB             deinit          init            write_readinto

宏定义

  下面的宏定义用于配置SPI发送字节数据的顺序。

宏定义 含义
Pin.MSB 从一个字节中的最高位依次到最低位开始发送该字节数据
Pin.LSB 从一个字节中的最低位依次到最高位开始发送该字节数据

  以下是SPI1的构造:

>>> from machine import SPI
>>> spi=SPI(1,sck=Pin(0))
>>> spi
SPI(id=1, baudrate=500000, polarity=0, phase=0, bits=8, endia=1, sck=0, mosi=-1, miso=-1)

  以下是SPI0的构造:

>>> from machine import SPI
>>> spi0=SPI(0,sck=Pin(6))
>>> spi0
SPI(id=0, baudrate=500000, polarity=0, phase=0, bits=8, endia=1, sck=6, mosi=-1, miso=-1)

  class machine.SPI(id,baudrate, polarity, phase, bits, endia, sck, mosi, miso)

  • id:取决于特定端口及其硬件。 值0、1等常用于选择硬件SPI0或SPI1。
  • baudrate:SCK时钟频率 范围 0 < baudrate ≤ 0x0FFFFFFF (十进制:0 < baudrate ≤ 2147483647)
  • polarity:极性
    • 0 时钟空闲时候的电平是低电平,所以当SCLK有效的时候,就是高电平
    • 1 时钟空闲时候的电平是高电平,所以当SCLK有效的时候,就是低电平
  • phase:相位
    • 0 在下降沿采样数据
    • 1 在上升沿采样数据
  • bits:传输数据位数
  • endia:字节数据传输的方式,可为 SPI.MSB即0 或 SPI.LSB即1
  • sck 时钟信号引脚
  • mosi 主设备输出,从设备输入引脚
  • miso 主设备输入,从设备输出引脚

  示例:

from machine import SPI, Pin
spi0 = SPI(0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0, sck=Pin(6), mosi=Pin(8), miso=Pin(7))
#构造SPI0,SCK时钟频率为40000000,SCK空闲状态为高电平,SCK下降沿采样
#传输数据位8位,字节数据传输的方式为SPI.MSB从高到低
#sck时钟信号引脚是pin6,mosi主设备输出引脚是pin8,msio主设备输入引脚是pin7

函数

初始化

  SPI.init(baudrate, polarity, phase, sck, mosi, miso)

  函数说明:初始化SPI总线   参数含义同上文类构造一致

  示例:

>>>from machine import SPI, Pin
>>>spi0 = SPI(0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0, sck=Pin(6), mosi=Pin(8), miso=Pin(7))#构造硬件SPI0
>>>spi0.init(baudrate=100000, polarity=1, phase=0, sck=Pin(6), mosi=Pin(8), miso=Pin(7))#初始化SPI总线
>>>spi0
SPI(id=0, baudrate=100000, polarity=1, phase=0, bits=8, endia=0, sck=6, mosi=8, miso=7)
写数据

  SPI.write(buf)

  函数说明:将 buf 中的所有数据写入到总线。   示例:

>>>from machine import SPI, Pin
>>>spi0 = SPI(0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0, sck=Pin(6), mosi=Pin(8), miso=Pin(7))#构造硬件SPI0
>>>write_buf = bytearray([1,2,3,4,5,6,7,8])
>>>sw=spi0.write(write_buf)#将write中的所有数据写入到总线
读数据

  SPI.read(len, data=0x00)

  函数说明:读取len个数据的同时写入len个data数据,以数组的形式返回读取到的数据。

  len: 需要读取的字节长度   data: 写入的单字节数据

  示例:

>>>from machine import SPI, Pin
>>>spi0 = SPI(0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0, sck=Pin(6), mosi=Pin(8), miso=Pin(7))#构造硬件SPI0
>>print(spi0.read(2, 0x00)) #读取2个字节,写入数据0x00
b'\x00\x00'

  SPI.readinto(buf, data=0x00)

  函数说明:读取buf.len个数据并存入buf中,同时写入buf.len个data数据,函数返回None。

  buf: 数据缓冲区   data: 写入的单字节数据

  SPI.write_readinto(write_buf, read_buf)

  函数说明:写入write_buf并读取到 read_buf,写入并读取的长度为buf长度,要求两个缓冲区长度相同。

  write_buf: 写数据缓冲区   read_buf: 读数据缓冲区

  示例:

>>>from machine import SPI, Pin
>>>spi0 = SPI(0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0, sck=Pin(6), mosi=Pin(8), miso=Pin(7))#构造硬件SPI0
>>>write_buf = bytearray([1, 2, 3, 4, 5, 6, 7, 8])
>>>read_buf = bytearray(8)
>>>spi.write_readinto (write_buf, read_buf)#写入write_buf并读取8个字节
>>>print(read_buf)
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00')
释放资源

  SPI.deinit()

  函数说明:关闭SPI。   示例:

>>>from machine import SPI, Pin
>>>spi0 = SPI(0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0, sck=Pin(6), mosi=Pin(8), miso=Pin(7))#构造硬件SPI0
>>>spi0.deinit()#关闭SPI0
>>>spi0
SPI(id=0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0, sck=6, mosi=8, miso=7)

软件SPI构造machine.SoftSPI

  硬件SPI构造的引脚功能必须全为SPI0或全为SPI1的,软件SPI构造更为灵活,可以随机选择SPI0或SPI1的sck,miso,msio引脚。

  使用from machine import SoftSPI导入machine模块的类SoftSPI

  再使用TAB 按键来查看SoftSPI中所包含的内容:

>>>from machine import SoftSPI
>>>SoftSPI.
read            readinto        write           LSB
MSB             deinit          init            write_readinto

宏定义

  软件SPI构造宏定义和硬件构造相同

  class machine.SoftSPI(id,baudrate, polarity, phase, bits, endia, sck, mosi, miso)

  • baudrate:SCK时钟频率 范围 0 < baudrate ≤ 0x0FFFFFFF (十进制:0 < baudrate ≤ 2147483647)
  • polarity:极性
    • 0 时钟空闲时候的电平是低电平,所以当SCLK有效的时候,就是高电平
    • 1 时钟空闲时候的电平是高电平,所以当SCLK有效的时候,就是低电平
  • phase:相位
    • 0 在下降沿采样数据
    • 1 在上升沿采样数据
  • bits:传输数据位数
  • firstbi:字节数据传输的方式,可为 SPI.MSB即0 或 SPI.LSB即1
  • sck 时钟信号引脚
  • mosi 主设备输出,从设备输入引脚
  • miso 主设备输入,从设备输出引脚

  示例:

>>>from machine import SoftSPI, Pin
>>>softspi = SoftSPI(baudrate=400000, polarity=0, phase=0, bits=8, firstbit=0, sck=Pin(6, dir=Pin.OUT), mosi=Pin(8, dir=Pin.OUT), miso=Pin(7, dir=Pin.OUT))
#构造SPI,SCK时钟频率为400000,SCK空闲状态为低电平,SCK下降沿采样
#传输数据位8位,字节数据传输的方式为SPI.MSB从高到低
#sck时钟信号引脚是pin6、,mosi主设备输出引脚是pin8,msio主设备输入引脚是pin7,引脚都是输出模式

函数

  软件构造的函数与硬件构造的函数相同

示例

  分别构建硬件SPI和软件SPI

from machine import SPI, Pin, SoftSPI
# 硬件 SPI
spi = SPI(0, baudrate=2000000, polarity=0, phase=0, bits=8, endia=0, sck=Pin(6), mosi=Pin(8), miso=Pin(7))
# 软件 SPI
softspi = SoftSPI(baudrate=400000, polarity=0, phase=0, bits=8, firstbit=0, sck=Pin(6, dir=Pin.OUT), mosi=Pin(8, dir=Pin.OUT), miso=Pin(7, dir=Pin.OUT))

  第一行导入machine模块的硬件类Pin,硬件SPI类SPI和软SPISoftSPI

  第三行构造硬件SPI

  • 0代表构建的是SPI0
  • baudrate=2000000表示SCK时钟频率为2000000
  • polarity=0表示SCK空闲状态为低电平
  • phase=0表示SCK下降沿采样
  • bits=8传输数据位8位
  • endia=0表示字节数据传输的方式为SPI.MSB从高到低
  • sck=Pin(6)表示sck时钟信号引脚是pin6
  • mosi=Pin(8)表示mosi主设备输出引脚是pin8
  • miso=Pin(7)msio主设备输入引脚是pin7

  第五行构造软件SPI

  • baudrate=2000000表示SCK时钟频率为2000000
  • polarity=0表示SCK空闲状态为低电平
  • phase=0表示SCK下降沿采样
  • bits=8传输数据位8位
  • firstbit=0表示字节数据传输的方式为SPI.MSB从高到低
  • sck=Pin(6, dir=Pin.OUT)表示sck时钟信号引脚是pin6,引脚为输出模式
  • mosi=Pin(8, dir=Pin.OUT)表示主设备输出引脚是pin6,引脚为输出模式
  • miso=Pin(7, dir=Pin.OUT))表示主设备输入引脚是pin6,引脚为输出模式
Python
1
https://gitee.com/blackwalnutlabs/waffle_nano_v1_python_api_document.git
git@gitee.com:blackwalnutlabs/waffle_nano_v1_python_api_document.git
blackwalnutlabs
waffle_nano_v1_python_api_document
Waffle NanoV1 Python API Doc
master

搜索帮助