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**** 2185245 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 该文件中的相关代码片段:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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)
{
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 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);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

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

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

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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)
{
}
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

感谢您的帮助。

此致、
Filipe

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

    尊敬的 Filipe:

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

    谢谢!

    Joseph

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

    尊敬的 Joseph:

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

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    __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);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


    用于发送数据的函数为:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    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);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


    宏是:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #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)
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


    此致、

    Filipe

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

    尊敬的 Filipe:

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

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 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);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

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

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 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);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    请注意、我注释掉了用于清除 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