ターゲットESP32をESP-IDFで使う覚書です。I2Cマスターなので目新しいことは無いですが、dsPICやSTM32と混在して開発していると混乱しやすいので、ESP32用のひな形としてコーディングしました。
2022/05/16 c++表記に変更
C++の場合は構造体のアクセス表記など少し変わるので変更しました。
ソースはここ
ESP-IDFのペリフェラル設定はだいたい同じ
初期設定はi2c_config_tに値をセットして関数を呼び出す
マスター/スレーブ、ポート、クロックなど指定します。
R/Wアクセスは各状態を組み合わせる
例えば、バイト書き込み操作では、スタートコンディション、書き込みバイト、ACK/NCK、書き込みバイト・・・、ストップコンディションの順ですが、それぞれが関数になっているので、組み合わせるだけです。
今回接続した24AA01のランダム書き込みは
- i2c_cmd_link_create(); // i2c通信開始
- i2c_master_start(cmd); // スタートコンディションセット
- i2c_master_write_byte(cmd, E24AA01_ADDR, ACK_CHECK_EN); // Control Byteセット
- i2c_master_write_byte(cmd, addr, ACK_CHECK_EN); // WordAddress セット
- i2c_master_write_byte(cmd, dt, ACK_CHECK_EN); // Data セット
- i2c_master_stop(cmd); // ストップコンディション セット
- i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000); // 送信開始
- 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の公式デモにあるエラー出力は省略してあります。
コーディング量はそこそこの量ですが、シンプルで分かり易いですね。