Rick N.
Rick N.

Reputation: 41

FDCAN problems on STM32G4

I am developing a new project for the STM32G474 processor using the STM32G474E-EVAL1 board but am having a problem with FDCAN. I have two issues:

  1. I configure FDCAN and use the function HAL_FDCAN_AddMessageToTxFifoQ but the queue quickly fills up and no CAN transmission takes place. I have verified the physical connection and cable termination.

  2. I set up a receive filter to accept all incoming messages and send them to RX FIFO 0, and I activate notifications with HAL_FDCAN_ActivateNotification using the argument FDCAN_IT_RX_FIFO0_NEW_MESSAGE, but I never get a CAN interrupt when messages are sent from the host. I am using a CAN analyzer to verify that the messages are sent.

I am using Classic CAN at 125Kbps.

Here is the STM32CubeMX generated code and the filter I set up:

/**
  * @brief FDCAN1 Initialization Function
  * @param 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_DIV1;
  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 = 160;
  hfdcan1.Init.NominalSyncJumpWidth = 1;
  hfdcan1.Init.NominalTimeSeg1 = 2;
  hfdcan1.Init.NominalTimeSeg2 = 2;
  hfdcan1.Init.DataPrescaler = 1;
  hfdcan1.Init.DataSyncJumpWidth = 16;
  hfdcan1.Init.DataTimeSeg1 = 15;
  hfdcan1.Init.DataTimeSeg2 = 5;
  hfdcan1.Init.StdFiltersNbr = 1;
  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 */

  // Set up filters
  FDCAN_FilterTypeDef sFilterConfig;
  sFilterConfig.IdType = FDCAN_STANDARD_ID; // vs. Extended ID
  sFilterConfig.FilterIndex = 0; // the number of the filter we are using
  sFilterConfig.FilterType = FDCAN_FILTER_MASK;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; // what to do filter match
  sFilterConfig.FilterID1 = 0; // filter
  sFilterConfig.FilterID2 = 0; // mask: 0=>accept all messages
  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
  {
    // Filter configuration error
    Error_Handler();
  }
  // There will be no remote messages
  if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, 
                                   FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE END FDCAN1_Init 2 */

}

I subsequently call the following functions:

void canfestival_CAN_Initialize(CO_Data* can_handle)
{
  // Set up the transmit header
  TxHeader.IdType = FDCAN_STANDARD_ID;
  TxHeader.TxFrameType = FDCAN_DATA_FRAME;
  TxHeader.DataLength = FDCAN_DLC_BYTES_8;
  TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE; // Error State Indicator for Tx errors
  TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
  TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
  TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
  TxHeader.MessageMarker = 0;

  // Start CAN timer for use by CANfestival
  if (HAL_TIM_Base_Start_IT(&hCAN_FESTIVAL_TIMER) != HAL_OK)
  {
    Error_Handler();
  }

  // Start FDCAN module
  if (HAL_FDCAN_Start(&hFDCAN_MODULE) != HAL_OK)
  {
    Error_Handler();
  }

  // Set up to interrupt when a new message arrives in the RX Fifo 0
  if (HAL_FDCAN_ActivateNotification(&hFDCAN_MODULE, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
  {
    Error_Handler();
  }
}

Issue 1: I use the function HAL_FDCAN_AddMessageToTxFifoQ but the queue quickly fills up and no CAN transmission takes place.

void canxmit_Task(void)
{
  Message message;
  osStatus_t status;

  while(true)
  {
    // Check to see if the Tx FIFO is full.
    if ((hFDCAN_MODULE.Instance->TXFQS & FDCAN_TXFQS_TFQF) != 0)
    {
      break; // Tx FIFO is full.
    }

    // Check for any messages in the RTOS queue.
    status = osMessageQueueGet(CanXmitQueueHandle, &message, NULL, 0);
    if (status == osErrorTimeout)
    {
      break; // No new messages to send.
    }
    if (status != osOK)
    {
      Error_Handler();
    }

    // Copy message from data structure used by CANfestival into that required for HAL.
    TxHeader.Identifier = message.cob_id;
    TxHeader.TxFrameType = (message.rtr != 0) ? FDCAN_REMOTE_FRAME : FDCAN_DATA_FRAME;
    TxHeader.DataLength = message.len;
    for (uint32_t i = 0; i < message.len; i++)
    {
      TxData[i] = message.data[i];
    }

    // Add message to CAN Fifo queue for transmission.
    if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData) != HAL_OK)
    {
      Error_Handler();
    }
  }
}

From debug, I see that HAL_FDCAN_AddMessageTxFifoQ is called 3 times and after this the FDCAN_TXFQS_TFQF bit is permanently set. I don’t see any output on the CAN bus.

Issue 2: I never get a CAN interrupt when messages are sent from the host

Even with host transmitting CAN data, the function: void FDCAN1_IT0_IRQHandler(void) is never called.

I loaded the code on an STM32G474E-EVAL1 board, connected a properly terminated CAN cable to a host, connected a PEAK PCAN-USB analyzer with PCAN-View software, and power up the board. I never see any CAN activity from the code, the 3-deep transmit queue fills up, and I never get any CAN interrupts.

Upvotes: 1

Views: 3230

Answers (1)

vict
vict

Reputation: 318

I think you are currently encountering a few issues, but without physical testing it is only speculation. Try to take a look at those:

  1. Without loop-back CAN peripherals filter out incoming frames that are identical to the current TX frame, to avoid echoes.
  2. If your CAN peripheral is operating in normal mode it expects it to be received by something on the line. It knows it thanks to the ACK bit. If there are no other devices on the line nothing will set the ACK bit, which CAN peripheral will treat as an error and will try to resend the frame.
  3. If I remember right, PEAK-CAN has 2 modes: a transparent listener and a node. Difference is in the ACK bit mentioned before.

If I were you I would first test this in a loop-back mode on the MCU itself (maybe even the fancy new external loop-back that comes with FDCAN, which also sends the TX line out, so you can see communication happening). Only when you know that something works I would connect an external device. At that point make sure your timing settings are correct, as this can be a tricky thing to set up (there are bunch of calculators online for this). Also look at PEAK-CAN documentation to find information about the ACK bit behavior. If it doesn't help, try to connect a different listener node e.g. other STM32 MCU with a CAN transceiver. That way you can be sure that you are receiving frames properly.

Upvotes: 2

Related Questions