cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G431: No FDCAN interrupts

Brian H
Senior

I have two STM32 micros connected via CAN transceivers.  The sending unit is transmitting without issue, as evidenced by measuring both the CANH/CANL bus wires, as well as the CAN_RX/CAN_TX logical wires on the transmitter.  I did have to slow the bus down significantly due to high capacitance (troubleshooting at 20 kbps; hope to increase speed once I get the situation figured out).  I am using classic 11-bit identifiers, subdivided into a 7-bit message type and a 4-bit node ID.

I can see the ACK bit on the CAN wire, so I know the receiver in the chip is correctly identifying the frame.  However, the receiver's two FDCAN interrupts never fire.  I have both set the non-matching 11-bit identifier action to FDCAN_ACCEPT_IN_RX_FIFO0 as well as set a id/mask filter with a mask of 0, as well as a filter set up the way I would intend for my application.  I will now let the code speak for itself:

 

First, the MX-generated initializer is called:

 

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_DIV10;
  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 = 16;
  hfdcan1.Init.NominalSyncJumpWidth = 1;
  hfdcan1.Init.NominalTimeSeg1 = 2;
  hfdcan1.Init.NominalTimeSeg2 = 2;
  hfdcan1.Init.DataPrescaler = 1;
  hfdcan1.Init.DataSyncJumpWidth = 1;
  hfdcan1.Init.DataTimeSeg1 = 1;
  hfdcan1.Init.DataTimeSeg2 = 1;
  hfdcan1.Init.StdFiltersNbr = 2;
  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 */

}

 

 

Following that, my application CAN setup happens.  First generic settings:

 

HAL_StatusTypeDef CAN_Init(void) {
	// Clear any existing filters and whatnot, set up callbacks, etc.
	// NB: Callbacks are implemented via weak functions, not registration.
	// See notes in stm32g4xx_hal_fdcan.c regarding macro definitions

	HAL_StatusTypeDef rc = HAL_OK;

	// Make sure filter slot 0 is configured so we receive broadcast
	// messages.
	{
		FDCAN_FilterTypeDef broadcastFilter = {
				.IdType = FDCAN_STANDARD_ID,
				.FilterIndex = 0,
				.FilterType = FDCAN_FILTER_MASK,
				.FilterConfig = FDCAN_FILTER_TO_RXFIFO0_HP, /* Broadcast messages are treated as high-priority */
				.FilterID1 = 0, /* ID bits */
				.FilterID2 = 0x00f /* ID mask */
		};
		// 0/0x00f => xxxxxxx0000 filter
		rc = HAL_FDCAN_ConfigFilter(&hfdcan1, &broadcastFilter);
		if(rc != HAL_OK) return rc;
	}

	// Set global filter options
	rc = HAL_FDCAN_ConfigGlobalFilter(&hfdcan1,
			FDCAN_ACCEPT_IN_RX_FIFO0 /* Non-matching 11-bit */,
			FDCAN_REJECT /* Non-matching 28-bit */,
			FDCAN_REJECT /* Classic RTR frames (we won't be using them) */,
			FDCAN_REJECT /* Extended RTR frames (we're in classic mode anyway) */);
	if(rc != HAL_OK) return rc;

	// We don't care about timestamps
	rc = HAL_FDCAN_DisableTimestampCounter(&hfdcan1);
	if(rc != HAL_OK) return rc;

	// At least for now, we aren't going to use the timeout counter either
	rc = HAL_FDCAN_DisableTimeoutCounter(&hfdcan1);
	if(rc != HAL_OK) return rc;

	// Other configuration options will be left to POR defaults.
	// Start the peripheral, allowing it to sync to the bus.
	return HAL_FDCAN_Start(&hfdcan1);

}

 

 

...followed by setting a filter for the local intended CAN ID:

 

HAL_StatusTypeDef CAN_SetLocalNodeID(uint8_t node_id) {
	// NB: We only use the low four bits of node_id.
	// Filters can only be configured while the peripheral is stopped.
	HAL_StatusTypeDef rc = HAL_FDCAN_Stop(&hfdcan1);
	if(rc != HAL_OK) return rc;
	// \todo Create the proper filter for xxxxxxx<node_id> (that is, 7 don't cares plus the four node-id bits)
	{
		FDCAN_FilterTypeDef broadcastFilter = {
				.IdType = FDCAN_STANDARD_ID,
				.FilterIndex = 1,
				.FilterType = FDCAN_FILTER_MASK,
				.FilterConfig = FDCAN_FILTER_TO_RXFIFO0,
				.FilterID1 = (node_id & 0x0f), /* ID bits */
				.FilterID2 = 0x00f /* ID mask */
		};
		// 0/0x00f => xxxxxxx0000 filter
		rc = HAL_FDCAN_ConfigFilter(&hfdcan1, &broadcastFilter);
		if (rc != HAL_OK) return rc;

		FDCAN_FilterTypeDef promiscuousFilter = {
				.IdType = FDCAN_STANDARD_ID,
				.FilterIndex = 2,
				.FilterType = FDCAN_FILTER_MASK,
				.FilterConfig = FDCAN_FILTER_TO_RXFIFO1, /* Packets that aren't meant for us go into FIFO1 */
				.FilterID1 = 0, /* ID bits */
				.FilterID2 = 0 /* ID mask  - no bits matter*/
		};
		// 0/0x00f => xxxxxxx0000 filter
		rc = HAL_FDCAN_ConfigFilter(&hfdcan1, &promiscuousFilter);
		if (rc != HAL_OK) return rc;

	}
	local_node_id = node_id;
	return HAL_FDCAN_Start(&hfdcan1);
}

 

No errors are returned in any of these functions.

Once all this is done, the main loop sits around waiting for CAN messages to be received.  I have enabled both interrupts in the NVIC section of the MX configuration UI (and can see the relevant NVIC calls in the generated HAL_FDCAN_MspInit function).  I have breakpoints set in both interrupt handlers, FDCAN1_IT0_IRQHandler and FDCAN1_IT1_IRQHandler.  However, neither of the breakpoints are hit. 

I've also adjusted the code to check the FIFO fill level, and that does indicate that the packet went into FIFO0. So I don't understand why the interrupt didn't fire.  I don't want to waste processor time polling the FIFO fill level.

I'm not sure where to look next.  Any guidance will be greatly appreciated.

1 ACCEPTED SOLUTION

Accepted Solutions
Brian H
Senior

Solved it myself.  It was a very simple oversight; I was missing the following call to activate the HAL FDCAN notification:

rc = HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);

Once I added that line to my startup code, the interrupt began firing as expected.

View solution in original post

1 REPLY 1
Brian H
Senior

Solved it myself.  It was a very simple oversight; I was missing the following call to activate the HAL FDCAN notification:

rc = HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);

Once I added that line to my startup code, the interrupt began firing as expected.