简 介: 本文给出了 MicroPython内核开发笔记:书内嵌入实验任务 中的 SPI 软件用例部分内容。
关键词
: MicroPython,MM32F3277,SPI
- 本书稿内容隶属于 MicroPython内核开发笔记:书内嵌入实验任务 中的内容。
§01 书稿内容
在MM32F3277 MicroPython 所支持的 SPI 包括三个通道: SPI0、SPI1、SPI2,下面表格给出了它们占用的端口资源。
SPI管脚 | SCK | MOSI | MISO |
---|---|---|---|
SPI0 | PA5 | PA7 | PA6 |
SPI1 | PB10 | PB15 | PB14 |
SPI2 | PC9 | PA8 | PB9 |
一、基础实验
1、显示SPI信息
通过下面小程序,也可以直接通过 REPL 交互输入下面程序,显示 SPI 相关信息。
from machine import Pin,SPI
import time
print(SPI(0))
print(SPI(1))
print(SPI(2))
执行结果显示如下,给出了三个通道所占用的单片机管脚资源。
SPI(id=0, baudrate=80000000, polarity=0, phase=0), on MOSI(PA7), MISO(PA6), SCK(PA5)
SPI(id=1, baudrate=80000000, polarity=0, phase=0), on MOSI(PB15), MISO(PB14), SCK(PB10)
SPI(id=2, baudrate=80000000, polarity=0, phase=0), on MOSI(PA8), MISO(PB9), SCK(PC9)
可以看到,缺省情况下,SPI 的时钟频率为 8MHz,极性和相位模式为 00。四种不同的时钟极性相位模式对应的 SPI 信号如下图所示。
▲ 图1.1.1 SPI时钟极性与相位
2、SPI相关函数
通过下面代码,可以查看 spi 对象提供的相关函数。
from machine import SPI
spi = SPI(0, baudrate=100000, polarity=1, phase=0)
dir(SPI)
代码输出信息为:
['read', 'readinto', 'write', 'LSB', 'MSB', 'deinit', 'init', 'write_readinto']
- init:初始化 SPI 总线;
- deinit:关闭 SPI 总线;
- read,readinto:从 SPI 读入若干字节,同时写出固定字节;
- write,write_readinto:从 SPI 输出若干字节,同时将读入数据存入内部缓存;
- LSB,MSB:分别设置字节的低位先发送和高位先发送;缺省情况下,是字节高位先发送;
3、测试SPI输出信号
(1)SPI输出字节
下面代码将 SPI0 设置成波特率 100kHz, 时钟 polarity=1,phase=0。 每隔 10ms 发送字节 0x55,0xaa。spi 通过函数 write 输出数据。
在PA5(SCK)、PA7(MOSI)测量 SPI0 输出信号。
from machine import Pin,SPI
import time
spi = SPI(0, baudrate=100000, polarity=1, phase=0)
print("Begin to send 0x55aa from SPI0.")
buf = bytes((0x55,0xaa))
while True:
spi.write(buf)
time.sleep_ms(10)
▲ 图1.1.2 MOSI,SCK信号波形
(2)SPI读入字节
由于 SPI 总结是全双工总线,也就是发送与接收可以同时进行。下面代码从 SPI 总线读入两个字节,在读入字节的同时,输出 0x55。
from machine import Pin,SPI
import time
spi = SPI(0, baudrate=100000, polarity=1, phase=0)
print("Begin to read 2 bytes from SPI0.")
buf = bytes((0x55,0xaa))
while True:
data = spi.read(2,0x55)
time.sleep_ms(10)
测量 PA5(SCK)、PA7(MOSI)两个管脚的信号。从信号波形上可以看到,SPI 读入函数 read 在执行的时候,读入两个字节的同时发送了两个字节的 0x55。
▲ 图1.1.3 MOSI,SCK信号波形
二、读写FLASH
在 PLUS-F3270 实验板上配置有一颗 SPI接口的FLASH芯片 W25Q64 ,连接在 SPI1接口上。 使用 PE3 作为芯片的片选信号。
▲ 图1.2.1 实验板上的FLASH
1、读W25Q64 ID数据
根据 W25Q64 数据手册可知,通过指令 0x90,0xab,0x4b 可以分别读出厂商ID、器件ID、64位唯一序列号。下面代码演示了读取这些 ID 数据方法。使用了 SPI 的 write_readinto 函数,完成了命令的发送与数据的接受。
from machine import Pin,SPI
import time
W25Q_CE = Pin("PE3", Pin.OUT_PUSHPULL, value=1)
W25Q_SPI = SPI(1, baudrate=8000000, polarity=0, phase=1)
def w25qIO6Bytes(outb,inbs):
outbuf = bytes([outb] + [0]*(inbs-1))
inbuf = bytearray(inbs)
W25Q_CE(0)
W25Q_SPI.write_readinto(outbuf, inbuf)
W25Q_CE(1)
return inbuf
inb = w25qIO6Bytes(0x90,6)
print(list(inb))
inb = w25qIO6Bytes(0xab,5)
print(list(inb))
inb = w25qIO6Bytes(0x4b,13)
print(list(inb))
下面是代码运行结果。对比 W25Q64 数据手册,可以知道读出的数据是正确的。
[255, 255, 255, 255, 239, 23]
[255, 255, 255, 255, 23]
[255, 255, 255, 255, 255, 210, 100, 108, 51, 91, 20, 19, 45]
2、W25Q64数据读写
下面给出了利用 SPI 对 W25Q64 进行读、写、擦除等函数。
def w25qReadData(address, readlen):
inbuf = bytearray(readlen)
W25Q_CE(0)
W25Q_SPI.write(b'\x03' + address.to_bytes(3, 1))
W25Q_SPI.readinto(inbuf, 0x0)
W25Q_CE(1)
return inbuf
def w25qWritePage(address, data):
W25Q_CE(0)
W25Q_SPI.write(b'\x02' + address.to_bytes(3, 1) + data)
W25Q_CE(1)
def w25qWriteEnable():
W25Q_CE(0)
W25Q_SPI.write(b'\x06')
W25Q_CE(1)
def w25qSectorErase(address):
W25Q_CE(0)
W25Q_SPI.write(b'\x20' + address.to_bytes(3, 1))
W25Q_CE(1)
利用上述函数可以完成对 W25Q64 的编程。
下面是在对 W25Q64 编程之前读取 W25Q64前 16 字节数据,都是0xff,这说明这些地址可以允许后期写入新的数据。
bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff')
下面代码是将 0x0 ~ 0xf 写入 W25Q64。
w25qWriteEnable()
w25qWritePage(0x0, bytes(list(range(0x10))))
time.sleep_ms(10)
inb = w25qReadData(0, 0x10)
print(inb)
然后在读取前 0x10 个数据,显示的结果如下:
bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f')
※ 总 结 ※
本文给出了 MicroPython内核开发笔记:书内嵌入实验任务 中的 SPI 软件用例部分内容。
一、存在问题
1、SPI输出管脚
当 SPI 的 CLK 的极性设置为 0, polarity=0 时,CLK信号在静态时似乎是高阻状态。下面是抓取到的信号波形。可以看到在CLK波形基线存在50Hz干扰信号。
▲ MOSI,CLK 信号波形
但是,当 polarity=1时, CLK信号处在高电平时,电压是稳定的。
猜测:具体原因不详。 似乎需要将 CLK 信号线通过下拉电阻接地。
■ 相关文献链接:
● 相关图表链接: