home1.gif

next1.gif
back1.gif
 

Serial EEPROM

 

基礎編
 PORT入出力
 シリアル通信
 タイマー機能
 A/Dコンバータ
 D/Aコンバータ
 外部割り込み
 液晶モニタ

応用編
 アウトプットコンペア
 インプットキャプチャ
 SRAM増設

Tips
 関数集
 シリアルEEPROM
 20桁×4行液晶モニタ
  (SC2004C)
 加速度センサを読む

 シリアルEEPROM

 イントロダクション
  Windowsのプログラムや、マイコンのプログラムでも内蔵ROM/RAMだけを扱ってプログラミングをしているとほとんど意識することがないし、下手をすれば知らずにプログラミングを行っている人すらいるかも知れないが、あらゆるデータの処理には「アドレス」「データ」の2つを常にペアで扱わなければいけません
 つまり、「このデータは何番地に格納する」という事を意識しておかなければプログラムを理解しているとは言い難いでしょう。

 これから紹介するシリアルEEPROM(Microchip社製24LC256)はそれがより一層身近に経験できるチップです。まず、右の写真を見てください。これは256Kbit(=32KB)の記憶容量を持つEEPROMです。「あれ?」と思った方は勘が鋭いか、すでに「シリアルEEPROM」の意味を理解していると言って良いでしょう。

 先ほどから述べているように、それが記憶装置である以上はかならずアドレスを指定するアドレスバスと、データを送受信するデータバスの2種類が存在します。それは内蔵であろうと外付けであろうと原理はまったく変わりません。そして、それらのバス幅というのは、たとえばアドレス空間(=記憶容量)が0x0000〜0x7fffまで(32KB)とすると、2進数で表すためには15桁が最低でも必要です。これは物理的にはアドレス指定用の端子が15本必要であると言うことです。もうひとつのデータバスについては、アクセスが8ビットアクセスか16ビットアクセスかによって8本または16本必要になります。

 しかし、この写真のチップは8本しか端子がありません。なぜこれでアドレスとデータの両方をリード・ライトできるのでしょう? その答えのキーワードが「シリアル」です。つまり、本来はアドレスとデータを同時にパラレルでリード・ライトするところを、時間を掛けてシリアルでリード・ライトするわけです。

 右の図を見てください。この図で「SDA」と書いてある端子がアドレスバス兼データバス兼チップセレクト兼ライトイネーブル兼アウトプットイネーブルになります。

 では他の端子は何のためにあるのでしょう? まず、A0〜A2はチップセレクトです。このチップでは最大8個のチップを並列に繋いで32KB×8=256KBの容量として使うことができます。そこで、ホストとなるマイコン(ここではH8)からはSDAを通じてどのチップにアクセスしたいのかを指定しますが、チップ本体の方はこのピンがVss電圧になっているか、それともVdd電圧になっているかで自分が何番目のチップとして指定されているのかを判断します。
 たとえば、A0〜A2が全部GNDになっていれば、チップ0番として扱われます。逆に全部Vddに繋がっていればチップ7番として扱われます。そして、ホスト側は「何番目のチップの、何番のアドレスに、このデータを書く」とか、「何番目のチップの、何番のアドレスのデータを読む」というように命令を送ります。これが冒頭でアドレスの考え方がよく分かるチップと言った理由です。

 次にWP端子ですが、これはWrite Protectの略ですから、そのままの意味ですね。バー( ̄)が付いていませんから、Highで有効という風に考えます(かならずしも全国共通ではありませんから実際の使用ではちゃんと確認してください)。だから、これをGNDに繋いである間はリードもライトも可能になります。

 VssとVddは電子回路を扱っていれば絶対に遭遇するので改めて説明は不用かもしれませんが、Vssが一般にGND電圧で、Vddが電源電圧(このチップは2.5〜5.5Vと幅が広い)です。

 最後のSCLですが、これは言葉で説明するのは面倒ですので、まずは下の図を見てください。

  EEPROMにデータを送る際にはまずSDAの信号をHighかLowの目的とする方に変化させます。それから一定時間待ってからSCL(クロック信号)をLowからHighに変化させます。すると、図の赤で示した部分だけがEEPROMにとって有効な情報として認識されます。
 ですから、8ビットの情報を送りたいときにはこのSCLのクロック信号を8回送らなければいけないという事になります。これがなかなか面倒なので、タイマーのPWM機能などに任せてしまいたくなるのですが、クロック数は過不足があっては決していけないので、余計に難しくなってしまいます。ですから面倒でも自力でこのタイミングを作り出しましょう。

     (注)
     厳密には実際のタイミングはこの図のようにエッジの頂点で有効になるわけではありません。それぞれのチップによってHighと認識する電圧と、Lowと認識する電圧、およびその電圧に達してから本当にチップが認識できるまでの時間が絡み合ってきます。これらはそれぞれの仕様書で確認するしかありません。

 リード・ライトの方法
 リードとライトは命令としてはほとんど同じですが、何カ所か落とし穴があるので早勝手しないように気を付けてください。

circle15_pink.gifライト
 普通は「読むことすらできないものを書こうなんて気が早い」と言われるのですが、書かないことにはそもそも読めているのかどうかも分かりませんし、このチップに関しては書く方が楽なのでこちらから説明します。

 送信する命令は次のように6つのフェーズに分かれており、それぞれを「Acknowledge Bit」と呼ばれる区切りを挟んで連続して送信します。

フェーズ

名称

説明

スタートビット

アクセス開始合図

コントロールコード

チップ指定、ライトの指定

上位アドレス

アドレスの8〜15ビット目を上位から順に送ります

下位アドレス

アドレスの0〜7ビット目を上位から順に送ります

