Skip to main content
Associate
March 4, 2026
Solved

OBD2 request frames rejection issues

  • March 4, 2026
  • 4 replies
  • 1223 views
I tried doing an OBD2 request via Car's OBD2 port.

I am able to see the CAN BUS traffic using an oscilloscope , just my request frames are rejected by car. I am using STM32h735G-DK development board to send OBD2 requests. It consists of an inbuilt FDCAN transceiver.

Settings are fine (removed termination resistor as car already has two), baudrate is 500kbps  with 87.5% sample point. I am using the following code to send OBD2 request frames:

I am able to receive CAN frames and able to log CAN frame frames it is just that frames sent are rejected. What am i doing wrong here?

FDCAN Code excerpt:
 
/* ============ 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);
 }
}
Best answer by mƎALLEm

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:

IMG_4830.png

You shoud select HSE in bypass mode and set the crystal value to 25MHz in the clock view.

4 replies

Ozone
Principal
March 4, 2026

> I am able to see the CAN BUS traffic using an oscilloscope , just my request frames are rejected by car. 

You need to be more specific here. What does "rejected by car" look like ?

I don't know OBD specifics, but this is basically the higher protocol transported via CAN.
Does the physical layer cause errors, or does your application violate OBD protocol ?
If the former is the case, the CAN error counters (TEC and REC) should indicate that.

MR17Author
Associate
March 4, 2026

Please see the file attached , filter ID column with 7E and select all. You will see that DLC 0 and DATA empty and CRC invalid , not  ACKed and Valid 0. 

TEC increased more than 127 , goes to error passive after a few milliseconds. 

OBD2 request frames.png

02 01 0C with first byte 02 means it is a request for RPM in live mode (show current data). I don't even flood the bus since my requests are periodic with 1s , and i address it to each physical address from 7E0-7E7 and 7DF(broadcasting to all ECUs)

Ozone
Principal
March 4, 2026

> TEC increased more than 127 , goes to error passive after a few milliseconds. 

Which means you almost certainly have a problem with the physical signal, either wiring, or missing/improper termination resistance.

As said, I don't know OBD, but Wikipedia states :

  - ISO 15765 CAN (250 kbit/s or 500 kbit/s).

Have you tried 250kbit/s ?

mƎALLEm
Technical Moderator
March 4, 2026

Hello @MR17 and welcome to the ST community,

As you are receiving well the CAN frames sent by the car, the communication is fine as well as your hardware. If your car is not accepting your frames (especially when they were acknowledged) that means the CAN IDs are dropped by the car. So we cannot help you at this stage as we are not OBD specification experts here. You need to check it again and verify the correct IDs and the data content needed for that communication.

Good luck!

"To give better visibility on the answered topics, please click on ""Accept as Solution"" on the reply which solved your issue or answered your question."
Andrew Neil
Super User
March 4, 2026

Perhaps this example by @Gretchev can help you: Simple Classic CAN + FreeRTOS Demo simulating OBD and a vehicle ?

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
MR17Author
Associate
March 4, 2026

will definitely have a look

LCE
Principal II
March 4, 2026

Still not clear:

Do you receive the car's messages on the bus in the STM32 ?

MR17Author
Associate
March 4, 2026

@LCE wrote:

Still not clear:

Do you receive the car's messages on the bus in the STM32 ?



yes, i do !
Seems like clock source might be the issue like @mƎALLEm mentioned. As receiving frames are different from sending frames on the CAR's CAN Bus as slight drift cannot be tolerated.