2026-04-08 12:37 AM - last edited on 2026-04-08 2:54 AM by Andrew Neil
TX works but RX interrupt not triggered
Hello,
I am currently using a custom board based on STM32H563ZIT6. My goal is to establish communication over RS485 between the STM32 and a PC (using Hterm). The system is designed to receive a command and send a response.
Communication Details:
Current Situation:
Problem:
At 12 Mbaud:
Additional Notes:
What I Suspect:
Questions:
Any insights or similar experiences would be very helpful.
Thanks in advance!
Solved! Go to Solution.
2026-04-10 9:04 AM
@MES98 wrote:
- I am required to use interrupt-based reception
Why ?
This is exactly the kind of situation that DMA is for!
As @Ozone said previously, "High interrupt loads ... can easily consume most of the available core performance".
That's why we have DMA - to offload that burden!
You haven't shown your code - how are you handling the interrupt?
It will probably need to be well-optimised - straight HAL probably won't hack it.
@MES98 wrote:Is there any recommended way to handle high baud rate UART reception .
DMA.
@MES98 wrote:
Any suggestions or best practices
Use DMA.
2026-04-10 9:35 AM
10 Mbaud = 1 byte per microsecond. This data rate can be handled using interrupts (assuming the MCU is running at 250 MHz). However, the interrupt routine must be written efficiently. If you’re using HAL, you’ll almost certainly have to use LL or simply direct register access and write the routine yourself (which isn’t complicated). You’ll also have to ensure that interrupt routines with higher priority (Systick?!) don’t take so long that the FIFO fills up and an overrun occurs.
However, it makes more sense to use DMA. I can’t think of any reason not to use DMA in such a case.
2026-04-11 4:56 AM
> I am required to use interrupt-based reception
I don't know why you think that.
A bitrate of 10MBit/s only requires you to handle the input efficiently.
Although DMA can be problematic with burst transmissions, especially of unknown length.
However, interrupts become problematic when approaching a rate of 1 MHz, and you are beyond that.
Context switching latencies are unavoidable (12 cycle in and out, with FPU register even more).
And as mentioned, the typical HAL implementation with callbacks is inappropriate for this use case.
You would need to handle data in the interrupt handler directly, with the least possible amount of instructions.
High interrupt loads and lengthy handlers easily break an application, many posters here managed this at much lower bit rates.
> Are there specific FIFO, interrupt, or buffering strategies that could help in this scenario?
You would have to look up the reference manual of your MCU, but I don't know any STM32 MCU employing a UART FIFO. ST mostly bets on DMA here, which serves a similiar purpose.
The benefit is, the interrupt rate is a fraction ( byte rate / buffer size), but it would not necessarily be aligned with the timing of the transmissions. And error handling might get tricky.
Did you consider reducing the bitrate ?
I can see no justification from the application side for such a high low-latency throughput.
2026-04-13 1:09 AM
Use DMA with circular buffer so you don't miss any data. You can use character timeout interrupts, but at such high baudrates the data is most likely very bursty so you would get interrupts on partial packets.
2026-04-14 1:19 AM
@unsigned_char_array @Ozone @Michal Dudka @Andrew Neil
Thank you for your suggestions.
I have now started using DMA for UART reception as recommended. However, I may be doing something wrong since I don’t have much experience with DMA yet.
I am sharing the relevant part of my code and my clock configuration for reference.
Current behavior:
Additionally, I noticed something unexpected:
HAL_UART_IRQHandler(&huart8);This makes me think that I might be misconfiguring the interaction between DMA and interrupt handling, but I’m not sure what I am missing.
Any guidance on correct DMA + UART configuration or what I might be doing wrong would be greatly appreciated.
---main.c---
#define UART_RX_BUFFER_SIZE 2048
uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE];
volatile uint16_t dma_old_pos = 0;
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the peripherals common clocks */
PeriphCommonClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_GPDMA1_Init();
MX_UART8_Init();
/* USER CODE BEGIN 2 */
ring_buffer_init(&ring_buffer_xxx_1, buf_arr_uart1, sizeof(buf_arr_uart1));
// HAL_UART_Receive_IT (&huart8, &rx_data_uart1, 1);
init_xxx_ports(&huart8, &huart10, &huart12, &huart11, &huart2, &huart9, &huart7, &huart3, &huart5, &huart1);
HAL_StatusTypeDef ret;
ret = HAL_UART_Receive_DMA(&huart8, uart_rx_buffer, UART_RX_BUFFER_SIZE);
if(ret != HAL_OK){
return;
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
parse_rx_data_rs422_others(&ring_buffer_xxx_1, 1);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart){
UART_ProcessData();
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
if (huart->Instance == USART1) {
UART_ProcessData();
// Handle received data in pRxBuff
// ...
// Re-enable DMA to receive next package
HAL_UART_Receive_DMA(&huart8, uart_rx_buffer, UART_RX_BUFFER_SIZE);
}
}
void UART_ProcessData(){
uint16_t dma_pos = UART_RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart8.hdmarx);
if(dma_pos != dma_old_pos) {
if(dma_pos > dma_old_pos){
ProcessBytes(&uart_rx_buffer[dma_old_pos], dma_pos - dma_old_pos);
}
else{
ProcessBytes(&uart_rx_buffer[dma_old_pos], UART_RX_BUFFER_SIZE - dma_old_pos);
ProcessBytes(&uart_rx_buffer[0], dma_pos);
}
dma_old_pos = dma_pos;
}
}
void ProcessBytes(uint8_t *data, uint16_t len){
for(uint16_t i = 0; i<len; i++){
ring_buffer_queue(&ring_buffer_xxx_1, data[i]);
}
}
---stm32h5xx_it.c---
/**
* @brief This function handles UART8 global interrupt.
*/
void UART8_IRQHandler(void)
{
/* USER CODE BEGIN UART8_IRQn 0 */
/* USER CODE END UART8_IRQn 0 */
HAL_UART_IRQHandler(&huart8);
/* USER CODE BEGIN UART8_IRQn 1 */
if (__HAL_UART_GET_FLAG(&huart8, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart8);
UART_ProcessData();
// uint8_t data = huart8.Instance->RDR;
// ring_buffer_queue(&ring_buffer_xxx_1, data);
}
if(__HAL_UART_GET_FLAG(&huart8,UART_FLAG_ORE)){
__HAL_UART_CLEAR_OREFLAG(&huart8);
}
/* USER CODE END UART8_IRQn 1 */
}
2026-04-14 1:20 AM
2026-04-14 2:51 AM
> Additionally, I noticed something unexpected:
> If I remove the following line:
HAL_UART_IRQHandler(&huart8);
The idea of DMA (or a FIFO) ist to not have UART interrupts in the first place.
You should only need to process DMA interrupts (complete transfers of your configured size). And errors, of course.
2026-04-14 3:14 AM
@MES98 wrote:
// Re-enable DMA to receive next packageIn circular mode this is not needed. DMA can run forever. Just make sure you process the data before it is overwritten. You can do this by using a sufficiently large buffer.
Here is a tutorial that might help you: https://controllerstech.com/stm32-uart-4-receive-data-using-dma/
2026-04-15 8:06 AM
Thank you all for your support and valuable suggestions.
I would like to briefly summarize the issue and the solution, in case it helps others in the future.
Initially, when using interrupt-based reception, I was able to reach up to around 4 Mbaud reliably.
After switching to DMA, I was able to increase this up to 8 Mbaud.
However, I could never reach the 10 Mbaud value stated in the datasheet — at that speed, I was neither able to receive nor transmit data reliably.
While going through the datasheets more carefully, I noticed that the UART clock is 24 MHz, and in simple terms, the achievable baud rates follow a relation like 24 / n (Mbaud).
Based on this, I tested different baud rates again:
So it seems that certain baud rates are more “naturally aligned” with the clock configuration, while others are not achievable due to divider limitations.
Thanks again to everyone for the help.
Have a great day!
2026-04-15 8:11 AM
@MES98 wrote:So it seems that certain baud rates are more “naturally aligned” with the clock configuration, while others are not achievable due to divider limitations.
Yes, this is common.
This is why there are crystals manufactured with what seem like strange frequency values - like 11.059MHz.
That number is chosen precisely because it easily divides to give common serial baud rates.