DMA, adresses

RP2040 based microcontroller boards running MicroPython.
Target audience: MicroPython users with an RP2040 boards.
This does not include conventional Linux-based Raspberry Pi boards.
rgcoldeman
Posts: 14
Joined: Sat Jan 30, 2021 11:18 pm

Re: DMA, adresses

Post by rgcoldeman » Thu Feb 18, 2021 11:49 am

Very nice, thanks for sharing!

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: DMA, adresses [Solved]

Post by Roberthh » Thu Feb 18, 2021 9:22 pm

Two things: Once again I was chatched by the fact, that one cannot redefine a const. so I changed the setting in creating the TRIG_CTRL patter outside the DMAStart function and supply it as an argument. Looks like:

Code: Select all

RQ_QUIET = (0x1) # do not generate an interrupt
TREQ_SEL = (0x00) # wait for PIO0_TX0
CHAIN_TO = (0) # do not chain
RING_SEL = (0)
RING_SIZE = (0) # no wrapping
INCR_WRITE = (0) # for write to array
INCR_READ = (1) # for read from array
DATA_SIZE = (0) # 8-bit word transfer
HIGH_PRIORITY = (1)
EN = (1)
DMA_stream_control = ((IRQ_QUIET << 21) | (TREQ_SEL << 15) | (CHAIN_TO << 11) | (RING_SEL << 10) |
                      (RING_SIZE << 9) | (INCR_WRITE << 5) | (INCR_READ << 4) | (DATA_SIZE << 2) |
                      (HIGH_PRIORITY << 1) | (EN << 0))

@micropython.viper
def DMA_start(chan:uint, ar, nword:uint, control:uint):
    dma=ptr32(uint(DMA_BASE) + chan * 0x40)
    dma[READ_ADDR] = uint(ptr32(ar))
    dma[WRITE_ADDR] = uint(PIO0_BASE_TXF0)
    dma[TRANS_COUNT] = nword
    dma[CTRL_TRIG] = control
The other problem catches me now for a while: I cannot set more than 8 pins at once in a PIO script. Whatever I do, it sticks to <=8. Has anyone a clue why? The code below works fine, consuming 16 bit patterns, but the 9th bit is not set. The lower 8 bits show up right. It seems that this 9th bit is not set to output mode.

Code: Select all

@rp2.asm_pio(
    sideset_init=(rp2.PIO.OUT_HIGH,) * 2,
    out_init=(rp2.PIO.OUT_HIGH,) * 9, 
    out_shiftdir=rp2.PIO.SHIFT_RIGHT,
    autopull=True,
    pull_thresh=16)
def data9_write():
    # fmt: off
    out(pins, 9)            .side(0b10)
    out(null, 7)            .side(0b11)
    # fmt: on
Edit: It looks like a pin direction init problem. If I enable in the PIO code the pindirs, by setting the first words of my data appropriately, it works fine. So the out_init= is not processed rigth, or I am missing something. The PIO code the looks like:

Code: Select all

@rp2.asm_pio(
    sideset_init=(rp2.PIO.OUT_HIGH,) * 2,
    out_init=(rp2.PIO.OUT_HIGH,) * 9, 
    out_shiftdir=rp2.PIO.SHIFT_RIGHT,
    autopull=True,
    pull_thresh=16)
def data9_write():
    # fmt: off
    out(pindirs, 9)         .side(0b00)
    out(null, 7)            .side(0b00)
    wrap_target()
    out(pins, 9)            .side(0b10)
    out(null, 7)            .side(0b11)
    wrap()
    # fmt: on

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: DMA, adresses

Post by Roberthh » Fri Feb 19, 2021 12:19 pm


User avatar
marfis
Posts: 215
Joined: Fri Oct 31, 2014 10:29 am
Location: Zurich / Switzerland

Re: DMA, adresses

Post by marfis » Sat Feb 20, 2021 9:43 pm

For anyone who might be interested in a REPL friendly way to interact with the DMA module, I wrote a uctypes wrapper
https://github.com/hoihu/projects/blob/ ... ico/dma.py

example (memcopy of 2 bytearrays):
https://github.com/hoihu/projects/blob/ ... ransfer.py

Note that this might not be as performant as the other proposals, but I found it helpful while using the REPL (since the register names come up with tab completition etc).

User avatar
marfis
Posts: 215
Joined: Fri Oct 31, 2014 10:29 am
Location: Zurich / Switzerland

Re: DMA, adresses

Post by marfis » Sun Feb 21, 2021 10:39 pm

some snippets on how to glue the PIO configured for ws2812 (Neopixel) with the DMA controller can be found here:
https://github.com/hoihu/projects/blob/ ... _ws2812.py

basically all it does is to setup a dma channel to push out the data to the PIO's TXFIFO. The configuration of the PIO is the same as on the existing official example (pio_ws2812.py). I only tested it with my logic analyser.

Some notes / thought..

I guess what would be nice is to use a second DMA channel channel that reconfigures the first one, once it has finished the transfer (as detailed in the chapter 2.5.6.2. DMA Control Blocks). This would allow to continuously stream/update the framebuffers data to the Neopixels in the background... imagine a neopixel screen. Not sure though about the necessary 50usec reset in between the refresh cycles.... Perhaps using an IRQ at the end of the transfer is simpler to handle (?)

A blocker to stream the framebuffer data out is also the missing support of RGB888 mode... This would have been a good match for the 8 bit wide neopixel colors.

Post Reply