marusu が 2024年02月05日15時22分42秒 に編集
コメント無し
本文の変更
# CircuitPython による GreenPAK (SLG46828) のプログラミング いろいろと FPGA について調べていると、ルネサスの GreenPAK というデバイスにたどり着いた。アナデジ混在でプログラマブルなデバイスとのこと。 ほとんどのチップは一度しか書き込みのできない OTP だが、一部書き換えの可能なものがある。今回はその中の SLG46828 を使ってみた。 使った感想としては、FPGA の代わりとはならず、集積度は GAL 程度。開発は基本的に GUI で行う必要があり、かなり面倒くさい。アナログ(といってもコンパレータ程度だが)と組み合わせて簡単なシーケンスを組むなど、上手い使いどころがあれば役立つかと思われる。 実験に関しては、評価ボードを入手するのが一番早いのだが、残念ながらどこも売り切れていた。また、書き込みは I2C で出来るとのことだったのでデータシートなどを見ながらソフトウェアを作成したのだが、実際書いてみるといろいろとハマり所があった。また、DIP 変換基板もちょっと普通とは感覚が違っており、基板を作り直すことになってしまった。そんなわけで、これから使おうと考えている人たちのためにもメモとして残しておこうと思う。 --- |はまり所| |:-| |1. レジスタに書き込むとき、0xCA に I2C アドレス (Control Code) の設定があるので、書き換えてしまうと I2C でアクセスできなくなる。| |2. NVM の消去を行うとき、I2C で ACK が返ってこないので対策が必要。これは、**チップのバグ**。| |3. DIP 変換基板(SLG46826V-DIP) のピン配置は、TSSOP-20 とは異なる。| |4. DIP 変換基板(SLG46826V-DIP) のピン配置は、文字が読める向きで置いたとき、右上が1ピン。| |5. SLG46828 の各ポートには IO5 のように IO 番号がついているが、設計ツールではピン番号で指定するので混乱する。 | --- ### 回路設計
SLG46828 は I2C でプログラミングを行うので、I2C ポートを持ったマイコンを使用する。独立したプログラマーとして使用することも考慮し、記録デバイスとして認識できるように RP2040 を選択した。素直に Raspberry Pi PICO を使用してもよいが、小型化のために RP2040-Zero を採用した。RP2040-Zero は、ピンに出ている I/O ポートが少ないだけで、基本的には Raspberry Pi PICO と同じであり、ファームウェアも同一のものが使用できる。
SLG46828 は I2C でプログラミングを行うので、I2C ポートを持ったマイコンを使用する。独立したプログラマーとして使用することも考慮し、記録デバイスとして認識できるように RP2040 を選択した。素直に Raspberry Pi Pico を使用してもよいが、小型化のために RP2040-Zero を採用した。RP2040-Zero は、ピンに出ている I/O ポートが少ないだけで、基本的には Raspberry Pi Pico と同じであり、ファームウェアも同一のものが使用できる。
SLG46828 は、I/O が2つのグループに分かれている。IO0 ~ IO6 および SDA、SCL が VDD に接続されており、それ以外の IO7 ~ IO14 が VDD2 に接続されている。ここで、VDD2 ≦ VDD という制限がある。今回の設計では、SDA、SCL が 3.3V で接続されるため、VDD=3.3V であり、VDD2 も 3.3V に接続した。 動作確認で使用できるように LED を IO13 および IO14 に接続した。 また、レジスタへの書き込みと NVM への書き込みを切り替えるためのスイッチを RP2040-Zero 側に接続した。 ![回路図](https://camo.elchika.com/608a14d7427c9c250246d1c250246ef2d4f634c9/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f61333765643236642d643264352d346562632d623435322d3530656634353466306465642f35376536613538342d393735312d343933632d613435642d346536613532656238393232/) ![基板](https://camo.elchika.com/8925eb1194d97195d1aff99c5f3bf8c5c35cc17e/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f61333765643236642d643264352d346562632d623435322d3530656634353466306465642f34666330666430632d383031652d343262302d626538352d663130356638636333663039/) --- ### ファームウェア RP2040-Zero にファームウェアを実装した。 PC から記録メディア(USBドライブ)として見えると便利と考え、CircuitPython を動作環境とした。 CircuiyPython をインストールすると、RP2040-Zero は、PC から USB ドライブとして認識される。GreenPAK の開発ツール (GreenPAK Designer) から直接このドライブにファイルを書き込み、コードを実行すると書き込みを行うようにファームウェアを設計する。
CircuitPython は公式のサイトから RP2040 の UF2 をダウンロードしてインストールする。インストールとは言っても、USB ドライブにコピーするだけ。
CircuitPython は公式のサイトから Pico 用の UF2 をダウンロードしてインストールする。インストールとは言っても、USB ドライブにコピーするだけ。
https://circuitpython.org/board/raspberry_pi_pico/ 開発環境(IDE)は、Thonny を使用している。 https://thonny.org/ --- **IC2 の制御** SLG46828 への書き込みは I2C で行う。書き込みの際の通信データは、Control Byte、書き込み開始アドレス、書き込みデータの順に送信する。 ![キャプションを入力できます](https://camo.elchika.com/0aea3d125b249beea59d06eb7cb8756e50ef50dc/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f61333765643236642d643264352d346562632d623435322d3530656634353466306465642f35633665376666632d646137642d343736302d396536302d653833343231346434376138/) ここで、Control Byte は、上位4ビットの Control Code と、下位3ビットの Block Address に分かれている。 - Control Code は、チップ自体の I2C アドレスに対応しており、レジスタでの設定ないしIOピンでの設定が可能である。 - Block Address は、チップ内部の書き込み領域の切り替えに使用される。レジスタへの書き込みは Block Address=0、NVM への書き込みは Block Address=1 とする。 - レジスタへの書き込みは、任意のデータ長で可能である。 - 一方、NVM への書き込みは 16Byte 単位で行う必要がある。かつ、書き込み開始アドレスの下位4ビットが 0 でなくてはいけない。(例えば、0x00 ~ 0x0Fのように) --- **NVM ファイル読み込み** GreenPAK Designer が出力する NVM のファイルは、レジスタ値が1行に1ビットずつ書かれたテキストファイルである。このファイルを順次読み込み、256 バイトのデータに変換する。 変換したデータは、レジスタないし NVM に書き込む。 --- **注意事項** ハマり所でも記載したように、I2C 通信をするうえでいくつかの注意事項がある。
1. I2C のアドレスが 0xCA に書かれている。そのため、0xCA のレジスタの値を書き換えると、次の I2C 通信ではアドレス (Control Code) が変更されてしまい、通信できなくなる。これを防止するため、下記のソフトウェアでは 256バイトを一回の I2C 通信で行っている。
1. I2C のアドレスが 0xCA に書かれている。そのため、0xCA のレジスタの値を書き換えると、次の I2C 通信ではアドレス (Control Code) が変更されてしまい、通信できなくなる。これを防止するため、下記のソフトウェアでは 256バイトの書き込みを一回の I2C 通信で行っている。
2. NMV の消去コマンド発行時、I2C の ACK が戻ってこない。チップのバグである。CircuitPython では、消去コマンド発行の次の通信でエラーが生じるため、消去コマンド後に、無意味な書き込みコマンドを発行し、エラートラップを行っている。 > https://www.renesas.com/us/en/document/dve/slg46826-errata 3. Control Code が変わってしまった場合に I2C でのアクセスができなくなることを防ぐため、処理開始時に Control Code を取得する処理を入れている。具体的には、Control Code を0から15まで順番に変え、それぞれで書き込みコマンドを発行している。通信が行えた Control Code を有効な Control Code として使用する。 --- **ソースコード** 以下に、作成した CircuitPython のコードを示す。 本当は、書き込み開始ボタンや動作状態を示す LED の制御などを行いたいのだが、本質でないコードが多くなるので、基本動作を行うプログラムとして公開する。
GreekPAK Designer で NVM ファイルを NVMdata.txt として CIRCUITPY ドライブにエクスポートし、下記コードを実行することでレジスタないし NVM に書き込むことができる。NVM の消去にはちょっと時間がかかる。
GreenPAK Designer で NVM ファイルを NVMdata.txt として CIRCUITPY ドライブにエクスポートし、下記コードを実行することでレジスタないし NVM に書き込むことができる。NVM の消去にはちょっと時間がかかる。
参考にしていただければ幸いである。 ```Python:SLG46828.py import busio, board import digitalio import time sw = digitalio.DigitalInOut(board.GP4) sw.direction= digitalio.Direction.INPUT i2c= busio.I2C(board.GP15,board.GP14) while not i2c.try_lock(): pass def SLG_getCurrentCC(): for i in range(16): try: i2c.writeto(i << 3, bytes([0xFF, 0])) return i except: pass return -1 def readNVMFile(fname): d= [0] * 256 with open(fname,'r') as f: f.readline() for i in range(256): for j in range(8): d[i]+= (int(f.readline().split()[1]) << j) return d def SLG_writeToREG(cc, d): i2c.writeto(cc << 3, bytes([0] + d)) def SLG_eraseNVM(cc): for i in range(16): try: i2c.writeto(cc << 3, bytes([0xE3, 0x80 | i])) time.sleep(0.03) i2c.writeto(cc << 3, bytes([0xFF, 0])) except: pass def SLG_writeToNVM(cc, d): for i in range(0,256,16): i2c.writeto((cc << 3)|0x02, bytes([i] + d[i:i+16])) time.sleep(0.03) def SLG_softReset(cc): i2c.writeto(cc << 3, bytes([0xC8, 0x02])) cc= SLG_getCurrentCC() d = readNVMFile('NVMdata.txt') if sw.value: print('Erasing NVM') SLG_eraseNVM(cc) print('Write to NVM') SLG_writeToNVM(cc, d) SLG_softReset(cc) print('Done') else: print('Write to REG') SLG_writeToREG(cc, d) print('Done') ``` --- ### テスト GreenPAK Designer で、サンプルを作成した。
OSC0 の出力 (2.048MHz / 512) をさらに CNT0 で2分周して PIN20 (IO14) に出力した。
OSC0 の出力 (2.048kHz / 512) をさらに CNT0 で2分周して PIN20 (IO14) に出力した。
PIN20 に出力される信号は、2Hz であり、接続された赤色の LED が点滅する。 ![blink](https://camo.elchika.com/7796ebecd2d37c67c3fe53bde8c0fbd1e7aaa97b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f61333765643236642d643264352d346562632d623435322d3530656634353466306465642f63356362376237352d633436622d343637342d613435642d633962363139653537616262/) --- ### 免責事項とか 特にライセンスとかはありません。そういうの面倒くさいです。 自由に使ってください。その代わり、何ら保証もありません。 基板やソースコードが動作することは確認していますが、万一バグを見つけたら直して使ってください。特に報告もいりません。