前回までに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と書かれておるようです。予定通りの動作っす。