CAN Transmit FIFO

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hello

I work with the MultiCan kernel from the XMC4500. I use a CAN node with a transmit and receive FIFO. The system works very well, but each time when I send multiple messages, one after the other, I have to wait in my CAN transmit function. I have implemented the following while loop
while ( CAN_MOx->MOSTAT & CAN_MO_MOSTAT_TXRQ_Msk );
CAN_MOx is my transmit FIFO base object ( all defined slave objects are used )
With this loop it works well and no messages are lost, but is there a way to send CAN messages, one after the other, without this while loop. The wait time is about 100us.

Regards

Gerhard
0 Likes
3 Replies
Not applicable
Hi Grehard,
you please try to work in interrupt mode, you can use separate interrupt output lines for Tx & Rx of CAN Message, then there will not be any requirement of waiting for one action to complete.

Thanks & Regards,

Ashish
0 Likes
Not applicable
Hi Ashish,

thanks for your answer, but I have already done all your suggestions. For the receiving of CAN messages I use the CAN0_0_IRQHandler and for TX the CAN0_1_IRQHandler.
I have implemented another kind of the while loop. If I write my CAN message to the transmit base object, I save the actual value of the Current Object Pointer (MOFGPR register of the transmit base object). Before I write the next CAN message to the transmit base object I wait until the Current Object Pointer was incremented. Accordingly to the reference manual 18.3.9.4 "When a message transfer takes place with this object, CUR is set to the next message object in the list structure of the slave objects" and I think this is done by hardware.
My problem or my question is, why is this taking so long?

Regards

Gerhard
0 Likes
Not applicable
Hi Gerhard,

I use the TxFifo of the MCAN module without interrupts. The "trick" is to use the MOFGPR.SEL value to select the next msgObj inside the Fifo. I paste you my code, to explain it would be a little bit to complicated...

Best regards,

Mario


sint32_t MCAN0_UpdateMsgObjTxDataAndTransmit(uint8_t objIdx, uint8_t length, const uint8_t * data)
{
sint32_t status = FUNC_RETURN_OK;
uint32_t objIdx_intern = objIdx;
CAN_MO_TypeDef * msgObj = (CAN_MO_TypeDef *)CAN_MO0_BASE;

// *** Check parameter ***
// Check objIdx
if ( objIdx_intern >= MCAN0_MSG_OBJ_CNT )
{
status = FUNC_RETURN_ERROR;
}
else if ( length > 8 )
{
status = FUNC_RETURN_ERROR;
}
else
{ // Parameter ok..
if ( (msgObj[objIdx_intern].MOSTAT & CAN_MO_MOSTAT_DIR_Msk) != 0 )
{
// DIR Bit in MOSTAT is set -> transmit message object

if ( (msgObj[objIdx_intern].MOFCR & CAN_MO_MOFCR_MMC_Msk) != 0 )
{
// Fifo or Gateway Source...
if ( (msgObj[objIdx_intern].MOFCR & CAN_MO_MOFCR_MMC_Msk) == (((uint32_t)2< {
// Transmit Fifo Base Object
uint32_t next, sel, top, bot;

sel = (msgObj[objIdx_intern].MOFGPR & CAN_MO_MOFGPR_SEL_Msk) >> CAN_MO_MOFGPR_SEL_Pos;
top = (msgObj[objIdx_intern].MOFGPR & CAN_MO_MOFGPR_TOP_Msk) >> CAN_MO_MOFGPR_TOP_Pos;
bot = (msgObj[objIdx_intern].MOFGPR & CAN_MO_MOFGPR_BOT_Msk) >> CAN_MO_MOFGPR_BOT_Pos;
if ( sel == top )
{
next = bot;
}
else
{
next = sel+1U;
}
msgObj[objIdx_intern].MOFGPR &= ~(uint32_t)CAN_MO_MOFGPR_SEL_Msk;
msgObj[objIdx_intern].MOFGPR |= (uint32_t)(((uint32_t)next<
objIdx_intern = sel;
}
else
{
// not supported...
status = FUNC_RETURN_ERROR;
}
}

if ( status == FUNC_RETURN_OK )
{
if ( (msgObj[objIdx_intern].MOSTAT & CAN_MO_MOSTAT_TXRQ_Msk) != 0 )
{
// Message object is busy TODO
status = FUNC_RETURN_ERROR;
}
else
{
uint8_t i;
uint32_t tmp;

// Reset Message Object valid bit
msgObj[objIdx_intern].MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk;

// Configure data length
tmp = msgObj[objIdx_intern].MOFCR & ~CAN_MO_MOFCR_DLC_Msk; // clear old settings
msgObj[objIdx_intern].MOFCR = tmp | (((uint32_t)length << CAN_MO_MOFCR_DLC_Pos) & CAN_MO_MOFCR_DLC_Msk);

// Configure Data registers
for ( i = 0U; i < length; i++ )
{
if (i < 4U)
{
uint32_t pos = (uint32_t)i*8UL;
uint32_t mask = CAN_MO_MODATAL_DB0_Msk << ((uint32_t)i*8UL);
uint8_t dataByte = data;
msgObj[objIdx_intern].MODATAL = msgObj[objIdx_intern].MODATAL & ~mask; // delete old byte
msgObj[objIdx_intern].MODATAL |= ((uint32_t)dataByte << pos) & mask;
}
else
{
uint32_t pos = ((uint32_t)i-4UL)*8UL;
uint32_t mask = CAN_MO_MODATAL_DB0_Msk << (((uint32_t)i-4UL)*8UL);
uint8_t dataByte = data;
msgObj[objIdx_intern].MODATAH = msgObj[objIdx_intern].MODATAH & ~mask; // delete old byte
msgObj[objIdx_intern].MODATAH |= ((uint32_t)dataByte << pos) & mask;
} // if(i < 4)
} // for ( i = 0U; i < length; i++ )
// Set NEWDAT bit
msgObj[objIdx_intern].MOCTR = CAN_MO_MOCTR_SETNEWDAT_Msk;

// Reset RTSEL and Set MSGVAL ,TXEN0 and TXEN1 bits
msgObj[objIdx_intern].MOCTR = (CAN_MO_MOCTR_RESRTSEL_Msk |
CAN_MO_MOCTR_SETMSGVAL_Msk );

if( (msgObj[objIdx_intern].MOSTAT & CAN_MO_MOSTAT_TXRQ_Msk) != 0U )
{
status = FUNC_RETURN_ERROR;
}
else
{
// set TXRQ bit
msgObj[objIdx_intern].MOCTR = CAN_MO_MOCTR_SETTXRQ_Msk;
}
} // if ( (msgObj[objIdx_intern].MOSTAT & CAN_MO_MOSTAT_TXRQ_Msk) != 0 ) ... else
} // if ( status == FUNC_RETURN_OK )
} // if ( (msgObj[objIdx_intern].MOSTAT & CAN_MO_MOSTAT_DIR_Msk) != 0 )
else
{
// selected an RX Message Object for TX operation
status = FUNC_RETURN_ERROR;
}
}
return status;
} // sint32_t MCAN0_UpdateMsgObjTxData(uint8_t objIdx, uint8_t length, uint8_t * data)
0 Likes