第5回でTinyGoでI2Cを制御、今回はSPIを制御してみます。接続するのは米MicroChip社製の23LC512 SPI Serial SRAMです。メモリを相手にSPIの読み書きを確認する目論見。Xiao搭載のSAMD21G18は32KバイトRAM、もし一時保存領域が足らないような場合には利用するのもありか。
※「AT SAMの部屋」 投稿順indexはこちら
MicroChip社の製品ページへのリンクは以下です。8ピンDIP版を購入してあるのでブレッドボードに直ぐ刺せるので楽。やっぱりDIPは工作の友。
23LC512 2.5-5.5V 512Kb SPI Serial SRAM
TinyGoのXiaoボードのMachineパッケージ(機種毎の定数や関数などが含まれている)の説明ページは以下に。多分SPIに関する制御はどのボードも似たりよったりかと。知らんけど。
そして23LC512ですが、以下の回で他のボードに接続したことがあるのです。
MicroPython的午睡(18) ラズパイPico、SPIでシリアルSRAM接続
ブロックを積みながら(30) BBC micro:bit、512K SRAMをSPI接続
ラズパイPicoの方はMicroPython使用でした。BBC micro:bitの方はビジュアルプログラミング環境Microsoft MakeCodeです(MakeCodeは裏でJavaScript生成しています。)こうしてみると真正面からCで書いてないのね。手抜き。
今回は、BBC micro:bit のときに「ビジュアル」に描いたSPIアクセス関数を、ほぼほぼそのまま Go 言語に移植してみました。MakeCodeはお子様の教育向けにも使われているので、とても「読みやすい」デス。移植はお楽で良いです。
実験に使用した回路
このところ使用していた回路のとなりにブレッドボード増設して23LC512を搭載しました。現物の様子は冒頭のアイキャッチ画像をご覧ください。回路図は以下に(描きっぱなしのノー検証なので、回路図はいつも怪しいです。すみません。)
XAIOボードは端子数が限られているので前回まで存在していたタクトスイッチ1個を外してCS(チップセレクト)信号に転用しています。
実験に使用したGo言語ソース
SRAMに読み書きが「できる」というお印だけの確認です。メモリテストであればすんごいシーケンスが必要ですがそういうものではありません。
-
- 1000番地(10進)から1004番地に特定の値(11から15)を書く
- 書き終わった後、1000番地(10進)から1004番地の値を読み出してUSBシリアルに出力
これだけです。先ほど述べたようにBBC micro:bit用に作製したMakeCodeの「絵」をGoに移植してます。ほぼほぼそのままで一発完動。TinyGoが凄いのか、MakeCodeが凄いのか。。。いずれにしても立派な処理系に感謝。
package main import ( "fmt" "machine" "time" ) func readReg23LC512(cs machine.Pin) []byte { readTMP := make([]byte, 2) writeTMP := []byte{5, 0} cs.Low() machine.SPI0.Tx(writeTMP, readTMP) cs.High() return readTMP } func write23LC512(cs machine.Pin, adr uint16, dat byte) []byte { writeTMP := make([]byte, 4) readTMP := make([]byte, 4) writeTMP[0] = 2 writeTMP[1] = byte((adr >> 8) & 0xFF) writeTMP[2] = byte(adr & 0xFF) writeTMP[3] = dat cs.Low() machine.SPI0.Tx(writeTMP, readTMP) cs.High() return readTMP } func read23LC512(cs machine.Pin, adr uint16) []byte { writeTMP := make([]byte, 4) readTMP := make([]byte, 4) writeTMP[0] = 3 writeTMP[1] = byte((adr >> 8) & 0xFF) writeTMP[2] = byte(adr & 0xFF) writeTMP[3] = 0 cs.Low() machine.SPI0.Tx(writeTMP, readTMP) cs.High() return readTMP } func main() { cs := machine.D7 cs.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.SPI0.Configure(machine.SPIConfig{ Frequency: 1000000, SCK: machine.SPI0_SCK_PIN, SDO: machine.SPI0_SDO_PIN, SDI: machine.SPI0_SDI_PIN, LSBFirst: false, Mode: 3}) var testadr uint16 = 1000 var testdat byte = 11 for { for idx := 0; idx < 5; idx++ { write23LC512(cs, testadr+uint16(idx), testdat+byte(idx)) } for idx := 0; idx < 5; idx++ { retV := read23LC512(cs, testadr+uint16(idx)) fmt.Print("ADR=", testadr+uint16(idx), " ") fmt.Println("DAT=", retV[3]) } time.Sleep(1000 * time.Millisecond) } }
動作確認
fmt.Printで、USBシリアルに垂れ流されてきたアドレス、データを眺めています。使用しているのは「伝統にして定番」のTeratermです。いつもお世話になっております。
ちゃんと読み書きできているんでないかい。ほんとか?