Configuration and use of FlexCAN on MPC5604P

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Configuration and use of FlexCAN on MPC5604P

1,759 Views
michaeldubois
Contributor I

In my project, my application is not receiving approximately 1-2 out of every 100 CAN frames transmitted. My tool is sending a variety of test CAN messages, all with a period of 8 ms. I poll the interrupt flag of each CAN mailbox every 500us, retrieve the data into a buffer specific to that mailbox if the flag is set, and process the retrieved data buffer for each mailbox every 10 ms. When the retrieved data buffers are processed, between 1-2% of the time the timestamp in a buffer is the same as the last time the buffer was processed.

In addition, although I believe I am correctly locking and unlocking each mailbox when I process it, if I set up numerous mailboxes with the same CAN ID, after receiving between zero and a dozen messages, each mailbox no longer becomes "free to receive" and all of my messages are received in the LAST mailbox with that ID, which experiences frequent overruns according to the CODE field.

Can anyone assist me?

This is my CAN device configuration (the BOFF and ERR interrupts are configured elsewhere):

void scan_drv_config_peripheral(volatile struct FLEXCAN_tag * CAN_device)
{

U8 PCR_CAN_TX_PIN;
U8 PCR_CAN_RX_PIN;
U16 i = 0;

scanl_drv_device = CAN_device;

/* Set the CAN Tx and Rx pins depending on the CAN_device */
PCR_CAN_TX_PIN = CAN0_CANTX;
PCR_CAN_RX_PIN = CAN0_CANRX;

/* Disable the CAN module before configuring the Control Register (CR) */
CAN_device->MCR.B.MDIS = 1; /* Disable FlexCAN module */
CAN_device->MCR.B.FRZ = 1; /* Enable Freeze Mode */
CAN_device->MCR.B.HALT = 1; /* Enter Freeze Mode */
CAN_device->MCR.B.MAXMB = 0x1F; /* Set max message buffers = 32 (MAXMB + 1) */

/* FIFO disabled */
CAN_device->MCR.B.FEN = 0;
CAN_device->MCR.B.BCC = 1;
/* Reject all messages from the FIFO */
CAN_device->MCR.B.IDAM = 3;

while ((CAN_device->MCR.B.FRZACK != 1) && (CAN_device->MCR.B.NOTRDY != 1))
{
}

/* Initialize the Control Register */
CAN_device->CR.B.BOFFMSK = 1;
CAN_device->CR.B.ERRMSK = 1;

/* Disable all the CAN interrupts */
CAN_device->IMRL.R = 0;


/* CAN TXD Pin configuration */
SIU.PCR[PCR_CAN_TX_PIN].B.PA = 1;
SIU.PCR[PCR_CAN_TX_PIN].B.OBE = 1;
SIU.PCR[PCR_CAN_TX_PIN].B.WPE = 1;
SIU.PCR[PCR_CAN_TX_PIN].B.WPS = 1;

/* CAN RXD Pin configuration */
SIU.PCR[PCR_CAN_RX_PIN].B.PA = 1;
SIU.PCR[PCR_CAN_RX_PIN].B.IBE = 1;
SIU.PCR[PCR_CAN_RX_PIN].B.WPE = 1;
SIU.PCR[PCR_CAN_RX_PIN].B.WPS = 1;

/* Enable the CAN module */
CAN_device->MCR.B.MDIS = 0;

/* Initialize message buffers */
for (i=0; i < SCAN_MESSAGE_BUFFERS; i++)
{

CAN_device->RXIMR[i].R = 0xFFFFFFFF;

CAN_device->BUF[i].ID.R = 0;
CAN_device->BUF[i].CS.B.SRR = 0;
CAN_device->BUF[i].CS.B.IDE = 0;
CAN_device->BUF[i].CS.B.RTR = 0;
CAN_device->BUF[i].CS.B.CODE = 0;
CAN_device->BUF[i].CS.B.LENGTH = 0;
CAN_device->BUF[i].CS.B.TIMESTAMP = 0;
CAN_device->BUF[i].DATA.W[0] = 0;
CAN_device->BUF[i].DATA.W[1] = 0;
CAN_device->BUF[i].ID.B.STD_ID = 0;

}

/* set baud 500 kbps */
CAN_device->CR.B.PRESDIV = 0;
CAN_device->CR.B.PROPSEG = 6;
CAN_device->CR.B.PSEG1 = 3;
CAN_device->CR.B.PSEG2 = 3;
CAN_device->CR.B.RJW = 3;

/* Negate the HALT bit in MCR */
CAN_device->MCR.B.HALT = 0;

/* Once out of Freeze Mode, FLEXCAN tries to re-synchronize to the CAN bus
by waiting for 11 consecutive recessive bits */
while (CAN_device->MCR.B.NOTRDY != 0)
{
}

}

