cancel
Showing results for 
Search instead for 
Did you mean: 

Receiving intermittent interrupts on CAN Rx by using FreeRTOS for STM32U5A5 nucleo board

Vibhor_Meshram
Visitor

Hi,

I Have developed a code to send and receive CAN messages using STM32U5A5 nucleo board. I am able to send and receive CAN messages however when receiving FDCAN interrupt is not always triggered leading to message loss. The behavior is random. I am using FreeRTOS to send the received messages to task using queue and re-transmit the same message. 

The HAL software pack I am using for U5 is 1.6.0.

Following is the relevant code snippet. And attached is the .ioc snippet.

#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "stm32u5xx_nucleo.h"

#define MAX_CAN_DATA_LENGTH         8U

typedef struct {
    FDCAN_RxHeaderTypeDef CanHeader;
    uint8_t CanData[MAX_CAN_DATA_LENGTH];
} CanFrame_t;

/**
  * @brief FDCAN1 Initialization Function
  *  None
  * @retval None
  */
static void MX_FDCAN1_Init(void)
{

  /* USER CODE BEGIN FDCAN1_Init 0 */

  /* USER CODE END FDCAN1_Init 0 */

  /* USER CODE BEGIN FDCAN1_Init 1 */

  /* USER CODE END FDCAN1_Init 1 */
  hfdcan1.Instance = FDCAN1;
  hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV2;
  hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
  hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
  hfdcan1.Init.AutoRetransmission = DISABLE;
  hfdcan1.Init.TransmitPause = DISABLE;
  hfdcan1.Init.ProtocolException = DISABLE;
  hfdcan1.Init.NominalPrescaler = 128;
  hfdcan1.Init.NominalSyncJumpWidth = 1;
  hfdcan1.Init.NominalTimeSeg1 = 14;
  hfdcan1.Init.NominalTimeSeg2 = 5;
  hfdcan1.Init.DataPrescaler = 1;
  hfdcan1.Init.DataSyncJumpWidth = 1;
  hfdcan1.Init.DataTimeSeg1 = 1;
  hfdcan1.Init.DataTimeSeg2 = 1;
  hfdcan1.Init.StdFiltersNbr = 0;
  hfdcan1.Init.ExtFiltersNbr = 0;
  hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
  if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN FDCAN1_Init 2 */

  /* USER CODE END FDCAN1_Init 2 */

}

void FDCAN_Module_Init(uint32_t CanID)
{

    FDCAN_FilterTypeDef sFilterConfig;

    /// Configure the CAN filter
    sFilterConfig.IdType = FDCAN_EXTENDED_ID;
    sFilterConfig.FilterIndex = 0;                          /// Use Filter 0
    sFilterConfig.FilterType = FDCAN_FILTER_MASK;           /// Use mask filtering
    sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;   /// Route to Rx FIFO 0

    /// Listen for any ID where the first 16 bits match 0x18F0, regardless of the lower 13 bits (ID bits 28-16 checked)
    sFilterConfig.FilterID1 = CanID;
    sFilterConfig.FilterID2 = 0x1FFFFFE0;                   /// Mask for extended ID

    if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
    {
        printf("CAN Receive filter configuration failed \r\n");
        Error_Handler();
    }

    if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
    {
        printf("Failed to start CAN communication \r\n");
        Error_Handler();
    }

    /// Enable the Rx FIFO 0 interrupt
    if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
    {
        printf("Failed to activate CAN notification \r\n");
        Error_Handler();
    }
}

void FDCAN_Transmit_Extended_Frame(uint32_t extended_id, uint8_t* data, uint8_t length)
{
    FDCAN_TxHeaderTypeDef TxHeader;

    /// Configure the Tx Header for Extended Format
    TxHeader.Identifier = extended_id;                      /// The 29-bit ID 
    TxHeader.IdType = FDCAN_EXTENDED_ID;                    /// Set ID type to Extended
    TxHeader.TxFrameType = FDCAN_DATA_FRAME;                /// Data frame
    TxHeader.DataLength = FDCAN_DLC_BYTES_8;                /// Data Length Code (DLC)
    TxHeader.FDFormat = FDCAN_CLASSIC_CAN;                  /// Use classic CAN mode
    TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;    /// Don't use Tx Event FIFO
    TxHeader.BitRateSwitch = FDCAN_BRS_OFF;                 /// Bit rate switch off
    TxHeader.MessageMarker = 0;                             /// Message marker (optional)

    // Use timeout 0 to just attempt transmission without blocking
    if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, data) != HAL_OK)
    {
        printf("Failed to transmit CAN message \r\n");
        Error_Handler(); 
    }
}

