We use some essential cookies to make our website work.

We use optional cookies, as detailed in our cookie policy, to remember your settings and understand how you use our website.

4 posts • Page 1 of 1
renebarto
Posts: 10
Joined: Thu Apr 20, 2023 7:36 pm

DMA on UART0

Sun Sep 14, 2025 8:41 pm

Hi all,

I've been trying to get DMA working on UART0. I've done memory to memory DMA, which seems to work.
However when I try to set up for UART0, I see one character appearing, and then it stops.
I have a callback set up for the interrupt on the DMA channel, and it does get called, and the END bit is set, however I only received the first character.
The DMA channel is set to 12 (UART_TX), I specify the UART0 DR register as the address (after converting the memory address space.
I tried setting the DMACR register on the UART to 0x07, but that also does nothing.
Any pointers?

I tried looking into the Circle code, but that only seems to implement DMA on SPI and I2S.

Regards,

Rene

cleverca22
Posts: 9593
Joined: Sat Aug 18, 2012 2:33 pm

Re: DMA on UART0

Sun Sep 14, 2025 8:50 pm

did you setup dma pacing with dreq?

renebarto
Posts: 10
Joined: Thu Apr 20, 2023 7:36 pm

Re: DMA on UART0

Sun Sep 14, 2025 11:46 pm

That was the right trigger, thanks. I also noticed you need to adapt for the fact that the data register is 32 bits but only holds a single character:

Code: Select all

 m_controlBlock->TransferInformation = (static_cast<uint32>(dreq) << RPI_DMA_TI_PERMAP_SHIFT) |
 (RPI_DMA_DEFAULT_BURST_LENGTH << RPI_DMA_TI_BURST_LENGTH_SHIFT) |
 RPI_DMA_TI_SRC_WIDTH | RPI_DMA_TI_SRC_INC | RPI_DMA_TI_DST_DREQ | RPI_DMA_TI_WAIT_RESP;
 if (srcStride != 0)
 {
 // Writes are always a full 32 bit register, but we want to send a different width
 // This is a.o. used for UART writes
 m_controlBlock->TransferInformation |= RPI_DMA_TI_TDMODE;
 m_controlBlock->TransferLength = length << RPI_DMA_TXFR_LEN_YLENGTH_SHIFT | 1 << RPI_DMA_TXFR_LEN_XLENGTH_SHIFT;
 }
 else
 {
 m_controlBlock->TransferLength = length;
 }
 m_controlBlock->ModeStride2D = 0;
 m_controlBlock->SourceAddress = ARM_TO_GPU((uintptr)srcAddress);
 m_controlBlock->DestinationAddress = dstIOAddress;
 m_controlBlock->NextControlBlockAddress = 0;
So here I use a stride of 1 to make sure we only advance one byte at a time.

Thanks for the help!

(mod edit for code tags)

DougieLawson
Posts: 43604
Joined: Sun Jun 16, 2013 11:19 pm

Re: DMA on UART0

Mon Sep 15, 2025 6:31 am

renebarto wrote:
Sun Sep 14, 2025 11:46 pm
That was the right trigger, thanks. I also noticed you need to adapt for the fact that the data register is 32 bits but only holds a single character:

Code: Select all

 m_controlBlock->TransferInformation = (static_cast<uint32>(dreq) << RPI_DMA_TI_PERMAP_SHIFT) |
 (RPI_DMA_DEFAULT_BURST_LENGTH << RPI_DMA_TI_BURST_LENGTH_SHIFT) |
 RPI_DMA_TI_SRC_WIDTH | RPI_DMA_TI_SRC_INC | RPI_DMA_TI_DST_DREQ | RPI_DMA_TI_WAIT_RESP;
 if (srcStride != 0)
 {
 // Writes are always a full 32 bit register, but we want to send a different width
 // This is a.o. used for UART writes
 m_controlBlock->TransferInformation |= RPI_DMA_TI_TDMODE;
 m_controlBlock->TransferLength = length << RPI_DMA_TXFR_LEN_YLENGTH_SHIFT | 1 << RPI_DMA_TXFR_LEN_XLENGTH_SHIFT;
 }
 else
 {
 m_controlBlock->TransferLength = length;
 }
 m_controlBlock->ModeStride2D = 0;
 m_controlBlock->SourceAddress = ARM_TO_GPU((uintptr)srcAddress);
 m_controlBlock->DestinationAddress = dstIOAddress;
 m_controlBlock->NextControlBlockAddress = 0;
So here I use a stride of 1 to make sure we only advance one byte at a time.

Thanks for the help!
Code (any language) works so much better on here between [code]... your code here ...[/code] tags.
Languages using left-hand whitespace for syntax are ridiculous

DMs sent on Bluesky or by LinkedIn will be answered next month.
Fake doctors - are all on my foes list.

The use of crystal balls and mind reading is prohibited.

4 posts • Page 1 of 1

Return to "Bare metal, Assembly language"

AltStyle によって変換されたページ (->オリジナル) /