2026-02-18 6:53 AM
Hello, I am having a issue with HAL_UARTEx_ReceiveToIdle_DMA on a NUCLEO-H7A3ZI-Q, when using the following code:
uint8_t rx_buffer [4096];
HAL_UARTEx_ReceiveToIdle_DMA(&huart3, rx_buffer, sizeof(rx_buffer));
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t size){
/*code*/
}My rx_buffer is only populating the first 512 bytes, with the remaining data remaining as 0.
__HAL_DMA_GET_COUNTER(huart3.hdmarx);Provides the incorrect amount of data being passed over serial.
I have used serial plotter and CoolTerm to try and send packets but both hit this 512 byte limit.
rx_buffer not populated past 512 bytes
length correctly calculated as 640 bytes long
Solved! Go to Solution.
2026-02-26 5:57 AM
My solution to this issue was using a resettable buffer to copy data from the dma buffer straight to memory before processing it separately. This was in circular mode with fifo disabled as this prevented idle bytes that didn't align to half time or full time events from populating the dma buffer.
for non aligned data I reconfigured the uart settings in stm32h7xx_it.c to manage idle events differently by clearing the idle flag and running a custom function that populates the memory from the rx_buffer.
2026-02-18 7:13 AM - edited 2026-02-18 7:14 AM
This is the same question as here:
(sorry, probably not)
2026-02-18 7:15 AM
I originally made that post and didn't find an answer, I cannot find any hardware or software limitations so thought rewording my post to focus on the DMA interrupt rather than the population of the LUT would be more successful as I have found this to be the route cause.
2026-02-18 7:17 AM - edited 2026-02-18 7:18 AM
This looks like a cache issue. You will need to disable data cache or manage it appropriately. Invalidate after data is received but before reading it.
How many bytes are you expecting to receive? 640?
2026-02-18 7:30 AM - edited 2026-02-18 7:33 AM
Thank you,
In the attached instance I was expecting 640 bytes + 5 confirmation bytes. However I want to send payloads up to 4096 bytes.
I have mapped the MPU to match the memory areas from the linker script
MEMORY
{
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
DTCMRAM1 (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
DTCMRAM2 (xrw) : ORIGIN = 0x20010000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 1024K
RAM_CD (xrw) : ORIGIN = 0x30000000, LENGTH = 128K
RAM_SRD (xrw) : ORIGIN = 0x38000000, LENGTH = 32K
}
Should I disable the MPU during hard faults? Is there anything else standing out.
This is how each region is configured.
| Region memory | Instruction access | Shareable | Cacheable | Bufferable |
| ITCM RAM (0x0000 0000, 64 KB) | Enabled | Not shareable | Not cacheable | Not bufferable |
| FLASH (0x0800 0000, 2 MB) | Enabled | Not shareable | Cacheable | Not bufferable |
| DTCM RAM 1 (0x2000 0000, 64 KB) | Disabled | Not shareable | Not cacheable | Not bufferable |
| DTCM RAM 2 (0x2001 0000, 64 KB) | Disabled | Not shareable | Not cacheable | Not bufferable |
| AXI SRAM (0x2400 0000, 1 MB) | Disabled | Not shareable | Cacheable | Bufferable |
| SRAM_CD (0x3000 0000, 128 KB) | Disabled | Not shareable | Cacheable | Bufferable |
| SRAM_SRD (0x3800 0000, 32 KB) | Disabled | Shareable | Not cacheable | Not bufferable |
2026-02-18 7:43 AM
Initialize the array to something unique/nonzero so you can see if bytes 512-640 are actually written.
2026-02-19 4:16 AM
I added the following script to replace all of the rx_buffer values with 7:
for (uint16_t i = 0; i < 4096; ++i) {
rx_buffer[i] = 7;
}Whilst rx_buffer is initially fully populated with 7's, by using breakpoints I can see that it is not updating to match the information sent over serial when the following interrupt is triggered.
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t size){it would appear my LUT, that has static memory allocation, is being populated by the first correct 512 bytes from somewhere else. (the first 5 bytes are the arbitration field which is why they are skipped in the for loop).
for (uint16_t k = 0, i = 5; i < length + 5; ++k, i += 2) {
lut[k] = (rx_buffer[i+1] | rx_buffer[i] << 8);
if (lut[k] >= 4095) {
lut[k] = 4095;
}
}with the code bellow should the callback have a DMA specific function? is uint16_t size the correct value at the end.
2026-02-19 4:40 AM
Sorry, update to this; by changing the way I populated the rx_buffer in the while loop I have achieved the screenshots below. suggesting the issue still lies with how the rx_buffer is populated and not the transfer to the look up table.
while (1) {
if (mode == 0) {
if (rx_buffer[0] == 0) {
for (uint16_t i = 0; i < 4096; ++i) {
rx_buffer[i] = 7;
}
}
}
/ code /
}payload had length 640, yet only the first 512 bytes of rx_buffer were populated (including [0]).
The LUT is correctly populated from the rx_buffer with uint16_t based on the uint8_t captured in rx_buffer. this stops working at the 254 value as the 5 start bits account for the remaining values to reach 512 bytes. Each subsequent value is populated as 0x0707=1799 all the way to 319 as requested.
2026-02-19 5:48 AM
I have switched the DMA to circular mode to direct bytes into rx_buffer with the DMA before it becomes fully populated. This has fixed my rx_buffer issue, however caused some downstream issues that should be easier to fix. Thank you everyone for the continued support.
2026-02-19 6:05 AM
Hmm, I see no reason why it would stop at 512 bytes. There is no limitation that would explain this.
> __HAL_DMA_GET_COUNTER(huart3.hdmarx);
> Provides the incorrect amount of data being passed over serial.
Incorrect how? Does it suggest only 512 bytes have been transferred?
Does information in the huart handle and linked dma handles still appear valid?