本节详细讲解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。
如上图,红色编号1和6即为起始和停止信号的发生区域。
CS片选信号(图中的NSS)电平由高变低,则产生起始信号;
CS片选信号电平由低变高,则产生停止信号。
从机检测到自己的CS片选信号线电平被置低,则开始与主机进行通讯;
反之,检测到NSS电平被拉高,则停止通讯。
MOSI和MISO线在SCK的每个时钟周期传输一位数据,开发者可以自行设置MSB或LSB先行,不过需要保证两个通讯设备都使用同样的协定。
从以下的时序图可以看出,在SCK时钟周期的上升沿和下降沿时进行触发和采样。
这里的触发和采样其实是两个特殊的时间节点,分别对应了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上升沿 |
配合下图理解:
很重要的一点是,主机和从机需要工作在相同的模式下才能正常通讯
SPI接口定义了操作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总线:
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
即1sck
时钟信号引脚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)
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
即1sck
时钟信号引脚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
第五行构造软件SPI
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарий ( 0 )