
前回までにTimerは何とか制御できそうな気がしてきたので、今回からインタフェース回路に進みます。最初はSPIです。シリアルだけれどもそこそこ高速な転送速度を使えるインタフェースです。STM32版のMicroPythonの場合、ソフトウエア的には2系統のモジュールでSPIにアクセスできます。別に同じハードなんだけれども。
※「MicroPython的午睡」投稿順 Indexはこちら
SPI接続のSRAMを接続してみる
STM32版MicroPythonからSPIを使用してみる実験に、今回はSPI接続のSRAMを使ってみることにいたしました。SRAMの特定のアドレスにテキトーなデータを書き込んだのち読み出して、同じものが読めればOKっという目論見。
接続するSRAMは既に何度も使っている米マイクロチップ社の以下のチップです。
23LC512 2.5-5.5V 512Kb SPI Serial SRAM
さてSTM32との接続ですが、STM32版のMicroPythonはソフトウエアSPIもサポートしているので、ぶっちゃけほとんどの端子をSPI接続に使えるようですが、やはり速度性能等を考えるとハードウエアのSPIを使った方が良いです。今回はSTM32上でSPI1と呼ばれているハードウエアSPIを使用してみます。
SPIの機能端子と、STM32チップ上での端子名、そしてNucleo-F401REボード上のArduino互換ピンソケットでの端子名の表が以下に。
| SPI端子 | STM32端子名 | Arduino互換ピンソケット端子名 |
|---|---|---|
| SPI1_SCLK | PA_5 | D13 |
| SPI1_MISO | PA_6 | D12 |
| SPI1_MOSI | PA_7 | D11 |
| SPI1_SSEL | PA_4 | A2 |
後でみますが、使用するMicroPythonモジュールによっては、SPI1_SSELはソフト制御にできるので、上記端子でなくても良いと思われます。
さて、Nucleo-F401REボードに23LC512を接続した実験用の回路が以下に(現物の様子は冒頭のアイキャッチ画像に。)
2つのモジュール
さてSTM32版のMicroPythonでは、2系統のモジュールでSPIをサポートしています。といって制御対象は同じハードウエアなので、冗長と言えば冗長。多分、pyboardとの互換性をとるか、他ボードとの互換性の高い方法をとるかという配慮かと。
まずpyboard互換のクラスは以下のようです。import pybすればhelpを見れます。
こちらを使用した場合の制御方法は以下のページに記されてます。
class SPI — a controller-driven serial protocol
上記方法は、SPIのCS端子なども所定の端子を使って制御してくれたりしてくれてSTM32のハード密着型でSTM32特有の機能を使える一方、キメウチのハードウエア制御のみなので多少柔軟性にかけるじゃないか、と思われます。
もう一つが machineモジュール内のSPI機能を使う方式です。こちらも import machineすれば helpを見れます。
pybとは関数セットなどもかなり異なっていることがわかります。こちらについてのマニュアルページは以下で良いかと思います。
クラス SPI — シリアルペリフェラルインタフェース バスプロトコル(コントローラ側)
こちらの方が、他機種のMicroPythonと互換性をとったりするにはよろしいように思われるのですが、同じソースが無修正でそのまま走るかどうかは微妙です。今回、大分以前にやってみたRaspberry Pi Picoボード用のMicroPython上で動かした以下の回のMicroPythonソースを持ってきたのですが、SPIの初期化のところはPico用の記述の端子名を変更した程度ではダメでした。
MicroPython的午睡(18) ラズパイPico、SPIでシリアルSRAM接続
読み書きは同じようにできたので、ま、いいか。
今回実験に使用したMicroPythonスクリプト
以下に示すスクリプトは、ラズパイPicoのMicroPython用だったものを小改造したものであります。キメウチのSPI‐SRAMアドレスにキメウチのデータを書いて、読んでみるだけのもの。速度は控えめの100kHzです(ブレッドボードのグダグダ配線だし。)SPIなのでもっと早くしてもいいかな~。
#STM32: SPI1 SRAM 23LC512 R/W test
#SPI1_SCLK PA_5 D13
#SPI1_MISO PA_6 D12
#SPI1_MOSI PA_7 D11
#SPI1_SSEL PA_4 A2
import time
from machine import Pin, SPI
spi1 = SPI(1, 100_000)
cs1 = Pin(machine.Pin.board.A2, Pin.OUT)
cs1.value(1)
def rdmr():
buf = bytearray(1)
command = bytes([0x05])
cs1.value(0)
spi1.write(command)
spi1.readinto(buf)
cs1.value(1)
return buf
def writeSEQ(memadr, datlis):
command = bytes([0x02, ((memadr >> 8) & 0xFF), (memadr & 0xFF)])
dat = bytes([(x & 0xFF) for x in datlis])
cs1.value(0)
spi1.write(command)
spi1.write(dat)
cs1.value(1)
def readSEQ(memadr, datlen):
buf = bytearray(datlen)
command = bytes([0x03, ((memadr >> 8) & 0xFF), (memadr & 0xFF)])
cs1.value(0)
spi1.write(command)
spi1.readinto(buf)
cs1.value(1)
return buf
def main():
print("STM32F401RE SPI1 SRAM R/W Test.")
result = rdmr()
print("Mode Register = 0x{0:02x}".format(result[0]))
memADR = 0x1000
memDAT = [0x31, 0x32, 0x33, 0x34]
while True:
writeSEQ(memADR, memDAT)
result = readSEQ(memADR, 4)
print("ADR=0x{0:04x} {1}".format(memADR, str(result)))
if memADR == 0x1000:
memADR = 0x1004
memDAT = [0x35, 0x36, 0x37, 0x38]
else:
memADR = 0x1000
memDAT = [0x31, 0x32, 0x33, 0x34]
pyb.LED(1).on()
time.sleep(1)
pyb.LED(1).off()
time.sleep(1)
if __name__ == "__main__":
main()
動作結果
動作結果がほれこのように。
アドレス0x1000番地からアスキーコードで 1234、次の0x1004番地には5678と書かれておるようです。予定通りの動作っす。

