AnsweredAssumed Answered

FlexCAN transmit + receive on K64F with KSDK 1.2 - Rx causes hardfault

Question asked by Angus Galloway on Aug 20, 2015

Note: This post seems to have been posted twice and much of the detail in the original post has been lost. I will try to recall those details.

 

I am using the KSDK fsl_flexcan_driver to implement basic transmitting and receive functionality in my application. The transmitting works consistently, however I have found that receive either only works when code execution is paused and I step through the code, or it causes a hardfault when the code is run at full speed and an attempt is made to receive a message.

 

I am using the FRDM-K64F with a custom shield using a Freescale 33901 CAN transceiver, however the hardware is 100% confirmed to be working correctly, since TX works and the RX messages do make it to the RX message buffer, the failure lies at some stage after that.

 

I have boiled the problem down to a very simple program. I will post the relevant bits here and I have attached the complete project. The hardfault is entered immediately after returning from the FLEXCAN_DRV_IRQHandler in the KSDK. I am copying it here:

 

/*FUNCTION**********************************************************************  *  * Function Name : FLEXCAN_DRV_IRQHandler  * Description   : Interrupt handler for FLEXCAN.  * This handler read data from MB or FIFO, and then clear the interrupt flags.  * This is not a public API as it is called whenever an interrupt occurs.  *  *END**************************************************************************/ 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)             {                 /* Lock 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); // Commented out by Angus, 8/13/2015                 FLEXCAN_HAL_ClearMsgBuffIntStatusFlag(base, temp & flag_reg);             }             /* WHY DO THIS CHECK HERE IF WE DO IT AGAIN REGARDLESS OF "ELSE" CONDITION             // Check mailbox completed transmission             temp = (1 << state->tx_mb_idx);             if (temp & flag_reg)             {                 // Complete transmit data                 FLEXCAN_DRV_CompleteSendData(instance); // Commented out by Angus, 8/13/2015                 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); // Commented out by Angus, 8/13/2015                 FLEXCAN_HAL_ClearMsgBuffIntStatusFlag(base, temp & flag_reg);         }     }       /* Clear all other interrupts in ERRSTAT register (Error, Busoff, Wakeup) */     FLEXCAN_HAL_ClearErrIntStatusFlag(base);       return; }

 

In MQX 4.2, the IMASK flag is never changed in an ISR, but the IMASK is reset to 0 here in "FLEXCAN_DRV_CompleteRxMessageBufferData(instance)".

Also, it shouldn't matter, but it appears there is some redundant code in the KSDK IRQ Handler for checking mailbox transmission.

 

In FLEXCAN_HAL_GetMsgBuff(), I am wondering why for this loop:

 

    /* Copy MB data field into user's buffer*/

    for (i = 0 ; i < kFlexCanMessageSize ; i++)

 

They did not use the actual DLC of the received message, rather than kFlexCanMessageSize which is defined as a constant 8.

 

Below are the relevant pieces of custom code, main and my RX function.

 

main.c

 

