簡 介: 本文給出了 MicroPython內核開發筆記:書內嵌入實驗任務 中的 SPI 軟件用例部分內容。
關鍵詞
:MicroPython,MM32F3277,SPI
在MM32F3277 MicroPython 所支持的 SPI 包括三個通道: SPI0、SPI1、SPI2,下面表格給出了它們占用的端口資源。
通過下面小程序,也可以直接通過 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時鐘極性與相位
通過下面代碼,可以查看 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']
下面代碼將 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信號波形
由於 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信號波形
在 PLUS-F3270 實驗板上配置有一顆 SPI接口的FLASH芯片 W25Q64 ,連接在 SPI1接口上。 使用 PE3 作為芯片的片選信號。
▲ 圖1.2.1 實驗板上的FLASH
根據 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]
下面給出了利用 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 軟件用例部分內容。
當 SPI 的 CLK 的極性設置為 0, polarity=0 時,CLK信號在靜態時似乎是高阻狀態。下面是抓取到的信號波形。可以看到在CLK波形基線存在50Hz干擾信號。
▲ MOSI,CLK 信號波形
但是,當 polarity=1時, CLK信號處在高電平時,電壓是穩定的。
猜測:具體原因不詳。 似乎需要將 CLK 信號線通過下拉電阻接地。
■ 相關文獻鏈接:
● 相關圖表鏈接: