2022年8月25日木曜日

FV01 マルチエフェクタの製作 その3 EEPROMのプログラミングにRaspberry Pi Picoを利用

FV-1はEEPROMに書き込んだ外部プログラムを利用できます。プログラム開発はSpinAsm IDEで行います。FV-1の公式ページの一番下あたりに「software :: SpinAsm assembler for the SPN1001V1.1.31 (Windows executable)」というリンクがあり、ダウンロードできます。

SpinAsm IDEから出力されるのはHEXファイル(Intel HEX形式)です。SPN1001-DEVBという開発ボードを使えばSpinAsm IDEから直接EEPROMに書き込み可能でスマートに開発できるようです。

あまりスマートではないですが、HEXファイルをバイナリに変換しEEPROMに書き込めば良いので、安価なマイコンボードであるRapsberry Pi Picoを利用することにしました。

ブロック図

太い線で囲ったところがRaspberry Pi picoを使って製作したPico Rom Writerです。

WindowsのターミナルソフトにはTeraTermがよく使われていますが、私は機能が豊富なRLoginを使用しています。今回もRLoginのファイル送信機能に頼っています。

ハードウェアPicoRomWriterの製作



回路図

I2CのSCLとSDAはFV-1で内部プルアップされ、Raspberry Pi picoでも内部プルアップされています。さらにPico Rom Writerでもピンソケットを使ってプルアップ可能としています。外部プルアップは信号線の波形を見て決めます。並列にプルアップされることになるのでプルアップする場合は抵抗値を大きめにします。

Raspberry Pi Picoはリセットボタンがないので、RESET(RUN)ボタンを外付けしています。

Raspberry Pi PicoでMicro Pythonを実行する準備


MicroPythonファームウェア(UF2ファイル)をダウンロードしておきます。


以下の手順でUF2ファイルをPicoに書き込みます。

  • PicoをBOOTSELボタンを押しながらパソコンにUSBケーブルで繋げる。
  • ストレージとして認識され、エクスプローラーが開く。
  • UF2ファイルをPicoのドライブにコピー。

EEPROMライティングプログラム SpinRomWriter


USBシリアル通信でパソコンから.hexファイルを受信し、バイナリに変換した後、I2C経由でFV01の外付けEEPROMに書き込むMicroPythonのプログラムです。

SpinRomWriter.py
#
# SpinRomWriter.py
#
# SpinAsmが出力したHEXファイルを24LC32A(EEPROM)に書き込む
#
# Target: Raspberry Pi pico / micropython
#
# 2022.08.20
#
import time
import sys
from machine import Pin, I2C

TITLE_STR = 'SpinRomWriter 20220820'

N_BYTES = 4         # 一度に読み書きするバイト数
DATA_LEN = 4096     # 32KBits
MAX_LINES = 1026    # シリアルで読み込む最大行数

PIN_LED = Pin(25, Pin.OUT)

# HEX文字列をバイナリに変換
def hex2bin(hexstr):
    if hexstr[0] != ':':
        print('Invalid header character')
        return -1
    hexstr = hexstr[1:]
    data = []
    for i in range(0, len(hexstr), 2):
        s = hexstr[i : i + 2]
        data.append(int(s, 16))
    return data
    
# チェックサム
def checksum(data):
    sum = 0
    for n in data:
        sum += n
    sum &= 0xff
    return sum

# シリアルからHEXファイルを受信
def receiveData():
    bArr = bytearray(DATA_LEN)
    for i in range(MAX_LINES):
        if i % 32 == 0:
            PIN_LED.value(not PIN_LED.value())
        hexStr = input()
        data = hex2bin(hexStr)
        if (data == -1):
            print('line:', i + 1, ': data is invalid')
            return -1
        # チェックサム
        if (checksum(data) != 0):
            print('line:', i + 1, ': checkusm is invalid')
            return -1
        # データエンドを検出
        if (data[3] == 1):
            return bArr;
        # データをbytearrayに格納
        n = data[0]
        addr = (data[1] << 8) | data[2]
        for i in range(n):
            bArr[addr + i] = data[4 + i]
    else:
        print('No data end detected.')
        return -1

# EEPROMに書き込み
def writeEEPROM(bArr, dataLen, nBytes):
    for memaddr in range(0, dataLen, nBytes):
        if memaddr % 32 == 0:
            PIN_LED.value(not PIN_LED.value())
        ba = bArr[memaddr:memaddr+nBytes]
        i2c.writeto_mem(0x50, memaddr, ba, addrsize=16)
        time.sleep_ms(5)

# EEPROMから読み込み
def readEEPROM(dataLen, nBytes):
    bArr = bytearray()
    for memaddr in range(0, dataLen, nBytes):
        ba = i2c.readfrom_mem(0x50, memaddr, nBytes, addrsize=16)
        bArr.extend(ba)
    return bArr

# EEPROMのベリファイ
def verifyEEPROM(bArr1, bArr2):
    bytesOK = 0
    for memaddr in range(len(bArr1)):
        b1 = bArr1[memaddr]
        b2 = bArr2[memaddr]
        if (b1 == b2):
            bytesOK += 1
        else:
            print('%04X:%02X:%02X Data is invalid.' % (memaddr, b1, b2))
    return bytesOK
    
# データを比較して表示
def showComparison(bArr1, bArr2):
    for memaddr in range(0, DATA_LEN, N_BYTES):
        ba1 = bArr[memaddr:memaddr+N_BYTES]
        ba2 = bArr2[memaddr:memaddr+N_BYTES]
        print('ORG:%04X:' % memaddr, end='')
        for b1 in ba1:
            print('%02X:' % b1, end='')
        print('')
        print('ROM:%04X:' % memaddr, end='')
        for b2 in ba2:
            print('%02X:' % b2, end='')
        print('')

# メインルーチン
time.sleep_ms(3000)
while True:
    print(TITLE_STR)
    print('Please send a HEX file.')
    # データを受信
    bArr = receiveData()
    PIN_LED.value(0)
    if (bArr == -1):
        continue
    print('HEX file received successfully.')

    i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=100000)

    # EEPROMに書き込み
    print("Write to EEPROM.")
    writeEEPROM(bArr, DATA_LEN, N_BYTES)
    PIN_LED.value(0)

    # EEROMから読み込み
    print("Read from EEPROM.")
    bArr2 = readEEPROM(DATA_LEN, N_BYTES)

    #showComparison(bArr, bArr2)

    print("Verify data.")
    bytesOK = verifyEEPROM(bArr, bArr2)

    print('Verified:', bytesOK, 'bytes')

SpinASM IDEはソースの.spnファイルを8個まとめてIntel Hex形式の.hexファイルを出力します。Intel Hex形式(.hex)はバイナリファイルをテキスト形式にしたものです。

一例をあげるとこのような形式になります。
:04003C001333014D2C
:00000001FF
フォーマットについては割愛しますが、SpinASM IDEが出力する.hexファイルの最終行(データの終了)は「:00000001FF」です。

プログラム中で「bytearray」クラスを使用しています。通常、配列には「リスト」を用いますが、Raspberry Pi PicoのMicroPythonでは大きなサイズ(4kB以上)の配列を「リスト」では使えないためです。

EEPROMライティングプログラム SpinRomWrter.pyをpicoに書き込む


EEPROMライティングプログラムの書き込みはThonnyを使います。Thonnyをダウンロードしてインストールします。

「ツール」-「options..」-「インタプリタ」でインタープリタに「MicorPython(Raspberry Pi Pico」を指定します。

Raspberry Pi PicoをパソコンにUSBケーブルで接続します。

上記プログラムをThonnyのエディタに入力し、以下の手順でPicoに書き込みます。

  • Thonnyのツールバーの「STOP」ボタンを押す。(ThonnyがPicoに接続)
  • 「ファイル」-「Save As..」
  • 「Where to save to?」ダイアログで「Raspberry Pi Pico」を選択。
  • 「File Name」を「main.py」として保存。

ファイル名を「main.py」にするとPicoの起動時に自動実行されます。

使用手順


RLoginをダウンロードしてインストールしておきます。

SpinASM IDEで「Project Dialog」を開きます。


Projectのスロットに.spnファイルを割当て、「Build」ボタンを押すと.hexファイルが「SpinAsm_IDE\hexout」フォルダに作られます。


※Thonnyが起動している場合は、「実行」-「Disconnect」で接続を切っておきます

以下の手順でFV-1のプログラムをEEPROMに書き込みます。
  • RLoginを起動

  • PicoRomWriterをUSBケーブルで接続

  • RLoginでPicoにシリアル接続(115200bps)



  • PicoRomWriterのRESET(RUN)ボタンを押す

  • Rloginで約3秒以内に再接続
    PicoRomWriterのRESET(RUN)ボタンを押すとUSB接続が一旦切れるので約3秒以内に再接続します。

  • ターミナルに「Please send a HEX file.」と表示されるのを確認

  • RLoginの「ファイル」-「XYZModemファイル転送」-「5ファイルアップロード」

  • 「変換処理」と「送信処理」を以下のように設定。




  • SpinASMで作成した.hexファイルを開くと送信が始まり、進捗ダイアログが表示されます。また、Picoの基板上のLEDが点滅します。



  • 「Verified: 4096bytes」と表示され、再び「Please send a HEX file.」と表示されるのを確認します。

以上でEEPROMにFV-1のプログラムが書き込まれます。

ブレッドボードを使ってEEPROMに書き込んでいる様子

EEPROMの電源はPicoRomWriterから供給できます。(3.3V)

FV01のオンボードのEEPROMに書き込んでいる様子

0 件のコメント:

コメントを投稿