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.
工具与软件:
您好!
我目前使用 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