「C言語」タグアーカイブ

ESP32-IDFでI2C-Masterを試してみる

ESP32-IDF開発環境にてI2Cを操作する方法をまとめていきます。

こんにちは、北神です。IoTで良く使用するI2Cを使う場面もあるだろうと思い、まとめました。

詳しい資料は、以下の公式情報から辿ってみてください。

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html

また、以下の公式サンプルの一部を使用しております。

https://github.com/espressif/esp-idf/tree/master/examples/peripherals/i2c/i2c_tools

■ マスターのI2Cの設定

I2Cの設定情報を、以下の様に記載します。変更が多い SDAピン、SCLピン、クロック速度を外部で変更できるようにしてあります。
その他は固定で良いと思いますが、必要があれば変更してください。

#define I2C_MASTER_TX_BUF_DISABLE 0
#define I2C_MASTER_RX_BUF_DISABLE 0 
#define WRITE_BIT I2C_MASTER_WRITE 
#define READ_BIT I2C_MASTER_READ    
#define ACK_CHECK_EN 0x1           
#define ACK_CHECK_DIS 0x0         
#define ACK_VAL 0x0                 
#define NACK_VAL 0x1                

#define I2C_SDA     21
#define I2C_SCL     22

void i2c_master_setup(int sda_io_num,int scl_io_num,int clk_speed,i2c_port_t i2c_port)
{
    int i2c_master_port = 0;
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = sda_io_num,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_io_num = scl_io_num,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = clk_speed,
        
    };
    i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
    i2c_param_config(i2c_port, &conf);
}

■ i2cdetectを試しに作ってみる

I2Cの設定を記述できたので、早速試してみようと思いました。
一番簡単で便利なi2cdetectをカバーしてみます。
多くの処理は、公式のサンプルを利用しています。

void app_main(void)
{

    i2c_port_t i2c_port = I2C_NUM_0;
    i2c_master_setup(I2C_SDA,I2C_SCL,100000,i2c_port);


    uint8_t address;
    printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\r\n");
    for (int i = 0; i < 128; i += 16) {
        printf("%02x: ", i);
        for (int j = 0; j < 16; j++) {
            fflush(stdout);
            address = i + j;
            i2c_cmd_handle_t cmd = i2c_cmd_link_create();
            i2c_master_start(cmd);
            i2c_master_write_byte(cmd, (address << 1) | WRITE_BIT, ACK_CHECK_EN);
            i2c_master_stop(cmd);
            esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 50 / portTICK_RATE_MS);
            i2c_cmd_link_delete(cmd);
            if (ret == ESP_OK) {
                printf("%02x ", address);
            } else if (ret == ESP_ERR_TIMEOUT) {
                printf("UU ");
            } else {
                printf("-- ");
            }
        }
        printf("\r\n");
    }

    i2c_driver_delete(i2c_port);
    return 0;
}

プログラムを書込み、実行すると、以下の様にコンソールに表示されました。

めでたし、めでたし。

それでは!

ESP32-IDFでアプセスポイントを構築する

ESP32-IDFでAPモードで起動する方法を試してみます。

こんにちは北神です。

ESP32はArduino環境とチップメーカ公式のIDFという開発環境があります。
日本ではArduino環境での開発が多くみられますが、ESP32の本場はIDFによる構築ですので、それに合わせて開発を試してみたいと思います。

今回試すのは、アクセスポイント(APモード)にする方法です。

細かく説明するには、FreeRTOSについてや、イベントについて話す必要がありますが、今回はサクッと動作するソースを載せておきます。

開発環境は ESP-IDF v4.3.1 を使用しております。

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>


void wifi_init_softap(void);

static const char *TAG = "ESP32_WS_APP";

//==========================//
// wifi_event_handler
//==========================// 
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                                    int32_t event_id, void* event_data)
{
    if (event_id == WIFI_EVENT_AP_STACONNECTED) {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
                 MAC2STR(event->mac), event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
}

#define SSID    "ESP32_TEST"
#define PASS     "123456789012345"
//==========================// 
//  WiFi SoftAP
//==========================// 
void wifi_init_softap(void)
{
    esp_netif_create_default_wifi_ap();
 
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
 
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));
    wifi_config_t wifi_config = {
        .ap = {
            .ssid = SSID,
            .ssid_len = strlen(SSID),
            .channel = 7,
            .password = PASS,
            .max_connection = 2,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK
        },
    };
    if (strlen(PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
}

//==========================// 
//  app_main
//==========================// 
void app_main(void)
{
    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");    
    wifi_init_softap();
}

このソースを
idf.py flash -p COM11 で書き込み、 idf.py monitor -p COM11 で確認すると、以下の様にログが表示されます。


この状態で、スマフォ等でWiFiのSSIDを確認しに行くと、
SSID: ESP32_TEST
Pass: 123456789012345
で、接続しに行く事ができます。

無事に接続ができますと、IPを振り分けられます。
ログでは以下の様に表示されます。

これで、クライアントに「192.168.4.2」を配布できました。

ESP32-IDFはFreeRTOSで開発する為、一般的なシングルスレッドなマイコンの動作ではなく、決まった時間でタスクが切り替わる事を意識しながら開発する必要があります。

FreeRTOSは非常に便利な機能が多く、できなかった事が楽にできる様になりますのでおすすめです。

ではでは。

ESP32-IDFをWindowsで構築する

ESP32では、公式開発環境のESP32-IDFとAeduinoIDEの二種類の開発環境があります。
今までArduinoで開発してましたが、今回からESP-32-IDFを試してみたいと思います。

■ インストールの方法

 https://dl.espressif.com/dl/esp-idf/?idf=4.4

Online Installerで環境全体のインストールが可能です。

インストール後、デスクトップに「ESP-IDF 4.3 CMD」が登場し、ESP-IDF 4.3 CMDを使用してコマンドを入力します。

■ プロジェクト作成

「ESP-IDF 4.3 CMD」にて、プロジェクトファイルを生成します。
プロジェクトファイルを生成したいディレクトリまでcdコマンドで移動し

idf.py create-project プロジェクト名

例)

