RX660 CAN通信で2回目のメッセージ送信ができない

お世話になります。

RX660を使ってCAN通信を実装しているのですが、送信バッファ0を初めて使用したメッセージは送信できるのですが,

2回目以降は送信しようとしても送信されません。

どうしたら、送信されるようになるでしょうか?

何がわるいのでしょうか?

対応策等教えていただけないでしょうか

よろしくお願いします。

プログラムは下記になります。

#include "r_smc_entry.h"
#include "r_canfd_rx_pinset.h"

#include "r_canfd_rx_if.h"
// /** CANFD on CANFD Instance. */
// extern const can_instance_t g_canfd0;

// /** Access the CANFD instance using these structures when calling API functions directly (::p_api is not used). */
// extern canfd_instance_ctrl_t g_canfd0_ctrl;
// extern can_cfg_t g_canfd0_cfg;
// extern canfd_extended_cfg_t g_canfd0_extended_cfg;
// extern can_bit_timing_cfg_t g_canfd0_bit_timing_cfg;
// extern can_bit_timing_cfg_t g_canfd0_data_timing_cfg;

// /* Global configuration (referenced by all instances) */
// extern canfd_global_cfg_t g_canfd_global_cfg;

#define CAN_BUFFER_NUMBER_0 (0U) //バッファ番号
#define ZERO (0U)
#define CAN_ID (0x1100) //送信フレームのID
#define CAN_CLASSIC_FRAME_DATA_BYTES (8U) //従来のフレームのデータ長コード
#define SIZE_8 (8u)

can_frame_t g_canfd_tx_frame; //CAN FD送信フレーム
can_frame_t g_canfd_rx_frame;

#define RESET_VALUE (0x00)

/* rxフレームのステータス情報を格納する変数*/
can_info_t can_rx_info =
{
    .error_code = RESET_VALUE,
    .error_count_receive = RESET_VALUE,
    .error_count_transmit = RESET_VALUE,
    .rx_fifo_status = RESET_VALUE,
    .rx_mb_status = 1,
    .status = RESET_VALUE,
};
/* 承認フィルタ配列パラメータ CANFD_CFG_AFL_CH0_RULE_NUM = 1 */
/* 承認フィルタ配列パラメータ */
#define CANFD_FILTER_ID (0x00001000)
#define MASK_ID (0x0FFF0000)
#define MASK_ID_MODE (1)
//#define ZERO (0U) //Array Index value
const canfd_afl_entry_t p_canfd0_afl[CANFD_CFG_AFL_CH0_RULE_NUM] =
{
    /* 拡張IDが0x1000~0x1FFFのメッセージを承認 */
    /* 承認するID、ID種別、フレーム種別を指定します。*/
    {
        CANFD_FILTER_ID,
        0,
        CAN_FRAME_TYPE_DATA,
        CAN_ID_MODE_EXTENDED,
        MASK_ID,
        0,
        ZERO,
        MASK_ID_MODE,
        (canfd_minimum_dlc_t)ZERO,
        0,
        CANFD_RX_MB_0,
        0,
        CANFD_RX_FIFO_0
    },
};

void main(void);
void sw2_func(void);
void can_operation(void);
static void can_write_operation(can_frame_t can_transmit_frame);
void can_read_operation(void);
void canfd0_callback(can_callback_args_t *p_args);

static uint8_t su1_dummy;

