This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28375D:Tx 中缺少 CAN 帧

Guru**** 2803255 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1624992/tms320f28375d-missing-can-frames-in-tx

器件型号: TMS320F28375D

我之前使用了两个邮箱 (17 和 18) 的 CAN Tx 实现。 CAN 总线上约有 18 到 36 个节点、每个节点每秒发送 3 条消息。

遗憾的是、我看到总线上缺少 CAN 帧。 有时、其中一个 CAN 节点完全静默超过 30 秒。 这不是总线‑关闭的情况—我检查了错误计数器、它们保持为 0。

在我的 Tx 实现中、三条具有不同 ID 的消息在软件队列中被缓冲、然后在检查是否有任何邮箱空闲后移动到 IFCMD 寄存器。

我的调试表明邮箱是空闲的、但通过 IF CMD 寄存器发送后、一些消息仍然不会出现在 CAN 总线上。

您能帮助我了解如何进一步调试吗?

我还进行了一项新的更改、在通过 IFCMD 寄存器发送新消息之前、我特意使现有邮箱无效。 这显著提高了性能、现在我只看到很少有丢失的 CAN 帧。

请参阅以下代码:

can_ll_send_message(uint32_t ui32ObjID, tCANMsgObject *pMsgObject)
{
    uint32_t ui32CmdMaskReg;
    uint32_t ui32MaskReg;
    uint32_t ui32ArbReg;
    uint32_t ui32MsgCtrl;
    bool bTransferData;

    bTransferData = 0;

    // Wait for busy bit to clear
    while(HWREGH(CAN_BASE + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY)
    {
    }

    
    // New START 
    // Clear the MsgVal bit in the target mailbox first.
    HWREGH(CAN_BASE + CAN_O_IF1ARB) = 0;
    HWREGH(CAN_BASE + CAN_O_IF1ARB + 2) = 0;
    
    // Send only the arbitration clear command to the mailbox.
    HWREG_BP(CAN_BASE + CAN_O_IF1CMD) = CAN_IF1CMD_DIR | CAN_IF1CMD_ARB | (ui32ObjID & CAN_IF1CMD_MSG_NUM_M);

    // Wait for this clear command to finish.
    while(HWREGH(CAN_BASE + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY)
    {
    }
    // New END

    // This is always a write to the Message object as this call is setting a
    // message object.  This call will also always set all size bits so it sets
    // both data bits.  The call will use the CONTROL register to set control
    // bits so this bit needs to be set as well.
    ui32CmdMaskReg = (CAN_IF1CMD_DIR | CAN_IF1CMD_DATA_A | CAN_IF1CMD_DATA_B |
                      CAN_IF1CMD_CONTROL);

    // Initialize the values to a known state before filling them in based on
    // the type of message object that is being configured.
    ui32ArbReg = 0;
    ui32MsgCtrl = 0;
    ui32MaskReg = 0;

        // Set the TXRQST bit and the reset the rest of the register.
        ui32CmdMaskReg |= CAN_IF1CMD_TXRQST;
        ui32MsgCtrl |= CAN_IF1MCTL_TXRQST | CAN_IF1MCTL_NEWDAT;
        ui32ArbReg = CAN_IF1ARB_DIR;
        bTransferData = 1;


    // Set the Arb bit so that this gets transferred to the Message object.
    ui32CmdMaskReg |= CAN_IF1CMD_ARB;

    // Configure the Arbitration registers.
    // Set the 29 bit version of the Identifier for this message object.
    // Mark the message as valid and set the extended ID bit.
    ui32ArbReg |= (pMsgObject->ui32MsgID & CAN_IF1ARB_ID_M) |
                  CAN_IF1ARB_MSGVAL | CAN_IF1ARB_XTD;

    // Set the data length since this is set for all transfers.  This is also a
    // single transfer and not a FIFO transfer so set EOB bit.
    ui32MsgCtrl |= (pMsgObject->ui32MsgLen & CAN_IF1MCTL_DLC_M);

    // Mark this as the last entry if this is not the last entry in a FIFO.
    if((pMsgObject->ui32Flags & CAN_MSG_OBJ_FIFO) == 0)
    {
        ui32MsgCtrl |= CAN_IF1MCTL_EOB;
    }


    // Write the data out to the CAN Data registers if needed.
    if(bTransferData)
    {
        CANDataRegWrite(pMsgObject->pucMsgData,
                        (uint32_t *)(CAN_BASE + CAN_O_IF1DATA),
                        pMsgObject->ui32MsgLen);
    }

    // Write out the registers to program the message object.

    HWREGH(CAN_BASE + CAN_O_IF1MSK) = ui32MaskReg & CAN_REG_WORD_MASK;
    HWREGH(CAN_BASE + CAN_O_IF1MSK + 2) = ui32MaskReg >> 16;

    HWREGH(CAN_BASE + CAN_O_IF1ARB) = ui32ArbReg & CAN_REG_WORD_MASK;
    HWREGH(CAN_BASE + CAN_O_IF1ARB + 2) = ui32ArbReg >> 16;

    HWREGH(CAN_BASE + CAN_O_IF1MCTL) = ui32MsgCtrl & CAN_REG_WORD_MASK;

    // Transfer the message object to the message object specific by ui32ObjID.
    HWREG_BP(CAN_BASE + CAN_O_IF1CMD) = ui32CmdMaskReg | (ui32ObjID & CAN_IF1CMD_MSG_NUM_M);


    // Wait for busy bit to clear
    while(HWREGH(CAN_BASE + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY)
    {
    }

    return;
}


如果您能帮助解释可能发生的情况、那将会很好。
注意:由于我的应用程序限制、我不想使用 Tx 中断。

谢谢、
Reeno Joseph

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、 Joseph:

    当您写入 IF 寄存器以更新  消息 RAM 中当前设置了 TXRQST 位的消息对象时、 CPU 接口 和 消息处理程序之间会出现竞争条件。

    “无声“失败的机制
    1. 覆盖: CPU 将一条新消息写入 IF1 寄存器并触发到消息 RAM 的传输。
    2. 冲突: 同时、消息处理程序尝试“读取“同一邮箱、因为先前的 TXRQST 已处于活动状态。
    3. Desync: 消息处理程序看到 MsgVal 位仍然为高电平、但数据/控制位处于通量中。 它可能会卡在它认为邮箱被 CPU “正在使用“的状态、因此它会在当前仲裁周期跳过该邮箱。 但是、由于 TXRQST 位已由 CPU 成功写入到 RAM、硬件会认为请求是挂起的、自然不会清除它。
    4. 结果: 邮箱被“锁定“。  TXRQST 设置在 RAM 中、但消息处理程序“失去了气味“、并且永远不会拾取它以将其放在导线上。 这说明了节点静默 30 秒的原因—它正在等待一个永远不会出现的“完成“信号。

    但是、我注意到您在将数据发送到邮箱之前清除了 IF1ARB (MsgVal=0)。 此操作将重置邮箱、应能解决此问题。

    当节点静默时、读取 CAN_MSGVLD 和 CAN_TXRQ 寄存器。 如果 17 和 18 是“有效“和“请求“但从未发送、则表示您有硬件仲裁锁定。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Thansk QJ Wang 的解释。

    最后一个是共享代码 while Loop 是我添加的最新更新。 我们的错误实现方案是将新的 CAN 帧推送到 IF 寄存器、然后立即(在另一个函数内)检查 CAN_TXRQ_21 。 后来,我意识到我们需要检查 CAN_IF1CMD.BUSY 等效电路 CAN_TXRQ_21

    在我们的实现中、在实际传输完成之前、我们假设邮箱已空闲并将新的 CAN 帧推入其中。 正如您所解释的、这会导致 CAN 内核内部出现锁定。

    我计划保留邮箱无效逻辑、因为它将强制 CAN 消息处理程序执行新的扫描。


    谢谢、
    Reeno Joseph