Skip to main content
Associate II
May 29, 2025
Solved

STM32 FDCAN node sees nothing on bus when CAN-to-USB adapter removed

  • May 29, 2025
  • 27 replies
  • 3478 views

Board & Setup:

  • STM32H563RGT6 running FDCAN2 in Normal mode (HAL_FDCAN_Init, Mode=FDCAN_MODE_NORMAL)

  • SN65HVD230 transceiver in silent mode (Rs pin connected to 3.3V) (120 Ω intergrated) wired with a single 120 Ω terminator at the far end

  • No other pull-up/down or termination changes when the USB–CAN dongle is unplugged

  • Filters configured (Reading the data from the BMS of a custom battery):

    • FIFO0 → IDs 0x1E0 (BMS_STATE), 0x1E2 (PACK_MINMAX), 0x1E3 (PACK_AVG)

    • FIFO1 → ID 0x1E1 (PACK_VALUES)

Symptom:

  • With the USB–CAN adapter or another node on the bus, everything works: the real BMS sends all four messages, our STM32 ACKs them, and they appear in Cangaroo.

  • As soon as the USB–CAN dongle is unplugged (or if our transceiver is switched to any other mode -> Slope control or High speed (no slope control)), no messages are observed on the bus—even though the BMS should still be broadcasting at 1 Hz (it constantly spits out data at a 1 Hz rate) and our STM32 is in Normal mode.

What I need:

  1. Keep the SN65HVD230 in Normal (ACK-capable) mode—tie its RS pin LOW (or drive it low in GPIO init).

  2. Still “ignore” any frames I transmit (because I’m not sending any), so that I only see the BMS frames.

How do I ensure my SN65HVD230 is always in normal, ACK-capable mode (so the BMS sees at least one ACK and keeps talking), while my STM32 itself continues to filter out any of its own (non-existent) messages so I only capture IDs 0x1E0–0x1E3?

***My STM32CubeIDE "main.c" is given in attachments.

This topic has been closed for replies.
Best answer by aqua_dev

The problem was a semi faulty connector. Thanks for all the help, I learned a lot on the way CAN works on STM32.

27 replies

mƎALLEm
ST Technical Moderator
May 29, 2025

Hello @aqua_dev and welcome to the ST community,

Not sure I understood your configuration.

Just to be clear, if you are in Normal mode you need at least a second node on the bus to make acknowledgement mechanism works properly, otherwise you need to use Loopback mode instead.

There is no intelligence at the transceiver level, so the Acknoledgement is managed at CAN interface level in the MCU.

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.
aqua_devAuthor
Associate II
May 29, 2025

The battery (or BMS) I was talking about is a node which is connected to the CAN bus. The "master" is the SN65HVD230 transceiver which is connected to the CAN Tx and Rx of the STM32H563RGT6 (pins PB5 and PB13 to be exact -> FDCAN2).

Karl Yamashita
Principal
May 29, 2025

SN65HVD230 transceiver in silent mode (Rs pin connected to 3.3V) (120 Ω intergrated) wired with a single 120 Ω terminator at the far end

So, RS pin is connected to 3.3V directly or has a pull-up resistor to 3.3V? 

 

Does the USB–CAN adapter have a terminating resistor enabled?

If so, it sounds like the STM32 terminating resistor may be an open circuit? So when you remove the USB–CAN adapter, there is only 1 terminating resistor on the far end. The USB–CAN adapter is probably the node that is sending the ACK, not the STM32.

 

Draw a block diagram showing your nodes, CAN bus wires, and where the terminating resistors are.

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
aqua_devAuthor
Associate II
May 30, 2025

I have a switch that connects the Rs pin directly to 3.3V or to a 10k resistor to ground. Right now the only way it works is directly connected to 3.3V.

The USB-CAN terminating resistor is enabled, but I tried to disable it and it didn't seem to be the problem. This totally makes sense, it's the conclusion I'm leaning towards -> The USB–CAN adapter is probably the node that is sending the ACK, not the STM32.

mƎALLEm
ST Technical Moderator
May 30, 2025

There is no integrated 120 ohm resistor on the SN65HVD230 neither to any CAN transceiver in the market.

But is is available in your hardware outside  here:

mALLEm_0-1748615327849.png

Try to shunt the R1 resistor so Rs pin will be connected directly to the ground:

mALLEm_1-1748615402470.png

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.
CTapp.1
Senior III
May 30, 2025

Now many nodes are on the bus?

If it is just the BMS and the STM (when the CAN-USB is disconnected) and the STM is not able to transmit on the bus, then there is nothing to send the 'ack' bit when the BMS sends it's message and it will go error passive. A receive-only node like the STM will only receive messages that are acknowledged by another node that is capable of transmitting messages.

