SSブログ
English Version

GreenPAKで遊ぶ(その6)逐次比較型A/D変換 [GreenPAK]

 前回の記事で電子サイコロを作り、暫く習作はいいかな~と思っていました。しかし SLG46826 関連の情報をネットで見ていたところ、Single Slope Converter を見つけました。A/D変換の無いマイコンでCRでの充電 or 放電時間を計測して簡易的な A/D にする手法と同様にA/D変換が無い SLG46826 でCRの立ち上がり時間の長さをカウントすることで4段階にA/D変換するという試みです。コンパレータを4個使えばすぐにできそうではありますが他の用途でコンパレータを使っている場合には有効かもしれません。
 しかし、SLG46826 であれば、抵抗のラダー回路を付けてD/A変換を付加すれば、逐次比較型A/D変換も実現できるのでは・・?


1.今回の課題
 SLG46826 で4ビットの逐次比較型A/D変換を実現します。実用性はあまりありませんがパズルとしては面白そうですね。GreenPAK はある意味、現代版の電子ブロックと言えるかもしれません


2.基本設計
 処理内容はおおよそ次の通りです。
  1. D/A用のデータをゼロクリアする。
  2. D/Aデータの確定対象ビットをMSBとする。
  3. 被測定電圧(+側)とD/A出力の比較結果(コンパレータの出力)をD/Aデータの確定対象ビットに出力する。
  4. コンパレータの出力を再度確定対象ビットに出力する。
  5. 確定対象ビットをLSB側に1ビットずらし、3,4を繰り返す。
  6. LSBが確定するまで上記処理を繰り返す。
  7. 確定したD/AデータをA/D変換結果として外部出力用 D-FF に保存する。


3.回路設計
 設計した回路を下図に示します。外部のラダー回路も描くことでシミュレータで確認できるので GreenPAK Designer は便利ですね。

逐次比較型A/D変換回路


 タイミング制御用の信号は割合少ないリソースでできたのですが、ラッチが多く必要だったこともあり、下図のように機能要素(コンポーネント or マクロセル)の余りは殆ど無い状態です。

機能要素の使用状況


 シミュレーション結果を下図に示します。上から4段目までがD/Aデータ用 D-FF のクロックです。前述のように1回のA/D変換でコンパレータの出力を2回ラッチします。一番下が試験用のランプ出力の電圧源からの被測定信号です。

逐次比較型A/D変換シミュレーション結果(その1)


 シミュレーション結果の後半が下図です。一番上がD/Aの出力でA/D変換時の変化する様子が面白いですね。2番目以降の4つがA/D変換結果のMSBからLSBまでの4ビット分のデータです。
 このシミュレーションではA/D変換が6回実行されていてそれぞれの結果が、01H, 03H, 06H, 09H, 0BH, 0DH になっています。

逐次比較型A/D変換シミュレーション結果(その2)



4.まとめ
 無謀にも SLG46826 で逐次比較型A/D変換にチャレンジしましたが、なんとか実現できました。最初から「できそうだよなぁ」という感覚はありましたがリソース的にここまで余力がなくなる状態になるとは思いませんでした。最悪は出力データでのヒゲの発生を許容して、D/Aデータのクリア期間が最短になるようにして外部出力用ラッチを省くという対策案も考えていました。
 今回の逐次比較型A/D変換自体は実用的なメリットはあまりありませんが、非常に面白いパズルでした。冒頭にも書きましたがまさに現代版電子ブロックですね。


★追記 2024/06/09
 X(旧Twitter)に投稿したメッセージに添付した動画を貼っておきます。