void main(void)
{
    g_canfd0_extended_cfg.p_afl = p_canfd0_afl;
    g_canfd0_cfg.p_callback = canfd0_callback;
    /* 公称レート:1Mbps; DLL:40MHz */
    g_canfd0_bit_timing_cfg.baud_rate_prescaler = 1;
    g_canfd0_bit_timing_cfg.synchronization_jump_width = 1;
    g_canfd0_bit_timing_cfg.time_segment_1 = 20;
    g_canfd0_bit_timing_cfg.time_segment_2 = 19;
    /* 送信するtxフレームデータを設定 */
    for( uint16_t j = 0; j < SIZE_8; j++)
    {
        g_canfd_tx_frame.data[j] = (uint8_t) (j + 1);
    }
    su1_dummy = 0;

    /* Initialize Pin Mode */
    R_CANFD_PinSet_CANFD0();

    fsp_err_t tst_err1 = FSP_SUCCESS;
    /* APIの初期化*/
    tst_err1 = R_CANFD_Open(&g_canfd0_ctrl, &g_canfd0_cfg);
    if (tst_err1 != FSP_SUCCESS)
    {
        su1_dummy = 1;
    }

    fsp_err_t tst_err5 = FSP_SUCCESS;
    tst_err5 = R_CANFD_ModeTransition(&g_canfd0_ctrl, CAN_OPERATION_MODE_NORMAL, (can_test_mode_t) CAN_TEST_MODE_LOOPBACK_INTERNAL);
    if (tst_err5 != FSP_SUCCESS)
    {
        su1_dummy = 5;
    }

    while(1)
    {
        /* 新規メッセージの有無を確認... */
        can_read_operation();
        /* Delay 5000 milliseconds before returning */
        R_BSP_SoftwareDelay(1000, BSP_DELAY_MILLISECS);
        /* sw2を押下してメッセージをCANバスに送信 */
        //read_switches();
        sw2_func();
        /* Delay 5000 milliseconds before returning */
        R_BSP_SoftwareDelay(1000, BSP_DELAY_MILLISECS);
    }
}

/* sw2の押下時にsw2_func()を呼び出す */
void sw2_func(void)
{
    can_operation();
}/* sw2_func()の終了*/

void can_operation(void)
{
    /* 送信フレームパラメータの更新 */
    g_canfd_tx_frame.id = CAN_ID;
    g_canfd_tx_frame.id_mode = CAN_ID_MODE_EXTENDED;
    g_canfd_tx_frame.type = CAN_FRAME_TYPE_DATA;
    /* 従来のCAN 8バイト */
    g_canfd_tx_frame.data_length_code = CAN_CLASSIC_FRAME_DATA_BYTES;
    g_canfd_tx_frame.options = ZERO;
    // 送信データ
    g_canfd_tx_frame.data[0] = g_canfd_rx_frame.data[0] + 1;
    if (g_canfd_tx_frame.data[0] == 255)
    {
        g_canfd_tx_frame.data[0] = 0;
    }
    /* 従来のCANフレームでデータを送信 */
    can_write_operation(g_canfd_tx_frame);
}

static void can_write_operation(can_frame_t can_transmit_frame)
{
    fsp_err_t tst_err2 = FSP_SUCCESS;
    /* tx_frameでバッファ#0からデータを送信 */
    tst_err2 = R_CANFD_Write(&g_canfd0_ctrl, 0, &can_transmit_frame);
    if (tst_err2 != FSP_SUCCESS)
    {
        su1_dummy = 2;
    }
}

void can_read_operation(void)
{
    fsp_err_t tst_err3 = FSP_SUCCESS;
    /* CAN FD送信のステータス情報を取得 */
    tst_err3 = R_CANFD_InfoGet(&g_canfd0_ctrl, &can_rx_info);
    if (tst_err3 != FSP_SUCCESS)
    {
        su1_dummy = 3;
    }
    /* FIFO内に受信したデータがあるか確認 */
    if(can_rx_info.rx_mb_status)
    {
        fsp_err_t tst_err4 = FSP_SUCCESS;
        /* 受信した入力フレームの読み出し */
        tst_err4 = R_CANFD_Read(&g_canfd0_ctrl, ZERO, &g_canfd_rx_frame);
        if (tst_err4 != FSP_SUCCESS)
        {
            su1_dummy = 4;
        }
    }
}

