explanation of simple blocking FSL_FLEXCAN api:

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

explanation of simple blocking FSL_FLEXCAN api:

2,120 Views
craigcampbell
Contributor I

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...

Labels (1)
Tags (1)
0 Kudos
Reply
4 Replies

1,724 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

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;

}

0 Kudos
Reply

1,725 Views
craigcampbell
Contributor I

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

0 Kudos
Reply

1,725 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

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

0 Kudos
Reply

1,725 Views
craigcampbell
Contributor I

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

0 Kudos
Reply