2026年8月23日日曜日

stm32h753ziのCAN 2.0をArduinoで使う


背景

前回CANFDの使い方を把握したMCU stm32h753ziでCAN 2.0(classic)も使えそうだったので動かし方を把握しました。
備忘録として記事を残します。

使ったもの


プログラム: CANMessageを送信

CANFDのときはCANFDMEssageを使って送信しますが、CAN 2.0を送信したい場合はCANMessageを使って送信します。
受信はCANFDと同様の処理でできました。
ライブラリのサンプルコードissueでのCAN classicに関する情報を元に作成したプログラムを共有します。

static const uint32_t FDCAN1_MESSAGE_RAM_WORD_SIZE = 2000;
static const uint32_t FDCAN2_MESSAGE_RAM_WORD_SIZE = 0;

#include <ACANFD_STM32.h>

//-----------------------------------------------------------------

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
Serial.begin(115200);

// ACANFD_STM32_Settings settings(1000 * 1000, DataBitRateFactor::x1);
ACANFD_STM32_Settings settings(500 * 1000, DataBitRateFactor::x4);
// ACANFD_STM32_Settings settings(500 * 1000, DataBitRateFactor::x2);
// ACANFD_STM32_Settings settings(125 * 1000, DataBitRateFactor::x4);
// ACANFD_STM32_Settings settings(125 * 1000, DataBitRateFactor::x8);

Serial.print("Bit Rate prescaler: ");
Serial.println(settings.mBitRatePrescaler);
Serial.print("Arbitration Phase segment 1: ");
Serial.println(settings.mArbitrationPhaseSegment1);
Serial.print("Arbitration Phase segment 2: ");
Serial.println(settings.mArbitrationPhaseSegment2);
Serial.print("Arbitration SJW: ");
Serial.println(settings.mArbitrationSJW);
Serial.print("Actual Arbitration Bit Rate: ");
Serial.print(settings.actualArbitrationBitRate());
Serial.println(" bit/s");
Serial.print("Arbitration sample point: ");
Serial.print(settings.arbitrationSamplePointFromBitStart());
Serial.println("%");
Serial.print("Exact Arbitration Bit Rate: ");
Serial.println(settings.exactArbitrationBitRate() ? "yes" : "no");
Serial.print("Data Phase segment 1: ");
Serial.println(settings.mDataPhaseSegment1);
Serial.print("Data Phase segment 2: ");
Serial.println(settings.mDataPhaseSegment2);
Serial.print("Data SJW: ");
Serial.println(settings.mDataSJW);
Serial.print("Actual Data Bit Rate: ");
Serial.print(settings.actualDataBitRate());
Serial.println(" bit/s");
Serial.print("Data sample point: ");
Serial.print(settings.dataSamplePointFromBitStart());
Serial.println("%");
Serial.print("Exact Data Bit Rate: ");
Serial.println(settings.exactDataBitRate() ? "yes" : "no");

settings.mTxPin = PD_1;
settings.mRxPin = PD_0;
settings;
uint32_t errorCode = fdcan1.beginFD(settings);
Serial.print("FDCAN1 Message RAM required minimum size: ");
Serial.print(fdcan1.messageRamRequiredMinimumSize());
Serial.println(" words");
if (0 == errorCode) {
Serial.println("fdcan1 ok");
} else {
Serial.print("Error can: 0x");
Serial.println(errorCode, HEX);
}
}

uint32_t can1SentAt = 0;
auto sendIntervalMs = 2000UL;

void loop() {
if (millis() - can1SentAt >= sendIntervalMs) {
can1SentAt = millis();

CANMessage messageClassic;
messageClassic.id = 0x0f;
messageClassic.len = 8;
for (int i = 0; i < messageClassic.len; ++i) {
messageClassic.data[i] = i + 1;
}
messageClassic.data[0] = can1SentAt / 1000;
uint32_t sendStatusClassic = fdcan1.tryToSendReturnStatusFD(messageClassic);
Serial.println("FDCAN1 send classic " + String(sendStatusClassic) + " at " +
String(millis()));
}

CANFDMessage messageFD;
if (fdcan1.receiveFD0(messageFD)) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Serial.println("FDCAN1 received at " + String(millis()));
Serial.print("id: ");
Serial.println(messageFD.id);
Serial.print("data:");
for (uint8_t i = 0; i < messageFD.len; i++) {
Serial.print(" ");
Serial.print(messageFD.data[i]);
}
Serial.println();
}
}

通信速度は500kbpsです。
CAN classicはFDを使わないので、x4の部分は何でも良いです。
  ACANFD_STM32_Settings settings(500 * 1000, DataBitRateFactor::x4);

CANMessageクラスを利用して情報を送信します。
    CANMessage messageClassic;
messageClassic.id = 0x0f;
messageClassic.len = 8;
for (int i = 0; i < messageClassic.len; ++i) {
messageClassic.data[i] = i + 1;
}
messageClassic.data[0] = can1SentAt / 1000;
uint32_t sendStatusClassic = fdcan1.tryToSendReturnStatusFD(messageClassic);
Serial.println("FDCAN1 send classic " + String(sendStatusClassic) + " at " +
String(millis()));

CANFDMessageクラスを利用した送信処理があるとCANの通信線がCAN2.0から外れてCAN FDに対応していない装置の動作が停止したりするので、CAN2.0を維持したい場合はCANFDMessageでの送信処理は行わないのが良いです。

動作確認

前回と同様に繋いで通信させます。


stm32h753ziでTeensy4.1が送信するCAN2.0の情報を受信できました。
FDCAN1 send classic 0 at 742000
FDCAN1 received at 743708
id: 338
data: 1 2 3 4 5 6 7 8

Teensy4.1側もstm32h753ziが送信するCAN2.0の情報を受信できました。
teensy sent at 6966181
MB 99 OVERRUN: 0 LEN: 8 EXT: 0 TS: 6059 ID: F Buffer: EA 2 3 4 5 6 7 8 at 6966432

おわり

stm32h753ziでCAN 2.0 (CAN classic)の通信ができました。
ライブラリが便利に作られていて、書き方が分かったらすぐに実現できて良かったです。

参考

stm32h753ziのCAN FDをArduinoで使う
Using CAN 2.0 Classic Frame Format #1

0 件のコメント :