#include "flexcan.h"  // *************************************************************************** // Definitions // ***************************************************************************   //#define DO_PRINT // Un-comment this to print out debug info  void hardware_init();  /*! defined in main.c     */ void init_flexcan(void);  /*! defined in flexcan.c  */  void hardware_init() {    /* enable clock for PORTs */   CLOCK_SYS_EnablePortClock(PORTA_IDX); /*! */   CLOCK_SYS_EnablePortClock(PORTB_IDX); /*! The CAN pins are on port B */   CLOCK_SYS_EnablePortClock(PORTC_IDX); /*! */   CLOCK_SYS_EnablePortClock(PORTD_IDX); /*! The SPI pins are on port D */   CLOCK_SYS_EnablePortClock(PORTE_IDX); /*! The I2C pins are on port E */    /* Init board clock */   BOARD_ClockInit();   dbg_uart_init();    configure_can_pins(0);  // Configure CAN pins    OSA_Init();             //FXOS_Init seems to depend on this, so does OSA_TimeDelay(ms)    init_flexcan(); // For vscp events    STATUS_LED_EN; /* LED1_EN */   CLOCK_PIN_EN;  /* scope this pin to test the 1 ms clock pulse width */   INIT_BTN_EN;   /* init sw2 as input */  // Enable a gpio for taking the STB pin on the CAN PHY low   CAN0_STB_EN;   CAN0_STB_LO;  }   // *************************************************************************** // Main() - Main Routine // *************************************************************************** int main(void) {    int i;   FLEXCAN_RX_MSG_FLAGS flags;    /* For transmit */    uint32_t id = 0x1eadbeef; //29-bit can ID   flexcan_code_t ret;    uint8_t pdata[8] = {11,22,33,44,55,66,77,88}; // data    /* For receive */   uint32_t can_pid;   uint32_t can_pdlc;   uint32_t rxData[8];    // Init mcu and peripherals   hardware_init();    while(1) {     ret = FLEXCANSendMessage(id, 8, pdata, FLEXCAN_TX_XTD_FRAME);    OSA_TimeDelay(500);    ret = FLEXCANReceiveMessage(&can_pid, &can_pdlc, rxData, &flags);    if(ret){         if(can_pdlc > 8)             can_pdlc = 8;          printf("ID: 0x%lx, DLC=%lu \r\n",can_pid, can_pdlc);        printf("RX MB data: 0x");          for (i = 0; i < can_pdlc; i++){             printf("%02lx ", rxData[i]);        }        printf("\r\n");   }   }   return 0; }

 

init_flexcan() sets up 16 message buffers, the bottom 8 as RX (Inactive) and the top half as TX (Inactive). Only MB0 is used as an active RX buffer, while MB8 is used as the TX MB.


flexcan.c - FLEXCANReceiveMessage()

 

flexcan_code_t FLEXCANReceiveMessage(uint32_t *pid, uint32_t *pdlc, uint32_t *pdata, FLEXCAN_RX_MSG_FLAGS *msgFlags) {      uint32_t result = 0;      flexcan_msgbuff_t rxMb;           /* Configure RX MB fields       *       * global rxMailboxNum = 0;       * global rxIdentifier = 900;       * global rxInfo       *       * */            if(FLEXCAN_DRV_GetReceiveStatus(BOARD_CAN_INSTANCE) == kStatus_FLEXCAN_Success)      {           /* Attempt to receive a message into rxMb */           result = FLEXCAN_DRV_RxMessageBufferBlocking(BOARD_CAN_INSTANCE, rxMailboxNum, &rxMb, 1000);         //result = FLEXCAN_DRV_RxMessageBufferBlocking(BOARD_CAN_INSTANCE, rxMailboxNum, &rxMb, OSA_WAIT_FOREVER);         //result = FLEXCAN_DRV_RxMessageBuffer(BOARD_CAN_INSTANCE, rxMailboxNum, &rxMb);            if(!result) {                  /* Successfully received something! Begin extracting information from message                  * buffer which is defined on pg. 1400 of the K64 Sub-Family Ref. Manual */                   *pid = rxMb.msgId;  // The message ID occupies bits 0-28 (EXT) or 18-28 (STD)                     *pdlc = ((rxMb.cs) >> 16) & 0xF;  // The data length field (DLC) occupies bits 16 - 19                   *msgFlags = ((rxMb.cs) >> 21) & 0x1; // The ID Extended Bit field (IDE) is bit 21                    for (result = 0; result < *pdlc; result++){                        pdata[result] = rxMb.data[result];                    }                   return FLEXCAN_SUCCESS;             }        }        return FLEXCAN_FAIL; }

 

I am not attempting to do any sort of loopback, the goal is to be able to send and receive any message at any time with send and receive functions. A global mask is used to only receive extended messages ending in 0x900.

 

I am attaching screenshots of the CAN0 register contents before and after the hardfault:

CAN_IRQ_BEFORE_HF.PNG

 

After returning from the IRQ handler, we see that the IMASK AND IFLAG for MB0 have been disabled. There no errors in any of the CAN registers. 900 and 0x01, 0x02 are the correct data in WORD0.

CAN_AFTER_HF.PNG

Original Attachment has been moved to: basic_can_frdmk64f.zip

Outcomes