ESP32でEEPROM(93Cx6)と通信する

93C56というEEPROMからデータを読み書きする必要があったのだけれど、ROMリーダー/ライターが売られてない…
そこで手元にあったESP32とmicropythonでEEPROMと通信し、データの読み書きをしてみました。
こんな事やりたい人いないだろうけど、、

# 概要
EEPROMは家電や車載システムなどに搭載され、永続的にデータを保持するために用いる。
EEPROMにも通信方式や容量で様々な種類があるけど、今回は93CシリーズというチップをESP32+micropythonを使って通信する。

## 93Cx6
93Cx6は、EEPROMのシリーズの一つで、通信方式は`Microwire`。ROHMによるとこうらしい。~~なんか微妙だね。。~~
> Microwire
> 比較的古い通信方式です。通信速度もSPIと比較し遅く、低容量をラインアップしています。  
> インターフェースの本数は4本とI2Cと比較し多いです。
> 
> -   SPIと比較し、通信速度が遅い
> -   容量ラインアップが低容量のみ
>
>  [ROHM Webサイトより](https://www.rohm.co.jp/electronics-basics/memory/memory_what7)

容量によって型番が次のように決まっている。

| 型番 | 容量 |
| ----  | ---- |
| 93C46 | 128Byte |
| 93C56 | 256Byte |
| 93C66 | 512Byte |
| 93C76 | 1024Byte |
| 93C86 | 2048Byte |

尚、93Cx6という名前は通称名で、同じ名前のチップが各社から発売されている。
物によってはアドレス指定をバイト単位かワード単位か選べたり、シーケンシャルリードができたりするけど基本的には同じ。使ってるチップのデータシートを参照のこと。

### アドレッシング
メーカーによって違いがあるが、アドレス指定の単位をバイト(B)かワード(2B)か指定できる。
ワード単位を選んだ場合、指定できるアドレスの上限は総バイト数の半分となる。

# 環境
- ESP32-devkit-C
- S93C56(EEPROM)
- micropython
- M1 Macbook Air

# ESP32にMicropythonを書き込む
## ファームウェアをダウンロード
https://micropython.org/download/esp32/
**Firmware**から最新版のstableリリースをダウンロードする

## esptool, ampyをインストール
`pip install esptool`
`pip install adafruit-ampy`

## ファームウェアの書き込み
ESP32をPCに接続する。
macの場合は`/dev/`配下に`cu.usbserial-0001`が現れる。

### Flashの消去
`esptool.py --port /dev/cu.usbserial-0001 erase_flash`

### 書き込み
ダウンロードしたファームウェアが`esp32-20220117-v1.18.bin`の場合：
`esptool.py --chip esp32 --port /dev/cu.usbserial-0001 --baud 46080 write_flash -z 0x1000 esp32-20220117-v1.18.bin`
	

# main.pyを書く
main.pyにやりたい処理を書いてESP32に転送する。
拙作のライブラリ(https://github.com/namacha/micropython-93cx6) を使ってEEPROMとやりとりする。

`model`: 型番。対象のチップに合わせて変更する。
`org`: チップのアドレッシングがバイト単位かワード単位かによって変える
`cs sk di do`通信に使うピンを番号で指定。
以下は93C56(ワード単位)の例

### データ読み出し
データを読み出して16進ダンプを表示する例
```python
from eeprom_93cx6 import Device


dev = eeprom_93cx6.Device(
    model=56,
    org=eeprom_93cx6.EEPROM_MODE_16BIT,
    cs=12,
    sk=13,
    di=14,
    do=15,
)


def dump_buffer(buf, start=0):
    num_lines = len(buf) // 8
    for nlines in range(num_lines):
        addr = (8 * nlines) + start
        print(f"0x{addr:02X} ", end="")
        for v in buf[nlines * 8 : 8 * (nlines + 1)]:
            print(f"{v:04X} ", end="")
        print()


buf = []
for addr in range(0, 128):
    value = dev.read(addr)
    buf.append(value)

dump_buffer(buf, start=0)

```

### データ書き込み
0x0aに0xcdを書き込む例。
```python
from eeprom_93cx6 import Device


dev = eeprom_93cx6.Device(
    model=56,
    org=eeprom_93cx6.EEPROM_MODE_16BIT,
    cs=12,
    sk=13,
    di=14,
    do=15,
)

dev.ew_enable()
addr = 0xa
dev.write(addr, 0xcd)
dev.ew_disable()


def dump_buffer(buf, start=0):
    num_lines = len(buf) // 8
    for nlines in range(num_lines):
        addr = (8 * nlines) + start
        print(f"0x{addr:02X} ", end="")
        for v in buf[nlines * 8 : 8 * (nlines + 1)]:
            print(f"{v:04X} ", end="")
        print()


buf = []
for addr in range(0, 128):
    value = dev.read(addr)
    buf.append(value)

dump_buffer(buf, start=0)

```


# スクリプトをESP32に転送する
ESP32にはmicropythonの処理系が書き込まれている前提。
プログラムの転送には`ampy`を使った。

ライブラリをローカルに落としてくる。
`$ git clone https://github.com/namacha/micropython-93cx6`
ライブラリの転送
`ampy -p /dev/cu.usbserial-0001 put micropython-93cx6/eeprom_93cx6.py`
main.pyの転送
`ampy -p /dev/cu.usbserial-0001 put main.py`


# 配線
`main.py`で設定したピン番号に合わせてICと接続する

```
     VCC                                                                                                    
      | NC(Don't Care)                                                                                      
      |  | TEST(Don't Care)                                                                                 
      |  |  | GND                                                                                           
      |  |  |  |                                                                                            
    __|__|__|__|__                                                                                          
    | |  |  |  | |                                                                                          
    | 8  7  6  5 |                                                                                          
    |            |                                                                                          
    |.1  2  3  4 |                                                                                          
    |_|__|__|__|_|                                                                                          
      |  |  |  |                                                                                            
      |  |  |  DO(Data Out)                                                                                 
      |  |  DI(Data In)                                                                                     
      | SK(Serial clocK)                                                                                    
     CS(Chip Select)                                                                                        
```
オンボードのチップに接続する場合、グラバーというクリップがあるとICの足をつかみやすい。ただし、表面実装のICの場合１本だけは狭すぎてクリップが噛み込めないので読み書きの際に手で当てる。
![D3F1B01E-A91C-4746-9949-7C9803C460B4.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12825/6f3bc8d7-56fd-87d6-971e-08a3ca14c43f.jpeg)


# 読み出し・書き込み
`screen /dev/cu.usbserial-0001 115200`で、ESP32のシリアルコンソールに接続できる。

この状態でCtrl-DでESP32をリセットするとmain.pyが実行される。

```
0x00 FF80 FF80 FF80 FF80 FF80 FF80 FF80 FF80
0x08 FF80 FF80 FF80 FF80 FF80 FF80 FF80 FF80
0x10 FF80 FF80 FF80 FF80 FF80 FF80 FF80 FF80
0x18 FF80 FF80 FF80 FF80 FF80 FF80 FF80 FF80
0x20 FF80 FF80 FF80 FF80 FF80 FF80 FF80 FF80
0x28 FF80 FF80 FF80 FF80 FF80 FF80 FF80 FF80
0x30 FF80 66AF FF66 66AF FF66 66AF FF66 FFFF
0x38 FFFF FFFF FFFF A2AD A2AD A2AD A2AD CBA9
0x40 FFED A2AD CBA9 FFED A2AD CBA9 FFED A2AD
0x48 CBA9 FFED A2AD CBA9 FFED A2AD CBA9 FFED
0x50 FFFF 3333 FF33 ACFF ACFF ACFF FFFF FFFF
0x58 FFFF 1A1A 1A1A FFFF 1BFF FFFF 1EFB FFFF
0x60 1E1E 1E1E FFFF FFFF FFFF FFFF FFFF FFFF
0x68 FFFF FFFF 1F1F 1F1F 9EB6 FFFE FBFB FBFB
0x70 FBFB FFED FFED FFED FDFE FDFE FDFE FFFF
0x78 FFFF FFFF FFFF FFFF FFFF FFFF F7FF F7F7
```