void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
    CanFrame_t CanRxData;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    memset(&CanRxData.CanData[0], 0, sizeof(CanRxData.CanData));
    if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET)
    {
        // Retrieve the message from Rx FIFO 0
        while (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &CanRxData.CanHeader, CanRxData.CanData) == HAL_OK)
        {
            if (CanRxData.CanHeader.IdType == FDCAN_EXTENDED_ID)
            {   
                if (xQueueSendFromISR(xCanQueue, &CanRxData, &xHigherPriorityTaskWoken) != pdPASS)
                {
                    /// TODO: Handle ISR error
                }
                portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

            }
        }
    }
}

static void CanTaskHandler(void *pArgument)
{
    CanFrame_t ReceivedCanFrame;
    /// TODO: Fetch CAN ID from EEPROM before initializing
    FDCAN_Module_Init(0x18F00100);
    while (1)
    {
        if (xQueueReceive(xCanQueue, &ReceivedCanFrame, pdMS_TO_TICKS(QUEUE_TIMEOUT_MS)) == pdPASS)
        {
            FDCAN_Transmit_Extended_Frame(0x12300100, ReceivedCanFrame.CanData, 3);  
        } 
        vTaskDelay(1000);   
    }
}

#define CAN_QUEUE_SIZE              10
#define QUEUE_TIMEOUT_MS            1000
#define CAN_STACK_SIZE              256
#define CAN_TASK_PRIORITY           6 

QueueHandle_t xCanQueue;
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */
  BaseType_t Error = 0;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* Configure the System Power */
  SystemPower_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_FDCAN1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Init scheduler */
  osKernelInitialize();


  /* Initialize USER push-button, will be used to trigger an interrupt each time it's pressed.*/
  BSP_PB_Init(BUTTON_USER, BUTTON_MODE_EXTI);

  /* Initialize COM1 port (115200, 8 bits (7-bit data + 1 stop bit), no parity */
  BspCOMInit.BaudRate   = 115200;
  BspCOMInit.WordLength = COM_WORDLENGTH_8B;
  BspCOMInit.StopBits   = COM_STOPBITS_1;
  BspCOMInit.Parity     = COM_PARITY_NONE;
  BspCOMInit.HwFlowCtl  = COM_HWCONTROL_NONE;
  if (BSP_COM_Init(COM1, &BspCOMInit) != BSP_ERROR_NONE)
  {
    Error_Handler();
  }
  TaskHandle_t CanTaskHandle;

  xCanQueue = xQueueCreate(CAN_QUEUE_SIZE, sizeof(CanFrame_t));
  xTaskCreate(CanTaskHandler, "CanTaskHandle", CAN_STACK_SIZE, NULL, CAN_TASK_PRIORITY, &CanTaskHandle);
  
  /* Start scheduler */
  vTaskStartScheduler();

  return 0;
}

Vibhor_Meshram_0-1763727411126.pngVibhor_Meshram_1-1763727448670.pngVibhor_Meshram_2-1763727470708.pngVibhor_Meshram_3-1763727490861.png

 

1 REPLY 1
mƎALLEm
ST Employee

Hello @Vibhor_Meshram and welcome to the ST community,

I'm already curious how are you receiving CAN frames even in intermittent way with those parameters set to 0:

  hfdcan1.Init.StdFiltersNbr = 0;
  hfdcan1.Init.ExtFiltersNbr = 0;

Please test the communication without RTOS first. Test also with the Loopback mode. This is how to debug such kind of issues.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.