こんにちは
当社は、CANFD 通信機能を備えた S32K146 MCU をベースにブートローダ ソフトウェアを開発しています。しかし、私たちを本当に困惑させる問題に遭遇しました。それは、ECU が柔軟な遅延でメッセージを送信し、テストからの要求を受信してから 1 ミリ秒以内に肯定応答を CAN バスに送信することもあれば、遅延が非常に「大きく」、CAN_TP 送信タイマー制限 (As) を超える 224 ミリ秒になることもあります。誰かこの問題を解決するのを手伝ってくれませんか?
当社の ECU に関する情報は以下に示されており、添付の写真も掲載されています。
1. 2 つのメッセージを受信するには 2 MB を使用する必要があります (物理アドレスの ID: 0x714、機能アドレスの ID: 0x7DF)。
2. 1つのメッセージを送信するには1MBを使用する必要があります(ID:0x794)
3. CANFD調停ボーレートは500K/秒、データフィールドボーレートは2MB/秒
4. フレーム DLC は 64 バイトです。
5. ブートローダ ソフトウェアでは、受信または送信に割り込みを使用せず、代わりにポーリング タイプを使用します。
6. 私たちのトランシーバはTLE9263です
7. CANクロックソースはSYS_CLK(80MHZ)です
8. MB を書き込む直前に、Can_write 関数にモニター ポイントを配置します。ロジック アナライザーを使用して、モニター ポイントから CANTx PIN にメッセージが送信されるまでの期間を測定すると、次の結果が得られます。MB を書き込んだ後、CAN Tx PIN に肯定的な応答を送信するには約 223.95 ミリ秒かかります。(添付の画像を参照してください)。
使用されている合計MBはわずか7であり、CANループにはECUとテスター(CANOE VIN1640)以外のノードがないため、この大きな遅延は調停から発生したものではないようです。
私の CAN_init() 関数は以下のように投稿されました:
void Can_Init(void)
{
/**
* GPIO
* CAN_RX U4_9_CAN0_RX PE4 ALT5
* CAN_TX U4_8_CAN0_TX PE5 ALT5
*/
PORTE->PCR[4] = PORT_PCR_MUX(5);
PORTE->PCR[5] = PORT_PCR_MUX(5);
#CAN_FD == CAN_FD_TYPE_EN の場合
uint32_t i = 0;
uint32_t tempECR;
uint32_t 待機カウンタ = 0;
/* 時計 */
PCC->PCCn[PCC_FlexCAN0_INDEX] |= PCC_PCCn_CGC_MASK; /* CGC=1: FlexCAN0へのクロックを有効にする */
/* できる */
CAN0->MCR |= CAN_MCR_SOFTRST_MASK;
CAN0->MCR |= CAN_MCR_MDIS_MASK; /* MDIS=1: クロックを選択する前にモジュールを無効にする */
待機カウンタ = 0;
while(!((CAN0->MCR & CAN_MCR_SOFTRST_MASK) >> CAN_MCR_SOFTRST_SHIFT)) {WaitCounter++;}
CAN0->IMASK1 = 0x00000000ul;
CAN0->ESR1 &= ~CAN_ESR1_BOFFINT_MASK;
CAN0->CTRL1 |= (CAN_CTRL1_CLKSRC(1) /* CLKsrc=1: クロックソース = SYS_CLK (80 MHz) */
|CAN_CTRL1_BOFFMSK(0) /* バスオフ割り込み有効 */
|CAN_CTRL1_BOFFREC(0)); /* バスオフ車載回復を有効にする。*/
CAN0->MCR &= ~CAN_MCR_MDIS_MASK; /* MDIS=0; モジュール構成を有効にします。(FRZ、HALTを設定)*/
CAN0->MCR |= (CAN_MCR_FRZ_MASK | CAN_MCR_HALT_MASK);
待機カウンタ = 0;
while(!((CAN0->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT)) {WaitCounter++;}
/* 良い習慣: フリーズモードの開始/終了時に FRZACK=1 を待つ */
tempECR = CAN0->ECR;
CAN0->ECR = 0x00000000UL;
tempECR = tempECR;
/* 公称位相を設定: 500 KHz ビット時間、80 MHz クロック */
CAN0->CBT = CAN_CBT_BTF(1) /* ビットタイム定義の有効化。*/
|CAN_CBT_EPRESDIV(1) /* EPRESDIV = プリスケーラ + 1 = 2 */
|CAN_CBT_EPSEG2(15) /* EPSEG2 = 15 */
|CAN_CBT_EPSEG1(15) /* EPSEG1 = 15 */
|CAN_CBT_EPROPSEG(46)/* EPROPSEG = 46 */
|CAN_CBT_ERJW(15);/* ERJW = 15 */
/* BITRATEn =Fcanclk /( [(1 + (EPSEG1+1) + (EPSEG2+1) + (EPROPSEG + 1)] x (EPRESSDIV+1))
= 80 MHz /([(1 + ( 15 +1) + ( 15 +1) + ( 46 + 1)] x ( 1 +1))
= 80 MHz / ( [1 + 16 + 16 + 47] x 2) = 80 MHz / (80 x 2) = 500 Kz
サンプルポイント = (3 + PSEG1 + PROPSEG) /(4+ PSEG1 + PSEG2 + PROPSEG)
(17 + 15 + 46) / (18 + 15 + 15 + 46) = 80% */
/* データ位相を設定: 2 MHz ビット時間、80 MHz クロック */
CAN0->FDCBT = CAN_CBT_EPSEG2(3) /* FPSEG2 = 3 */
|CAN_CBT_EPSEG1(7) /* EPSEG1 = 7 */
|CAN_CBT_EPROPSEG(7) /* FPROPSEG = 7 */
|CAN_CBT_ERJW(3) /* FRJW = 3 */
|CAN_FDCBT_FPRESDIV(1);/* FPRESDIV = プリスケーラ + 1 = 2 */
/* BITRATEf = Fcanclk /( [(1 + (FPSEG1+1) + (FPSEG2+1) + (FPROPSEG)] x (FPRESDIV+1))
= 80 MHz /([(1 + ( 7 +1) + ( 3 +1) + ( 7 )] x ( 1 +1))
= 80 MHz /([1+8+4+7] x 2) = 80 MHz /(20x2) = 80 MHz / 40 = 2 MHz
サンプルポイント = (2 + PSEG1 + PROPSEG) /(3 + PSEG1 + PSEG2 + PROPSEG)
(4 + 7 + 7) / (5 + 7 + 3 + 7) = 80% */
CAN0->FDCTRL = CAN_FDCTRL_FDRATE(1) /* BRS=1: フレームのヘッダーでビットレートスイッチを有効にし、ビットレートスイッチ、データサイズ、トランシーバ遅延を設定します */
|CAN_FDCTRL_MBDSR0(3) /* MBDSR0=3: 領域0にはフレームのペイロードに64バイトのデータ(7Mb)があります */
|CAN_FDCTRL_TDCEN(1) /* MBDSR1: 該当なし */
|CAN_FDCTRL_TDCOFF(31); /* トランシーバ遅延補正オフセット15 */
/* PRIO = 0: CANFD が使用され、ISO CAN FD の CRC 修正が有効になります */
CAN0->CTRL2 |= CAN_CTRL2_TASD(30) | CAN_CTRL2_ISOCANFDEN(1);
/* TDCEN=1: トランシーバ遅延補正を有効にする */
/* TDCOFF=5: 5 CANクロック(300us)のオフセットを使用 */
for(i = 0; i < 128u; i++)
{
/* CAN0: FlexCAN 0の128ワードのRAMをクリアする
メッセージ バッファの単語をクリアします。すべてのバッファ CODE=0 (非アクティブ) */
CAN0->RAMn[i] = 0;
}
for(i=0; i < 16u; i++ )
{
/* FRZ モードでは、CAN0 16 msg buf フィルターを初期化します
受信メッセージのすべてのIDビットをチェックする*/
CAN0->RXIMR[i] = 0x1ffffffful;
}
/* グローバル受け入れマスク: すべてのIDビットをチェック */
CAN0->RXMGMASK = 0xFFFFFFFFul;
CAN0->RX14MASK = 0xFFFFFFFFul;
CAN0->RX15MASK = 0xFFFFFFFFul;
/* メッセージバッファ 0 - 受信セットアップ: */
/* メッセージバッファ 0、ワード 0: 受信を有効にする */
/* EDL = 1: CAN FDの拡張データ長 */
/* BRS = 1: ビットレートスイッチが有効 */
/* ESI = 0: エラー状態 */
/* CODE = 4: MBをRX非アクティブに設定 */
/* IDE = 0: 標準ID */
/* SRR、RTR、TIME STAMP = 0: 該当なし */
CAN0->RAMn[0 * CAN_MSG_BUF_SIZE + 0] = CAN_RAMn_EDL(1) +
CAN_RAMn_BRS(1) +
CAN_RAMn_ESI(0) +
CAN_RAMn_CODE(CAN_MSG_BUF_RX_EMPTY) +
CAN_RAMn_IDE(0) +
CAN_RAMn_SRR(0) +
CAN_RAMn_RTR(0);
CAN0->RAMn[0 * CAN_MSG_BUF_SIZE + 1] = ((uint32_t)ID_REQUEST_PHY) << 18u;
// CAN0->RXIMR[0] = (((uint32_t)(~(ID_REQUEST_PHY ^ ID_REQUEST_FUN))) << 18u) & 0x1ffffffful;
CAN0->RXIMR[0] = 0x1ffffffful;
CAN0->RAMn[1 * CAN_MSG_BUF_SIZE + 0] = CAN_RAMn_EDL(1) +
CAN_RAMn_BRS(1) +
CAN_RAMn_ESI(0) +
CAN_RAMn_CODE(CAN_MSG_BUF_RX_EMPTY) +
CAN_RAMn_IDE(0) +
CAN_RAMn_SRR(0) +
CAN_RAMn_RTR(0);
CAN0->RAMn[1 * CAN_MSG_BUF_SIZE + 1] = ((uint32_t)ID_REQUEST_FUN) << 18u;
CAN0->RXIMR[1] = 0x1ffffffful;
CAN0->MCR = 0x00030806ul; /* FlexCAN 0 停止状態を否定し、7 MB 間 CAN FD を有効にする */
gs_CanControllerStatus[0] = CAN_STATUS_IDLE;
待機カウンタ = 0;
while ((CAN0->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT){WaitCounter++;}
/* 良い方法: FRZACK がクリアされるまで待つ (フリーズモードではない) */
待機カウンタ = 0;
while ((CAN0->MCR & CAN_MCR_NOTRDY_MASK) >> CAN_MCR_NOTRDY_SHIFT){WaitCounter++;}
}
そして、私のCan_write()関数は以下のように投稿されました:
bl_Error_t Can_Write(bl_CanHandle_t ハンドル、const bl_Buffer_t *バッファ、bl_Size_t サイズ)
{
#CAN_FD == CAN_FD_TYPE_EN の場合
bl_Error_t ret = BL_ERR_NOT_OK;
uint32_t Can_ID = 0x0;
uint8_t 送信ハンドル = 0;
uint8_t dlc;
CAN_message_t msg_tx;
dlc = Can__SizeToDlc(サイズ);
if (ハンドル > CAN_TXHANDLE_NUM)
{
ret を返します。
}
Tx_handle = g_CanTxHandleCfg[ハンドル].コントローラ;
(gs_CanControllerStatus[Tx_handle] != CAN_STATUS_IDLE) の場合
{
ret = BL_ERR_CAN_BUSY;
ret を返します。
}
Can_ID = g_CanTxHandleCfg[ハンドル].id<< 18;
する
{
(uint8_t i = 0; i < CAN_MAX_NUMBER_OF_CONTROLLER; i++) の場合
{
gs_CanControllerCfg[i].usage == CAN_CONTROLLER_UNUSED の場合
{
続く;
}
if ( (Tx_handle == gs_CanControllerCfg[i].phyId)
&& (CAN_STATUS_IDLE == gs_CanControllerStatus[i]))
{
msg_tx.id = Can_ID;
Can__CopyData(msg_tx.data.bytes,buffer,size);
msg_tx.length = dlc;
TLE9261_Write(0x40, 0x5F);/*これは私がここに置いたソフトウェアモニターポイントです*/
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 17] = SWAP_UINT32(msg_tx.data.longs[15]);//((uint32_t)バッファ[60])<< 24 | ((uint32_t)バッファ[61]) << 16 | ((uint32_t)バッファ[62]) << 8 | ((uint32_t)バッファ[63]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 16] = SWAP_UINT32(msg_tx.data.longs[14]);//((uint32_t)バッファ[56])<< 24 | ((uint32_t)バッファ[57]) << 16 | ((uint32_t)バッファ[58]) << 8 | ((uint32_t)バッファ[59]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 15] = SWAP_UINT32(msg_tx.data.longs[13]);//((uint32_t)バッファ[52])<< 24 | ((uint32_t)バッファ[53]) << 16 | ((uint32_t)バッファ[53]) << 8 | ((uint32_t)バッファ[55]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 14] = SWAP_UINT32(msg_tx.data.longs[12]);//((uint32_t)バッファ[48])<< 24 | ((uint32_t)バッファ[49]) << 16 | ((uint32_t)バッファ[50]) << 8 | ((uint32_t)バッファ[51]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 13] = SWAP_UINT32(msg_tx.data.longs[11]);//((uint32_t)バッファ[44])<< 24 | ((uint32_t)バッファ[45]) << 16 | ((uint32_t)バッファ[46]) << 8 | ((uint32_t)バッファ[47]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 12] = SWAP_UINT32(msg_tx.data.longs[10]);//((uint32_t)バッファ[40])<< 24 | ((uint32_t)バッファ[41]) << 16 | ((uint32_t)バッファ[42]) << 8 | ((uint32_t)バッファ[43]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 11] = SWAP_UINT32(msg_tx.data.longs[9]);//((uint32_t)バッファ[36])<< 24 | ((uint32_t)バッファ[37]) << 16 | ((uint32_t)バッファ[38]) << 8 | ((uint32_t)バッファ[39]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 10] = SWAP_UINT32(msg_tx.data.longs[8]);//((uint32_t)バッファ[32])<< 24 | ((uint32_t)バッファ[33]) << 16 | ((uint32_t)バッファ[34]) << 8 | ((uint32_t)バッファ[35]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 9] = SWAP_UINT32(msg_tx.data.longs[7]);//((uint32_t)バッファ[28])<< 24 | ((uint32_t)バッファ[29]) << 16 | ((uint32_t)バッファ[30]) << 8 | ((uint32_t)バッファ[31]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 8] = SWAP_UINT32(msg_tx.data.longs[6]);//((uint32_t)バッファ[24])<< 24 | ((uint32_t)バッファ[25]) << 16 | ((uint32_t)バッファ[26]) << 8 | ((uint32_t)バッファ[27]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 7] = SWAP_UINT32(msg_tx.data.longs[5]);//((uint32_t)バッファ[20])<< 24 | ((uint32_t)バッファ[21]) << 16 | ((uint32_t)バッファ[22]) << 8 | ((uint32_t)バッファ[23]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 6] = SWAP_UINT32(msg_tx.data.longs[4]);//((uint32_t)バッファ[16])<< 24 | ((uint32_t)バッファ[17]) << 16 | ((uint32_t)バッファ[18]) << 8 | ((uint32_t)バッファ[19]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 5] = SWAP_UINT32(msg_tx.data.longs[3]);//((uint32_t)バッファ[12])<< 24 | ((uint32_t)バッファ[13]) << 16 | ((uint32_t)バッファ[14]) << 8 | ((uint32_t)バッファ[15]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 4] = SWAP_UINT32(msg_tx.data.longs[2]);//((uint32_t)バッファ[8])<< 24 | ((uint32_t)バッファ[9]) << 16 | ((uint32_t)バッファ[10]) << 8 | ((uint32_t)バッファ[11]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 3] = SWAP_UINT32(msg_tx.data.longs[1]);//((uint32_t)バッファ[4])<< 24 | ((uint32_t)バッファ[5]) << 16 | ((uint32_t)バッファ[6]) << 8 | ((uint32_t)バッファ[7]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 2] = SWAP_UINT32(msg_tx.data.longs[0]);//((uint32_t)バッファ[0])<< 24 | ((uint32_t)バッファ[1]) << 16 | ((uint32_t)バッファ[2]) << 8 | ((uint32_t)バッファ[3]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 1] = Can_ID; /* MB8ワード1: 指定されたIDの送信メッセージ */
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 0] = CAN_RAMn_EDL(1) /* EDL=1 CAN FDフォーマットフレーム*/
|CAN_RAMn_BRS(1) /* BRS=1: ビットレートはメッセージ内で切り替えられます */
|CAN_RAMn_ESI(0) /* ESI=0: ??? */
|CAN_RAMn_CODE(CAN_TX_MB_CODE_TRANS) /* CODE=0xC: 送信するためにメッセージバッファをアクティブにする */
|CAN_RAMn_SRR(0) /* SRR=1 送信フレーム(標準IDには必要ありません)*/
|CAN_RAMn_IDE(0) /* IDE=0: 標準ID */
|CAN_RAMn_RTR(0) /* RTR = 0: データ、リモート送信要求フレームではない*/
|CAN_RAMn_DLC(dlc); /* DLC=x; 1,2,3,4,5,6,7,8, 9-12,10-16, 11-20, 12-24, 13-32, 14-48, 15-64バイト */
// while (!(S32K_CAN(Tx_handle).IFLAG1 & 0x100)) {}; /* CAN 0 MB 8 フラグを待つ */
// S32K_CAN(Tx_handle).IFLAG1 = 0x00000100; /* CAN 0 MB 8フラグをクリアするが、他のフラグはクリアしない*/
gs_CanControllerStatus[i] = CAN_STATUS_TRANSMITTING;
ret = BL_ERR_OK;
}
}
} while(0);
ret を返します。
}
こんにちは、
正確な設定と使用されているコードがわからないため、この動作の原因を正確に説明することはできません。仲裁は停止されるか、何らかの理由で保留中になっているようです。たとえば、仲裁が MB 全体をスキャンする前に、任意の MB CS ワードに書き込むことが考えられます。
調停プロセスは MB をスキャンし、次の機会に送信するメッセージを保持している送信 MB を検索します。スキャンは最も小さい数値の MB から始まり、より大きな数値へと続きます。MB0 が送信に使用される場合、この MB に書き込むと、調停プロセスが開始され、すぐに勝者が見つかります。
BR、ペトル
こんにちは、ペトルス
MB シーケンスを調整してみましたが、正常に送信できました。しかし、なぜ問題ないのかという深いロジックがまだ理解できません。私の方法を簡単に説明しましょう:
受信または送信に使用する MB インデックスを調整します。つまり、元々 MB0 は物理アドレス診断メッセージ (ID:0x714) を受信するために使用され、MB1 は機能アドレス診断メッセージ (ID:0x7DF) を受信するために使用され、MB6 は ECU 応答メッセージ (ID:0x794) を送信するために使用されます。
新しいものは、MB0 は ECU 応答メッセージ (ID:0x794) の送信に使用され、MB1 は物理アドレス診断メッセージ (ID:0x714) の受信に使用され、MB2 は機能アドレス診断メッセージ (ID:0x7DF) の受信に使用されます。
この調整後、ECU は正常に受信または送信できるようになります。SO、MB6がflexCAN0内での調停に勝てないため、ECUがメッセージをSMBに移動しないということでしょうか?送信するメッセージは1つしかないので、MB6と調停する他のMBはないようです。
また、新しい送信を開始する必要があるときに MB がまだ送信中の場合は、MB を中止しようとします。
よろしくお願いします。
こんにちは、
何らかの理由で、MB が書き込まれた後、仲裁が開始されないか終了せず、メッセージが TX SMB に移動されないようです。バスはアイドル状態なので、通常通り実行されるはずです。
その後、別のメッセージが受信されると、CRC 部分で新しい仲裁が開始され、勝者 (単一の TX MB から) が選択され、SMB に移動されます。ようやく最初の機会に送信されました。
しかし、「新しい受信リクエストが、最後のリクエストへの応答の送信をトリガーしました。」という図は、送信MBが実際に正常に送信される前に更新されていることを示しています。MBの転送/可用性のチェックが適切に行われていれば、監視ポイント1に到達することはありません。
他に何を提案すればよいか分かりません。システムとモジュールのクロックを確認してください。コードを確認して、前回の転送が完了した時点でTXが書き込まれていることを確認してください。コード内でMBの無効化/中止を行っていますか?
BR、ペトル
こんにちは
ご返信SOありがとうございます。ここで引用した最初の質問にお答えしたいと思います。「SO MeasurementStartPoint,jpg から、0x714 メッセージが受信され、約 150us 後に 0x5FC0 が SPI SOUT に送信されていますが、このフレームはコードで使用される TLE9261_Write(0x40,0x5F) と同等ですか?」
はい、コードで使用されるTLE9261_Write(0x40,0x5F)と同等です。
測定停止ポイントについては、コードに別の 2 つの TLE9261_Write(0x40,0x5F) 関数を導入しました。これらは、「モニター ポイント」という名前の添付画像で確認できます。また、ここにコードも投稿します。
bl_Error_t Can_Write(bl_CanHandle_t ハンドル、const bl_Buffer_t *バッファ、bl_Size_t サイズ)
{
bl_Error_t ret = BL_ERR_NOT_OK;
uint32_t Can_ID = 0x0;
uint8_t 送信ハンドル = 0;
uint8_t dlc;
CAN_message_t msg_tx;
dlc = Can__SizeToDlc(サイズ);
if (ハンドル > CAN_TXHANDLE_NUM)
{
ret を返します。
}
Tx_handle = g_CanTxHandleCfg[ハンドル].コントローラ;
(gs_CanControllerStatus[Tx_handle] != CAN_STATUS_IDLE) の場合
{
ret = BL_ERR_CAN_BUSY;
ret を返します。
}
Can_ID = g_CanTxHandleCfg[ハンドル].id<< 18;
する
{
(uint8_t i = 0; i < CAN_MAX_NUMBER_OF_CONTROLLER; i++) の場合
{
gs_CanControllerCfg[i].usage == CAN_CONTROLLER_UNUSED の場合
{
続く;
}
if ( (Tx_handle == gs_CanControllerCfg[i].phyId)
&& (CAN_STATUS_IDLE == gs_CanControllerStatus[i]))
{
msg_tx.id = Can_ID;
Can__CopyData(msg_tx.data.bytes,buffer,size);
msg_tx.length = dlc;
TLE9261_Write(0x40, 0x5F);/*モニターポイント1*/
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 17] = SWAP_UINT32(msg_tx.data.longs[15]);//((uint32_t)バッファ[60])<< 24 | ((uint32_t)バッファ[61]) << 16 | ((uint32_t)バッファ[62]) << 8 | ((uint32_t)バッファ[63]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 16] = SWAP_UINT32(msg_tx.data.longs[14]);//((uint32_t)バッファ[56])<< 24 | ((uint32_t)バッファ[57]) << 16 | ((uint32_t)バッファ[58]) << 8 | ((uint32_t)バッファ[59]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 15] = SWAP_UINT32(msg_tx.data.longs[13]);//((uint32_t)バッファ[52])<< 24 | ((uint32_t)バッファ[53]) << 16 | ((uint32_t)バッファ[53]) << 8 | ((uint32_t)バッファ[55]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 14] = SWAP_UINT32(msg_tx.data.longs[12]);//((uint32_t)バッファ[48])<< 24 | ((uint32_t)バッファ[49]) << 16 | ((uint32_t)バッファ[50]) << 8 | ((uint32_t)バッファ[51]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 13] = SWAP_UINT32(msg_tx.data.longs[11]);//((uint32_t)バッファ[44])<< 24 | ((uint32_t)バッファ[45]) << 16 | ((uint32_t)バッファ[46]) << 8 | ((uint32_t)バッファ[47]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 12] = SWAP_UINT32(msg_tx.data.longs[10]);//((uint32_t)バッファ[40])<< 24 | ((uint32_t)バッファ[41]) << 16 | ((uint32_t)バッファ[42]) << 8 | ((uint32_t)バッファ[43]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 11] = SWAP_UINT32(msg_tx.data.longs[9]);//((uint32_t)バッファ[36])<< 24 | ((uint32_t)バッファ[37]) << 16 | ((uint32_t)バッファ[38]) << 8 | ((uint32_t)バッファ[39]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 10] = SWAP_UINT32(msg_tx.data.longs[8]);//((uint32_t)バッファ[32])<< 24 | ((uint32_t)バッファ[33]) << 16 | ((uint32_t)バッファ[34]) << 8 | ((uint32_t)バッファ[35]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 9] = SWAP_UINT32(msg_tx.data.longs[7]);//((uint32_t)バッファ[28])<< 24 | ((uint32_t)バッファ[29]) << 16 | ((uint32_t)バッファ[30]) << 8 | ((uint32_t)バッファ[31]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 8] = SWAP_UINT32(msg_tx.data.longs[6]);//((uint32_t)バッファ[24])<< 24 | ((uint32_t)バッファ[25]) << 16 | ((uint32_t)バッファ[26]) << 8 | ((uint32_t)バッファ[27]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 7] = SWAP_UINT32(msg_tx.data.longs[5]);//((uint32_t)バッファ[20])<< 24 | ((uint32_t)バッファ[21]) << 16 | ((uint32_t)バッファ[22]) << 8 | ((uint32_t)バッファ[23]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 6] = SWAP_UINT32(msg_tx.data.longs[4]);//((uint32_t)バッファ[16])<< 24 | ((uint32_t)バッファ[17]) << 16 | ((uint32_t)バッファ[18]) << 8 | ((uint32_t)バッファ[19]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 5] = SWAP_UINT32(msg_tx.data.longs[3]);//((uint32_t)バッファ[12])<< 24 | ((uint32_t)バッファ[13]) << 16 | ((uint32_t)バッファ[14]) << 8 | ((uint32_t)バッファ[15]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 4] = SWAP_UINT32(msg_tx.data.longs[2]);//((uint32_t)バッファ[8])<< 24 | ((uint32_t)バッファ[9]) << 16 | ((uint32_t)バッファ[10]) << 8 | ((uint32_t)バッファ[11]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 3] = SWAP_UINT32(msg_tx.data.longs[1]);//((uint32_t)バッファ[4])<< 24 | ((uint32_t)バッファ[5]) << 16 | ((uint32_t)バッファ[6]) << 8 | ((uint32_t)バッファ[7]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 2] = SWAP_UINT32(msg_tx.data.longs[0]);//((uint32_t)バッファ[0])<< 24 | ((uint32_t)バッファ[1]) << 16 | ((uint32_t)バッファ[2]) << 8 | ((uint32_t)バッファ[3]);
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 1] = Can_ID; /* MB8ワード1: 指定されたIDの送信メッセージ */
TLE9261_Write(0x40, 0x5F);/*モニターポイント2*/
S32K_CAN(Tx_handle).RAMn[CAN_USED_HRH_NUM*CAN_MSG_BUF_SIZE + 0] = CAN_RAMn_EDL(1) /* EDL=1 CAN FDフォーマットフレーム*/
|CAN_RAMn_BRS(1) /* BRS=1: ビットレートはメッセージ内でスイッチされます */
|CAN_RAMn_ESI(0) /* ESI=0: ??? */
|CAN_RAMn_CODE(CAN_TX_MB_CODE_TRANS) /* CODE=0xC: 送信するためにメッセージバッファをアクティブにする */
|CAN_RAMn_SRR(0) /* SRR=1 送信フレーム(標準IDには必要ありません)*/
|CAN_RAMn_IDE(0) /* IDE=0: 標準ID */
|CAN_RAMn_RTR(0) /* RTR = 0: データ、リモート送信要求フレームではない*/
|CAN_RAMn_DLC(dlc); /* DLC=x; 1,2,3,4,5,6,7,8, 9-12,10-16, 11-20, 12-24, 13-32, 14-48, 15-64バイト */
TLE9261_Write(0x40, 0x5F);/*モニターポイント3*/
// while (!(S32K_CAN(Tx_handle).IFLAG1 & 0x100)) {}; /* CAN 0 MB 8 フラグを待つ */
// S32K_CAN(Tx_handle).IFLAG1 = 0x00000100; /* CAN 0 MB 8フラグをクリアするが、他のフラグはクリアしない*/
gs_CanControllerStatus[i] = CAN_STATUS_TRANSMITTING;
ret = BL_ERR_OK;
}
}
} while(0);
ret を返します。
}
最初の監視ポイントは MB の ID を設定する前に配置され、2 番目の監視コードは MB のコードを 0xC(送信) に更新する直前に配置され、3 番目の監視ポイントは送信する MB のコード更新直後に配置されます。
コードをデバッグすると、以下に説明する 2 つの現象が見つかりました。
1. まず、DID を読み取るために診断要求サービスを送信し、バス上で 0x22 F1 87 をテスト送信しましたが、ECU は応答しません。添付の「要求を受信したが応答がない」という画像から、ECU が実際に要求メッセージを受信し、応答を送信して MB を更新しようとしていることがわかります (このスナップショットでは監視ポイント 1、2、および 3 がキャプチャされています)。ただし、CAN Tx PIN では応答メッセージが監視されていません。
2. 次に、ESR1、IFALG1、および RAM レジスタを監視し、送信 MB のコードが 0xC (送信) に正常に更新され、CAN バスがアイドル状態であり、ESR1 レジスタに他のエラーがないことを確認します。ただし、メッセージは CANTx で送信されませんでした。flexCAN0 が送信を開始する準備ができていないため、メッセージが SMB でスタックしているようです。
3. 3 番目に、別の診断要求を送信しようとして、0x10 01 サービスを送信すると、ECU はすぐに 0x62 F1 87 で応答します。添付の「新しく受信した要求によって、最後の要求の応答の送信がトリガーされました。」という画像で確認できます。メッセージは、モニター ポイント 1、2、3 のコードが実行される前に送信されました。SO、新たな要求メッセージが ECU をトリガーして、最後の要求の応答を送信するようです!!! これはSO不合理に思えます。
この問題を解決するには、皆様のご親切なサポートが本当に必要です。よろしくお願いします。
こんにちは、
したがって、MeasurementStartPoint,jpg から、0x714 メッセージが受信され、約 150us 後に 0x5FC0 が SPI SO に送信されていることがわかります。このフレームは、コードで使用される TLE9261_Write(0x40,0x5F) と同等ですか?
TX メッセージが送信されるときに停止時間にズーム機能はありますか?
通常の応答(1 ミリ秒以内)のスクリーンショットを取得できますか?
CANメッセージ間の周期的(30us)SPI転送とは何ですか?コードではどのように処理されますか?
TLE9261_Write(0x40,0x5F) と MB6 CS ワード書き込みの間のコードが中断されないことをテストする場合は、その前後の割り込みを無効/有効にするだけです。
BR、ペトル
こんにちは、PetrS
ご丁寧なご返信SOありがとうございます。まず最初にいくつかの点を明確にさせてください。
1.TDCOFF については、RF マニュアルを参照し、お客様の CAN 仕様で定義されているパラメータを使用して計算しているので、ここでは問題ないと思います。
2. 私のコードでは、MB0 は物理アドレス ID (0x714) メッセージの受信に使用され、MB1 は関数アドレス ID (0x7DF) メッセージの受信に使用されます。MB2 ~ MB5 は予約済みで、MB6 は送信に使用されます。S32K146 Flex CAN0 にはペイロード 64 バイトのメッセージ用に 7 MB がある。SO、私のコード内の CAN_USED_HRH_NUM は 6 です。
3. バスの仲裁については、おっしゃる意味は理解しています。写真から一部のスナップショットが抜けてしまっていることをお詫びします。こちらに追加しましたので、添付ファイルをご参照ください。私のテスト ベンチには ECU という 1 つのノードだけがあり、テスター (Vector CANOE VIN1640) を除いて ECU と調停する他のノードはありません。フラッシュが終了した後に ECU を起動するために、100 ミリ秒周期で NM メッセージを送信します。SO、私の観点からすると、この遅延はバスの調停によるものではないはずです。
4. 遅延が発生する場所を捕捉するために、コードにモニター ポイント TLE9261_Write (返信でも言及されています) を追加しました。こうすることで、TLE9261_Write() の呼び出しによってトリガーされる SPI 信号をキャプチャできます。これは、ロジック アナライザ プロジェクトの測定開始ポイントの名前です。つまり、このポイントはメッセージの送信直前です (送信 MB にデータを書き込むと、MB の CS コードも更新されます)。また、CANRx および CANTx PIN のデータも測定します。こうすることで、TLE9261_Write() を呼び出してからメッセージが CAN Tx PIN に送信されるまでの遅延が約 223 ミリ秒であることがわかります。それは本当に長いですね。測定結果は添付ファイルでCANます。
5. SO、返信で述べられているように、遅延は TLE9261_Write と CAN_USED_HRH_NUM MB CS ワード書き込み間のコードから発生すると考えられます。しかし、ブートローダ コードで使用した割り込みは、時間をカウントするために使用するシステム ティックと、いくつかの障害シナリオに対処するために使用するハードフォールトのみです。これによってSO大きな遅延が発生することはないと思います。
SO、これらの情報をもう一度確認して、遅延の原因を突き止めるのにご協力いただけますか?
SOありがとう。
こんにちは、
CAN init は正常に見えます。2Mbit では TDC はまったく必要ありません。とにかく、TDCOFF は適切に構成されているように見えます。デフォルトの TASD 値を維持することもCANますが、違いは期待できません。
説明によると、送信には単一のMBのみが使用されていますが、コードではCAN_USED_HRH_NUM(値?)となっています。このメッセージバッファのCSワードが書き込まれると、MBは調停プロセスへの参加を開始し、勝者として選択されてTX SMBに移動され、バス上で実際に送信される最初の機会を待ちます。ここで、バス上にIDが低い他のメッセージがある場合、バス調停によって遅延が発生する可能性があります。他のノードがコネクテッドされていないにもかかわらず、RXメッセージの1つがより高い調停値(IDが低い)を持っていることを確認してください。
遅延のもう一つの原因は、コード自体にある可能性があります。TLE9261_WriteとCAN_USED_HRH_NUM MB CSワード書き込みの間に何らかのコードがあります。他のコードやタスクによって中断されないことを確認し、SOここにソフトウェア遅延を追加してはいかがでしょうか?
また、送信中にエラーが検出されると実際の送信が遅れますが、バス/CAN ツールで間違ったメッセージやエラー メッセージが表示されることがあります。
BR、ペトル