All posts are made in a personal capacity. MISRA C++ Chair, MISRA C WG Member, Director The MISRA Consortium Limited (TMCL)
Karl Yamashita
Principal
May 30, 2025

  • STM32H563RGT6 running FDCAN2 in Normal mode (HAL_FDCAN_Init, Mode=FDCAN_MODE_NORMAL)

  • SN65HVD230 transceiver in silent mode (Rs pin connected to 3.3V) (120 Ω intergrated) wired with a single 120 Ω terminator at the far end


I missed this earlier but the CAN transceiver can not be in low power mode. You need to keep the RS pin grounded in order for the STM32 CAN Controller to ACK.

void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) {
	if (RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) {
		while (HAL_FDCAN_GetRxFifoFillLevel(&hfdcan2, FDCAN_RX_FIFO0) > 0) {
			if (HAL_FDCAN_GetRxMessage(&hfdcan2, FDCAN_RX_FIFO0, &RxH, RxD) != HAL_OK) {
				Error_Handler();
			}

			switch (RxH.Identifier) {
			 case 480: // BMS_STATE @ 1 Hz
				parse_BMS_STATE(RxD, &st);
				break;
			 case 482: // PACK_MINMAX_VALUES @ 1 Hz
				parse_PACK_MINMAX_VALUES(RxD, &mm);
				break;
			 case 483: // PACK_AVG_VALUES @ 1 Hz
				parse_PACK_AVG_VALUES(RxD, &av);
				break;
			}
		}
	}
}

What is the STM32 supposed to do when the BMS is sending messages and you parse them? I see the data structure st, mm and av, but i don't see any code else where that uses the data? Just trying to understand how do you know the STM32 is actually receiving messages? 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
aqua_devAuthor
Associate II
May 30, 2025

My transceiver has a 10k resistor to ground on Rs pin at the moment. Right now the data is now being used, I just translate it to the right variable types, see the lines 994 to 1085 but I don't do much more then that as of now.

Karl Yamashita
Principal
May 30, 2025

Instead of extracting bits using BE_BIT into the data structure, try using union

typedef union 
{
 struct
 {
 uint8_t data[8];
 }Byte;
 struct
 {
 // critical flags
 bool crit_current_high;			// 63
 bool crit_imbal_high;			// 62
 bool crit_pack_volt_low;		// 61
 bool crit_pack_volt_high;		// 60
 bool crit_cell_volt_low;		// 59
 bool crit_cell_volt_high;		// 58
 bool crit_temp_low;				// 57
 bool crit_temp_high;			// 56
 // warning flags
 bool warn_current_high;			// 55
 bool warn_imbal_high;			// 54
 bool warn_pack_volt_low;		// 53
 bool warn_pack_volt_high;		// 52
 bool warn_cell_volt_low;		// 51
 bool warn_cell_volt_high;		// 50
 bool warn_temp_low;				// 49
 bool warn_temp_high;			// 48
 // remaining capacity [As]
 uint16_t remaining_capacity;	// 32-47
 // state of health [%]
 uint8_t soh;					// 24-31
 // state of charge [%]
 uint8_t soc;					// 16-23
 // fault register
 uint8_t main_fault_reg;		// 8-15
 // overall pack state
 uint8_t state;					// 0-7
 }Status;
} BMS_State;

 

Then all you need to do is copy the bytes which requires less instruction cycles than extracting all the bits individually

void parse_BMS_STATE(const uint8_t data[8], BMS_State *s)
{
 int i;

 for(i = 0;i <8;i++)
 {
 s->Byte.data[i] = data[i];
 }
}

 

and to use the data

if(st.Status.crit_current_high)
{
 // do something
}

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
aqua_devAuthor
Associate II
May 30, 2025

I changed to the typedef union which is practical, but does not eliminate the problem of the communication. Also I changed to HSE clock which is 12 MHz in my case so I now have different parameters for the same bitrate (250 kbits/s), but it does not seem to be the solution.

mƎALLEm
ST Technical Moderator
May 30, 2025

Please attach your ioc file.

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.
Karl Yamashita
Principal
May 30, 2025

Assuming you have an external clock at 12MHz, try the attached IOC changed to use 66MHz and use the values below. I have values for 12MHz as well

 

 Baud 250000 bit/s
FDCAN clock freq(kHz)seg1seg2 prescaler
120003981
66000219441
If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
aqua_devAuthorBest answer
Associate II
June 2, 2025

The problem was a semi faulty connector. Thanks for all the help, I learned a lot on the way CAN works on STM32.