OrangePi-PCを使ってみる

EEPROMとのi2c通信

i2cのEEPROM(24C04)を入手しました。
このEEPROMは4KBit(512Byte)ですが、2KBit(256Byte)の24C02が2個、1つのパッケージに入っている感じで す。
i2cアドレスも以下の様に0x50と0x51の2つ見つかります。
$ sudo i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
50: 50 51 -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

以下のソースで確認してみました。
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

void dump(uint8_t *dt, uint32_t n) {
  uint16_t clm = 0;
  uint8_t data;
  uint8_t sum;
  uint8_t vsum[16];
  uint8_t total =0;
  uint32_t saddr =0;
  uint32_t eaddr =n-1;

  printf("----------------------------------------------------------\n");
  uint16_t i;
  for (i=0;i<16;i++) vsum[i]=0;
  uint32_t addr;
  for (addr = saddr; addr <= eaddr; addr++) {
    data = dt[addr];
    if (clm == 0) {
      sum =0;
      printf("%05x: ",addr);
    }

    sum+=data;
    vsum[addr % 16]+=data;

    printf("%02x ",data);
    clm++;
    if (clm == 16) {
      printf("|%02x \n",sum);
      clm = 0;
    }
  }
  printf("----------------------------------------------------------\n");
  printf("       ");
  for (i=0; i<16;i++) {
    total+=vsum[i];
    printf("%02x ",vsum[i]);
  }
  printf("|%02x \n\n",total);
}

int main(int argc, char **argv) {
  int addr;
  int fd;
  int data;
  int i;
  uint8_t buf[256];

  printf("argc=%d\n",argc);
  if (argc == 1) {
    printf("%s i2c_address\n",argv[0]);
    return 0;
  }

  addr = strtol(argv[1],NULL,16);
  printf("i2c address=%d\n",addr);

  fd = wiringPiI2CSetup(addr);
  // clear all data
  for(i=0;i<256;i++) {
    wiringPiI2CWriteReg8(fd,i,0);
    delay(2);
  }

  for(i=0;i<256;i++) {
    buf[i] = wiringPiI2CReadReg8(fd,i);
  }
  dump(buf,256);

  // write sequence data
  for(i=0;i<256;i++) {
    wiringPiI2CWriteReg8(fd,i,i);
    delay(2);
  }

  for(i=0;i<256;i++) {
    buf[i] = wiringPiI2CReadReg8(fd,i);
  }
  dump(buf,256);

}

起動時の引数に0x50を指定すると先頭の256Byte、0x51を指定すると末尾の256Byteを読み書きできます。
$ sudo ./a.out 0x50
argc=2
i2c address=0x50
----------------------------------------------------------
00000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
00090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
000a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
000b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
000c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
000d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
000e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00
----------------------------------------------------------
       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |00

----------------------------------------------------------
00000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |78
00010: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f |78
00020: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f |78
00030: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f |78
00040: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f |78
00050: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f |78
00060: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f |78
00070: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f |78
00080: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |78
00090: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f |78
000a0: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af |78
000b0: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf |78
000c0: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf |78
000d0: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df |78
000e0: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |78
000f0: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |78
----------------------------------------------------------
       80 90 a0 b0 c0 d0 e0 f0 00 10 20 30 40 50 60 70 |80

24C02(256Byte) 24C08(1024Byte) 24C16(2048Byte)も、全く同じ手順でアクセスできます。
A0ピン、A1ピン、A2ピンでi2cアドレスを選択できますが、選択できる範囲がチップにより異なります。

選択できるアドレス
24C02 0x50〜0x57
24C04 0x50/0x52/0x54/0x56
24C08 0x50/0x54
24C16 0x50

24C16では、1つのチップで0x50〜0x57の8個のi2cアドレスが見つかります。
$ sudo i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 51 52 53 54 55 56 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

i2cアドレスでメモリの読み書きする範囲を指定します。
i2cアドレス メモリ範囲
0x50 0x0000〜0x00FF
0x51 0x0100〜0x01FF
0x52 0x0200〜0x02FF
0x53 0x0300〜0x03FF
0x54 0x0400〜0x04FF
0x55 0x0500〜0x05FF
0x56 0x0600〜0x06FF
0x57 0x0700〜0x07FF



