ESP32をESP-IDFで使う。SPIのCS制御をコールバックでやってみたら

カテゴリー: ESP32  タグ:

ESP-WROOM-32EをESP-IDFで使う覚書。

過去にdsPICやPSoC5LP、mbed(STM32)でFreeRTOSを実装した流れでESP32でもRTOSを使いたいと思い、FreeRTOS搭載のESP-IDF開発モードで悪戦苦闘中!(Arduinoモードでも使えることが後に判明・・・)

まずは簡単なところから・・・HSPIマスタの送信。SPIイニシャルのコードをesp-idfサンプル「spi_master」「lcd」から抜粋してのテストです。

開発プラットホーム:VSCODE+PlatoformIO(ESP-IDFモード)

通常CSはハードウェアで制御

CSピンは制御はSPIのイニシャルで指定する

HSPIの初期化ルーチン例です。警告防止にサンプルでは省略されている変数の初期化も入れてます。

void HSPI::hspi_init() {
    esp_err_t ret;
    spi_bus_config_t buscfg={
        .mosi_io_num=PIN_NUM_MOSI,
        .miso_io_num=PIN_NUM_MISO,
        .sclk_io_num=PIN_NUM_CLK,
        .quadwp_io_num=-1,
        .quadhd_io_num=-1,
        .max_transfer_sz=32,
        .flags = 0,
        .intr_flags = 0,
    };
    spi_device_interface_config_t devcfg={
        .command_bits = 0,
        .address_bits = 0,
        .dummy_bits = 0,
        .mode=0,                        //SPI mode 0
        .duty_cycle_pos = 0,
        .cs_ena_pretrans = 0,
        .cs_ena_posttrans = 0,
        .clock_speed_hz=1*1000*1000,    //Clock out at 1MHz
        .input_delay_ns = 0,
        .spics_io_num = PIN_NUM_CS,     //ここでCSピンを指定しておく
        .flags = 0,
        .queue_size=7,                  //We want to be able to queue 7 transactions at a time
        .pre_cb = nullptr,     // 事前コールバック関数指定しない
        .post_cb = nullptr,    // 事後コールバック関数指定しない
    };
    //Initialize the SPI bus
    ret=spi_bus_initialize(LCD_HOST, &buscfg, DMA_CHAN);
    ESP_ERROR_CHECK(ret);
    //Attach the LCD to the SPI bus
    ret=spi_bus_add_device(LCD_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);
}

連続出力の波形を見てみる

SCLK(上段)とCS(下段)の波形

CSONから1stクロックまで約600ns。lastクロックからCSOFFまでは約1.5us

送信はspi_device_polling_transmit関数。送信間隔は結構長い。

CSをコールバック関数で制御してみる

通常、CS制御をコールバック関数でやることはなく、LCDのD/C制御などハードウェアでできない信号を制御するためのものです。過去に送信バッファの送信終了タイミングをつかむのに苦労したMCUがあったので、後学のための実験です。

というわけで、初期化ルーチンとコールバック関数。CSはgpioとして配置

// 事前コールバック関数の実装
static void pre_transfer_callback(spi_transaction_t *t) {
    gpio_set_level(PIN_NUM_CS, 0);  // for CS test
}

// 事後コールバック関数の実装
static void post_transfer_callback(spi_transaction_t *t) {
    gpio_set_level(PIN_NUM_CS, 1);  // for CS test
}

void HSPI::hspi_init() {
    esp_err_t ret;
    spi_bus_config_t buscfg={
        .mosi_io_num=PIN_NUM_MOSI,
        .miso_io_num=PIN_NUM_MISO,
        .sclk_io_num=PIN_NUM_CLK,
        .quadwp_io_num=-1,
        .quadhd_io_num=-1,
        .max_transfer_sz=32,
        .flags = 0,
        .intr_flags = 0,
    };
    spi_device_interface_config_t devcfg={
        .command_bits = 0,
        .address_bits = 0,
        .dummy_bits = 0,
        .mode=0,                        //SPI mode 0
        .duty_cycle_pos = 0,
        .cs_ena_pretrans = 0,
        .cs_ena_posttrans = 0,
        .clock_speed_hz=1*1000*1000,    //Clock out at 1MHz
        .input_delay_ns = 0,
        .spics_io_num = nullptr,     //CSピン使用しない
        .flags = 0,
        .queue_size=7,                  //We want to be able to queue 7 transactions at a time
        .pre_cb = pre_transfer_callback,  // 事前コールバック関数ポインタを指定
        .post_cb = post_transfer_callback,  // 事後コールバック関数ポインタを指定
    };
    //Initialize the SPI bus
    ret=spi_bus_initialize(LCD_HOST, &buscfg, DMA_CHAN);
    ESP_ERROR_CHECK(ret);
    //Attach the LCD to the SPI bus
    ret=spi_bus_add_device(LCD_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);
    gpio_reset_pin(PIN_NUM_CS);         // CSピンをgpioとしてリセット
    gpio_set_direction(PIN_NUM_CS,GPIO_MODE_OUTPUT);    // CSピンoutput
}

連続出力の波形を見てみる

CSONから1stクロックまで約1.3us。lastクロックからCSOFFまでは約8us

調べてませんが、送信終了割り込みを使っているとすればこの遅れは理解できますが、それにしても遅れはかなり大きいです

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

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