void canfd0_callback(can_callback_args_t *p_args)
{
    switch (p_args->event)
    {
        case CAN_EVENT_TX_COMPLETE:
        case CAN_EVENT_RX_COMPLETE:
            su1_dummy = 99;
            break;
        case CAN_EVENT_ERR_WARNING:             //error warning event
        case CAN_EVENT_ERR_PASSIVE:             //error passive event
        case CAN_EVENT_ERR_BUS_OFF:             //error Bus Off event
        case CAN_EVENT_BUS_RECOVERY:            //Bus recovery error event
        case CAN_EVENT_MAILBOX_MESSAGE_LOST:    //overwrite/overrun error event
        case CAN_EVENT_ERR_BUS_LOCK:            // Bus lock detected (32 consecutive dominant bits).
        case CAN_EVENT_ERR_CHANNEL:             // Channel error has occurred.
        case CAN_EVENT_TX_ABORTED:              // Transmit abort event.
        case CAN_EVENT_ERR_GLOBAL:              // Global error has occurred.
            break;
    }
}
Parents
  • データ送信後

    CANFD.TMSR[0].BIT.TXRF

    に送信結果が入りますので、どこかでクリアしてください。(送信割り込みを使った場合は割り込みルーチン内など)

    今回は、送信割り込みは有効化されていないようですので、例えば送信前に

    /* sw2の押下時にsw2_func()を呼び出す */
    void sw2_func(void)
    {
        CANFD.TMSR[0].BIT.TXRF = 0;  //追加
        can_operation();
    }/* sw2_func()の終了*/

     上記の様に変更すれば、2回目以降もデータが出力されると思います。

    なお、送信データが出ない件とは関係ありませんが、TSEGの設定値がCANFDCLK=40MHzの値で設定されています。RX660を最大動作周波数で動かした場合は、CANFDCLK=60MHz(もしくは30MHz)になると思います。(上記のコードはループバックで動かしているようですが、通常モードにして実際に通信相手をつなぐと、想定した1Mbpsではなく中途半端な通信速度となり通信が通らないかも知れません。)

  • ご回答, ご指摘, 大変ありがとうございます。
    CANFD.TMSR[0].BIT.TXRF
    を実施することで2回目以降も送信できることを確認できました。

    通常モードにして実際に通信相手をつなぐと、想定した1Mbpsではなく中途半端な通信速度となり通信が通らないかも知れません
    ご指摘頂いている通り, 外部通信もうまくいっていませんでした。計算しなおして試してみたいと思います。

    本当に助かりました。ありがとうございました。

  • さま

    上記コードでは、TSEG1とTSEG2の値がほとんど同じ、1Mbpsなので1usのパルス幅のちょうど真ん中ぐらいでデータをサンプリングする設定になっています。(普通のインタフェースは、データ信号の真ん中でクロックを叩くケースが多いのですが)CANの場合は、伝送距離が長く遅延時間が大きい場合は、後ろの方にサンプリングポイントを設定する(TSEG1>>TSEG2)と望ましい(受信マージンが広がる)という事もあります。(伝送距離が短いケースでは、50%近傍でも問題無く通信は通ります。)

  • tf様

    たびたび申し訳ありません。

    テストモードをインターナルに変更すると送受信可能になりましたが,
    外部と通信させるとRX660から送信ができていません(受信はできている)。
    ご指摘いただいているTSEG1とTSEG2は500kbpsになるように変更済です。
    何か思い当たることはありませんでしょうか?
    変更点は下記の通り
    1. 指摘いただいたコードの修正
    /* sw2の押下時にsw2_func()を呼び出す */
    void sw2_func(void)
    {
        CANFD.TMSR[0].BIT.TXRF = 0;  //追加
        can_operation();
    }/* sw2_func()の終了*/

    2. 本当にやりたかった速度は500kbpsなので設定を下記の様に変更

        g_canfd0_bit_timing_cfg.baud_rate_prescaler = 5;
        g_canfd0_bit_timing_cfg.synchronization_jump_width = 1;
        g_canfd0_bit_timing_cfg.time_segment_1 = 15;
        g_canfd0_bit_timing_cfg.time_segment_2 = 8;

    3. フレームIDは拡張ではなく標準に変えています
     g_canfd_tx_frame.id_mode = CAN_ID_MODE_STANDARD;
    【テスト環境 (500kbps)】
    NODE A(RX660) :
    送信:2秒毎にID0x200を送信
    受信:ID0x100, ID101は受信できてる
    NODE B(Kvaser Canking)
    送信:クリックしてID101を送信
    受信:ID0x100は受信できてる, ID0x200は受信せず
    NODE C(ESP32)
    送信:1秒毎にID0x100を送信
    受信:ID0x101は受信できてる, ID0x200は受信せず

    #define CANFD_CFG_PARAM_CHECKING_ENABLE   (BSP_CFG_PARAM_CHECKING_ENABLE)
    #define CANFD_CFG_AFL_CH0_RULE_NUM   (32)
    #define CANFD_CFG_FD_PROTOCOL_EXCEPTION   (0)
    #define CANFD_CFG_GLOBAL_ERR_SOURCES    (0x3)
    #define CANFD_CFG_TX_PRIORITY           ((R_CANFD_GCFG_TPRI_Msk))
    #define CANFD_CFG_DLC_CHECK             (0)
    #define CANFD_CFG_FD_OVERFLOW           (0)
    #define CANFD_CFG_CANFDCLK_SOURCE           (0)
    #define CANFD_CFG_RXMB_NUMBER           (0)
    #define CANFD_CFG_RXMB_SIZE             (0)
    #define CANFD_CFG_GLOBAL_ERR_IPL        (12)
    #define CANFD_CFG_RX_FIFO_IPL           (12)
    #define CANFD_CFG_RXFIFO0_INT_THRESHOLD ((3U))
    #define CANFD_CFG_RXFIFO0_DEPTH         (3)
    #define CANFD_CFG_RXFIFO0_PAYLOAD       (7)
    #define CANFD_CFG_RXFIFO0_INT_MODE      ((R_CANFD_RFCR_RFIE_Msk | R_CANFD_RFCR_RFIM_Msk))
    #define CANFD_CFG_RXFIFO0_ENABLE        (1)
    #define CANFD_CFG_RXFIFO1_INT_THRESHOLD ((3U))
    #define CANFD_CFG_RXFIFO1_DEPTH         (3)
    #define CANFD_CFG_RXFIFO1_PAYLOAD       (7)
    #define CANFD_CFG_RXFIFO1_INT_MODE      ((R_CANFD_RFCR_RFIE_Msk |
    #define CANFD_CFG_RXFIFO1_ENABLE        (0)
    #define CANFD0_EXTENDED_CFG_TXMB0_TXI_ENABLE (0ULL)
    #define CANFD0_EXTENDED_CFG_TXMB1_TXI_ENABLE (0ULL)
    #define CANFD0_EXTENDED_CFG_TXMB2_TXI_ENABLE (0ULL)
    #define CANFD0_EXTENDED_CFG_TXMB3_TXI_ENABLE (0ULL)
    #define CANFD0_EXTENDED_CFG_WARNING_ERROR_INTERRUPTS (0U)
    #define CANFD0_EXTENDED_CFG_PASSING_ERROR_INTERRUPTS (0U)
    #define CANFD0_EXTENDED_CFG_BUS_OFF_ENTRY_ERROR_INTERRUPTS (0U)
    #define CANFD0_EXTENDED_CFG_BUS_OFF_RECOVERY_ERROR_INTERRUPTS (0U)
    #define CANFD0_EXTENDED_CFG_OVERLOAD_ERROR_INTERRUPTS (0U)
    #define CANFD0_CFG_IPL (12)
    #define CANFD0_BIT_TIMING_CFG_BRP (5)
    #define CANFD0_BIT_TIMING_CFG_TSEG1 (15)
    #define CANFD0_BIT_TIMING_CFG_TSEG2 (8)
    #define CANFD0_BIT_TIMING_CFG_SJW (1)
    #define CANFD0_DATA_TIMING_CFG_BRP (5)
    #define CANFD0_DATA_TIMING_CFG_TSEG1 (15)
    #define CANFD0_DATA_TIMING_CFG_TSEG2 (8)
    #define CANFD0_DATA_TIMING_CFG_SJW (1)
    #define CANFD0_EXTENDED_CFG_DELAY_COMPENSATION (1)
  • >テストモードをインターナルに変更すると送受信可能になりましたが,

    実際に外部と通信を行う場合は、テストモードは解除

    CAN_TEST_MODE_DISABLED

    であると思います。(もしくはモード遷移を行わない)

    (テストモードではなく通常モードで、)私が試した限りでは、外部に接続した別なボードで、RX660が送信したデータを受信していました(通信速度や条件は、1つ前のメッセージの条件に合わせて確かめました。通信相手を500kbpsに設定して受信出来ていますので、クロック分周やTSEG値に問題はないと考えます)。なお、

     tst_err5 = R_CANFD_ModeTransition(&g_canfd0_ctrl, CAN_OPERATION_MODE_NORMAL, (can_test_mode_t) CAN_TEST_MODE_INTERNAL_BUS);設定でもやってみましたが、その場合も外部と通信出来ていました。

    しかし、R_CANFD_ModeTransition()の戻り値が、エラーになっており、モード変更されなかった(テストモードではなく、通常モードを維持)であったため、外部と通信出来ていました。

    さまの実行結果でも、受信は通っているとの事ですので、テストモード/通常モードの問題ではないものと考えられます。)

    (ここでの、R_CANFD_ModeTransition()自体実行不要かと思います。)

    void sw2_func(void)
    {
        CANFD.TMSR[0].BIT.TXRF = 0;  //追加 ★ここにブレークポイントを追加
        can_operation();
    }/* sw2_func()の終了*/

    2回目以降の★のところで、CANFD.TMSR[0].BIT.TXRFが0x02になっていれば、RX660が送信したパケットに対して、どちらか(もしくは両方)の受信相手がACKを返したということかと思いますので、通信速度の問題ではなく、受信側がIDやDLCの条件が一致せず、受信データを捨てているということは考えられます。

    例えばですが、NODE Cは切り離して、(バス上に2者のみとする)

    NODE Bを生かして、RX660からID0x100で送信するとどうなるでしょうか。

    (ID=0x200を受信しないという可能性はないでしょうか。)