24C02/04/08/16はいずれも、読み書きするメモリーアドレス(データシートではWord Addressと記載)が8ビットです。
従って以下のコマンドでも読み書きすることができます。
$ sudo i2cdump -y 0 0x50 i
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f    .???????????????
10: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f    ????????????????
20: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f     !"#$%&'()*+,-./
30: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f    0123456789:;<=>?
40: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f    @ABCDEFGHIJKLMNO
50: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f    PQRSTUVWXYZ[\]^_
60: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f    `abcdefghijklmno
70: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f    pqrstuvwxyz{|}~?
80: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f    ????????????????
90: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f    ????????????????
a0: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af    ????????????????
b0: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf    ????????????????
c0: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf    ????????????????
d0: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df    ????????????????
e0: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef    ????????????????
f0: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff    ???????????????.

$ sudo i2cset -y 0 0x50 0x00 0xff → 0x00番地に0xffを書き込み
$ sudo i2cdump -y 0 0x50 i
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: ff 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f    .???????????????
10: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f    ????????????????
20: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f     !"#$%&'()*+,-./
30: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f    0123456789:;<=>?
40: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f    @ABCDEFGHIJKLMNO
50: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f    PQRSTUVWXYZ[\]^_
60: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f    `abcdefghijklmno
70: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f    pqrstuvwxyz{|}~?
80: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f    ????????????????
90: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f    ????????????????
a0: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af    ????????????????
b0: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf    ????????????????
c0: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf    ????????????????
d0: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df    ????????????????
e0: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef    ????????????????
f0: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff    ???????????????.

$ sudo i2cset -y 0 0x50 0x00 → カレントアドレスに0x00番地を指定
$ sudo i2cget -y 0 0x50 → カレントアドレスのデータを読み込み
0xff

$ sudo i2cset -y 0 0x50 0x10 → カレントアドレス に0x10番地を指定
$ sudo i2cget -y 0 0x50 → カレントアドレスのデータを読み込み

0x10



同じピン配置のEEPROMに24C32/64/128/256/512が有ります。
これらは、読み書きするメモリーアドレス(データシートではFirst Word Address/Second Word Addressと記載)が16ビットに変更されています。
i2cアドレスの指定もA0、A1、A2のピンを使って以下の範囲で指定することができます。

使用できるピン 選択できるアドレス
24C32 A0 A1 A2 0x50〜0x57
24C64 A0 A1 A2 0x50〜0x57
24C128 A0 A1(*) 0x50〜0x53
24C256 A0 A1(*) 0x50〜0x53
24C512 A0 A1(*) 0x50〜0x53

(*)
こ ちらこ ちらのデータシートではi2cアドレスの指定はA0、A1の2つのピンで行うことになっていて、A2はN/Cとなっていますが、
A2をPullUpしたら以下の様に0x57になりました。
試しに0x57で読み書きしてみましたが問題なく読み書きできます。


24C256ではなぜか0x58にもアドレスが出現します。
これを使って読み書きしてみましたがエラーになりました。


WiringPiのi2c関数では、16ビットのメモリーアドレスを指定することができないので、i2c関数を使ってこれらを読み書きすることが できません。
同様の理由で、 i2cdumpでは読み出すことがができません。
こ ちらに公開されているeeprogでは、16ビットのメモリーアドレスを指定することができるようになっています。
ソースを確認しましたが、i2c_smbus_write_byte_data()や、i2c_smbus_write_word_data() を使ってアクセスしています。
起動時のオプションが結構複雑ですが-16を指定すると、16ビットのメモリーアドレス指定、
-8を指定すると、8ビットのメモリーアドレス指定となり、24CXX全てを読み書きすることができる優秀なアプリです。



eeprogのソースを拝借して、8ビットアドレス、16ビットアドレス両方に対応したアクセスライブラリを作りました。
8ビットアドレスの場合、ライブラリ内部でメモリー番地に応じてi2cアドレスを切り替えてアクセスするので、
8ビットアドレス、16ビットアドレス、どちらも全く同じ手順で読み書きすることができます。
所詮、最大でも512KBit(65KByte)までしか容量が無いので、あまり有効な使い道は有りません。
ソースはこちらで 公開しています。



AT24シリーズはAtmelの製品ですが、FT24C128Aとマーキングされたチップを入手しました。
調べてみるとFremont Micro Devices Ltdの互換製品の様です。
i2cアドレスは正しく認識されたので、読み書きしてみると、以下の様に書き込みエラーとなります。
エラーとなるアドレスは毎回変わります。
5個買って4個がエラーとなりました。
互換チップでこれだけ出来が悪いのも珍しいです。
DigiKeyで調べてみると、2014年には20億個のシリアルEEPROMを出荷したそこそこ有名なメーカです。
悪質なコピー商品かもしれません。


次回はSPI通信を紹介しま す。