I check the CAN mailboxes by polling IFRL every 500 us:

static void scanl_drv_txrx(volatile struct FLEXCAN_tag * CAN_device)
{

U8 i;
U8 j;
U32 ifrl;
struct FLEXCAN_BUF_t temp_buffer;
volatile U32 control_status;
CAN_PDU_T canRxPdu;
volatile U32 dummy_timer;

ifrl = CAN_device->IFRL.R;

/* Find the mail box in which the frame was received or transmitted */
for (i = 0; i < scanf_frame_cnt; i++)
{

/* Check IFLAG since CS is not coherent */
if ((ifrl & (U32)(1u << (i))) != 0)
{

if(SCAN_RX_MSG == scan_api_get_msg_direction((CAN_RX_FRAME_HANDLE_E)i) )
{

BOOL overrun = FALSE;

/* read the Control and Status word to lock the buffer */
control_status = CAN_device->BUF[i].CS.R;

/* Do not proceed until the BUSY bit is clear */
while (FLEXCAN_CS_BUSY_MSK == (control_status & FLEXCAN_CS_BUSY_MSK) )
{

/* wait */
control_status = CAN_device->BUF[i].CS.R;

}


/* Copy message buffer for processing */
memcpy(&temp_buffer, (struct FLEXCAN_BUF_t*)&CAN_device->BUF[i], sizeof(struct FLEXCAN_BUF_t));

/* Read TIMER to unlock the message buffer */
dummy_timer = CAN_device->TIMER.R;

/* Reset the interrupt flag */
CAN_device->IFRL.R |= (U32)(1u << (i));

/* Check the IDE bit to see if and extended ID is being used.
If the ID is extended, use ID.R as the ID. Otherwise, use
ID.B.STD_ID. */
if (TRUE == temp_buffer.CS.B.IDE)
{

canRxPdu.CanId = temp_buffer.ID.R;

}
else
{

canRxPdu.CanId = temp_buffer.ID.B.STD_ID;

}
canRxPdu.Dlc = (U8)(temp_buffer.CS.B.LENGTH);

for(j = 0; j < canRxPdu.Dlc; j++)
{

canRxPdu.Data[j] = temp_buffer.DATA.B[j];

}

canRxPdu.timestamp = (U32)temp_buffer.CS.B.TIMESTAMP;

if(CAN_MB_RX_OVERRUN == temp_buffer.CS.B.CODE)
{

overrun = TRUE;

}

scan_api_rx_callback(&canRxPdu, (CAN_TX_FRAME_HANDLE_E)i, overrun);

}
else if(SCAN_TX_MSG == scan_api_get_msg_direction((CAN_RX_FRAME_HANDLE_E)i) )
{

/* Reset the interrupt flag */
CAN_device->IFRL.R |= (U32)(1u << (i));

/* Call the callback */
scan_api_tx_callback((CAN_TX_FRAME_HANDLE_E)i);

}
else
{

/* invalid message - ignore */

}

}

}

}

This task is run every 10 ms in my test application:

static void scan_checktime(void)

{

U8 msg_ind;
U32 timestamp;

for(msg_ind = 0; msg_ind < NUM_RX_MSGS; msg_ind++)
{

timestamp = CanRxBuffer[msg_ind].CanPdu.Timestamp;

if(timestamp == sio_rx_msg_timestamp[msg_ind])
{

sio_can_rx_error_cnt[msg_ind]++;

}
sio_rx_msg_timestamp[msg_ind] = timestamp;

}

}

Tags (2)
0 Kudos
Reply
1 Reply

775 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi Michael,

do not use OR operation for clearing flags, it may easily happen other flags can be cleared too.

So instead of 

CAN_device->IFRL.R |= (U32)(1u << (i));

use simply

CAN_device->IFRL.R = (U32)(1u << (i));

BR, Petr

0 Kudos
Reply