GoにいればGoに従え(22) TinyGo、SPI接続、micro:bit v2の場合

Joseph Halfmoon

TinyGoを使ってBBC micro:bit v2を制御してます。「使ってなかった」のに「使った気でいた」ペリフェラル回路があり。SPIです。TinyGoでSAMD21マイコンで実験済、またmicro:bitのmakeCode環境でも実験済。でもTinyGoとmicro:bit v2 ではやってない。組み合わせ爆発?

※「GoにいればGoに従え」Go関連記事の総Index

SPI接続シリアルSRAM 27LC512

以下の別シリーズ記事にて、TinyGoでSPI接続のシリアルSRAM、マイクロチップ製27LC512をR/Wしてみたことがあるのです。

AT SAMの部屋(8) XiaoでもGo!TinyGoでSPI、27LC512接続

ただし上記のターゲット機は、Seeduino Xiao(搭載マイコンはマイクロチップSAMD21)でした。既に上記でTinyGoの実験用コードを書いて走らせているので、これをmicro:bit v2に「移植」できればOKということになります。

一方、BBC micro:bit に同じ27LC512を接続したこともあるのです。以下の別シリーズ記事です。

ブロックを積みながら(30) BBC micro:bit、512K SRAMをSPI接続

このときのターゲット機は、micro:bit v1.5でした。またソフトウエアはマイクロソフト社のグラフィカルなプログラミング環境 MakeCode でした(裏側ではJavaScriptのコードに翻訳されている)

BBC micro:bit のカードエッジに出ている信号は v1.5 と v2で互換性が高いので、多分同じ接続で動作する筈。上記の別シリーズのときの回路図を再掲します。以下と同じ接続で動けばOKっと。

microbit_23LC512_schematic

今回「移植」のGoソース

今回のソースはほぼほぼ「AT SAMの部屋 第8回」で作成したものそのままです。機種は違いますが、TinyGoレベルでのソースコードはかなり互換性が高いように思われます。アカラサマに異なるのは CS(チップセレクト) 端子のお名前です。これはSPI接続のデバイスをセレクトするための信号ですがソフト制御なので、どの出力端子を割り当てるのかは任意です。また、マイコン毎に端子名等は変わるので変更するのはいたしかたありません。今回はP0端子をCSに割り当ててます。

それ以外はSAMD21用のTinyGoコードそのままで動いてしまいました。1点補足しておくと TinyGoのソース上では、BBC micro:bit v2のカードエッジにでているSPIはSPI0と呼ぶようです。BBC micro:bit の公式ピンマップ等では、カードエッジに出ているSPIはSPI1という名前で呼ばれているハズですが、TinyGoではSPI0だと。まあ、おかげでSAMD21のソースそのままで動くのですが。

「移植」したソースが以下に。実際は一か所ピン名を変更しただけ。

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.P0 //modified
    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)
    }
}じ
実機動作確認

ビルドしてフラッシュ書き込み後の動作が以下に。mb20spiResults

特定のアドレスに特定のデータを書いて、読んでを繰り返してますが、予定通りみたいです。

GoにいればGoに従え(21) TinyGo、乱数発生器よみとり、micro:bit v2 へ戻る

GoにいればGoに従え(23) TinyGo、シリアル接続LED、micro:bit v2 へ進む