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 */ }
View more

 

 

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); }
View more

 

 

...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); }
View more

 

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.