背景
マイコンstm32h753ziはCAN FDの回路を積んでいます。使い方が気になったのでArduino環境で呼び出して使ってみました。
備忘録として対応内容を記事に残します。
使ったもの
- nucleo-h753zi
今回利用するマイコンであるstm32h753ziの開発ボードです。 - MCP2562FD
CANのトランシーバーです。 - ブレッドボード
部品の信号線を引き出します。 - ジャンパワイヤ
ブレッドボード上は硬いもの、ブレッドボード間は柔らかいものを利用しました。 - 120Ω抵抗
CAN busの終端抵抗に利用します。 - microB-USBケーブル
nucleoへのプログラム書き込みに利用します。 - 通信相手 teensy4.1とCAN FD用の回路
前回取り組んだteensy4.1でCAN FDを使えるようにした構成との通信を行います。
通信速度1Mbpsではstm32h753ziと同期できなかったので、基本速度を500kbps、FD部分を2Mbpsにして通信しました。 - プログラム書き込み環境 PlatformIO
ubuntu24.04 にVSCodeとPlatformIOをインストールした環境を使いました
回路
今回はCAN1の回路を使います。stm32h753ziの説明書でCAN1と検索すると、それ用のピンが分かります。
今回はnucleoで分かりやすく引き出されているPD0とPD1を使います。
nucleo-h753ziのピン配列を示す説明書でPD0とPD1の場所を探すとCN9端子にあると分かります。
実機だとここです。
CN9端子のCANと書かれた部分のGNDに近い側がPD0でCAN RX、GNDから遠い側がPD1でCAN TXです。
上記のPD1とPD2に加えて5V、3.3V、GNDをCANのトランシーバーに繋ぎます。
繋ぐとこうなりました。
この回路を後で使います。
ライブラリ準備 h753zi対応版acanfd-stm32
h743ziに対応しているライブラリacanfd-stm32をh753ziでも使えるようにした変更したライブラリを使います。変更内容のpull requestをadanfd-stm32に対して出していますが、1年ほど動きが無いライブラリなので、取り込まれる可能性が低そうです。
そのため、自分が変更を加えたライブラリをplatformioで取り込んで使います。
platformio.iniのlib_depsにgithubのブランチを指定すれば使えます。
lib_deps =
https://github.com/asukiaaa/acanfd-stm32#feature/support-h753zi
acanfd-stm32を利用するCAN FD通信プログラム
下記の処理を行うプログラムです。acanfd-stm32のサンプルプログラムH743ZI2-LoopBackDemoを書き換えて作成しました。
- PD0をCAN RX、PD1をCAN TXに利用
- 基本通信速度 500kbps
- FD部分の通信速度 2Mbps
- 2秒毎にCAN FDの情報配信
- 8bytesと64bytesの配信を交互に実施
- 情報を受信するたびにLEDのON OFFを切り替え
- 受信内容をシリアル通信で配信
#include <Arduino.h>
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(500 * 1000, DataBitRateFactor::x4);
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.mModuleMode = ACANFD_STM32_Settings::EXTERNAL_LOOP_BACK;
// settings.mTxPin = PB_9;
// settings.mRxPin = PB_8;
settings.mTxPin = PD_1;
settings.mRxPin = PD_0;
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;
bool flagSend64bytes = false;
auto sendIntervalMs = 2000UL;
void loop() {
if (millis() - can1SentAt >= sendIntervalMs) {
can1SentAt = millis();
CANFDMessage message;
message.id = 0x7FF;
message.len = flagSend64bytes ? 64 : 8;
flagSend64bytes = !flagSend64bytes;
for (int i = 0; i < message.len; ++i) {
message.data[i] = i + 1;
}
message.data[0] = can1SentAt / 1000;
const uint32_t sendStatus = fdcan1.tryToSendReturnStatusFD(message);
Serial.println("FDCAN1 send " + String(message.len) + " bytes status " +
String(sendStatus) + " 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、FD部分の通信速度2Mbpsを意味します。
500kの4倍だから2Mbpsということです。
ACANFD_STM32_Settings settings(500 * 1000, DataBitRateFactor::x4);
動作確認
Teensy4.1と通信させます。繰り返しになりますが、Teensy4.1も基本部分500kbps、FD部分2Mbpsで通信させます。
基本部分1Mbpsだと同期が取れず通信できなかったので、500kbpsにしました。
繋いで通信させます。
h753ziのログです。
期待通りに8bytesと64bytesの情報を受信しました。
FDCAN1 send 64 bytes status 0 at 16000
FDCAN1 received at 17411
id: 294
data: 18 2 3 4 5 6 7 8
FDCAN1 send 8 bytes status 0 at 18000
FDCAN1 received at 19449
id: 1617
data: 20 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
Teensy4.1のログです。
こちらも期待通りに受信しました。
sent 64bytes at 16008
received 64bytes at 16623
rx.id: 2047
rx.buf 16 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
sent 8bytes at 18009
received 8bytes at 18587
rx.id: 2047
rx.buf 18 2 3 4 5 6 7 8
しかしながら、たまに同期外れが発生して以後通信不能になるので、まだ把握できていないCANの再起動処理が必要そうです。
おわり
stm32h753ziでCAN FD通信ができました。気になっていた機能の使い方が分かって良かったです。
参考
acanfd-stm32h753ziでも使えるようにした変更







0 件のコメント :
コメントを投稿