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.

[参考译文] TMS320F280025C:C2000Ware 中的 CAN_readMessage 和 CAN_clearMessage 函数存在问题

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1486200/tms320f280025c-issue-with-can_readmessage-and-can_clearmessage-functions-in-c2000ware

器件型号:TMS320F280025C
Thread 中讨论的其他器件:C2000WARE

工具与软件:

您好!

我目前使用 F28002x 微控制器、并使用 C2000Ware driverlib 中提供的 CAN 驱动程序函数。 我遇到 CAN_readMessage 与和 CAN_clearMessage 功能有关的问题。

 CAN_readMessage 函数似乎从 IF2寄存器读取数据、而该 CAN_clearMessage 函数 NewDat 使用 IF1寄存器清除该位。 这种差异似乎会导致错误、即 NewDat 该位未被正确清除、从而导致邮箱在第一个消息之后无法接收新消息。  

我在曾尝试过的两个版本的 C2000Ware 中找到此实现: C2000Ware_4_03_00_00和 C2000Ware_521_SDK_5_04_00_00 Ware_Digital。

以下是 can.c 该文件中的相关代码片段:

// CAN_readMessage function
bool CAN_readMessage(uint32_t base, uint32_t objID, uint16_t *msgData)
{
    bool status;
    uint16_t msgCtrl = 0U;

    // Check the arguments.
    ASSERT(CAN_isBaseValid(base));
    ASSERT((objID <= 32U) && (objID != 0U));

    // Set the Message Data A, Data B, and control values to be read
    // on request for data from the message object.
    HWREG_BP(base + CAN_O_IF2CMD) =
    ((uint32_t)CAN_IF2CMD_DATA_A | (uint32_t)CAN_IF2CMD_DATA_B |
     (uint32_t)CAN_IF2CMD_CONTROL | (objID & CAN_IF2CMD_MSG_NUM_M) |
     (uint32_t)CAN_IF2CMD_ARB);

    // Wait for busy bit to clear
    while((HWREGH(base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY) == CAN_IF2CMD_BUSY)
    {
    }

    // Read out the IF control Register.
    msgCtrl = HWREGH(base + CAN_O_IF2MCTL);

    // See if there is new data available.
    if((msgCtrl & CAN_IF2MCTL_NEWDAT) == CAN_IF2MCTL_NEWDAT)
    {
        // Read out the data from the CAN registers.
        CAN_readDataReg(msgData, (base + CAN_O_IF2DATA),
                        ((uint32_t)msgCtrl & CAN_IF2MCTL_DLC_M));

        status = true;

        // Now clear out the new data flag
        HWREG_BP(base + CAN_O_IF2CMD) = ((uint32_t)CAN_IF2CMD_TXRQST |
                                        (objID & CAN_IF2CMD_MSG_NUM_M));

        // Wait for busy bit to clear
        while((HWREGH(base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY) ==
               CAN_IF2CMD_BUSY)
        {
        }
    }
    else
    {
        status = false;
    }

    return(status);
}

// CAN_clearMessage function
void CAN_clearMessage(uint32_t base, uint32_t objID)
{
    // Check the arguments.
    ASSERT(CAN_isBaseValid(base));
    ASSERT((objID >= 1U) && (objID <= 32U));

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

    // Clear the message valid bit in the arbitration register. This disables
    // the mailbox.
    HWREG_BP(base + CAN_O_IF1ARB) = 0U;

    // Initiate programming the message object
    HWREG_BP(base + CAN_O_IF1CMD) =
    (((uint32_t)CAN_IF1CMD_DIR | (uint32_t)CAN_IF1CMD_ARB) |
     (objID & CAN_IF1CMD_MSG_NUM_M));
}

下面的代码片段显示了 CAN 模块的配置和用于读取接收数据的例程:

    // Initialize the CAN-A module
    CAN_initModule(CANA_BASE);

    // Set up the CAN bus bit rate
    CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);

    // Enable loopback mode
    CAN_enableTestMode(CANA_BASE, CAN_TEST_EXL);

    // Enable the CAN module
    CAN_startModule(CANA_BASE);

    // Configure the CAN message object for transmission
    CAN_setupMessageObject(CANA_BASE, SEND_MAILBOX_1 + 1, SEND_MSG_ID_1, CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_NO_FLAGS, MSG_LEN);

    // Configure the CAN message object for reception
    CAN_setupMessageObject(CANA_BASE, RECEIVE_MAILBOX_1 + 1, RECEIVE_MSG_ID_2, CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_NO_FLAGS, MSG_LEN);

    // Configure the CAN message object for receiving PLC requests
    CAN_setupMessageObject(CANA_BASE, RECEIVE_MAILBOX_2 + 1, RECEIVE_MSG_ID_2, CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_NO_FLAGS, MSG_LEN);

    // Configure the CAN message object for sending diagnostics data
    CAN_setupMessageObject(CANA_BASE, SEND_MAILBOX_2 + 1, SEND_MSG_ID_2, CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_NO_FLAGS, MSG_LEN);

    // Configure the Loopback mailboxes
    // Configure the CAN message object for receiving PVL messages
    CAN_setupMessageObject(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1, SEND_MSG_ID_1, CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_NO_FLAGS, MSG_LEN);

    // Configure the CAN message object for receiving PLC requests
    CAN_setupMessageObject(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_2 + 1, SEND_MSG_ID_2, CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_NO_FLAGS, MSG_LEN);

    // Enable CAN interrupts
    CAN_enableInterrupt(CANA_BASE, CAN_INT_IE0 | CAN_INT_ERROR | CAN_INT_STATUS);
    CAN_enableGlobalInterrupt(CANA_BASE, CAN_GLOBAL_INT_CANINT0);

    // Register the CAN ISR
    Interrupt_register(INT_CANA0, &canISR);

    // Enable the CAN interrupt in the PIE
    Interrupt_enable(INT_CANA0);

    // Enable global interrupts
    EINT;
    ERTM;

            // Read the received message
            CAN_readMessage(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1, rxData);

            // Clear the New Data flag
            CAN_clearMessage(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1);
            
            // Clear the interrupt flag
            CAN_clearInterruptStatus(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1);
            
            // Clear CAN global interrupt flag
            CAN_clearGlobalInterruptStatus(CANA_BASE, CAN_GLOBAL_INT_CANINT0);
        
            // Acknowledge the interrupt
            Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

我面临一个问题、即 CAN_clearMessage 函数不清除该 NewDat 位、所以在接收到第一条消息后、微控制器没有在同一个邮箱接收到任何其他消息。 一旦该邮箱收到第一个消息、它就可以在其他邮箱接收消息、但不能在同一邮箱接收消息。

这是驱动程序中的错误吗?还是错误地使用了这些函数? 我应该如何正确地使用这些函数来确保该 NewDat 位被清除并且邮箱能够接收新消息?

在用以下指令替换 CAN_clearMessage (清除 IF2MCTL 寄存器的 NewDat 位)后、CAN 模块能够接收连续的消息:

void MyCAN_clearMessage(uint32_t base, uint32_t objID)
{
    // Check the arguments.
    ASSERT(CAN_isBaseValid(base));
    ASSERT((objID >= 1U) && (objID <= 32U));

    // Wait for busy bit to clear
    while((HWREGH(base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY) == CAN_IF2CMD_BUSY)
    {
    }

    // Clear the New Data flag
    HWREG_BP(base + CAN_O_IF2CMD) = ((uint32_t)CAN_IF2CMD_TXRQST |
                                     (objID & CAN_IF2CMD_MSG_NUM_M));

    // Wait for busy bit to clear
    while((HWREGH(base + CAN_O_IF2CMD) & CAN_IF2CMD_BUSY) == CAN_IF2CMD_BUSY)
    {
    }
}

感谢您的帮助。

此致、
Filipe

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

    尊敬的 Filipe:

    如何接收消息?  NewDat 位是否已轮询、如果已置位、则读取该消息、还是通过 CAN ISR 读取该消息?  如果通过中断、您还可以提供代码片段吗?  似乎存在一个置位的 oveflow 标志会阻止 NewDat 位的清除。

    谢谢!

    Joseph

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

    尊敬的 Joseph:

    数据 通过  CAN ISR 接收。 之前已经提供了 ISR 代码片段、但我将在这里完整介绍这些代码片段:

    __interrupt void canISR(void)
    {
        uint32_t status;
        uint32_t error_n_status;
        
        // Get the cause of the interrupt
        status = CAN_getInterruptCause(CANA_BASE);
        
        // LoopBack Mailboxes
        if (status == 0x8000) // Error and Status Register value is NOT 0x07 (0x07 means: No CAN bus event was detected since the last time when CPU has         read the Error and Status Register)
        {
            if (CanaRegs.CAN_IF1CMD.bit.MSG_NUM == SEND_MSG_ID_1)
            {
                // Read the received message
                CAN_readMessage(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1, rxData);
    
                // Clear the New Data flag
                MyCAN_clearMessage(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1);
    
                // Clear the interrupt flag
                CAN_clearInterruptStatus(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1);
            }
            
            // Read the Error and Status Register to update the Interrupt Register with the next lower priority interrupt value
            error_n_status = CAN_getStatus(CANA_BASE);
            status = CAN_getInterruptCause(CANA_BASE);
        }
        // Clear CAN global interrupt flag
        CAN_clearGlobalInterruptStatus(CANA_BASE, CAN_GLOBAL_INT_CANINT0);
    
        // Acknowledge the interrupt
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    }


    用于发送数据的函数为:

    void sendCANMessage(void)
    {
        // Define the data to be sent
        uint16_t txData = 0x1234;
    
        // Send the CAN message
        CAN_sendMessage_16bit(CANA_BASE, SEND_MAILBOX_1 + 1, MSG_LEN, &txData);
    }


    宏是:

    #define SEND_MSG_ID_1        (0x01)
    #define SEND_MSG_ID_2        (0x03)
    
    #define RECEIVE_MSG_ID_1     (0x02)
    #define RECEIVE_MSG_ID_2     (0x05)
    
    #define SEND_MAILBOX_1       (0)
    #define SEND_MAILBOX_2       (2)
    
    #define RECEIVE_MAILBOX_1    (16)
    #define RECEIVE_MAILBOX_2    (17)
    
    #define RECEIVE_LOOPBACK_MAILBOX_1       (30)
    #define RECEIVE_LOOPBACK_MAILBOX_2       (31)


    此致、

    Filipe

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

    尊敬的 Filipe:

    谢谢、抱歉漏掉了。  我认为您需要回顾 ISR 的这一部分:

        // Get the cause of the interrupt
        status = CAN_getInterruptCause(CANA_BASE);
        
        // LoopBack Mailboxes
        if (status == 0x8000) // Error and Status Register value is NOT 0x07 (0x07 means: No CAN bus event was detected since the last time when CPU has         read the Error and Status Register)
        {
            if (CanaRegs.CAN_IF1CMD.bit.MSG_NUM == SEND_MSG_ID_1)
            {
                // Read the received message
                CAN_readMessage(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1, rxData);
    
                // Clear the New Data flag
                MyCAN_clearMessage(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1);
    
                // Clear the interrupt flag
                CAN_clearInterruptStatus(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1);
            }
    

    目前、当 CAN_INT 寄存器返回0x8000时、ISR 仅在没有错误时读取消息 RAM。  您的例程应该做的是、当 CAN_INT 返回消息 RAM #时读取消息 RAM 内容、该消息#已填充、当符合条件的 CAN 帧在符合条件要求(例如有效消息 ID、无 CRC 错误、无接收错误等)后移入消息 RAM。  我会这样改写它:

        // Get the cause of the interrupt
        status = CAN_getInterruptCause(CANA_BASE);
        
        // LoopBack Mailboxes
        if (status ==RECEIVE_LOOPBACK_MAILBOX_1 + 1) 
        {
            if (CanaRegs.CAN_IF1CMD.bit.MSG_NUM == SEND_MSG_ID_1)
            {
                // Read the received message
                CAN_readMessage(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1, rxData);
    
    
                // Clear the interrupt flag
                CAN_clearInterruptStatus(CANA_BASE, RECEIVE_LOOPBACK_MAILBOX_1 + 1);
            }
    

    请注意、我注释掉了用于清除 NewDat 的函数。  如果 CAN_INT 返回导致中断的正确邮箱的值、那么 CAN_readMessage()将负责清除 NewDat 位。  现有 ISR 实际上并不处理由导致中断溢出的有效接收消息触发的中断。

    此致、

    Joseph

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

    您好、Joseph

    我尝试了您提出的解决方案、但它的价值 链路状态 在" 状态= CAN_getInterruptCASE (CANA_BASE) " 是 0x00008000  因此不会接收到任何数据。 错误和状态寄存器中唯一的位1是 TxOk。

    如果愿意、CAN 模块的 Tx 和 Rx 引脚直接连接到 CAN 监控器件、则没有 CAN 收发器。 该 CAN 监控器件仅测量信号。 CAN 监控设备测量的信号打印如下所示:



    你认为这个问题与 CAN_readMessage 函数从 IF2读取数据并 CAN_clearMessage 将 IF1寄存器中的 NewDat 位复位这一事实无关吗?

    如果您需要任何其他信息、请告诉我。

    此致、

    Filipe

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

    尊敬的 Filipe:

    只是为了清除 CAN_readMessage、它被用来从消息 RAM 传输接收到的数据、并会清除指定消息对象编号中的 NewDat 位。  从上面的描述来看、我觉得 C2000器件正在发送数据、CAN 监控器件只是接收 C2000可以发送的2个字节。  我不明白如果例程正在发送 CAN 帧、为什么要在 ISR 中使用 CAN_readMessage。  使用 CAN_readMessage API 的任何特殊原因?

    此致、

    Joseph

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

    您好!

     使用 CAN_readMessage 是因为我正在环回模式下使用 CAN 模块、并且我想检查它是否正确接收数据。

    它只是一个在回送模式中的单微控制器。  CAN_readMessage  应该在环回模式下正常工作、不是吗?

    PS:由于您说过  CAN_readMessage 函数会清除 NewDat 位、我刚刚尝试 从 ISR 中注释掉 CAN_clearMessage 函数、现在代码看起来会像我预期的那样运行。


    BR、

    Filipe

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

    尊敬的 Felipe:

    是的、它应该能够在环回模式下工作。  我想还缺少在报文对象定义中启用中断的变量、正因如此报文接收没有进入 ISR。  在消息对象定义中、将参数 CAN_MSG_OBJ_NO_FLAGS 替换为 CAN_MSG_RX_INT_ENABLE、然后您可以监控 CAN_getInterruptCause 的返回值。  它应该返回在消息对象定义中指定的邮箱编号。

    此致、

    Joseph

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

    尊敬的 Joseph:

    CAN_getInterruptCASE 在将 CAN_MSG_OBJ_NO_FLAGS 替换为 CAN_MSG_OBJ_RX_INT_ENABLE 后、仍将返回0x00008000 。

    还有什么缺失吗?

    我还有一个简短的问题、如果您不介意的话。  F280025的技术参考指南提出了一些有关 CAN GPIO 配置的建议、但对于上拉、它仅显示"可以在 GPyPUD 寄存器中配置内部上拉。" 是否建议或不启用 CAN GPIO 中的上拉电阻(考虑到使用了 CAN 收发器)?

    此致、

    Filipe

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

    尊敬的 Filipe:

    您可以在 can_enableInterrupt ()函数调用中删除这些标志(can_INT_error | can_INT_status ),或者在 ISR 中为 status=0x8000分配一个空处理程序。  发生的情况是、每个成功的 CAN 事务都会触发一个 CAN 中断。

    对于第二个问题、无需启用 CAN 引脚上的上拉电阻。  只需使用函数调用 GPIO_setPinConfig ()来为所选的 CAN 引脚设置外设引脚功能。  收发器  在 CANL 和 CANH 之间具有120欧姆端接电阻器、可转换 CAN 总线上的差分模式 CAN 信号。

    此致、

    Joseph