AtomS3でCAN通信

# 概要
仕事で必要になるかと思い、勉強も兼ねてAtomS3とパソコン間で相互にCAN通信を行ってみました。
色々なサイトを検索し、各種ライブラリを試したのですがエラーを解決することができず、
最終的に[メーカーサイトの例](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/twai.html)を参考になんとか完成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/ea831337-b194-1eff-2ff8-87bc117dc329.png)


# 環境
エディタ：VisualStudioCode（拡張機能：PlatformIO IDE）
ドライバー："driver/gpio.h"、"driver/twai.h"
CANコンバータ_AtomS3用：https://amzn.asia/d/5gZTPeh
CANコンバータ_パソコン用：https://amzn.asia/d/93V5su6
パソコン側ソフト：microbus（[こちらのメーカーサイト](https://github.com/INNO-MAKER/usb2can)よりダウンロード）

# 使用方法
1. パソコン用のCANコンバータを接続します。Windows10は接続するだけで使えるようです。
2. 「microbus」を起動し、接続するCANコンバータを設定します。
　①設定ボタン
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/dce36d2b-e68e-342b-a863-7197ce3fe3bd.png)
　②AddNetworkボタン
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/802c0d4d-8b3d-5564-70bb-21596ab12cb7.png)
　③左ペインでinterfaces選択→AddInterfaceボタン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/f634a4c1-4e11-81a4-735a-5b541c2fbb5a.png)
　④必要なBitrateを選択して、OKボタン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/25c4ab1b-bcd6-74fe-c29e-8544c28e3480.png)

　⑤Startボタンを押す。接続するネットワークを選択してOKボタン。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/c138c360-ce4d-6f39-2ad8-ebd97a5f224a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/8d974bc5-fda9-5ba7-dd2f-1fc1b6b5f47c.png)

3. AtomS3をPCと接続しシリアル通信を開始します。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/ca4a6f04-6b26-1848-bc13-595128fb2ecd.png)
4. AtomS3　⇒　パソコンへの送信
　Send as Text欄に1を入力し、送信ボタンを押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/2003cb79-81b1-72a5-5033-3e2e78b5ade9.png)

パソコン側で受信結果が表示されます。設定したCAN ID（10）、データ（255）が反映されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/855434b6-6c80-f646-8d9d-5abb9676b0ba.png)

同様に2を送信すると設定したCAN ID（20）、データ（65535）が送信できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/c99c4c7b-0078-afaf-901d-a9ca189e0a6a.png)

5.パソコン　⇒　AtomS3への送信
microbus右下に必要な情報ID（Address)、データ（Payload）記入しSend Singleボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/b4c1a1fe-3781-7c6b-2f1a-d10ea7d6b77e.png)

AtomS3で受信したデータがシリアル出力されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611426/8932a390-75de-1d5e-61bc-6765e6870b81.png)


# AtomS3 コード
``` cpp
#include <Arduino.h>
#include "driver/gpio.h"
#include "driver/twai.h"
#include <M5AtomDisplay.h>
#include <M5Unified.h>
//#include <stdlib.h>

#define CAN_RX_PIN GPIO_NUM_1
#define CAN_TX_PIN GPIO_NUM_2

twai_message_t message;

// TWAI Configuration & Installation
void init_CAN(){
  //Initialize configuration structures using macro initializers
  twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(CAN_TX_PIN, CAN_RX_PIN, TWAI_MODE_NORMAL);
  twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
  twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

  // Install TWAI driver
  if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK)
  {
    USBSerial.print("Driver installed\n");
  } else {
    USBSerial.print("Failed to install driver\n");
    return;
  }

  // Start TWAI driver
  if (twai_start() == ESP_OK) {
      USBSerial.print("Driver started\n");
  } else {
      USBSerial.print("Failed to start driver\n");
      return;
  }
}

void send_CAN(int ID,int value){
  message.identifier = ID;//ID設定
  //　int⇒byte配列変換
  byte* bytes = (byte*)&value; // int値の先頭アドレスをbyteポインタにキャストする
  for (int i = 0; i < sizeof(value); i++) {
  message.data[i] = bytes[i]; // ポインタからbyte値を取得する
  }

  // Queue message for transmission
  if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
      USBSerial.printf("Message queued for transmission\n");
  } else {
      USBSerial.printf("Failed to queue message for transmission\n");
  }
}

void receive_CAN(){
  USBSerial.printf("Message received\n");
  //Process received message
  if (message.extd) {
      USBSerial.printf("Message is in Extended Format\n");
  } else {
      USBSerial.printf("Message is in Standard Format\n");
  }
  USBSerial.printf("ID is %d\n", message.identifier);
  if (!(message.rtr)) {
      for (int i = 0; i < message.data_length_code; i++) {
          USBSerial.printf("Data byte %d = %d\n", i, message.data[i]);
      }
  }
}


void setup() {

  // AtomS3設定
  auto cfg = M5.config();
  M5.begin(cfg);
  USBSerial.begin(115200);

  // CAN初期設定 
  init_CAN();
  message.extd = 0;// 0:標準フォーマット　1:拡張フォーマット
  message.data_length_code = 8;//DLC 8byte

  // Display設定
  M5.Display.init();
  M5.Display.setRotation(0);
  M5.Display.setFont(&fonts::lgfxJapanGothicP_12);
  M5.Display.setTextColor(WHITE, BLACK);

  // Title表示
  M5.Display.setCursor(0,0);
  M5.Display.println("CANテスト");
}


void loop() {

//Wait for message to be received
if (twai_receive(&message, pdMS_TO_TICKS(10)) == ESP_OK) {  
    receive_CAN();
} 

if(USBSerial.available() > 0) {
    // USBSerialデータ受信
    char ch = USBSerial.read();
      if(ch == '1'){
        send_CAN(10,255);//CANデータ送信(ID,Value)
      }else if(ch == '2'){
        // CANデータ送信
        send_CAN(20,65535);//CANデータ送信(ID,Value)
      }
}

  delay(10);
}
```
# 分からない点
 (twai_receive(&message, pdMS_TO_TICKS(10)) == ESP_OK)のところで
受信待ち時間を設定していますが、この値の設定をどうすれば良いのかがいまいち分かりません。
サンプル例では10秒で設定されていましたが、そのままだとAtomS3→パソコンへの送信が最大10秒程度
待たされることになるので、待ち時間を少なくなるように10msecに設定しています。
動作的にには問題はなさそうでした。


# 参考サイト
https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/twai.html

https://qiita.com/ryokurta256/items/7adf1e9e1f987d248a1f

https://tekuteku-embedded.xyz/2022/02/26/esp32%E3%81%A7can%E9%80%9A%E4%BF%A1/