STM32マイコンでCAN-FD

自社製品CanLine-2 の製作にあたり、STM32 マイコンを用いた CAN-FD 通信の設定方法 について整理しました。
本記事では STM32CubeMX(HAL ドライバ)を使用した CAN-FD 通信 を対象とし、初期設定から送受信までを順に説明します。

開発環境STM32CubeMX(Version 6.5.0)(無料)
STM32CubeIDE(Version: 1.11.2)(無料)
デバッガJ-Link Plus
ボード自社製品(CanLine-2)用ボード
マイコンSTM32G474CET6
CANトランシーバMCP2542FD-E/SN
目次

初期設定

STM32でCAN-FD通信を行うため、CubeMXを使用してCANの初期設定を行います。

ピン設定

CAN-FDで使用するピンを以下のように設定します

  • PA11→FDCAN1_TX
  • PA12→FDCAN1_RX

各種パラメータの設定

CubeMXの画面左側のペリフェラル設定ツリーから「FDCAN1」を選択して、各種パラメータを設定します。

Frame Format

CAN-FDを使用する場合、「Frame Format」FD mode with BitRate Switchingにします。
これはCAN-FD フレームを使用し、データフェーズでビットレートを高速化する設定になります。

設定項目内容
Classic Mode従来の Classic CAN 通信モード。
最大 8 バイト、単一ビットレートで通信します。
FD mode without BitRate SwitchingCAN-FD 通信(BRS 無効)。
最大 64 バイト、データフェーズも同一ビットレートで通信します。
FD mode with BitRate SwitchingCAN-FD 通信(BRS 有効)。
データフェーズのみ高速ビットレートで通信します。

通信速度の設定方法

CAN-FDのフレームは調停フェーズ(Nominal Phase) とデータフェーズ(Data Phase) の2つに分かれています。そのため、通信速度は調停フェーズ用 と データフェーズ用 をそれぞれ個別に設定する必要があります。

調停フェーズのパラメータ

  • Nominal Prescaler
  • Nominal Time Seg1
  • Nominal Time Seg2

データフェーズのパラメータ

  • Data Prescaler
  • Data Time Seg1
  • Data Time Seg2

これらのパラメータを理解するには、Time Quantum1ビット時間の構成 を知る必要があります。

Time Quantum(TQ)とは、
CANの1ビット時間を構成する最小単位です。
TQは以下の式で求められます。
Time Quantam = Prescaler÷FDCANクロック
FDCANクロックはCubeMXのClock Configurationタブで確認できます。

1ビット時間の構成は、以下の3つの区間で構成されます

  • Sync Segment(固定:1TQ)
  • Time Segment 1(TSeg1)
  • Time Segment 2(TSeg2)

そのため、1ビット時間は次の式で表されます。
1ビット時間 = (1 + TSeg1 + TSeg2) × Time Quantum

設定例:調停フェーズ 500kbps(サンプリングポイント 80%)
ここでは以下の条件で設定します。

  • 通信速度:500kbps
  • サンプリングポイント:80%
  • FDCANクロック:80MHz

手順① Time Quantumを求める
Prescaler を 8 に設定すると、
Time Quantum = 8 ÷ 80MHz = 100ns

手順② 1ビット時間を計算する
500kbps の 1ビット時間は、
1 ÷ 500kbps = 2µs
Time Quantum が 100ns のため、
2µs ÷ 100ns = 20TQ
つまり、
1ビット = 合計 20TQ になるように設定します。

手順③ TSeg1 / TSeg2 を決める(80%)
サンプリングポイントは次の式で求められます。
サンプリングポイント= (1 + TSeg1) ÷ (1 + TSeg1 + TSeg2)
合計20TQ、サンプリングポイント80%になるようにすると、

  • TSeg1:15
  • TSeg2:4

(1 + 15) ÷ (1 + 15 + 4)= 16 ÷ 20= 80%

調停フェーズ(Nominal)の設定値まとめ

  • Nominal Prescaler:8
  • Nominal Time Seg1:15
  • Nominal Time Seg2:4

設定例:データフェーズ 2Mbps(サンプリングポイント 80%)
ここでは以下の条件で設定します。

  • 通信速度:2Mbps
  • サンプリングポイント:80%
  • FDCANクロック:80MHz

手順① Time Quantumを求める
Prescaler を 4 に設定すると、
Time Quantum = 4 ÷ 80MHz = 50ns

