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