データ

データ本体を送ります

ストップビット

アクセス完了合図

 まずスタートビットですが、これはSDAとSCLを特定の状態にすることによって、チップに対して「これからリードかライトをするぞ」と宣言します。具体的には、SDAとSCLは通常は両方ともHighになっていますが、これをSDAを先にLowに落とし、しばらく待ってからSCLもLowに落とします。

 コントロールコードとは、[1010]+[チップセレクト]+[リード(1)/ライト(0)] という書式になっており、たとえばチップ1番にライトする場合には「10100010」というコードになります。

 続いて上位アドレスですが、このチップでは0x0000〜0x7fffまでしかアドレス空間がありませんので、最上位ビットは使用しません。したがって、実際には8〜14ビット目までが有効で、15ビット目は0でも1でも無視されます。

 下位アドレスも同様に送信します。
 ですから、アドレスがたとえば0x3502だったとすると、アドレス指定は「00110101 (ACK) 00000010」のようになります。

 データ本体は上位からでも下位からでも好きなように格納できますが、リードとライトで逆にならないようにだけ注意してください。

 最後のストップビットは、「これで処理完了」という宣言ですから、いかなる場合も必ず最後はこれで終わらなければいけません。まずSCLをLowからHighに変化させ、しばらく待ってからSDAをLowからHighにすれば一連の命令は終わります。

 ここまでを連続して書くと、「チップ1番0x3502番地0x55というデータを書く」だったら、SDAは

 (Start) 10100010 (ACK) 00110101 (ACK) 00000010 (ACK) 01010101 (ACK) (Stop)

という風になります。ここで「ACK(Acknowledge Bit)」とは、SDAのデータはそのままでも、あえてHighかLowに統一しても良いのですが、なにしろ次のコードを送る前にSCLを1パルス送ることです。

 最後に、ライトで気を付けておかなければいけないのは、一度ライティングを行ってから次のライティングを行うまでの待ち時間です。1バイト書くだけならば実はかなり高速なライティングが可能なのですが、このチップでは残念なことにその速度で連続して書き続けることはできません。仕様書ではなんと5msecも待たなければいけないことになっています。私の実験では3.5msecでも次のライティングができましたが、当然保証の範囲外です。

 

circle15_pink.gifリード
 
リードはライトよりも面倒です。唯一の救いは1バイトとリードしてから次のリードまで待ち時間があるということはさすがに無いのがせめてもの救いです。

 フェーズは次のようになっています。

フェーズ

名称

説明

スタートビット

アクセス開始合図

コントロールコード

チップ指定、ライトの指定

上位アドレス

アドレスの8〜15ビット目を上位から順に送ります

下位アドレス

アドレスの0〜7ビット目を上位から順に送ります

スタートビット

もう一度アクセス開始の合図

コントロールコード

チップ指定、リードの指定

データ

データ本体が送られてきます

ストップビット

アクセス完了合図

なかなか腑に落ちないと思いますが、最初は「ライト」を指定します。これは続いてアドレスを「ライト」するからこういう指定になります。そして、ライトデータを送る代わりにもう一度スタートビットを送り、今度は「リード」を指定します。すると今までホストからチップへの一方通行だったSDAから逆にデータが送られてきます。当然ですが、フェーズ6のコードを送った後のAcknowledge Bitの時にはSDAは出力から入力に切り換えておかなければいけません。いうまでもなく、接続しているポートの「DDR」を「1」から「0」にするだけです。
 ちなみに今まで一度も言いませんでしたが、ポートの入出力の設定は動作中でも任意に切り換えることが可能です。「初期化の時に出力にしたから・・・」なんていう制約はありません。

 また、フェーズ7から8への移行の時だけはAcknowledge Bitは不要です。ここでSCLを1パルス送ると、「連続リードモード」になり、次のアドレスのデータが出てきてしまいます。だから終了する場合にはデータを受け取ったらすぐさまストップビットを送ります。

 それと、「仕様書に書いてある」と言われたらそれまでなのですが、リード時には物理的な大きな落とし穴が有ります。それは、このチップのSDA端子が「オープンドレイン端子」になっていることです。オープンドレイン端子とは、それ自身は電圧を出力する能力を持ちません。したがって別電源でプルアップしてやらなければ一度Lowに落ちてしまえば待てど暮らせどHighにはなりません
 なぜこのような難解な端子を使っているかですが、ちゃんと根拠があります。我々は普段0Vと5Vで動くチップを扱っているから意識から抜けがちですが、世の中には3.3Vで動く物や、その他もろもろの電圧が存在します。それらに対して5Vの出力を送りつけたのでは都合が悪いのです。悪ければ一撃で昇天させてしまいます。そこでこのようなポートを使えば任意の電圧で出力を出せ、汎用性が上がるという仕組みです。

 もちろん回路でプルアップしてもまったく問題有りませんし、マイクロチップ社が想定しているのもそういう使い方です。しかし、H8には都合の良いことにプルアップ抵抗の入ったポートが複数存在します。それらの内蔵プルアップ(PCR)を有効にすれば回路を増やさずに済みます。

 

circle15_pink.gifサンプルプログラム
 このプログラムは実際に私が実験に使用したバージョンです。LCDモニタを接続し、ライトしたデータを読み出し、それを表示するようにしています。EEPROMに関する関数はすべてfunc_EEP.cにまとめられていますので、それとmyfunc.hの2つをインクルードすれば他のプログラムでも使えるはずです。

 ただし、Hewのバージョンが1.2に上がっていますので、旧バージョンではプロジェクトを開けない可能性がありますのでその場合は適宜対応してください。

set01_download_on.gif
test13.lzh(30KB)