手順② 1ビット時間を計算する
2Mbps の 1ビット時間は、
1 ÷ 2Mbps = 0.5µs(=500ns)
Time Quantum が 50ns のため、
500ns ÷ 50ns = 10TQ
つまり、1ビット = 合計 10TQ になるように設定します。

手順③ TSeg1 / TSeg2 を決める(80%)
サンプリングポイント= (1 + TSeg1) ÷ (1 + TSeg1 + TSeg2)
合計10TQ、サンプリングポイント80%になるようにすると、

  • TSeg1:7
  • TSeg2:2

(1 + 7) ÷ (1 + 7 + 2)= 8 ÷ 10= 80%

データフェーズ(Data)の設定値まとめ

  • Data Prescaler:4
  • Data Time Seg1:7
  • Data Time Seg2:2

ポイントまとめ(理解のコツ)

  • 最初に Time Quantum を決める
  • 次に 1ビットあたりのTQ数 を決める
  • 最後に TSeg1 / TSeg2 を割り振る
  • サンプリングポイントは TSeg1の終端

「TQ → 合計TQ → サンプリングポイント」
の順で考えると迷いません。

CAN-FD送信

ここでは、STM32CubeMX で設定した FDCAN を使用してCAN / CAN-FD フレームを送信する方法を説明します。

送信処理の全体の流れ

