Other Parts Discussed in Thread: C2000WARE
Tool/software:
Hello,
I am currently working with the F28002x microcontroller and using the CAN driver functions provided in C2000Ware driverlib. I have encountered an issue with the CAN_readMessage
and CAN_clearMessage
functions.
It appears that the CAN_readMessage
function reads data from the IF2 register, while the CAN_clearMessage
function clears the NewDat
bit using the IF1 register. This discrepancy seems to cause issues where the NewDat
bit is not being cleared properly, leading to the mailbox not being able to receive new messages after the first one.
I found this implementation in the two versions of C2000Ware that I've tried: C2000Ware_4_03_00_00 and C2000Ware_DigitalPower_SDK_5_04_00_00.
Here is the relevant code snippet from the can.c
file:
// 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));
}
The code snippets below shows that configuration of the CAN module and the routine used to read the received data:
// 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);
I am facing a problem where the CAN_clearMessage
function is not clearing the NewDat
bit, so after receiving the first message, the microcontroller is not receiving any other messages in the same mailbox. It can receive messages in other mailboxes, but not in the same mailbox once this mailbox received the first message.
Is this an error in the driver, or am I using these functions incorrectly? How should I properly use these functions to ensure that the NewDat
bit is cleared and the mailbox can receive new messages?
After replacing the CAN_clearMessage by the one below, which clears the NewDat bit of the IF2MCTL register, the CAN module was able to receive successive messages:
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) { } }
Thank you for your assistance.
Best regards,
Filipe