idf.py create-project Hello

で、作成ができます。

■ プログラムを編集

プロジェクト名のフォルダにmainフォルダがあり、その中にC言語ソースがあります。
初期では


#include <stadio.h>
void app_main(void)
{

}

が書かれていると思います。

app_mainがmainでない点は、別途Bootloder等があり、app_mainが呼び出されるまで別の処理が先に行われます。

#include <stadio.h>
void app_main(void)
{
    printf("Hello\n");
}

保存し、以下のコマンドを実行します。

idf.py build

最初は時間かかりますが、2回め以降変更がない際は早くコンパイルができます。

※コンパイル中に「FAILED: esp-idf/mbedtls/x509_crt_bundle」というエラーが表示された際

このエラーは、cryptographyがバージョンアップした際に関数の使い方を変更した事が原因です。
問題のバージョンは、cryptographyの35.0.0 – 2021-09-29のものです。
IDF側で対応されてば良いですが、まだ対応されてない際は、以下のコマンドで一つ前のバージョンを使用します。

pip uninstall -y cryptography
pip install cryptography==3.4.8

■ ESP32に書き込む

buildがうまくいったら、以下のコマンドで書き込みます。

idf.py flash -p ポート番号

Windowsの場合、COMポートの指定は以下の例の様にします。

idf.py flash -p COM11

■ ESP32でシリアルモニタを確認する

以下のコマンドでシリアル通信の確認ができます。
デフォルトでは115200bpsになります。

idf.py -p com11 monitor

コマンドを使って、ESP32の開発ができそうです。

ではでは。

ESP32(Arduino)でタイマー割り込みを使う方法

ESP32(Arduino)でタイマー割り込みが使いたい!定時実行やセンサの状態取得等、一定時間が経過した際に実行させたい場合にタイマー割り込みを使いますが、
そんなタイマー割り込みをArduinoで使う方法をまとめました。

こんにちは、北神です。
ESP32(Arduino)でタイマーが使いたかったので試してみました。
以下のソースを貼り付けるだけで、タイマー割り込みが使用できます。

//===========================================================//
// Timer Interrupt
//===========================================================//
hw_timer_t *timer1 = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR onTimer1()
{
portENTER_CRITICAL_ISR(&timerMux);
// 実行させたい関数をここに記載
example();
portEXIT_CRITICAL_ISR(&timerMux);
}

void Timer1_interrupt_setup(int usec)
{
timer1 = timerBegin(0, getApbFrequency()/1000000, true);
timerAttachInterrupt(timer1, &onTimer1, true);
timerAlarmWrite(timer1, usec, true);
timerAlarmEnable(timer1);
}

実行する際は、
Timer1_interrupt_setup(マイクロ秒) を記述して、その間隔で関数が実行されます。

ESP32では、HTTPの送信や受信で数秒程度、処理に時間がかかりますので、
その間にセンサーやスイッチの立ち上がりだけ見たい! ハードウェア特有の処理を済ませておきたい!という時に割り込みが使用できます。

ただ、何重にも割り込みは発生させることができませんし、割り込み後の処理で時間がかかる処理はご法度ですので、割り込みプログラムには留意が必要です。

ではでは。

ESP32でI2Cに接続されたデバイスの一覧を表示する方法(Arduino-IDEを使用)

ESP32でI2Cに接続されたデバイスを確認したい時ありませんか?

どのアドレスにデバイスがつながってるか、一覧で表示して欲しいですよね。

こんにちは、北神です。

RaspberryPiでは、i2cdetectというコマンドがあります。

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- 4a -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

この様な表示のものです。

これを、ESP32でも行いたい。
早速、ESP32(Arduino環境)で行えるライブラリが無いか調べました。

ズバッと、ありました。

https://www.arduinolibraries.info/libraries/i2cdetect

ダウンロードしてライブラリに反映します。

早速サンプルを試してみました。

#include 
#include 
void setup() {
    Serial.begin(115200);
    Wire.begin();
    delay(1000);
}
void loop() {
  i2cdetect();  // default range from 0x03 to 0x77
  delay(2000);
}

試しに、BMX055という9軸加速度センサを試しに接続しました。
このセンサーは、ワンチップですが、それぞれI2Cは3個分(加速度センサ、ジャイロセンサ、磁気センサそれぞれ)あり、
i2cdetectで見ると、3台分のアドレスが表示されました。

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- 13 -- -- -- -- -- 19 -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- 69 -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

これで、センサーのアドレスの確認や状態の認識ができますので、開発もスピーディーに行えると思います。

ではでは。