« 400g級文鎮:ハンダ付け補助ツール4つ | トップページ | EEPROM I2Cのクロックを早くすると・・・ »

2021年11月26日 (金)

EEPROM、 2kバイトと4kバイトの間には壁がある (24LC16で)

タクトスイッチを押してみる …何万回も その4 続き
この回路に、外付けメモリー(FRAM:強誘電体メモリ)を増設。
スケッチをゴソゴソしてました。
   ※スケッチ:基がArduinoなんであえてこう呼ぼう

手持ちのFRAMで容量が大なのが16kビット=2kバイト。
サイプレスの「FM24C16B」という型番。
  ※32kバイトのFRAMはちょい高価。
   そのうち手配しときますわ。
使い方はI2C EEPROMの24LC16なんかと同じなんですが、
I2C EEPROMには「2kバイトと4kバイトの間に壁」がありま
すんで要注意。
これをちょっとまとめておきます。

よく使うEEPROM、32kバイトの24LC256でしょうか。
しかし、このスケッチをそのまま24LC16には移せません。
アドレスの指定方法が異なるのです。

32kバイトの24LC256のアドレスは0x0000~0x7FFF15bit
2kバイトの24LC16だと0x0000~0x07FF11bitになります。

24LC256だと、メモリアドレスの2バイトをこんな具合にH,Lバイト
2回に分けてコマンド送出します。

E14

ところが24LC16(これより小さいメモリ)だと、送出アドレスは
1バイト(下位の8bit:0x00~0xFF)だけになり、アドレスの上位は
コマンドの下位3ビットに含ませて指定しなければなりません。

E12

それが、「2kバイトと4kバイトの間の壁」です。
これを理解していないと、小容量EEPROMが使いこなせません。

2kバイト以下のはデバイスアドレスの下位3bitにメモリアドレスの
上位を混ぜるのです。
E11_20211126144301
メモリの大きさで、アドレスとして有効となるビット位置が
異なります。

さらに、この「壁」が、読み出しの時にも関係してくるのです。

読み出しのアドレスも、書き込みと同じように上位側はコマンドの
下位3ビットで指定します。
続いて読み出しコマンドを送出するのですが、この時にも書き込みと
同じように、デバイスアドレスに下位3ビットを加えておかなくては
ならないのです。
  ※長いこと使ってないと、これを忘れてしまって、
   「ありゃ?」っとなってしまうわけでして・・・

E13
この処理を忘れてデバイスアドレス(0xA0)だけを読み出し
コマンドに送ってしまうと、ページ0のデータが出てきて
しまい、0x01FF~0x03FFのページ1,2,3のデータが
読み出せません。

最初のアドレス指定コマンドと読み出し開始コマンドの
下位3bitは同じ値にしておかなくてはならないのです。

4kバイト以上の24LC32や24LC64、24LC256では2バイトで
アドレスを渡すので、ここらは気にしなくてかまいません。

・4kバイト以上のEEPROMでの書き込み例
 Wire.beginTransmission(DEV_ADR); // デバイスアドレス ★1
 Wire.write(mem_adr >> 8);     // メモリアドレス MSB
 Wire.write(mem_adr & 0xFF);    // LSB
 Wire.write(data);         // 1バイトデータ書き込み
 Wire.endTransmission();      // 転送開始
 delay(10);            // 書き込み時間待ち

・4kバイト以上のEEPROMでの連続読み出し例
 Wire.beginTransmission(DEV_ADR); // デバイスアドレス ★1
 Wire.write(mem_adr >> 8);     // メモリアドレス MSB
 Wire.write(mem_adr & 0xFF);    // LSB
 Wire.endTransmission();      // アドレスを転送
 Wire.requestFrom(DEV_ADR, qty)  // qtyバイトデータ要求 ★2
 for(i = 0; i < qty; i++){     // loop
   if(Wire.available())  bff[i] = Wire.read(); // bffにコピー
 }

2kバイト以下のEEPROMの場合、★1と★2を加工しなければなりません。
そして、忘れるのが★2の処理。
これをDEV_ADRだけで実行してしまうと、欲しいアドレスのデータが
出てこずにページ0のメモリが出てきちゃうのです。

