前回はシリアルEEPROM、I2C接続でした。今回はシリアルSRAM、SPI接続であります。前回はMicroPythonからのI2C制御、釈然としない部分ありだったのですが、今回のSPIは明朗会計なんであります。ほとんど何も考えずに接続すれば動作してしまう感じ。落差大きいです。
※「MicroPython的午睡」投稿順 Indexはこちら
ラズパイPicoに接続するデバイスは、前回に続きマイクロチップ社製であります。23LC512、512Kビット(64Kバイト)品です。流石にこの容量になってくると高速とは言えないI2Cバス接続は辛い。SPI接続であります。まずはデータシートへのリンクを貼り付けておきます。
23LC512 2.5-5.5V 512Kb SPI Serial SRAM
このデバイス、8ピン小パッケージのデバイスでありますが、通常のSPIモード(データ線は入出力独立各1ビット)に加えて、QSPIモード(データ線は入出力共用4ビット幅)にも対応しています。またクロック周波数は最大20MHzです。電源落としたら記憶が飛んでしまうSRAMですが、その代わり前回のEEPROMなどと異なり書き換え回数の上限などなく、また書き込み中は待たされるようなことなどありません。頻繁に書き換えるデータの一時保存などには重宝するんじゃないかと思います。
ラズパイPicoは、ハードウエアのSPIを2チャンネル搭載しています。PIOのSMをSPI用にプログラムするという手もありますが、今回は折角なのでハードウエアIPの方を使わせていただきます。RP2040のデータシートを見ると、このSPIは、Arm社のIPライブラリである PrimeCellであるようです。型番PL022。
今回は2個の搭載SPIのうち、SPI0の方をSPIモードで1MHzという低速設定で使ってみたいと思います。MicroPythonでの読み書きテストプログラムの全文は末尾にあります。
以下に今回実験した回路を示します。例によってラズパイPicoは端子アサインの自由度が高いです。必ずしもGP2からGP5に接続しなければならないわけでも無いのです。手元のブレッドボード上接続しやすかったのでココにした、というだけのものです。シンプルな接続で64Kバイト分のメモリが接続できて良い感じです。
現物の接続の様子を以下に掲げました。前回のI2CシリアルEEPROMも同じ8ピンのデバイスでしたが、プルアップなど無い分、回路はスッキリした印象です。一応、波形をとれるようにピンたてたのですが、波形を見るまでもなく動いてしまったので、見てません。
I2Cの時と同様、ラズパイPicoのMicroPython SDKのドキュメントには、サンプルプログラムが書いてありますが、メソッドの説明がありません。「だいたい」該当する説明文書(日本語)は以下のもので良いのではないかと思うので、URLを掲げておきます。
クラス SPI — シリアルペリフェラルインタフェース バスプロトコル(マスタ側)
ここでポイントは、「CSバー」信号は別途ソフト制御に任されているということです。SPIのハードでは制御してくれません。しかし、その方がナンボか良かったです。下手にハード制御されると、デバイス固有の読み書きシーケンスに合致しない可能性もあり、です。ソフトでCSをロウ(アクティブ)にした後、必要な順番でプリミティブなWriteとReadシーケンスを並べ、最後にCSをハイ(インアクティブ)に戻す、というやり方で読み書きともバッチリじゃないかと思います。
末尾のサンプルプログラムでは、まず動作モードの設定レジスタを読み出し(変更する場合には書き込まないとならないですが、今回はデフォルト値でそのまま動作させています)て確認、そのあと0x1000番地からアスキーコードで’0′, ‘1’, ‘2’, ‘3’と4バイト書き込み、そして読み出して表示というシーケンスです。
以下に動作させた結果を示します。
Mode Register = 0x40 bytearray(b'1234')
モードレジスタが0x40というのは、「シーケンシャルモード」になっていることを示しています。このチップは、バイトとか、32バイトページとか、でも読み書きできるのですが、シーケンシャルモードであると、最初に先頭アドレスを与えた後、何バイトでも(実メモリは64Kバイト。上限超えるとラップ。)読みでも書きでも続けられます。これだけあればええじゃないか、と思えるモードです。なおMicroPython上の入出力データは、I2Cの時と同様、以下の型の入れ物に入れておく必要があります。
- 書き込み元は bytes型(変更不可)で良い
- 読み込み先はbytearray型(変更可能)でなければならない
今回は、特にトラブルこともなく動作してしまいました。次回は再びラズパイPicoの特徴であるPIOのSMを使って、異なるインタフェースに接続してみる予定。
MicroPython的午睡(17) ラズパイPico、I2CでシリアルEEPROM接続 へ戻る
MicroPython的午睡(19) ラズパイPico、「普通の」SRAM接続に手こずる へ進む
SPI接続シリアルSRAM READ/WRITE テストプログラム
import time from machine import Pin, SPI spi0 = SPI(0, 100_000, sck=Pin(2), mosi=Pin(3), miso=Pin(4)) cs0 = Pin(5, Pin.OUT) cs0.value(1) def rdmr(): buf = bytearray(1) command = bytes([0x05]) cs0.value(0) spi0.write(command) spi0.readinto(buf) cs0.value(1) return buf def writeSEQ(memadr, datlis): command = bytes([0x02, ((memadr >> 8) & 0xFF), (memadr & 0xFF)]) dat = bytes([(x & 0xFF) for x in datlis]) cs0.value(0) spi0.write(command) spi0.write(dat) cs0.value(1) def readSEQ(memadr, datlen): buf = bytearray(datlen) command = bytes([0x03, ((memadr >> 8) & 0xFF), (memadr & 0xFF)]) cs0.value(0) spi0.write(command) spi0.readinto(buf) cs0.value(1) return buf result = rdmr() print("Mode Register = 0x{0:02x}".format(result[0])) writeSEQ(0x1000, [0x31, 0x32, 0x33, 0x34]) result = readSEQ(0x1000, 4) print(str(result))