Skip to main content
Associate
July 10, 2026
Question

The STM32G431 API of USB double‑buffer transmit‑complete interrupt processing contains a bug.

  • July 10, 2026
  • 15 replies
  • 170 views

After I configure EP1 to the double‑buffered mode, debugging reveals an issue inside stm32g4xx_hal_pcd.c. At line 1761, the endpoint register value is read. After executing PCD_CLEAR_TX_EP_CTR(hpcd->Instance, epindex); to clear the interrupt flag, the actual register content has already been updated. However at line‑1906, (void)HAL_PCD_EP_DB_Transmit(hpcd, ep, wEPVal); still receives the register value captured before interrupt‑flag clearing. This triggers incorrect conditional judgements inside the HAL_PCD_EP_DB_Transmit() function.

Probable root‑cause: When transmitting data for the first time under double‑buffered setup, USB_EPStartXfer populates both buffers by default. After Buffer‑0 finishes transmission and triggers an interrupt, the program reads register data at line‑1761 of stm32g4xx_hal_pcd.c. Right after this read operation, Buffer‑1 also completes its transmission and updates the endpoint register. Since HAL_PCD_EP_DB_Transmit uses the stale register value obtained earlier rather than the latest value, abnormal behaviour occurs.

Besides, are there any sample project for USB double‑buffered RX‑TX operation?

captured endpoint register value
The input value is inconsistent with the actual current value.

 

15 replies

ST Technical Moderator
July 10, 2026

Hi ​@LuoMing 

Thank you for the detailed analysis and screenshots.

Can you please provide a minimal firmware project that reproduces the issue on my side?

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
LuoMingAuthor
Associate
July 10, 2026

I selected the CDC class inside CubeMX and made modifications based on the generated project. During debugging, I observed that after the second data transmission via the CDC_Transmit_FS API upon each reset cycle, the MCU responds to nearly all IN‑requests from the host. I carried out numerous revisions to fix this issue, which makes it impossible for me to provide a stripped‑down version of my current project.

I regenerated a CDC‑based project with CubeMX and re‑assigned endpoints: EP1 for CDC‑CMD, EP2 as the IN endpoint and EP3 as the OUT endpoint. EP2 and EP3 are configured in double‑buffered mode.

During testing: When send_cmd is set to 1 for the first time, the MCU transmits data frames normally and replies with NAK to all subsequent host IN‑requests without triggering the CTR interrupt. However, once send_cmd is set to 1 a second time, the MCU continuously answers host IN‑requests and causes frequent CTR‑interrupt triggering. Could you advise how I can resolve this‑behaviour?

 

Associate II
July 12, 2026

It seems the value for EP1R@0x4 00000121 and  EP1R@0x4 000001a1 should be same while it is different 121 and 1a1?

LuoMingAuthor
Associate
July 13, 2026

You can view the screenshots of my debugging‑trace here.

After I start debugging, I fill 65‑byte data into the double‑buffers via the WinUSB_Transmit_FS interface, with 64 bytes for buffer0 and 1 byte for buffer1, then wait for IN requests from the host.

When the first IN request from the host is received, a transfer‑complete interrupt is triggered, and the EP1 registers are configured with corresponding values. Everything up to this point works exactly as expected.

However, if the next IN request sent by the host arrives before executing PCD_CLEAR_TX_EP_CTR(hpcd->Instance, epindex); or HAL_PCD_EP_DB_Transmit(hpcd, ep, wEPVal);, the value of the EP1 register conflicts with the usbd driver library.

I’m not sure whether I explained this clearly, or if I have misunderstood the usbd driver‑library.

Richard Li
Senior
July 13, 2026

In RM0440 page 2023:


On receiving the ACK receipt by the host, the USB_EPnR register is updated in the 
following way: DTOG_TX bit is toggled, the endpoint is made invalid by setting 
STAT_TX=10 (NAK) and bit CTR_TX is set. The application software must first identify the 
endpoint, which is requesting microcontroller attention by examining the EP_ID and DIR bits 
in the USB_ISTR register. Servicing of the CTR_TX event starts clearing the interrupt bit; 
the application software then prepares another buffer full of data to be sent, updates the 
COUNTn_TX table location with the number of byte to be transmitted during the next 
transfer, and finally sets STAT_TX to ‘11 (VALID) to re-enable transmissions. While the 
STAT_TX bits are equal to ‘10 (NAK), any IN request addressed to that endpoint is NAKed, 


Your second screenshot the STAT_TX are 0x10, is this correct?

 

LuoMingAuthor
Associate
July 13, 2026

The values for STAT‑TX are correct. you can refer to RM0440 rage 2027.

….Unlike common transactions, and the first one after DBL_BUF setting, STAT bit pair is not affected by the transaction termination and its value remains ‘11 (Valid).However, as the token packet of a new transaction is received, the actual endpoint status is masked as ‘10 (NAK) when a buffer conflict between the USB peripheral and the application software is detected (this condition is identified by DTOG and SW_BUF having the same value, see Table 424 on page 2027).

….

You have to run step‑by‑step debugging on both the MCU‑side firmware and PC‑side program so that IN requests get sent one‑by‑one as expected. It will be difficult to reproduce my observed issue if ready‑made CDC‑based software tools are used. Alternatively, you can directly analyze the CTR interrupt routine inside the USB driver library, HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd), and check whether the scenario I described earlier can actually occur.

Richard Li
Senior
July 13, 2026

In G4 firmware package, one CDC - USB example in there, I don’t think use double buffer.

(Under G474-evel -application.

LuoMingAuthor
Associate
July 13, 2026

You’re right. Therefore I enabled double‑buffer after adjustments. My real‑world application doesn’t use the CDC class at all; I just modified it based on the CDC example project.

 

Richard Li
Senior
July 13, 2026

One suggestion, could you add one flag inside the ISR, for my early experience, STM32G4 interrupt most case can’t jump in ISR., I used one GPIO toggle test ISR.

LuoMingAuthor
Associate
July 13, 2026

Thanks a lot for your suggestion.

The USB‑CTR interrupt works properly. According to my previous screenshots, wEPVal acquisition and the call to PCD_EP_ISR_Handler take place within this interrupt.

It is fairly clear that the bug originates from the HAL library.

Associate II
July 23, 2026

OK...It seems the issue linked with HAL library.Does the issue look like one of the link below about USB double buffer cases?

STM32F302 use USB double buffer, the transmit data will over buffer setting | Community

STM32L4 USB double buffer HAL bug | Community

Richard Li
Senior
July 13, 2026

Please add one more register in your debug SCB->ICSR.

ST Technical Moderator
July 13, 2026

Thank you for reporting the issue ​@LuoMing 

An internal ticket has been submitted to dedicated team. Internal ticket number CDM0064314 for internal tracking.

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Richard Li
Senior
July 13, 2026

You may find 0x23 or 0x24 in vector pending.