2025年10月4日土曜日

ESP32-C6でCANを2ポート使ってみる

 モータドライバをCAN対応で作ったので、ESP32からコントロールしていたんだけども、ESP32-C6はCANが2つあるのでモータドライバのID変更が面倒なときは2ポートそれぞれに同じIDのモータドライバ接続できたら便利なんじゃ?という意味不明なことをやってみたくて買ってみた。せっかくデイジーチェーンできる規格なのにもったいない。(ただ新しいESP32シリーズを試したかっただけ

というわけでESP32-C6が使いやすい状態になっているSeeed Studio XIAO ESP32C6にしてみた。M5Stack NanoC6だとIOが少なすぎるしね…

今までのESP32シリーズのCANはSJA1000互換実装だったんだけど、ESP32-C6はCANの実装が変わっているようで今までのライブラリが使えなさそう。ESP32版SLCANを作ったときみたいにIDFのTWAIドライバを直接使えば良さそうなんだけど、TWAI driver v2ってのが出ていて、関数名にv2が付いてるっぽい。ESP32-C6はTWAI driver v2じゃないと動かないかも?

今回はArduino ESP32 v3.3.1を使用してみた。これならIDF5.5.1ベースなのでESP32-C6のDual TWAIにも対応しているはず…

#include "driver/twai.h"

#define CAN0_TX GPIO_NUM_2
#define CAN0_RX GPIO_NUM_21
#define CAN1_TX GPIO_NUM_22
#define CAN1_RX GPIO_NUM_23

static twai_handle_t twai0 = NULL;
static twai_handle_t twai1 = NULL;

void setup()
{
    Serial.begin(115200);

    twai_general_config_t g0 = {
        .mode = TWAI_MODE_NORMAL,
        .tx_io = CAN0_TX,
        .rx_io = CAN0_RX,
        .clkout_io = TWAI_IO_UNUSED,
        .bus_off_io = TWAI_IO_UNUSED,
        .tx_queue_len = 5,
        .rx_queue_len = 5,
        .alerts_enabled = TWAI_ALERT_NONE,
        .intr_flags = 0,
    };
    twai_timing_config_t t0 = TWAI_TIMING_CONFIG_250KBITS();
    twai_filter_config_t f0 = TWAI_FILTER_CONFIG_ACCEPT_ALL();
    esp_err_t ret = twai_driver_install_v2(&g0, &t0, &f0, &twai0);
    if (ret != ESP_OK) {
        Serial.printf("CAN0 install failed: %s\n", esp_err_to_name(ret));
    } else if ((ret = twai_start_v2(twai0)) != ESP_OK) {
        Serial.printf("CAN0 start failed: %s\n", esp_err_to_name(ret));
    } else {
        Serial.println("CAN0 started");
    }

    twai_general_config_t g1 = {
        .mode = TWAI_MODE_NORMAL,
        .tx_io = CAN1_TX,
        .rx_io = CAN1_RX,
        .clkout_io = TWAI_IO_UNUSED,
        .bus_off_io = TWAI_IO_UNUSED,
        .tx_queue_len = 5,
        .rx_queue_len = 5,
        .alerts_enabled = TWAI_ALERT_NONE,
        .intr_flags = 0,
    };
    twai_timing_config_t t1 = TWAI_TIMING_CONFIG_250KBITS();
    twai_filter_config_t f1 = TWAI_FILTER_CONFIG_ACCEPT_ALL();

    ret = twai_driver_install_v2(&g1, &t1, &f1, &twai1);
    if (ret != ESP_OK) {
        Serial.printf("CAN1 install failed: %s\n", esp_err_to_name(ret));
    } else if ((ret = twai_start_v2(twai1)) != ESP_OK) {
        Serial.printf("CAN1 start failed: %s\n", esp_err_to_name(ret));
    } else {
        Serial.println("CAN1 started");
    }
}

void loop()
{
    if (twai0) {
        twai_message_t msg0 = {0};
        msg0.identifier = 0x100;
        msg0.data_length_code = 2;
        msg0.data[0] = 0x01;
        msg0.data[1] = 0x02;

        esp_err_t ret = twai_transmit_v2(twai0, &msg0, pdMS_TO_TICKS(100));
        if (ret == ESP_OK) {
            Serial.println("CAN0 TX OK");
        }
    }

    if (twai1) {
        twai_message_t msg1 = {0};
        msg1.identifier = 0x200;
        msg1.data_length_code = 2;
        msg1.data[0] = 0x03;
        msg1.data[1] = 0x04;

        esp_err_t ret = twai_transmit_v2(twai1, &msg1, pdMS_TO_TICKS(100));
        if (ret == ESP_OK) {
            Serial.println("CAN1 TX OK");
        }
    }
    delay(1000);
}

SLCANを移植したときに使ったTWAI driver v1と違ってDEFAULT マクロがないのでピンアサイン以外も全部手動で設定しないといけないのが面倒だけども。もはやArduinoでIDFのコード動かしているレベルでArduino感がなくなってしまったので送信の部分だけは関数にしておきたいな。

CANトランシーバももちろん2セット必要なのでSN65HVD230を使用してみた。

0 件のコメント:

コメントを投稿