I'm trying to trigger a DMA channel to perform a memory-to-memory transfer within the SRAM. The channel throws up the busy flag, but there is no change to the transfer count.
I have the following code:
;reset dma
ldr r0, *resets_clr ;clear reset
mov r1, 4
str r1, (r0, 0)
ldr r0, *resets_rw ;confirm reset clear
*rst_dma
ldr r2, (r0, 2)
and r2, r1
beq *rst_dma
;start dma channel
ldr r0, *dma_rw
adr r1, *var
str r1, (r0, 0) ;read addr
ldr r1, *sram_addr
str r1, (r0, 1) ;write addr
mov r1, 8
str r1, (r0, 2) ;trans count
mov r1, 47 ;incr_write | size_word | high_priority | en
str r1, (r0, 3) ;ctrl trig
;wait for transfer marked complete
mov r2, 1
lsl r2, r2, 24
*busy_dma
ldr r1, (r0, 3)
and r1, r2
bne *busy_dma
;test
ldr r0, *sram_addr
ldr r1, (r0, 0)
mov lr, pc
cmp r1, 7
beq *led_on
With the following word-sized values:
resets_rw 0x4000c000
resets_clr 0x4000f000
var 7
dma_rw 0x50000000
sram_addr 0x20001000
The chip hangs up in the rst_dma
loop, which waits until the channel drops its busy flag. If I run without the loop, the memory test fails. The channel throws no AHB error.
I already typed the question out so might as well answer it.
The channel control register has a field to select a transfer request signal (TREQ_SEL
), which resets to the first data request channel, DREQ_PIO0_TX0
. If you're not using the DMA with a peripheral, and don't care about timing the transfer pace, you should set the field to 0x3f
for unpaced transfers.
mov r1, 63 ;treq_sel unpaced transfer
lsl r1, r1, 15
add r1, 47 ;inc_write | size_word | en
str r1, (r0, 3) ;ctrl trig
Without this, the DMA will just sit there, waiting for a non-existent signal.