The SDK 1.2 FSL_FlexCAN is confusing me for simple blocking send/receive calls.
I have a simple model where I send a command and wait for a response.
Send works fine:
while(FLEXCAN_DRV_GetTransmitStatus(FSL_CANCOM1) == kStatus_FLEXCAN_TxBusy);
FLEXCAN_DRV_ConfigTxMb(FSL_CANCOM1, TX_mailbox_num, &data_info, destination_id);
result = FLEXCAN_DRV_SendBlocking(FSL_CANCOM1, TX_mailbox_num, &data_info, destination_id, (uint8_t*) message->data, CAN_TX_TIMEOUT);
I would think receive would be similar:
FLEXCAN_DRV_ConfigRxMb(FSL_CANCOM1, RX_mailbox_num, &rx_info, MAIN_MODULE_ID);
flexcan_status_t status = FLEXCAN_DRV_RxMessageBufferBlocking(FSL_CANCOM1, RX_mailbox_num, &rx_buf, CAN_RX_TIMEOUT);
The problem is that the RxMessageBufferBlocking call does not block waiting on the received packet. The comment indicates that it blocks after a receive interrupt. I don't get what the proper sequence here is for a simple send/receive.
FWIW, when the above code is run odd things happen, the most disturbing thing is invalid faults to random un-handled processor exceptions, usually in FLEXCAN_DRV_IRQHandler at the last line, FLEXCAN_HAL_ClearErrIntStatusFlag(base);
This seems to be a hardware issue with the K64 as far as I can tell, as a random fault like this should never occur. I have seen others have had similar problems, but the resolution of them was not documented.
I have looked at the simple flexcan demo code, but it does not do blocking.
Best Regards...
Hi, Craig,
I have read the example code of flexCan located at the directory:
D:\Freescale\KSDK_1.3.0\examples\twrk64f120m\driver_examples\flexcan\flexcan_network\kds
I think the FLEXCAN_DRV_RxMessageBufferBlocking(FSL_CANCOM1, RX_mailbox_num, &rx_buf, CAN_RX_TIMEOUT) function can block the FlexCan receiver MB. I listed all the functions having something to do with the above function.
When a FlexCan interrupt happens, the FLEXCAN_DRV_IRQHandler() is executed automatically, in the function, the interrupt source is identified. If the FlexCan receiving MB leads to the interrupt, the FLEXCAN_DRV_CompleteRxMessageBufferData(instance); is called, the
OSA_SemaPost(&state->rxIrqSync) is called, the FLEXCAN_DRV_RxMessageBufferBlocking() will unblock. Otherwise, the FLEXCAN_DRV_RxMessageBufferBlocking() function will be blocked by the code:
do
{
syncStatus = OSA_SemaWait(&state->rxIrqSync, timeout_ms);
}while(syncStatus == kStatus_OSA_Idle);
If the other fault of FlexCan except for receiving MB interrupt happens, the FLEXCAN_DRV_IRQHandler() is executed, but the FLEXCAN_DRV_CompleteRxMessageBufferData(instance) is NOT called, OSA_SemaPost(&state->rxIrqSync) is NOT signaled, the FLEXCAN_DRV_RxMessageBufferBlocking() will be in blocking state.
Hope it can help you.
BR
Xiangjun Rong
/*FUNCTION**********************************************************************
*
* Function Name : FLEXCAN_DRV_RxMessageBufferBlocking
* Description : Start receive data after a Rx MB interrupt occurs.
* This function will lock Rx MB after a Rx MB interrupt occurs.
*
*END**************************************************************************/
flexcan_status_t FLEXCAN_DRV_RxMessageBufferBlocking(
uint8_t instance,
uint32_t mb_idx,
flexcan_msgbuff_t *data,
uint32_t timeout_ms)
{
assert(instance < CAN_INSTANCE_COUNT);
assert(data);
flexcan_status_t result;
flexcan_state_t * state = g_flexcanStatePtr[instance];
osa_status_t syncStatus;
state->isRxBlocking = true;
result = FLEXCAN_DRV_StartRxMessageBufferData(instance, mb_idx, data);
if(result == kStatus_FLEXCAN_Success)
{
do
{
syncStatus = OSA_SemaWait(&state->rxIrqSync, timeout_ms);
}while(syncStatus == kStatus_OSA_Idle);
/* Wait for the interrupt*/
if (syncStatus != kStatus_OSA_Success)
{
return kStatus_FLEXCAN_TimeOut;
}
}
return result;
}
/*FUNCTION**********************************************************************
*
* Function Name : FLEXCAN_DRV_StartRxMessageBufferData
* Description : Initiate (start) a receive by beginning the process of
* receiving data and enabling the interrupt.
* This is not a public API as it is called from other driver functions.
*
*END**************************************************************************/
static flexcan_status_t FLEXCAN_DRV_StartRxMessageBufferData(
uint8_t instance,
uint32_t mb_idx,
flexcan_msgbuff_t *data
)
{
flexcan_status_t result;
CAN_Type * base = g_flexcanBase[instance];
flexcan_state_t * state = g_flexcanStatePtr[instance];
/* Start receiving mailbox */
if(state->isRxBusy)
{
return kStatus_FLEXCAN_RxBusy;
}
state->isRxBusy = true;
state->mb_message = data;
/* Enable MB interrupt*/
result = FLEXCAN_HAL_SetMsgBuffIntCmd(base, mb_idx, true);
/* Enable error interrupts */
FLEXCAN_HAL_SetErrIntCmd(base,kFlexCanIntErr,true);
return result;
}
/*FUNCTION**********************************************************************
*
* Function Name : FLEXCAN_DRV_CompleteRxMessageBufferData
* Description : Finish up a receive by completing the process of receiving
* data and disabling the interrupt.
* This is not a public API as it is called from other driver functions.
*
*END**************************************************************************/
static void FLEXCAN_DRV_CompleteRxMessageBufferData(uint32_t instance)
{
assert(instance < CAN_INSTANCE_COUNT);
CAN_Type * base = g_flexcanBase[instance];
flexcan_state_t * state = g_flexcanStatePtr[instance];
FLEXCAN_HAL_SetMsgBuffIntCmd(base, state->rx_mb_idx, false);
/* Disable error interrupts */
FLEXCAN_HAL_SetErrIntCmd(base,kFlexCanIntErr,false);
/* Signal the synchronous completion object. */
if (state->isRxBlocking)
{
OSA_SemaPost(&state->rxIrqSync);
}
/* Update the information of the module driver state */
state->isRxBusy = false;
}
void FLEXCAN_DRV_IRQHandler(uint8_t instance)
{
volatile uint32_t flag_reg;
uint32_t temp;
CAN_Type * base = g_flexcanBase[instance];
flexcan_state_t * state = g_flexcanStatePtr[instance];
/* Get the interrupts that are enabled and ready */
flag_reg = ((FLEXCAN_HAL_GetAllMsgBuffIntStatusFlag(base)) & CAN_IMASK1_BUFLM_MASK) &
CAN_RD_IMASK1(base);
/* Check Tx/Rx interrupt flag and clear the interrupt */
if(flag_reg)
{
if ((flag_reg & 0x20) && CAN_BRD_MCR_RFEN(base))
{
if (state->fifo_message != NULL)
{
/* Get RX FIFO field values */
FLEXCAN_HAL_ReadRxFifo(base, state->fifo_message);
/* Complete receive data */
FLEXCAN_DRV_CompleteRxMessageFifoData(instance);
FLEXCAN_HAL_ClearMsgBuffIntStatusFlag(base, flag_reg);
}
}
else
{
/* Check mailbox completed reception*/
temp = (1 << state->rx_mb_idx);
if (temp & flag_reg)
{
/* Unlock RX message buffer and RX FIFO*/
FLEXCAN_HAL_LockRxMsgBuff(base, state->rx_mb_idx);
/* Get RX MB field values*/
FLEXCAN_HAL_GetMsgBuff(base, state->rx_mb_idx, state->mb_message);
/* Unlock RX message buffer and RX FIFO*/
FLEXCAN_HAL_UnlockRxMsgBuff(base);
/* Complete receive data */
FLEXCAN_DRV_CompleteRxMessageBufferData(instance);
FLEXCAN_HAL_ClearMsgBuffIntStatusFlag(base, temp & flag_reg);
}
/* Check mailbox completed transmission*/
temp = (1 << state->tx_mb_idx);
if (temp & flag_reg)
{
/* Complete transmit data */
FLEXCAN_DRV_CompleteSendData(instance);
FLEXCAN_HAL_ClearMsgBuffIntStatusFlag(base, temp & flag_reg);
}
}
/* Check mailbox completed transmission*/
temp = (1 << state->tx_mb_idx);
if (flag_reg & temp)
{
/* Complete transmit data */
FLEXCAN_DRV_CompleteSendData(instance);
FLEXCAN_HAL_ClearMsgBuffIntStatusFlag(base, temp & flag_reg);
}
}
/* Clear all other interrupts in ERRSTAT register (Error, Busoff, Wakeup) */
FLEXCAN_HAL_ClearErrIntStatusFlag(base);
return;
}
Hi Xiangjun and Freescale folks
I find this flexcan driver undocumented, incomplete, and confusing.
While you indicate that FLEXCAN_DRV_RxMessageBufferBlocking can be blocking, it only does if Rx is not already busy.
The blocking Tx call has a similar issue.
While normally this is not an issue for my code, when there is a CAN bus error, the interrupt routine provided does not handle the error or follow the protocol to reset the Tx or Rx buffers as far as I can see.
Is there any document or example code that gives an idea of what is required to make this driver work and properly handle a CAN bus error? When errors occur now, there seems to be a high probability that the interrupt handler will hard-fault when it accesses a buffer improperly since it does not check for errors before doing so, at least the way that I read the code.
Best regards,
Craig
Hi, Craig,
Regarding the documentation of FlexCan driver, the <<Kinetis SDK v1.3 API Reference Manual.pdf>> located at: D:\Freescale\KSDK_1.3.0\doc is the only doc.
For the flexCan driver itself, you are right, the disadvantage is that void FLEXCAN_DRV_IRQHandler(uint8_t instance) only handles the interrupt source of the message buffer of transmitter/receiver, for the other interrupt source, the api function does not poll the case, just clear all the flags with the code:
/* Clear all other interrupts in ERRSTAT register (Error, Busoff, Wakeup) */
FLEXCAN_HAL_ClearErrIntStatusFlag(base);
BR
XiangJun Rong
Hi XiangJun
Thanks for the reply.
Can you point me to any existing code that does properly handle errors, perhaps in the MQX or other drivers? A driver like this that is so incomplete is not usable except for quick, unimportant demonstration code, and I have a production product to get out.
Best regards,
Craig