Skip to content

[Bug]: HAL_SD_IRQHandler never reaches its error branch on data error in IT mode (IRQ storm) #347

Description

@mrjimenez

Bug Summary

HAL_SD_IRQHandler never reaches its error branch when a data error occurs
during an interrupt-mode transfer, causing the SD interrupt to refire forever
and lock up the system.

Detailed Description

In stm32h7xx_hal_sd.c, HAL_SD_IRQHandler() tests its conditions in a single
if / else if chain, and the FIFO branches come before the error branch:

void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd)
{
  /* Check for SDMMC interrupt flags */
  if ((__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) != RESET) && ((context & SD_CONTEXT_IT) != 0U))
  {
    SD_Read_IT(hsd);
  }
  ...
  else if ((__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXFIFOHE) != RESET) && ((context & SD_CONTEXT_IT) != 0U))
  {
    SD_Write_IT(hsd);
  }
  ...
  else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT |
                                  SDMMC_FLAG_RXOVERR  | SDMMC_FLAG_TXUNDERR) != RESET)
  {
    /* error handling: never reached in the scenario below */
  }
}

TXFIFOHE and RXFIFOHF are level-triggered status flags that cannot be
cleared by software — they only change when the FIFO is drained or filled. If a
data error (TXUNDERR, RXOVERR, DCRCFAIL, DTIMEOUT) occurs while such a
flag is asserted, the handler keeps taking the FIFO branch, the error branch is
never evaluated, the error flags are never cleared, and the interrupt refires
immediately and indefinitely.

A second, related problem: when the error branch does run, its
__HAL_SD_DISABLE_IT() mask does not include SDMMC_IT_TXFIFOHE /
SDMMC_IT_RXFIFOHF, so the IRQ line can remain asserted even after the error is
handled.

How it was observed. An SD card stopped accepting data mid-write (a physical
card fault; only a power cycle recovers it). The resulting TXUNDERR left
TXFIFOHE asserted and the board became completely unresponsive: the ISR
starved every thread, so networking and the console died while interrupts kept
firing. Diagnosed via SWD — the CPU was permanently inside HAL_SD_IRQHandler.

Suggested fix, which has been running in our firmware since 2026-07-10
(including a 10-minute stress test writing 512 KB blocks continuously while
acquiring sensor data, with no regression):

  1. skip the FIFO branches while any data error flag is pending, so the error
    branch becomes reachable;
  2. add SDMMC_IT_TXFIFOHE / SDMMC_IT_RXFIFOHF to the disable mask on the
    error path.

The patch is proposed to the Zephyr HAL mirror as a temporary fix in
zephyrproject-rtos/hal_stm32#395, whose maintainer asked that the issue be
reported here first.

Note on other series. The same if / else if ordering is present in the
HAL_SD_IRQHandler of the STM32F7, H5, H7RS, L4, L5, MP13, MP2, N6, U3 and U5
drivers. I could only test on STM32H7.

Expected Behavior

A data error during an interrupt-mode transfer is handled: the error flags are cleared, the interrupts are disabled, and the transfer is aborted with the error reported to the application.

Actual Behavior

The error branch is never reached; the interrupt refires forever and starves the entire system, which requires a reset to recover.

Environment

STM32H747I-DISCO (STM32H747XI, Cortex-M7), STM32CubeH7 v1.12.1, SDMMC1 in interrupt mode (not IDMA), GCC (Zephyr SDK), Zephyr RTOS 4.4.1.

Severity

Critical

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinghalHAL-LL driver-related issue or pull-request.internal bug trackerIssue confirmed and logged into the internal bug tracking systemsdSecure Digital interfacesdmmcSecure Digital input/output Multimedia Card interface

Type

Projects

Status
Analyzed

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions