Hello,
using S32K344 with Zephyr OS. I set a DTS for LPUART14
DTS: dmas = <&edma0 16 46>, <&edma0 17 47>;
Channel 16,17 should be in DMAMUX1 range, where LPUART14 is on slot 46 and 47.
Unfortunately, when ASYNC API calls callback for a next buffer (immidiatelly after uart_rx_enable)
Any Idea?
ERROR:
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.010,000]
[00:00:00.618,000]
Hello,
Thank you very much for your help.
I was also communicating with Zephyr and it seems they found a bug in eDMA driver.
Hello @PavelRydl ,
Thank you for the update and for confirming that the issue persists across multiple S32K344 modules. This helps rule out hardware-related causes.
Based on the faulting instruction inside the EDMA driver (edma_reload_loop) and the crash address (0x4025803c), I have reviewed the EDMA implementation and would like to suggest the following checks and recommendations:
1. Ensure CONFIG_DMA_TCD_QUEUE_SIZE is ≥ 2
The cyclic mode requires at least two TCDs to form a valid loop. If the queue size is set to 1, the reload logic may fail.
2. Validate write_idx bounds before accessing the TCD pool
The driver uses write_idx to index into the TCD pool:
tcd = &DEV_CFG(dev)->tcdpool[channel][data->transfer_settings.write_idx];
Please ensure that write_idx is always less than CONFIG_DMA_TCD_QUEUE_SIZE. You may add a debug log to confirm:
LOG_DBG("write_idx = %d", data->transfer_settings.write_idx);
3. Confirm buffer alignment and size
Your buffer declaration:
__aligned(32) uint8_t async_rx_buffer[2][RX_CHUNK_LEN];
is correct. Just ensure that RX_CHUNK_LEN is a multiple of the data unit size (e.g., 1, 2, or 4 bytes).
4. Disable cyclic mode if not required
If your application does not require cyclic DMA, please ensure:
config->cyclic = false
This will avoid triggering the edma_reload_loop() logic entirely.
5. Enable DMA error IRQ and check error flags
Make sure the DTS does not disable error IRQs (no_error_irq = false). Then monitor:
EDMA_GetErrorStatusFlags(...)
for any reported faults during runtime.
6. Use basic DMA mode for initial testing
If cyclic or scatter-gather is not needed, consider using the basic configuration path:
dma_mcux_edma_configure_basic(...)
This simplifies the setup and avoids complex reload logic.
Best regards,
Pavel
Hello,
"If the issue persists, try replacing the DMA-based RX with polling temporarily to confirm that the UART peripheral itself is functional and the issue is isolated to DMA usage."
Actually, I Used interrupt-driven uart before and it's working fine. I need DMA becuase of high CPU usage and interrupt based uart is not reliable enough, mostly becuase of really small RX FIFO buffer (4 words)
"Verify uart_rx_buf_rsp() is not called too early"
tested, same problem. Also, this request next buffer and I should provide it as fast as possible.
"Try using async_rx_buffer[0] instead of [1]"
Tested, but same problem. Reference manual says I should not bind to the same memory, so I still have to use different part of memory for a next buffer.
"Try reducing the buffer size"
Tested. same problem.
I have no idea, what I should do now
Is it a bug in a NXP drivers? It's strange, MUX0 is fine, only MUX1.
It's really like DMA cannot access somewhere, but that a bit above my current nxp knownledge to solve that.
Thank you for helping me!
Hello @PavelRydl ,
Thank you sharing details.
Please find my hints below:
1. Check buffer alignment and cache settings
In your code, the buffer is declared as:
__nocache __aligned(32) uint8_t async_rx_buffer[2][RX_CHUNK_LEN];
This is correct and should be DMA-safe. However, please verify that:
- RX_CHUNK_LEN is a multiple of 32 (it is 32, so OK).
- The buffer is not being accessed concurrently from another context (e.g., logging or polling).
2. Verify uart_rx_buf_rsp() is not called too early
Even though the callback is triggered only once, it's possible that the DMA controller hasn't finished setting up the initial transfer when uart_rx_buf_rsp() is called. Try delaying the response slightly:
case UART_RX_BUF_REQUEST:
k_sleep(K_MSEC(1)); // Small delay before responding
uart_rx_buf_rsp(dev, async_rx_buffer[1], RX_CHUNK_LEN);
break;
3. Try using async_rx_buffer[0] instead of [1]
Since [0] is the initial buffer used in uart_rx_enable(), and [1] is never used before the crash, try responding with [0] to rule out any issues with [1]:
uart_rx_buf_rsp(dev, async_rx_buffer[0], RX_CHUNK_LEN);
4. Try reducing the buffer size
Although 32 bytes is small, try using 16 or 8 bytes to see if the crash behavior changes. This can help isolate whether the issue is size-related.
5. Optional Debug Step
If the issue persists, try replacing the DMA-based RX with polling temporarily to confirm that the UART peripheral itself is functional and the issue is isolated to DMA usage.
Best regards,
Pavel
Hello,
I did some changes.
1. I removed that variable, I don't need it.
2. The request is called only once and it crashes, so I will never assign same buffer again
3. It's not in any special section, just bss, I tried to use nocache just for a test with same error
4. I verified slots again
| 46 | LPUART14 | Transmit DMA Request |
| 47 | LPUART14 | Receive DMA Request |
5. Added
6. Added
Error:
*** Booting Zephyr OS build 69ce66d49133 ***
[00:00:00.020,000]
[00:00:00.020,000]
[00:00:00.020,000]
[00:00:00.020,000]
[00:00:00.021,000]
[00:00:00.021,000]
[00:00:00.021,000]
[00:00:00.021,000]
[00:00:00.021,000]
[00:00:00.021,000]
[00:00:00.021,000]
[00:00:00.021,000]
[00:00:00.022,000]
[00:00:00.022,000]
[00:00:00.022,000]
[00:00:00.022,000]
[00:00:00.022,000]
[00:00:00.022,000]
[00:00:00.022,000]
[00:00:00.022,000]
[00:00:00.023,000]
[00:00:00.023,000]
[00:00:00.023,000]
[00:00:00.023,000]
[00:00:00.023,000]
[00:00:00.023,000]
[00:00:00.029,000]
[00:00:00.029,000]
[00:00:00.029,000]
[00:00:00.029,000]
[00:00:00.029,000]
[00:00:00.029,000]
Tried to use different channel
dmas = <&edma0 17 46>, <&edma0 18 47>;
Hello @PavelRydl ,
Thank you for the detailed report. Based on the provided logs and code snippet, here are a few suggestions:
1. Initialize async_rx_buffer_idx before use
Ensure that async_rx_buffer_idx is explicitly initialized to 0 before calling uart_rx_enable(). Uninitialized global variables may lead to undefined behavior.
async_rx_buffer_idx = 0;
2. Correct buffer selection in UART_RX_BUF_REQUEST
In the callback, you're always responding with async_rx_buffer[1], regardless of the current index. This may cause the driver to use an invalid or already active buffer. Instead, use the current index and toggle it after responding:
uart_rx_buf_rsp(dev, async_rx_buffer[async_rx_buffer_idx], RX_CHUNK_LEN);
async_rx_buffer_idx ^= 1; // Toggle between 0 and 1
3. Verify DMA buffer location
Ensure that async_rx_buffer is located in a memory region accessible by the DMA controller (typically in SRAM, not in .noinit or other special sections). Misplaced buffers can cause bus faults during DMA access.
4. Double-check DMA channel and DMAMUX slot mapping
While channels 16 and 17 should be valid for DMAMUX1, please verify that:
- These channels are not used by other peripherals.
- The DMAMUX slot numbers 46 and 47 are correctly mapped to LPUART14 RX/TX in your SoC's reference manual and Zephyr's SoC integration.
5. Add a short delay before enabling RX
In some cases, adding a small delay before calling uart_rx_enable() can help avoid race conditions between peripheral and DMA initialization:
k_sleep(K_MSEC(10));
uart_rx_enable(...);
6. Enable DMA and UART debug logs
To get more insight into what happens before the crash, consider enabling debug logs for DMA and UART in your prj.conf:
CONFIG_DMA_LOG_LEVEL_DBG=y
CONFIG_UART_LOG_LEVEL_DBG=y
Best regards,
Pavel