以前、KZ80マイコン用に8255(PPI)を使ってI2C通信するボードを作成しました。
おなじようなかたちで、PC-8001にも装備してみたいと8255(PPI)装備のI2Cボードを作りました。
対象とするデバイスについて
KZ80マイコンのI2Cボードでは、RTC DS3231モジュールからの日時データ読み出しや日時データ書き込みができました。今回は、買ってあってI2C通信用なので死蔵していたRTC DS1307+(DIP品)や、I2C EEPROM 24LC1025も読み書きしてみたいと考えました。またRTC DS3231モジュールには小容量ながらもI2C EEPROM(AT24C32)が搭載されています。
※ちなみに、この記事ではRTC DS3231とDS1307まで動作確認しています。
I2Cアドレスを確認したところ、RTC IC同士やEEPROM同士はI2Cアドレスが重複していることがわかりました。
デバイス名 | I2Cアドレス |
RTC DS3231 | 0x68 |
RTC DS1307+ | 0x68 |
EEPROM 32k 24C32 | 0x57(変更可) |
EEPROM 1024k 24LC1025 | 0x50〜0x57 |
秋月電子などでI2Cのバスマルチプレクサなどの切り替えICも売ってて何に使うのかなぁとぼんやりと思っていたのですが、意外とI2Cアドレスは重複しがちなんですね。
切り替え回路の案-1
切り替え装置としては、8255(PPI)のI2C用としてはポートCだけを使ってますので、使っていない余ったポートAを使って相手を選択してスイッチングするICで実現できそうと考えました。
以前 ArduinoMEGA用 FM音源ボードの基板をいただいたときに買ってあった 74HC4066アナログスイッチICが良さそうと思い採用。横ちょからスイッチ端子をH/Lレベルで操作してやることで双方向通信を切り替えできそうです。
回路図はこんな感じで考えました。
I2CバスマルチプレクサはSCL/SDA両方の信号線を切り替える仕組みが多いですが、MAX4733のプリケーションノートでSDAラインだけのスイッチングをしている作例がありまして(SDAさえ切り替えてしまえばスタートコンディションが該当デバイスにだけ発生するので…)、これなら74HC4066で4デバイス行けそうと思いました。SCLラインは芋づるでつないでしまいます。
74HC4066で切り替えできるのは4デバイス分ですが、EEPROM 24LC1025はA0〜A2のピンをH/Lレベルどちらに接続するかでアドレスを設定できるため、芋づるでつなぎます。
実験してみたら….
上記回路で、いろいろと実験してみたのですが、どうもデバイス切り替えがうまくいきませんでした。試作したユニバーサル基板はこんな感じです。
テスターであたってみたりして気がついたのですが、よく考えると前回の8255(PPI)でI2C通信を実施する記事でも書きましたが、I2C信号線のHレベル/Lレベルの切り替えは8255(PPI)のポート設定についてコントールワードを送信することで「入力(HiZ)=Hレベル」「出力=Lレベル」を切り替えています。8255(PPI)のコントロールワードはポートごとの設定とはいかず全ポートの情報を出力します。よって今回の設定変更に関係ないポートまで初期化されてしまうのでした。(あたりまえ)8255(PPI)は出力用に初期化されると、全ビットがLレベルとなります。….. orz
つまり、8255 ポートAにI2Cデバイスの選択信号を出力していてもI2C通信が始まるとポートAは全ビットLに落ちてしまうので切り替えスイッチの用をなしません。考えてみたらあたりまえ。
切り替え回路の案-2
改良?した回路図がこちらです。
結局、8255(PPI)の外側にラッチIC 74HCT573を配置しまして、I2Cデバイス選択信号を保持してもらうことにしました。8255(PPI)がちゃんとラッチの機能をもっているのに、外側にラッチを持つのは負けた感じです。データラッチタイミングもPA7端子をL→H→Lみたいに操作するというちょっと不格好なソフトウェアとなりました。
最初の回路ではアドレスデコーダーの74LS138にZ80のIOREQ をENABLE端子に入れてRD、WR を直接8255につないでみましたが、タイミングの関係うまく動作しなかったため74LS32のORゲートで IORQ、IOWR信号を生成するかたちへ変更しました。
ひとまずこれでRTC DS3231との通信ができましたので、githubではリリース1としてリリースしました。
ユニバーサル基板上にはICを搭載するスペースが無かったので、苦肉の策で子基板を作成して74HC4066のICソケットを嵩上げして対応しました。不格好ですが…
RTC DS3231はOK、DS1307+はナゼかNG
つぎに苦しんだのが、KZ80マイコンでI2C通信ができたRTC DS3231は通信できたものの、同じ手順で通信できるはずのDS1307+ DIPとの通信がいくらやってもNGなことでした。当初はあまりデータシートを読まず、以下のような回路としていたのでした。
DS1307+はバックアップ電源用にVbat端子を持っています。通常はCR2032などを直結しておくと思うのですが、電池交換しなくて良いように私が以前作った他のRTCボードと同様電気二重層コンデンサを使おうと思いました。Vccから逆流防止用のダイオードと、突入電流防止の抵抗100Ωを通じて1F 5.5Vの電気二重層コンデンサを充電し、Vccが切れたら電気二重層コンデンサから給電する仕組みとしてみました。この回路だとどうしてもDS1307+がI2C通信に返事をしません。
ためしに、バックアップ用の電源をつながずに、ブレッドボードなどでKZ80マイコンのI2Cボードなどで動かしてみると普通に日時データの読み書きがOKでした。また今回作ったボードの切り替え回路を通さないI2C外部端子に、件のブレッドボードで仮設して作ったDS1307+をつなぐと動作するのであります。
結局のところ問題はVccとVbatの電位差の問題でした。データシートを読むとVBATにつなぐ電圧は以下のように2.0V〜3.5Vなのですが、テスターで計測してみたところ電気二重層コンデンサの両端は4.5Vとなっていました。定格オーバーです。もともとCR2032などボタン電池でバックアップする仕様となっているようです。
DS1307 DATASHEET
また、DS1307データシートのVBAT端子の説明が以下のようになってまして、Vccが低下してVbat x 1.25倍になったらアクセス禁止状態になるみたいでした。つまり、VBATが4.5Vもあるとアクセス禁止です。
DS1307 DATASHEET
ちゃんと3.3Vのレギュレーターなどをつなげようかなど色々と考えた結果、抵抗分圧で良いのでは?ということで以下のような回路としました。この回路定数でだいたい3.5Vあたりまでで安定します。もうちょっとR5の抵抗値が大きいほうが安全かもしれないです。(800Ωあたりとか)
I2Cボード・リリース2の検討
I2Cについては以下の参考書なども読みまして、内容はH8やPICの話がベースですが大変参考になっているわけであります。
この書籍のコラムに「汎用I/OポートでI2C通信をする場合」に関するコラムがありまして、KZ80マイコンやPC-8001用I2Cポートリリース1で実装したポートをHiZ(Hレベル)と出力Lレベルでコントロールする方法とは別に、汎用入出力ポート2つを使って通信をするという話が出てました。I2C信号線それぞれに出力用と入力用の2ポートを使うという構成です。これだと入出力方向の決定は初期設定時1回でOKとなります。その代わり、出力ボートに74HC07などのオープンコレクタ(オープンドレイン)のバッファゲートICを装備する必要があります。
8255(PPI)のポートCは8ポート中2ポートを使っているだけですし、4bit分づつ入力/出力設定を分けることも出来ますので行けそうです。
中日電工さんがロジックICで同様のI2C通信回路を公開されていますが、信号線のところに74HC03を使用されています。
I2Cボード・リリース2の回路図と動作確認
回路図はこのような感じになりました。I2Cデバイスの切り替えについては74HC4051を新たに買ったので8分岐にチャレンジです。(当面は4デバイスしか手持ちは無いですが)
あとは、またユニバーサル基板で試作するので配線の都合上74HC4051でつくるI2C SDAライン切り替えのコントロールは、8255(PPI)ポートBを使用することにしました。自作した基板はこんな感じです。
RTC DS1307、DS3231との通信ドライバーもシンプルになりまして、SDA、SCL信号線をON/OFFするロジックもリリース1のように8255(PPI)の初期化をしまくるのではなく、以下のように純粋にポートCの各ビットのON/OFFとなりました。(詳しくは、こちらをご覧ください。)
;--------------------------------------
; SDA_ON/OFF
;--------------------------------------
SDA_ON:
LD A,SDA_HIGH
OUT (PPI_CTL),A
RET
SDA_OFF:
LD A,SDA_LOW
OUT (PPI_CTL),A
RET
;--------------------------------------
; SCL_ON/OFF
;--------------------------------------
SCL_ON:
LD A,SCL_HIGH
OUT (PPI_CTL),A
RET
SCL_OFF:
LD A,SCL_LOW
OUT (PPI_CTL),A
RET
このZ80機械語ドライバー部分を取り込んだRTC読み書き機械語サブルーチンを、N-BASICのUSER関数からCallできるようにしまして、N-BASICのDATE$、TIME$で日時設定できるうようになりました。機械語サブルーチンとN-BASIC間は文字列でやりとりするようにしています。
こちらがハード、ソフトの完成写真です
いったんハード、ソフトが出来上がりましたのでgithub上もリリース2としてタグ付けしました。まだEEPROMのテストが未済なので、今後テストしていきたいと思ってます。
コメント