ESP-IDFでI2C接続EEPROMにアクセス。C++追加

カテゴリー: ESP32  タグ:

ターゲットESP32をESP-IDFで使う覚書です。I2Cマスターなので目新しいことは無いですが、dsPICやSTM32と混在して開発していると混乱しやすいので、ESP32用のひな形としてコーディングしました。

2022/05/16 c++表記に変更

C++の場合は構造体のアクセス表記など少し変わるので変更しました。

ソースはここ

ESP-IDFのペリフェラル設定はだいたい同じ

初期設定はi2c_config_tに値をセットして関数を呼び出す

マスター/スレーブ、ポート、クロックなど指定します。

R/Wアクセスは各状態を組み合わせる

例えば、バイト書き込み操作では、スタートコンディション、書き込みバイト、ACK/NCK、書き込みバイト・・・、ストップコンディションの順ですが、それぞれが関数になっているので、組み合わせるだけです。

今回接続した24AA01のランダム書き込みは

  1. i2c_cmd_link_create(); // i2c通信開始
  2. i2c_master_start(cmd);  // スタートコンディションセット
  3. i2c_master_write_byte(cmd, E24AA01_ADDR, ACK_CHECK_EN); // Control Byteセット
  4. i2c_master_write_byte(cmd, addr, ACK_CHECK_EN);  // WordAddress セット
  5. i2c_master_write_byte(cmd, dt, ACK_CHECK_EN);  // Data セット
  6. i2c_master_stop(cmd);  // ストップコンディション セット
  7. i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000); // 送信開始
  8. i2c_cmd_link_delete(cmd);  // i2c通信終了

となります。

ランダムリード/ライトでEEPROMの簡易版マーチングテストプログラム

#include <stdio.h>
#include "driver/i2c.h"

#define I2C_MASTER_SCL_IO           22		// I2C master SCK
#define I2C_MASTER_SDA_IO           21      // I2C master SDA
#define I2C_MASTER_NUM              0		// I2C module Number
#define I2C_MASTER_FREQ_HZ          400000	// I2C master freq
#define I2C_MASTER_TX_BUF_DISABLE   0		// I2C master doesn't need buffer
#define I2C_MASTER_RX_BUF_DISABLE   0		// I2C master doesn't need buffer

#define	E24AA01_ADDR	0xA0				// 0xA0
#define ACK_CHECK_EN 0x1					// I2C master will check ack from slave
#define ACK_CHECK_DIS 0x0					// I2C master will not check ack from slave
#define ACK_VAL 0x0							// I2C ack value
#define NACK_VAL 0x1						// I2C nack value

// E2P random write 1byte
void	i2c_eep_write(int addr, unsigned char dt) {
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, E24AA01_ADDR, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, addr, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, dt, ACK_CHECK_EN);
    i2c_master_stop(cmd);
    i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000);	// 1000ms timeout
    i2c_cmd_link_delete(cmd);
	vTaskDelay(5);
}

// E2P random read 1byte
unsigned char i2c_eep_read(int addr) {
	unsigned char ch;

    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, E24AA01_ADDR, ACK_CHECK_EN);
    i2c_master_write_byte(cmd, addr, ACK_CHECK_EN);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, E24AA01_ADDR | 0x1, ACK_CHECK_EN);
    i2c_master_read_byte(cmd, &ch, NACK_VAL);
    i2c_master_stop(cmd);
    i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000);
    i2c_cmd_link_delete(cmd);
	return ch;
}

// I2C initial
void	i2c_master_init(void) {
    int i2c_master_port = I2C_MASTER_NUM;

    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };
    i2c_param_config(i2c_master_port, &conf);
    i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}

// E2PROM marching test
void app_main(void) {
    i2c_master_init();
	for(int i=0;i<128;i++) {		// 0xaaを書き込む
		i2c_eep_write(i,0xaa);
	} 
	for(int i=0;i<128;i++) {
		if(i2c_eep_read(i)==0xaa) {	// 読出し0xaaならそのアドレスに0x55を書く
			i2c_eep_write(i,0x55);
		} else {					// 読出し≠0xaaならエラー
			printf("NG %d\r\n",i);
			for(;;) vTaskDelay(100);
		}
	}
	printf("OK\n\r");
	for(;;) vTaskDelay(100);
}

上記マーチングテストの最初の書き込み「0xA0,0x00,0xAA」の波形を観測

ロジアナ表示ではコントロールコード0xA0はWビットの1ビットを抜いた7ビット表現なので0x50となっています

ESP-IDFの公式デモにあるエラー出力は省略してあります。

コーディング量はそこそこの量ですが、シンプルで分かり易いですね。

お気軽にコメントをどうぞ。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)