[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

GreenPAKで遊ぶ(その5)電子サイコロ [GreenPAK]

 前回の記事では習作として自身にリセット命令を送信するという奇抜な課題でしたが、今回は打って変わって電子サイコロを作ってみたいと思います。

1.今回の課題
 SLG46826G に LED と スイッチを付けて電子サイコロを作ります。条件としては
  • スタートスイッチを押すことで何度でもサイコロを振れるようにする。
  • 表示は LED を使い、本物のサイコロの模様を表現する。
  • 転がっているサイコロが次第に停止する様子も表現する。
  • 回路は可能な限り簡潔なものにする。
 です。


2.基本設計
 今回の課題を実現するために必要と思われる主要な機能について次のようにします。
  • 乱数発生
     K4zuki さんが公開されている GPAK-AppsNote-c55ed02.pdf を参考にさせて頂き、 Pipe Delay を使い、15 ビットの M系列を利用します。
     但し、後段に 15 ビット目の D-FF は置かず、Pipe Delay から 14 と 15 ビット目が出力されるようにします。これを XOR して帰還すると all 0 になり、乱数が生成されないので 14,15 ビットを XNOR し、入力として帰還します。先頭のビットは 1 PIPE OUT として出力されているのでこの先頭ビットと14と15の3ビットを0~7の乱数として扱います。

  • 次第に停止するサイコロの表現
     PGEN を使用します。設定パターンを 1011011101111100 とし、0 の値が出力された時に乱数発生を一時停止し、サイコロの目を表示するようにします。最後の 00 はデリミタとして扱い、00 を検出すると乱数発生を止めサイコロの動きを停止します。乱数の停止時(一時停止も含む)は乱数値が6か7の場合は乱数発生を継続し、5以下になった時点で乱数の発生を停止するようにします。

  • サイコロの LED 制御
     1~6の目を表現するためには LED が7個必要ですが、LED の点灯制御は4ビットで可能です。今回は次のように割り振ります(番号は SLG46826G のピン番号)。
     19 18   17 16 17   18 19 

3.回路設計
 今回作成した回路を下図に示します。機能の割にはかなりコンパクトにまとまったのではないでしょうか? もし汎用ロジック IC で組んだらかなりのチップ数になると思います。

電子サイコロの回路


 電源は 3.3V を使用して、それぞれの LED 制御用の 16~19 ピンには LED と直列に 2.7k の電流制限抵抗を接続後、GND に接続します。スタート入力用の1ピンはスイッチを介して GND に接続します。

 下図はシミュレーション結果です。

電子サイコロのシミュレーション結果


 尚、今回作成した GreenPAK Designer の設計ファイルはここからダウンロードできます(商用利用以外であれば自由に使用可能)。


★追記 2024/06/08
 X(旧Twiiter)に投稿したメッセージに添付した動画を貼っておきます。



[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]
nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

GreenPAKで遊ぶ(その4)セルフリセット [GreenPAK]

 前回の記事に続き、GreenPAK Designer での設計習熟度の向上のため、習作として何かを設計してみたいと思います。ありふれたお題では詰まらないので奇抜な課題を考えてみました。で思い付いたのが次の課題です。なかなか突飛で面白そうな課題でしょ?


1.今回の課題
 SLG46826 は I2C インターフェースを使って動作を制御できます。そこで自分自身を制御してみましょう。具体的には I2C インターフェースのマスタになって自分自身にリセットコマンドを送付します。Z80 のマシン語等での自己書換えのように 46826 が自身のコンフィグを書き換えられたら新たな制御法が可能になるかもしれませんね。
 下図に「GreenPAKで遊ぶ(その2)書き込み環境完成」の記事に記載したソフトリセットコマンド発行時のロジアナ波形を再掲します。ソフトリセットを実行するためには C8H レジスタ(以降、リセットレジスタと記す)に 02H を書き込みます。

ソフトリセット開始時のロジアナ波形例


 但し、次の条件を付けます。
  • I2C のアドレスは 00H 固定とする。
  • I2C マスタ側の SCL と SDA はそれぞれ IO13 と IO14 に割り振り、10k でプルアップしたオープンドレイン出力とする。
  • 受信側が ACK 応答するタイミングでの SDA は high 出力とする。
  • リセットビットは 02H ですが LSB が未使用(予約ビット)なのでリセットレジスタへの出力は 03H でも可とする。


2.概要設計
 SLG46825 の内蔵の機能要素による回路設計は結構時間が掛かります。機能要素の一覧を眺めながら概要としては次のように考えました。
  • ディレー要素
     POR から一定時間待つのに1個、I2C のクロック生成用に1個の最低2個は必要

  • ワンショット要素
     I2C アドレス送出用に1個、リセットレジスタ設定用に1個の最低2個は必要

  • リセットレジスタ設定用パターン
     ここは PGEN(Pattern Generator) を使いたい局面です。しかし、ACK 受信用ビットを加えると18ビットのパターンが必要(I2C アドレスに対する ACK ビットも加えると19ビット)になりますが、PGEN は最大16ビット長です。そこで I2C アドレスに対する ACK ビットと リセットレジスタアドレス(C8H)の先頭の2ビットの合計で3ビット分の high ビットパターンをサイクリックに使用する(出力データの03Hの最後の2ビット+ ACK ビットの3ビット分に流用)ことにします。

  • I2C セッションの終了
     I2C 通信のセッション終了(SCL を high 状態にして SDA 立ち上がりエッジを生成)のためにワンショットや D-FF が必要になりそうですが実際に回路を組み立てながら考えることにします。


3.回路設計
 設計した回路が下図になります。中々コンパクトにまとめられたのではないでしょうか? コンビネーション機能要素はまだ半数以上未使用の状態です^^

I2C でリセット送信する回路


 上記の概要設計でのワンショット関連のシミュレーション結果が下図になります。最後の2つは I2C セッションの終了を生成するためのものです。

シミュレーション結果1


 I2C の SCL と SDA のパターンを生成している部分のシミュレーション結果が下図になります。上から3つ目の PGEN ->OUT が PGEN の出力で概要設計で書いたように3ビット長の high 部分を2回使用しています。

シミュレーション結果2


4.ロジアナでの確認結果
 生成した I2C 波形をロジアナで確認した結果が下図になります。下半分が上記の回路で生成した波形です。想定通りの波形になっていますね。まだ SLG46826 の I2C 入力ピン(下図の上半分)には繋いでいないので ACK 応答が無いために NAK 状態になっています。

生成した I2C マスタ波形


 生成した波形を I2C 入力ピンに接続後のロジアナ波形が下図になります。GreenSCL と GreenSDA の内部の 10k でのプルアップでは弱かったので外部に 4.7k のプルアップ抵抗を追加しました。ACK 部に若干ひげが発生していますが、自身で生成した I2C 信号に対して自身で ACK 応答しているので上の図での NAK 部分が ACK に変化しています。


I2C 入力ピンに接続後の波形


 下図は 電源投入後に繰り返されるソフトリセットコマンドのロジアナ波形です。ソフトリセットの実行には 2ms 程度の時間が掛かっているようです。

ソフトリセット波形


 今回設計した I2C マスタ機能で送信したソフトリセット命令により実際にリセットが掛かっていることが確認できたので、今回の課題は達成できたと言えますね^^


★追記 2024/06/06
 早速ですが PGEN の nRESET 入力を活用することで LUT1 を省略することができました。

I2C でリセット送信する回路(改善版)




[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

GreenPAKで遊ぶ(その3)シリアル受信機能 [GreenPAK]

前回の記事で書いたように SLG46826 への書き込み環境ができたので実際の回路への適用について検討しました。具体的な目標を立てた方が GreenPAK への理解が増すと思ったのでプログラマブルロジック IC である GAL22V10(以降、GALと記す) を使用したコンパクトな Z80 ボード(Z80GAL)に対して SLG46826 を使ったらどうなるかを検討しました。
 GAL の単なる置き換えであれば検討の余地はなく、置き換え可能なので Z80GAL での下記の課題を解消できなかを考えてみました。

・Z80GALの課題
 Z80GAL の周辺回路で必要な機能は
  1. 調歩同期方式シリアル通信
  2. SDカード用 SPI インターフェース
  3. ROM/RAM切り替え用 D-FF
ですが、Z80GAL では実装する IC の数を削減するため、Z80 を高速(20MHz)で動かすことで、シリアル通信や SPI インターフェースをソフトウェア処理で実現しました。しかし、9600bps のシリアル通信の受信の取りこぼしを防ぐため、ビットレートの3倍の周期(34.7us)でタイマ割込み処理をしたことから実質 16MHz 程度の処理速度になりました
 ということで最初に SLG46826によるシリアル受信の検討を行うことにします。



■シリアル受信機能の検討
 Z80GALGALSLG46826 に変更して性能を向上させるための最大の難関は上記のシリアル受信をハード化することです。
 SLG46826 での設計は GAL の設計より格段に難しく時間がかかります。GAL では各ピンの機能の対称性が高く、論理式で割合容易に設計ができます。しかるに SLG46826 では機能要素の種類が沢山あり、かつ、各機能要素を適切に設定する必要があります。例えて言うなら命令に直行性の高い MC68K と個々のレジスタの機能が異なる Z80 のようなものですw
 かくの如く SLG46826 での設計はパズル性が高く、Z80 のマシン語のように面白い面もあります(設計時に使う脳の部位は同じかも)。

 最初は受信用のクロックを生成するために立ち上がりと立下りにそれぞれ DLY 機能要素を使い、全部で4つの DLY を使ってしまいましたが次第に慣れてきたこともあり、DLY を2個使うことでクロックが生成できました。

・シリアル受信機能の回路
 下図がシリアル/パラレル変換も含めた状態の GreenPAK Designer の画面です。それでもかなりの機能要素を使ってしまいました。上記の Z80GAL にはシリアル通信の他に SPI と RAM/ROM 切り替え用に少なくとも4個の D-FF は必要なのでそれらも入れ込めるかきわどい状況・・・と言うかアドレスデコード等も必要なので無理ですねw
 とは言っても SLG46826 はチップ内にクロック生成とシリパラ変換まで実装できたので GAL よりもかなり高機能であると言えます(今回使用していませんがアナログ機能もあります)。

シリアル受信機能デザイン画面


 主な機能要素の機能は下記のとおりです。
  1. DLY1
     シリアルデータをサンプリングするためのクロックを生成します。DLY2 が非アクティブの時はシリアルデータのスタートビットが入力になります。DLY2 がアクティブの時は DLY1 の反転出力が入力となり矩形波を発生します。

  2. DLY2
     1バイト長分の one shot 波形を生成します。

  3. LTU1
     シリアル入力データと DLY2/ の AND に DLY1/ を OR しています。

  4. DFF1,2,5,6,7,8,13,14
     受信したシリアルデータをパラレル変換するためのシフトレジスタです。

  5. DFF15
     ストップビットを保持します。受信データ有フラグに使用します。最終的には CPU により受信データが読み込まれた時に自動的にクリアします。

  6. 2-LO
     受信フラグです。


・シリアル受信機能のシミュレーション結果
 シミュレーション結果を下図に示します。シミュレーション結果画面は縦に縮小出来ないので(ぜひ追加して欲しい機能です)、2回に分けて画面をキャプチャーしました。このシミュレーションで使用したシリアルデータは '3' (31H)です。手書きで追記したようにシフトレジスタの最終値が31Hになっています。データ受信後に受信フラグもアクティブになっていますね。

シリアル受信機能シミュレーション結果1


シリアル受信機能シミュレーション結果2



★追記 2024/06/01
 GreenPAK での回路設計は Z80 アセンブラの最適化と類似性が高いですね。出力内容は同等で 2bit LUT0 を省略できました。

シリアル受信機能デザイン画面(改善案)



★追記 2024/06/02
 X(旧Twitter)の投稿したメッセージに添付した実際のチップを使った動作試験の動画を貼っておきます。
 初期値はスペース:20Hの状態で'0'(30H)から'9'(39H)までのシリアル信号を順次受信しています。LEDは左端がMSB、シリアルデータは先頭のスタートビットに続きLSB~MSBの順番です。




[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー

GreenPAKで遊ぶ(その2)書き込み環境完成 [GreenPAK]

 前回の記事の最後に書いたように PIC を使った自作の汎用制御基板の Pic24ジェネラルボックス(以降、GenBox と記す)を使った SLG46826 の書き込み環境が完成したので開発する上で調査した内容等をまとめてメモしておきます。
 久しぶりに自作のセルフコンパイラである独自言語の picle を使いました。全てを自分のコードで構築していく作業はある意味世界を一から創造していくようでもあり、独特な趣きがあります。
 尚、今回開発した書き込み環境を Grenwriter と命名しました。



■書き込み処理での確認事項
 主に下記の2つの資料を参考にしましたが今回のソフトを開発する上での重要事項について確認結果も含めて書いてみます。
  • 資料1:In-System Programming Guide SLG46824/6/7-A
  • 資料2:SLG46826 Datasheet


①NVMメモリの消去方法
 設計情報を保存している NVM は Pic24 等のようなフラッシュメモリを実装している一般的なマイコンの場合と同様にメモリ内容を消去してから書き込む必要があります(消去で'0'の状態になり、書き込みで'1'に変更できる)。消去と書き込みの最小単位(ページ
)は 16 バイトです。
 上記の資料1には書き込み方法として下図のフローチャートが記載されています。

書き込みフローチャート


 無料の資料なので言い辛いのですが、'Data'の初期値が未記載ですし'Yes'が変な位置にあります。メモリマップは下図のようになっていて、先頭がコンフィグ情報等が設定されるレジスタで 200H からがコンフィグ情報を保持する不揮発メモリ、300H からが EEPROM 用の不揮発メモリの領域です。

SLG46826 メモリマップ


 消去用のレジスタの構造は下図のようになっていて、NVM は 16 バイト(=1ページ)x16 の構成で最後のページはチップ情報なので書き込み禁止であることから上記のフローチャートでの'Data'の初期値は 80H であることが判りました。

消去レジスタの構造


 消去レジスタの説明には I2C でレジスタ内容を受け取った後に I2C 規格に準拠した ACK を返さず、詳細は SLG46824/6/7-A errata document (revision XC)を参照するように書かれています。

 下図は実機で確認した消去時の動作で、消去開始時のロジアナ波形です。ACK が無いだけでなく、微妙なタイミングでセッション終了(最初の橙色の四角)が発生しています。消去中はバスマスター等の動作は停止すると書いてあるので消去動作の完了は ACK 応答がある(I2C 通信では無反応の場合は NAK と見なされる)ことで確認する処理にしました。消去は最大 20ms と書いてあるのでタイマウェイトでもいいのですが ACK 方式の方が速いと思います。消去試験をしていたため、下図では I2C アドレスが 00H になっています。
 尚、前回記事では I2C のクロックが 100kHz でしたが今回から 400kHz に変更しています。

消去開始時のロジアナ波形例


 下図は ACK 応答を受け取り、消去処理の完了を確認しているタイミングのロジアナ波形です。ACK 応答に続くリードデータに対してはセッションを終了するために NAK 応答するようにしています。最終的な消去処理の実装はライトコマンドでポーリングし、ACK 応答が来た時は即座にセッションを終了するようにしました。この ACK ポーリング方式は NVM の書き込み時の書き込み処理終了の判断でも使いました。

消去完了時のロジアナ波形例


 消去処理全体の波形が下図になります。この時は 9ms 程度で消去処理が完了しています。

消去時全体のロジアナ波形例


②ソフトリセット時の待ち時間
 コンフィグデータを NVM に書き込んだ後に動作に反映させるためには電源を再投入するかソフトウェアでのリセット処理を行うことで NVM のコンフィグデータをコンフィグ用のレジスタにコピーする必要があります。今回は I2C でレジスタを設定することで実行されるソフトリセット方式を採用します。

 ソフトリセットは C8H レジスタに 02H を書き込むことで実行されます(下図参照)。

ソフトリセット関連レジスタ


 リセットコマンドを受信すると I2C のセッション終了をトリガにしてPOR(パワーオンリセット)と同じ処理が実行されるとのことです(下図参照)。

リセットコマンドタイミング


 リセット処理の時間が資料に見当たらないので上記の ACK ポーリング方式でリセット処理の完了を判断することにしました。
 下図はリセットコマンド発行時の波形です。書き込みデータに対してもきちんと ACK が返ってきてますね。セッション終了(橙色の四角)でリセット処理が開始されるので直後の ACK ポーリングに対しては NAK 状態になっています。

ソフトリセット開始時のロジアナ波形例


 下図は ACK を受信でき、 ACK ポーリング処理を終了した部分の波形です。

ソフトリセット終了時のロジアナ波形例


 下図はソフトリセット実行時の全体の波形です。リセット処理には 1.2ms 程度の時間がかかっているようです。この時間は電源電圧や設計した回路内容等にも依存するかもしれません。

ソフトリセット実行中のロジアナ波形例


③ I2C アドレスの設定方法
 SLG46826 は設定により I2C のアドレスを変更できますし、IO ピンで設定するようにもできます。
 下図がアドレス設定用レジスタの構成です。上位4ビットでレジスタ設定か外部ピン設定かを指定します。レジスタ設定の場合は下位4ビットの値になります。従って CAH レジスタに1が設定(これはディフォルト値)されるとアドレスの上位4ビット(GrrenPAK の資料では Control Code と記載)が 0001B になります。

I2C アドレス設定レジスタ


 このように I2C のアドレス設定は柔軟性があるので今回開発した書き込みソフト Grenwriter では後述するように I2C スキャン機能やアドレス設定機能を付けました。



■Grenwriter に実装した機能
 下図のメニュー画面で表示されている機能を実装しました。I2C によるレジスタの書き込み機能も実装するか迷いましたが、NVM から レジスタへの転送時はほぼすべての機能を停止して実行しているようなのでレジスタの詳細を理解せずに下手に動かしながら変更した場合、問題が発生する可能性があること、及び NVM の書き込みは 1000 回程度は可能なようなのでレジスタ書き込みは実装しないことにしました。

メニュー画面

 個々の機能に関して以降に記載します。
  1. I2C スキャン
     I2C のアドレス空間をスキャンする機能です。現在のアドレス設定値に加え、見つかったアドレス候補の値も表示するようにしました。複数の SLG46826 が接続されているケースも考慮して、現在のアドレス設定値は自動変更されません。

    スキャン画面

  2. I2C アドレス設定
     SLG46826 と I2C 通信するためのアドレスを設定します。

  3. コンフィグ用 I2C アドレス設定
     本設定をした場合、NVM 書き込み時にコンフィグ内の I2C アドレスが設定値に置き換えられます。I2C 通信用のアドレスも自動で変更されるので NVM 書き込み後も継続して通信できます。

  4. ヘキサファイルロード
     GreenPAK Designer で作成したヘキサファイルを TeraTerm の画面にドラッグ&ドロップすることで読み込み、読み込んだデータの内容を画面に表示します。Grenwriter には内部に256バイトのバッファがあり、ヘキサファイルの内容はこのバッファに読み込まれます。以降に記載しているダンプ系コマンドを実行した際もバッファ内データがダンプ内容に置き換えられます。

    ヘキサファイルロード画面

  5. NVM 書き込み
     バッファ内容を NVM へ書き込みます。コンフィグ用 I2C アドレスが設定済みの場合はバッファ内のアドレス値を設定値に変更してから NVM へ書き込みます。書き込みにより I2C アドレスが変更される場合でもその後の操作が継続できるようにアドレスの設定値が自動的に追従します。

    NVM 書き込み画面

  6. EEP 書き込み
     バッファ内容を EEP に書き込みます。後述の EEP 読み込み後にバッファにパッチを当て EEP 書き込みを行うことでチップ内のデータへのパッチが可能となります。

    EEP 書き込み画面

  7. NVM ダンプ
     NVM の内容を SLG46826 から読み込みます。内部バッファの内容も読み込んだものに置き換えられます。

    NVM ダンプ画面

  8. EEP ダンプ
     EEP の内容を SLG46826 から読み込みます。内部バッファの内容も読み込んだものに置き換えられます。画面構成は NVM ダンプと同様です。

    EEP ダンプ画面

  9. レジスタダンプ
     レジスタの内容を SLG46826 から読み込みます。内部バッファの内容も読み込んだものに置き換えられます。

    REG ダンプ画面

  10. バッファデータパッチ
     バッファ内の内容を変更します。

    バッファパッチ画面





■Grenwriterソフトウェア
 ソースを以下に貼っておきます。picle言語はC言語に近いのでC言語が使えるなら処理内容を確認するのは容易だと思います。

メイン処理(picle言語)
# GreenPAK writer Ver 0.01 2024/05/26 by skyriver # Grenwriter written with picle language use LibGreen; # serial reset proc SeriReset() { var dmy; if (I2CAdr(Padr,I2C_WR) = 0) { if (I2CSnd($c8) = 0) { dmy = I2CSnd( 2 ); # reset } I2CStop(); } } # erase NVM proc EraNvm() { PrnStr_( "Erase NVM :" ); EraRom(0,14); } # erase EEPROM proc EraEep() { PrnStr_( "Erase EEP :" ); EraRom(16,31); } # write NVM func WriteNvm() { PrnStr_( "¥nWrite NVM :" ); return = WritePages( 2, 14 ); PrnStr_( "¥n" ); } # write EEPROM func WriteEep() { PrnStr_( "¥nWrite EEP :" ); return = WritePages( 3, 15 ); PrnStr_( "¥n" ); } # input I2C adr func InpAdr( now ) { PrnStr_( "¥ninput I2C adr(0..F) " ); if ( now >= 0 ) { PrnHexB_( now / 8 ); } else { PrnStr_( "xx" ); } PrnStr_( " -> " ); return = GetHex(); } # patch buffer data proc Patch() { var adr,dat,c; PrnStr_( "¥n input adr:" ); adr = GetHexByte(); if ( (adr>=0) & (adr<=$FF) ) { PrnHexB_( adr ); PrnStr_( " data " ); PrnHexB_( _Buf[ adr ] ); PrnStr_( " -> " ); dat = GetHexByte(); PrnHexB_( dat ); PrnStr_( " sure?(Y/N) : " ); c = InpChar_(); PrnChar_( c ); if ( ToUpper(c) = 'Y' ) { _Buf[ adr ] = dat; } PrnStr_( "¥n" ); } } proc PrnErr() { PrnStr_( " .. Error !!¥n" ); } proc Help() { PrnStr_("¥n<<<< Grenwriter for Green PAK SLG46826 >>>>¥n"); PrnStr_(" S:scan I2C A:set I2C current adr¥n"); PrnStr_(" L:load HexFile B:set I2C adr(NVM)¥n"); PrnStr_(" W:write NVM E:write EEP¥n"); PrnStr_(" D:dump NVM F:dump EEP¥n"); PrnStr_(" R:dump REG P:patch buffer data¥n"); PrnStr_(" Q:quit¥n"); PrnStr_(" V0.01 2024/05/26 by skyriver¥n¥n"); } proc main() { var c,adr,nadr,flg; Init(); Padr = $08; # I2C addr nadr = -1; while (1) { Help(); PrnChar_( ']' ); c = ToUpper(InpChar_()); PrnChar_( c ); if ( c = 'S' ) { PrnStr_( "¥nscan I2C adr" ); adr = Scan(); PrnStr_( "¥n now adr:" ); PrnHexB_( Padr / 8 ); if ( adr >= 0 ) { PrnStr_( " estimate adr:" ); PrnHexB_( adr / 8 ); } PrnStr_( "¥n" ); } else if ( c = 'A' ) { adr = InpAdr( Padr ); if ( (adr>=0)&(adr<16) ) { PrnHexB_( adr ); Padr = adr * 8; } PrnStr_( "¥n" ); } else if ( c = 'L' ) { PrnStr_( "¥nDrag HexFile" ); if ( LoadHex() = 0 ) { DumpBuf(); } } else if ( c = 'B' ) { adr = InpAdr( nadr ); if ( (adr >=0)&(adr<16) ) { PrnHexB_( adr ); nadr = adr * 8; } PrnStr_( "¥n" ); } else if ( c = 'W' ) { if ( nadr >= 0 ) { _Buf[ $CA ] = nadr / 8; } PrnStr_( "¥nErase NVM :" ); flg = 1; EraRom( 0, 14 ); if ( WriteNvm() = 0 ) { DumpBuf(); flg = 0; } SeriReset(); Padr = _Buf[ $CA ] * 8; WaitAck(); if ( flg ) { PrnErr(); } } else if ( c = 'E' ) { PrnStr_( "¥nErase EEP :" ); flg = 1; EraRom( 16, 31 ); if ( WriteEep() = ) { DumpBuf(); flg = 0; } if ( flg ) { PrnErr(); } } else if ( c = 'D' ) { PrnStr_( "¥n dump NVM" ); if ( ReadMem( 2 ) = 0 ) { DumpBuf(); } } else if ( c = 'F' ) { PrnStr_( "¥n dump EEP" ); if ( ReadMem( 3 ) = 0 ) { DumpBuf(); } } else if ( c = 'R' ) { PrnStr_( "¥n dump REG" ); if ( ReadMem( 0 ) = 0 ) { DumpBuf(); } } else if ( c = 'P' ) { Patch(); } else if ( c = 'Q' ) { break; } } PrnStr_( "¥nSee you again!" ); }



LibGreen ライブラリ(picle言語)
#LibGreen GreenPAK writer libraly Ver 0.01 2024/05/26 by skyriver # written with picle language use LibPic; use LibI2C; use LibGreen1; # load Hex into buffer # return -> 0:ok func LoadHex() { var i,c,cnt,adr,type,dmy; for ( i = 0; i < 256; i=i+1 ) { _Buf[ i ] = 0; } do { do { c = InpChar_(); if ( c = $1B ) { # ESC return = -1; break; # $__$ } } while ( c <> ':' ); Sum = 0; cnt = GetHexByte(); if ( (cnt>$20) | (cnt<0) ) { return = 1; } else { adr = GetHexByte() * 256 + GetHexByte(); if ( adr >$F0 ) { return = -2; } else { type = GetHexByte(); for ( i = 0; i < cnt; i=i+1 ) { _Buf[ adr + i ] = GetHexByte(); } dmy = GetHexByte(); if ( Sum & $FF ) { return = 3; # SUM err } } } } while ( (return=0) & (type=0) ); } # write ROM 1 page # badr <- block adr 00:RAM,02:NVM,03:EEP # page <- write page num # return -> 0:ok func WrRom( badr, page ) { var i,cbyte,tmp; cbyte = Padr | badr; page = page * 16; return = I2CAdr( cbyte, I2C_WR ); if ( return = 0 ) { return = I2CSnd( page ); if ( return = 0 ) { for ( i = 0; (i < 16) & (return = 0); i=i+1 ) { return = I2CSnd( _Buf[ page + i ] ); } I2CStop(); WaitAck(); if ( return = 0 ) { return = 1; if ( I2CAdr( cbyte, I2C_WR ) = 0 ) { if ( I2CSnd( page ) = 0 ) { if ( I2CAdr( cbyte, I2C_RD ) = 0 ) { for ( i = 0; i < 16; i=i+1 ) { return = I2CRcv(1); if ( return = 0 ) { if ( I2CRcv <> _Buf[ page + i ] ) { PrnStr_( " missmatch at " ); PrnHex_( page + i ); PrnChar_( ' ' ); PrnHexB_( _Buf[ page + i ] ); PrnStr_( "->" ); PrnHexB_( I2CRcv ); return = 2; # miss match break; # $__$ } } } tmp = I2CRcv(0); } } } I2CStop(); } } } } # write pages in ROM # basr <- block adr 00:RAM,02:NVM,03:EEP # until <- last page num func WritePages( badr, until ) { var i; for ( i = 0; (i<=until) & (return=0); i=i+1 ) { PrnChar_( ' ' ); PrnHexB_( i ); return = WrRom( badr, i ); } } proc Init() { var i; InitReg(); InitI2C( $0210 ); # I2C 2ch:$0210 LATA[0] = 0; LATB[0] = 0; LATA[-2] = $0000; LATB[-2] = $0b0c; I2C_RD = 1; I2C_WR = 0; _Buf = Alloc( 256 ); for ( i = 0; i < 256; i=i+1 ) { _Buf[ i ] = 0; } } proc main() { var est; Init(); Padr = $08; # I2C addr PrnStr_( "¥nread RAM" ); if ( ReadMem( 0 ) = 0 ) { DumpBuf(); } PrnStr_( "¥nread NVM" ); if ( ReadMem( 2 ) = 0 ) { DumpBuf(); } PrnStr_( "¥nread EEP" ); if ( ReadMem( 3 ) = 0 ) { DumpBuf(); } est = Scan(); if ( est >= 0 ) { PrnStr_( "¥n estimate:" ); PrnHexB_( est ); } PrnStr_( "¥nDrag Hex file" ); if ( LoadHex() = 0 ) { DumpBuf(); } }



LibGreen1ライブラリ(picle言語)
#LibGreen1 GreenPAK writer libraly Ver 0.01 2024/05/26 by skyriver # written with picle language var I2C_RD, I2C_WR, Padr, _Buf, Sum; func ToUpper( c ) { if ( (c >= 'a') & (c <='z' ) ) { c = c - ('a' - 'A'); } return = c; } # scan I2C # return -> estimate adr func Scan() { var i,j,adr,cnt,est; cnt = 0; return = -1; est = -1; adr = 0; for ( i = 0; i < 8; i=i+1 ) { PrnStr_( "¥n " ); PrnHexB_( adr ); PrnStr_( " :" ); for ( j = 0; j < 16; j=j+1 ) { PrnChar_( ' ' ); if ( I2CAdr(adr,I2C_WR) ) { PrnStr_( "--" ); if ( cnt = 4 ) { return = est; } cnt = 0; } else { PrnHexB_( adr ); cnt = cnt + 1; if ( cnt = 1 ) { est = adr; } } I2CStop(); adr = adr + 1; } } PrnStr_( "¥n" ); } # wait until ack proc WaitAck() { var dat; do { dat = I2CAdr(Padr,I2C_WR); I2CStop(); } while (dat); } # erase ROM # st <- start block # en <- end block proc EraRom( st, en ) { var i,dmy; if ( st <= en ) { for ( i=st; i<=en; i=i+1 ) { PrnChar_(' '); if (I2CAdr(Padr,I2C_WR) = 0) { if (I2CSnd($E3) = 0) { # ERSR dmy = I2CSnd(i | $80); } } I2CStop(); WaitAck(); PrnHexB_(i); } } } # dump buffer proc DumpBuf() { var adr,i,j; adr = 0; for ( j=0; j<16; j=j+1 ) { PrnStr_( "¥n " ); PrnHexB_( adr ); PrnStr_( " :" ); for ( i=0; i< 16; i=i+1 ) { PrnChar_( ' ' ); if ( i = 8 ) { PrnStr_( "- " ); } PrnHexB_( _Buf[adr] ); adr = adr +1 ; } } PrnStr_( "¥n" ); } # read memory # badr <- block adr 00:RAM,02:NVM,03:EEP # return -> 0:no error func ReadMem( badr ){ var i, cbyte; cbyte = Padr | badr; return = I2CAdr( cbyte, I2C_WR ); if ( return = 0 ) { return = I2CSnd( 0 ); if ( return = 0 ) { return = I2CAdr( cbyte, I2C_RD ); if ( return = 0 ) { for ( i = 0; i < 256; i=i+1 ) { return = I2CRcv( 1 ); if ( return ) { break; # $__$ } _Buf[ i ] = I2CRcv; } cbyte = I2CRcv( 0 ); # dummy read(nack) I2CStop(); } } } } # get hex data from input # GetHex() { func GetHex() { var c; c = InpChar_(); c = ToUpper( c ); if ( (c >= '0') & (c <= '9') ) { return = c - '0'; } else if ( (c >= 'A') & (c <= 'F') ) { return = c + ( 10 - 'A' ); } else { return = -1; } } # get hex byte data func GetHexByte() { return = GetHex(); if ( return >= 0 ) { return = return * 16 + GetHex(); Sum = Sum + return; } }



LibI2C ライブラリ(picle言語)
#LibI2C I2C libraly v0.02 2024/05/25 # written with picle language by skyriver var RegRcv,RegTrn,RegBrg; var RegCon,RegStat; var I2CRcv; # send data to slave # data <- send data # return -> 0:no error func I2CSnd( data ) { while ( RegCon[0] & $1f ) {} RegTrn[0] = data; while ( RegStat[0] & $4000 ) {} return = RegStat[0] & $8000; # check nack } # receive data form slave # ack <- 0:nak, else:ack # I2CRcv -> receive data # return -> 0:no error func I2CRcv( ack ) { while ( RegCon[0] & $1f ) {} RegCon[0] = RegCon[0] | $0008; # enable receive while ( RegCon[0] & $0008 ) {} if ( ack ) { RegCon[0] = RegCon[0] & ~$0020; # set ack } else { RegCon[0] = RegCon[0] | $0020; # set nack } RegCon[0] = RegCon[0] | $0010; # send ack/nack while ( RegCon[0] & $0010 ) {} I2CRcv = RegRcv[0]; return = RegStat[0] & $0040; # check overflow } # start seqence and send salave adrs # adr <- slave_adrs # rd <- 1:rd,0:wr # return -> 0:no error func I2CAdr( adr, rd ) { RegCon[0] = RegCon[0] | 3; # repeated start return = I2CSnd( (adr+adr)|rd ); } # stop I2C sequence proc I2CStop() { RegCon[0] = RegCon[0] | $0004; # set PEN(stop) while ( RegCon[0] & $0004 ) {} } proc InitI2C( base ) { RegRcv = base; RegTrn = base + 2; RegBrg = base + 4; RegCon = base + 6; RegStat = base + 8; RegBrg[0] = 37; # Fcy:16MHz -> 157:100kHz 37:400kHz RegCon[0] = $8000; # enable I2C } proc main() { var adr,err,i,j; InitI2C( $0210 ); # I2C 2ch:$0210 adr = 0; for ( j = 0; j < 8; j=j+1 ) { PrnHexB_( adr ); PrnStr_( " :" ); for ( i = 0; i < 16; i=i+1 ) { PrnChar_( ' ' ); if ( I2CAdr( adr, 0 ) ) { PrnStr_( "--" ); } else { PrnHexB_( adr ); } I2CStop(); adr = adr + 1; } PrnStr_( "¥n" ); } }



LibPic ライブラリ(picle言語)
#LibPic major registance v0.01 2018/08/20 var _REG,LATA,LATB,LATC; var ArIdx,Word,_Byte; func Alloc( size ) { return = Array_(ArIdx); ArIdx=ArIdx+size; } proc InitReg() { var Ad1pcfg; Ad1pcfg = $032c; Ad1pcfg[0] = $ffff; # set digital mode LATA=$02c4; LATB=$02cc; LATC=$02d4; Word = Alloc(1); _Byte = Word; } func GetHigh( dat ) { Word[0] = dat; return = _Byte[1]; } func GetLow( dat ) { return = dat & $ff; }



★追記 2024/05/28
 X(旧Twitter)に投稿したメッセージに添付した操作例の動画を貼っておきます。




[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]

nice!(0)  コメント(0) 
共通テーマ:趣味・カルチャー