CAN-FD の送信は、以下の手順で行います。

  1. FDCAN を開始する
  2. 送信ヘッダ(ID、DLC、FD/BRS設定)を準備する
  3. 送信データを設定する
  4. Tx FIFO に書き込んで送信する

    ① FDCAN の開始

    CubeMX で初期化した後、以下の関数で通信を開始します。

    HAL_FDCAN_Start(&hfdcan1);

    ※ 送信・受信ともに、この関数を呼び出す必要があります。

    ② 送信ヘッダの設定

    送信フレームの情報は FDCAN_TxHeaderTypeDef 構造体で指定します。

    FDCAN_TxHeaderTypeDef TxHeader;
    TxHeader.Identifier          = 0x123;                 // 送信ID
    TxHeader.IdType              = FDCAN_STANDARD_ID;     // 標準ID
    TxHeader.TxFrameType         = FDCAN_DATA_FRAME;      // データフレーム
    TxHeader.DataLength          = FDCAN_DLC_BYTES_8;     // DLC
    TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
    TxHeader.BitRateSwitch       = FDCAN_BRS_OFF;         // BRS設定
    TxHeader.FDFormat            = FDCAN_CLASSIC_CAN;     // Classic / FD
    TxHeader.TxEventFifoControl  = FDCAN_NO_TX_EVENTS;
    TxHeader.MessageMarker       = 0;

    ③DLC と FD / BRS の関係

    送信時は Frame Format と DLC の組み合わせに注意が必要です。

    設定内容
    FDCAN_CLASSIC_CANDLCは最大 8バイト
    FDCAN_FD_CANDLCは最大 64バイト
    BitRateSwitch = ONデータフェーズ高速化(CAN-FD)

    CAN-FD(64バイト+BRS ON)の例

    TxHeader.FDFormat     = FDCAN_FD_CAN;
    TxHeader.BitRateSwitch = FDCAN_BRS_ON;
    TxHeader.DataLength   = FDCAN_DLC_BYTES_64;

    ④ 送信データの設定

    uint8_t TxData[64] = {0};

    Classic CAN(8バイト)の場合は、先頭 8 バイトのみ使用されます。

    ⑤Tx FIFO に書き込んで送信

    準備したヘッダとデータを、Tx FIFO に登録します。

    HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData);

    この関数を呼び出すことで、FDCAN コントローラが自動的に送信を行います。

    送信前の注意点(重要)

    Tx FIFO が空いているか確認する
    高頻度送信を行う場合は、Tx FIFO の空き確認を行うと安全です。

    if (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) > 0) {
        HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData);
    }

    まとめ(送信処理)

    • HAL_FDCAN_Start() で通信開始
    • 送信条件は FDCAN_TxHeaderTypeDef で指定
    • DLC・FDFormat・BRS の組み合わせに注意
    • HAL_FDCAN_AddMessageToTxFifoQ() で送信

    CAN-FD 受信

    1. Rx FIFOを有効化する
    2. フィルタで Rx FIFO0 / FIFO1 を指定
    3. 割り込み(通知)を有効化
    4. Rx FIFO にデータが入る
    5. コールバック関数で受信処理を行う

    ①フィルタ設定(Rx FIFO指定)

    受信処理では フィルタ設定が必須です。フィルタで「どのFIFOに入れるか」を指定します。

    例:標準IDを FIFO0 に入れる設定

    FDCAN_FilterTypeDef sFilter;
    
    sFilter.IdType       = FDCAN_STANDARD_ID;
    sFilter.FilterIndex  = 0;
    sFilter.FilterType   = FDCAN_FILTER_MASK;
    sFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    sFilter.FilterID1    = 0x000;
    sFilter.FilterID2    = 0x000;
    
    HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilter);

    ※Maskモードで FilterID2=0x000 は“全ビットdon’t care”となるため 全IDを通す 例です

    ②割り込み(通知)の有効化

    Rx FIFO にメッセージが入ったことを通知するため、以下の割り込みを有効にします。

    HAL_FDCAN_ActivateNotification(
        &hfdcan1,
        FDCAN_IT_RX_FIFO0_NEW_MESSAGE,
        0
    );

    ③受信コールバック関数

    Rx FIFO に新しいメッセージが入ると、以下のコールバック関数が自動的に呼ばれます。

    void HAL_FDCAN_RxFifo0Callback(
        FDCAN_HandleTypeDef *hfdcan,
        uint32_t RxFifo0ITs)
    {
        FDCAN_RxHeaderTypeDef RxHeader;
        uint8_t RxData[64];
    
        if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE)
        {
            HAL_FDCAN_GetRxMessage(
                hfdcan,
                FDCAN_RX_FIFO0,
                &RxHeader,
                RxData
            );
    
            // ここに受信処理を書く
        }
    }

    ④DLC とデータ長の注意点

    受信時は、RxHeader.DataLength に**DLC(コード値)**が入ります。
    実際のバイト数はDLC → バイト数変換が必要です。

    uint32_t len = FdcanDlcToBytes(RxHeader.DataLength);
    __STATIC_INLINE uint8_t FdcanDlcToBytes(uint32_t dlc)
    {
    	switch (dlc) {
    		case FDCAN_DLC_BYTES_0:  return 0;
    		case FDCAN_DLC_BYTES_1:  return 1;
    		case FDCAN_DLC_BYTES_2:  return 2;
    		case FDCAN_DLC_BYTES_3:  return 3;
    		case FDCAN_DLC_BYTES_4:  return 4;
    		case FDCAN_DLC_BYTES_5:  return 5;
    		case FDCAN_DLC_BYTES_6:  return 6;
    		case FDCAN_DLC_BYTES_7:  return 7;
    		case FDCAN_DLC_BYTES_8:  return 8;
    		case FDCAN_DLC_BYTES_12: return 12;	// CAN-FD
    		case FDCAN_DLC_BYTES_16: return 16;
    		case FDCAN_DLC_BYTES_20: return 20;
    		case FDCAN_DLC_BYTES_24: return 24;
    		case FDCAN_DLC_BYTES_32: return 32;
    		case FDCAN_DLC_BYTES_48: return 48;
    		case FDCAN_DLC_BYTES_64: return 64;
    	    default:
    	        return 0;   // 異常値ガード
    	}
    }

    まとめ(受信処理)

    • 受信データは Rx FIFO に格納される
    • フィルタで FIFO0 / FIFO1 を指定する
    • 割り込み通知でコールバック処理を行う
    • DLC と実データ長の違いに注意

    おわりに

    本記事では、STM32を用いたCAN-FD通信の基本設定や実装例について解説しました。

    実際の現場では、これらの設定や動作検証を一つずつ行うのに、想像以上の時間と手間がかかります。

    ヒトミソフト開発では、STM32ベースで Classic CAN / CAN-FD の実通信検証にすぐ使えるUSB-CANインターフェース「CanLine-2」 を開発・提供しています。

    DLLも用意しているため、PCアプリケーションから直接CAN/CAN-FD通信を制御することが可能で、
    独自のモニタリングソフトや評価用ツールの開発にも対応できます。

    CAN-FD通信の評価やデバッグ、既存システムとの接続確認などを、より手軽に行いたい場合は、ぜひ CanLine-2 もご覧ください。

    よろしければシェアを!
    • URLをコピーしました!
    目次