Reply
  • >テストモードをインターナルに変更すると送受信可能になりましたが,

    実際に外部と通信を行う場合は、テストモードは解除

    CAN_TEST_MODE_DISABLED

    であると思います。(もしくはモード遷移を行わない)

    (テストモードではなく通常モードで、)私が試した限りでは、外部に接続した別なボードで、RX660が送信したデータを受信していました(通信速度や条件は、1つ前のメッセージの条件に合わせて確かめました。通信相手を500kbpsに設定して受信出来ていますので、クロック分周やTSEG値に問題はないと考えます)。なお、

     tst_err5 = R_CANFD_ModeTransition(&g_canfd0_ctrl, CAN_OPERATION_MODE_NORMAL, (can_test_mode_t) CAN_TEST_MODE_INTERNAL_BUS);設定でもやってみましたが、その場合も外部と通信出来ていました。

    しかし、R_CANFD_ModeTransition()の戻り値が、エラーになっており、モード変更されなかった(テストモードではなく、通常モードを維持)であったため、外部と通信出来ていました。

    さまの実行結果でも、受信は通っているとの事ですので、テストモード/通常モードの問題ではないものと考えられます。)

    (ここでの、R_CANFD_ModeTransition()自体実行不要かと思います。)

    void sw2_func(void)
    {
        CANFD.TMSR[0].BIT.TXRF = 0;  //追加 ★ここにブレークポイントを追加
        can_operation();
    }/* sw2_func()の終了*/

    2回目以降の★のところで、CANFD.TMSR[0].BIT.TXRFが0x02になっていれば、RX660が送信したパケットに対して、どちらか(もしくは両方)の受信相手がACKを返したということかと思いますので、通信速度の問題ではなく、受信側がIDやDLCの条件が一致せず、受信データを捨てているということは考えられます。

    例えばですが、NODE Cは切り離して、(バス上に2者のみとする)

    NODE Bを生かして、RX660からID0x100で送信するとどうなるでしょうか。

    (ID=0x200を受信しないという可能性はないでしょうか。)
Children
  • tf様

    調べていただきありがとうございます。

    >CANFD.TMSR[0].BIT.TXRFが0x02になっていれば

    調べてみましたが0でした。

    またCHSRはBOST=1, TRMST=1, CRDY=1でバスオフ拾っていました。

    TJA1044GT/3Zの各ピンをオシロで調べるとTXD, RXD, CANH, CANLは何かしら信号の入出力がありましたが, VCC, VIOがGNDになっていました。

    動作条件をもう一度見直してみましたら, E2-Lite (3V3) で電源供給している場合,【CAN、LIN、5V PmodTmインタフェースは使用できません。】

    と書いてありましたので, 外部に送信できない理由はこれが原因かと考えています。

    今手元に5V電源ないのすぐに確認できませんが確認できましたら報告させていただきます。

    いろいろとご助言ありがとうございました。

  • tf様

    本日5V電源入手できましたので確認したところ通信できることを確認できました。

    色々ご助力いただき誠にありがとうございました。