なお、連続読み出しする場合のページ境界は意識しなくて大丈夫です。
0x00FFの次は0x0100のデータが、0x02FFの次は0x0300のが出て
きます。
  ※書き込みはページサイズが関係しますんで、
   連続書き込みは別の処理が必要です。 (ページライト処理)

  ※wireライブラリ、I2Cの送受バッファが32バイトなんで、
   長大な連続読み書きは一度にはできません。

  ※ライブラリWireのI2Cクロックは100kHzで、ちょい遅い。
   24LC256は400kHzで動作ok。
   setup()内でこんな具合にして高速化。
    Wire.begin();   // 外付けEEPROM用I2C
    Wire.setClock(400000L);  // 100kHz→400kHzに ちょい早く

小容量のEEPROMやFRAMを使う時は、ちょっと注意が必要
ということで。

※表はMICROCHIPの「I2C. シリアルEEPROM ファミリ データシート」
 より。

※もうひとつ: デバイスアドレスについて
一般的な24LC256などのEEPROM、データシートを見ると
0xA0 : 0b10100000」がデバイスアドレス(制御コード)
になってます。
ところが・・・ArduinoのWireライブラにに食わせるアドレスは
0x50 : 0b01010000」。
右に1ビットシフトした値を与えます。

これ、ライブラリ「twi.c」の中で
 twi_slarw = TW_WRITE;
 twi_slarw |= address << 1;
と、address値が左シフト処理されてI2C関連レジスタに
渡されるのです。
わざわざ、「なんでこうなった?」が不明。
誰か教えて!

※参考
ArduinoでI2Cの外付けEEPROMを使う(radiopench.blog)
Arduinoで外付けEEPROMを使う 続編

※追記
Arduino WireへのI2Cのアドレス、
そのままで良いのか
1/2(右シフト)すべきか・・・

・DHT20センサー : 7ビットで記載。これはそのまま
22_20211129145901

・AM2320センサー : おそらく、1/2だろう
23_20211129145901

・富士通FRAM : 1/2で
24_20211129150001

・ローム照度センサー : 7ビットで記載。
     そして最下位ビット1なんで間違いなくそのまま。
25_20211129150001

・I2C液晶表示器 : 1/2で。
26_20211129150101
8bitのI2Cコマンドとして「絵」が書いてあったら、
そのままで良いのか1/2しないと動かないのかが
はっきりします。

サンプル・スケッチの無いI2Cデバイス、使う時はご注意を。

|

« 400g級文鎮:ハンダ付け補助ツール4つ | トップページ | EEPROM I2Cのクロックを早くすると・・・ »

Arduino」カテゴリの記事

コメント

7bitのAddressと1bitのR/_Wで8bitの制御コードを構成していますが、
I2Cのデバイスによってはデータシートに7bitのAddress(7'b101_0000)が記載されていることもあるので、
引数に7bitのAddressを指定させ、内部で1bit左シフトした上でR/_Wを設定しているのではないでしょうか?

投稿: とり | 2021年11月29日 (月) 11時08分

というのか・・・メーカーがデーターシートで示しているアドレス(コマンド)は8bit。
そのLSBであるbit0がR/W区分としてI2C信号列に現れます。

ArduinoでEEPROMを使う時、「メーカーが示すアドレスを1/2して食わせろ」を知らないと・・・動かない。
これを「なぜ?」と思ったのです。

I2C EEPROMのメーカー、ロームや富士通、マイクロチップなどざっと見た限りでは、デバイスコードの上位が「1010に固定」と記されています。
そして、下位側にA2、A1、A0、R/Wが続き、その動きが8ビットのコマンドで説明されています。

しかし・・・センサーチップなど確かに7bitでアドレスを示しているデバイスもあります。(R/Wを除いて)
ここらの注意、初めて使う石だと、Arduino内部の処理を知らないと「動かない」ということに。

投稿: 居酒屋ガレージ店主(JH3DBO) | 2021年11月29日 (月) 13時49分

コメントを書く



(ウェブ上には掲載しません)




« 400g級文鎮:ハンダ付け補助ツール4つ | トップページ | EEPROM I2Cのクロックを早くすると・・・ »