2026-03-03 9:56 PM
/* ============ 500 kbit/s Bit Timing Derivation ============
*
* Step 1: FDCAN Kernel Clock
* fCAN = 80 MHz (from Clock Configuration)
*
* Step 2: Prescaler
* Prescaler = 10
*
* Step 3: Time Quantum (tq)
* tq = Prescaler / fCAN
* tq = 10 / 80,000,000 Hz = 0.125 µs = 125 ns
*
* Step 4: Bit Segments (in TQ)
* Sync Segment = 1 TQ (fixed, always 1)
* Time Segment 1 = 12 TQ (Prop_Seg + Phase_Seg1)
* Time Segment 2 = 3 TQ (Phase_Seg2)
*
* Step 5: Total Time Quanta per Bit
* Total TQ = Sync + TS1 + TS2 = 1 + 12 + 3 = 16 TQ
*
* Step 6: Bit Time
* Bit Time = Total TQ × tq = 16 × 125 ns = 2000 ns = 2 µs
*
* Step 7: Nominal Bit Rate
* Bit Rate = 1 / Bit Time = 1 / 2 µs = 500 kbit/s
*
* Step 8: Sample Point
* Sample Point = (Sync + TS1) / Total TQ = (1 + 13) / 16 = 87.5%
*
*/
----------------
MX_FDCAN2_Init();
-----------------
FDCAN_FilterTypeDef sFilterConfig;
sFilterConfig.IdType = FDCAN_STANDARD_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_MASK; /* Classic ID + mask mode */
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; /* Matching frames → RX FIFO 0 */
sFilterConfig.FilterID1 = 0x7E8; /* Expected ECU response base ID */
sFilterConfig.FilterID2 = 0x7F8; /* Mask: match 0x7E8 – 0x7EF */
if (HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig) != HAL_OK) {
Error_Handler();
}
/* Reject all non-matching frames (no global accept) */
if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_REJECT, FDCAN_REJECT, FDCAN_REJECT_REMOTE, FDCAN_REJECT_REMOTE) != HAL_OK) {
Error_Handler();
}
if (HAL_FDCAN_Start(&hfdcan2) != HAL_OK) {
Error_Handler();
}
-----------------
static void MX_FDCAN2_Init(void) {
/* USER CODE BEGIN FDCAN2_Init 0 */
/* USER CODE END FDCAN2_Init 0 */
/* USER CODE BEGIN FDCAN2_Init 1 */
/* USER CODE END FDCAN2_Init 1 */
hfdcan2.Instance = FDCAN2;
hfdcan2.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan2.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan2.Init.AutoRetransmission = ENABLE;
hfdcan2.Init.TransmitPause = DISABLE;
hfdcan2.Init.ProtocolException = DISABLE;
hfdcan2.Init.NominalPrescaler = 10;
hfdcan2.Init.NominalSyncJumpWidth = 1;
hfdcan2.Init.NominalTimeSeg1 = 13;
hfdcan2.Init.NominalTimeSeg2 = 2;
hfdcan2.Init.DataPrescaler = 1;
hfdcan2.Init.DataSyncJumpWidth = 1;
hfdcan2.Init.DataTimeSeg1 = 1;
hfdcan2.Init.DataTimeSeg2 = 1;
hfdcan2.Init.MessageRAMOffset = 0x000;
hfdcan2.Init.StdFiltersNbr = 1;
hfdcan2.Init.ExtFiltersNbr = 0;
hfdcan2.Init.RxFifo0ElmtsNbr = 32;
hfdcan2.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
hfdcan2.Init.RxFifo1ElmtsNbr = 0;
hfdcan2.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8;
hfdcan2.Init.RxBuffersNbr = 0;
hfdcan2.Init.RxBufferSize = FDCAN_DATA_BYTES_8;
hfdcan2.Init.TxEventsNbr = 0;
hfdcan2.Init.TxBuffersNbr = 0;
hfdcan2.Init.TxFifoQueueElmtsNbr = 32;
hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
hfdcan2.Init.TxElmtSize = FDCAN_DATA_BYTES_8;
if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN FDCAN2_Init 2 */
/* USER CODE END FDCAN2_Init 2 */
}
-----------------
/* This callback is triggered by TIM1 overflow every 1 second to send an OBD-II RPM request frame */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) {
if (htim->Instance == TIM1) {
FDCAN_TxHeaderTypeDef TxHeader;
uint8_t TxData[DATA_LEN] = {0};
TxHeader.Identifier = 0x7E0; // OBD-II request ID for Engine ECU, cycled through 0x7E0-0x7E7 for different ECUs, same rejection issue
TxHeader.IdType = FDCAN_STANDARD_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
TxHeader.MessageMarker = 0;
TxData[0] = 0x02; // SF, 2 data bytes
TxData[1] = 0x01; // Service 01
TxData[2] = 0x0C; // PID 0C — RPM
HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &TxHeader, TxData);
}
}
Solved! Go to Solution.
2026-03-04 2:07 AM
Perhaps this example by @Gretchev can help you: Simple Classic CAN + FreeRTOS Demo simulating OBD and a vehicle ?
2026-03-04 2:30 AM
@mƎALLEm wrote:What clock source are you using for FDCAN? HSI or HSE+Crystal? if HSI, please use HSE + a crystal or any other external precise source.
Please find the Clock configuration in the attached files.
I must confess few days back i saw my request frames on the bus ACKed by some node on the car. Do you perhaps think the clock source is not stable enough?
2026-03-04 2:35 AM - edited 2026-03-04 2:51 AM
Indeed you are using HSI. It’s recommended to use HSE and a crystal for CAN communication. I don’t have my PC now (i’m posting with my phone) but the disco board has already a crystal (crystal oscillator XO).
So please use it instead of HSI:
You shoud select HSE in bypass mode and set the crystal value to 25MHz in the clock view.
2026-03-04 2:36 AM
@mƎALLEm wrote:But that doesn’t make sense if his can node is receiving well the frames from the car. That seems to be not a baudrate issue but more related to a jitter or something similar.
That is where I think the problem could be related , as I was seeing frames validated by car few days back but still there was no response from the car(this is secondary problem). Will also attach the file when my frames became valid and ACKed. Filter Columns using 7E.
2026-03-04 2:39 AM - edited 2026-03-04 3:34 AM
@mƎALLEm wrote:Indeed you are using HSI. It’s recommended to use HSE and a crystal fir CAN communication. I don’t have my PC now but the disco board has already a crystal. So please use it instead of HSI.
will definitely try it tomorrow, as per my code , do i have to better handle FreeFiFolevel? as when i changed the ID to a different address i still saw probably queue FiFo appear on the bus which was ODD.
edit: @mƎALLEm Please see if the configs are fine , i was able to get 500kbps bitrate with HSE as BYPASS Clock Source and FDCAN kernel Clock 25 Mhz resulting to 80% sample point. Hope it is valid sample point,
2026-03-04 2:42 AM
will definitely have a look
2026-03-04 3:03 AM
Still not clear:
Do you receive the car's messages on the bus in the STM32 ?
2026-03-04 3:10 AM - edited 2026-03-04 3:11 AM
2026-03-04 4:35 AM
Sample point set at 80% works but the recommended sample point is at 87.5% of the bit time as you mentionned in your first post.
2026-03-04 6:26 AM
Because the OP seems to receive CAN packets correctly, and BRS is off (or is it used on the bus?), and at the bit rate of 500kbit, this should not matter too much when transmitting - or does it?
Maybe for getting the ACK correctly?
2000 ns * 80.0% SP -> 1600 ns
2000 ns * 87.5% SP -> 1750 ns
-> delta 150 ns
Hmm, can't imagine that this is the problem, but it's worth a try to reduce TS1 by 1 and increase TS2 by 1.