DMA, adresses
-
- Posts: 14
- Joined: Sat Jan 30, 2021 11:18 pm
Re: DMA, adresses
The code is complete. It should work out of the box. I used the original 1.13 RP2 micropython version. Where would you expect a 'SetChannelData' method/function?
Re: DMA, adresses
I think here (from your snippet above):
DmaChan0.SetChannelData(uctypes.addressof(screen), uctypes.addressof(screen1), 30, True)
DmaChan0.SetChannelData(uctypes.addressof(screen), uctypes.addressof(screen1), 30, True)
-
- Posts: 14
- Joined: Sat Jan 30, 2021 11:18 pm
Re: DMA, adresses
Ah, you refer to the DMA classes posted by mw66 on this list?
It looks awesome and I hope those classes or similar will eventually be included with the RP2 micropython.
(actually I don't find the implemation of 'SetChannelData' method used in the examples)
The code I posted directly writes the DMA registers with mem32[] commands.
Not pretty and should be modified, but it works for now.
It looks awesome and I hope those classes or similar will eventually be included with the RP2 micropython.
(actually I don't find the implemation of 'SetChannelData' method used in the examples)
The code I posted directly writes the DMA registers with mem32[] commands.
Not pretty and should be modified, but it works for now.
Re: DMA, adresses
ups, yes that was @mw66 snippet sorry..
Re: DMA, adresses
Sorry, I don't know how I missed that out.
Here it is
Here it is
Code: Select all
@micropython.viper
def SetChannelData(self, readAddress : uint , writeAddress : uint, count: uint, trigger : bool):
ptr= ptr32(self.ReadRegister)
ptr2= ptr32(self.WriteRegister)
ptr3= ptr32(self.TransferCountRegister)
ptr[0] = readAddress
ptr2[0] = writeAddress
ptr3[0] = count
if trigger:
ptr4= ptr32(self.TriggerControlRegister)
ptr4[0] = uint(self.ControlValue)
Last edited by mw66 on Mon Feb 08, 2021 9:02 am, edited 1 time in total.
-
- Posts: 14
- Joined: Sat Jan 30, 2021 11:18 pm
Re: DMA, adresses
Thanks, it looks very neat!
I've posted a more detailed description of the project on https://www.instructables.com/Arbitrary ... ry-Pi-Pic/
I've posted a more detailed description of the project on https://www.instructables.com/Arbitrary ... ry-Pi-Pic/
Re: DMA, adresses
Thanks. Your code supports a lot more of the various features than mine though. As I haven't put in any functions to change things like the ring values yet.rgcoldeman wrote: ↑Mon Feb 08, 2021 8:04 amThanks, it looks very neat!
I've posted a more detailed description of the project on https://www.instructables.com/Arbitrary ... ry-Pi-Pic/
One thing I did note about your code is that you are using mem32, even though you are using viper. According to my tests and the following thread, using a direct viper pointer is much faster than mem32. Although it seems in your case you are getting the max throughput you could get anyway.
viewtopic.php?t=6994
-
- Posts: 14
- Joined: Sat Jan 30, 2021 11:18 pm
Re: DMA, adresses
Indeed mem32 is slow. I used viper to get the address of the array to pass on to the registers, not for speed, since it's only for configuration.
In another test I compared blink speed between mem32 and ptr (both viper). ptr could get me up to 15.625MHz, (4 clock cycles per loop), mem32 well below 100kHz.
Ring wrapping seemed interesting at first, but it seems to have many limitations/complications (power-of-2 blocks, no infinite transfers, alignment of the buffer with the memory map)
Your code is very useful. First thing I tried out with DMA was memory-to-memory block transfer, and realized that it could be very useful to access from micropython, so it's definitely worth pushing for getting something like that into the nominal RP2 micropython.
In another test I compared blink speed between mem32 and ptr (both viper). ptr could get me up to 15.625MHz, (4 clock cycles per loop), mem32 well below 100kHz.
Ring wrapping seemed interesting at first, but it seems to have many limitations/complications (power-of-2 blocks, no infinite transfers, alignment of the buffer with the memory map)
Your code is very useful. First thing I tried out with DMA was memory-to-memory block transfer, and realized that it could be very useful to access from micropython, so it's definitely worth pushing for getting something like that into the nominal RP2 micropython.
Re: DMA, adresses
@rgcoldeman Thank you for the good example on using DMA. It took for me some time today to tell, how to write to 8 pins at the same time. I had seen somewhere the way to do ot, but could not recall where. Finally I looked into the MP source code.
I agree that the setting looks a little bit strange, but found a shorter way to write it as:
out_init=(PIO.OUT_HIGH,) * 8,
I agree that the setting looks a little bit strange, but found a shorter way to write it as:
out_init=(PIO.OUT_HIGH,) * 8,
Re: DMA, adresses
@rgcoldeman. Thanks again. I have now a first version of a 8080 style bus transmit, which works well. The bus uses three control signals, so I used three bit sideset. The PIO code is just two instructions. There would be similar functions of command_write() and data_read(), two instructions each. I streamlined DMASetup a bit avoiding mem32, supplying the DMA number and avoiding temporary stores by using const. The data is transferred bytewise, since not all data sets are a multiple of 4 bytes. Sample code below:
Code: Select all
# Example using PIO to drive a 8080 type bus
from machine import Pin, mem32
from time import sleep_us
import rp2
import array
import uctypes
DMA_BASE = const(0x50000000)
READ_ADDR = const(0)
WRITE_ADDR = const(1)
TRANS_COUNT = const(2)
CTRL_TRIG = const(3)
AL1_CTRL = const(4)
PIO0_BASE = 0x50200000
PIO0_BASE_TXF0 = PIO0_BASE+0x10
NUM_WORDS = 259
@rp2.asm_pio(
sideset_init=(rp2.PIO.OUT_HIGH,) * 3,
out_init=(rp2.PIO.OUT_HIGH,) * 8,
out_shiftdir=rp2.PIO.SHIFT_RIGHT,
autopull=True,
pull_thresh=8)
def data_write():
# fmt: off
out(pins, 8) .side(0b111)
nop() .side(0b110)
# fmt: on
@micropython.viper
def startDMA(chan:uint, ar, nword: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
IRQ_QUIET = const(0x1) # do not generate an interrupt
TREQ_SEL = const(0x00) # wait for PIO0_TX0
CHAIN_TO = const(0) # do not chain
RING_SEL = const(0)
RING_SIZE = const(0) # no wrapping
INCR_WRITE = const(0) # for write to array
INCR_READ = const(1) # for read from array
DATA_SIZE = const(0) # 8-bit word transfer
HIGH_PRIORITY = const(1)
EN = const(1)
CTRL0 = const((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))
dma[CTRL_TRIG] = uint(CTRL0)
def run():
ar = array.array("B", [_ for _ in range(NUM_WORDS)])
# Create the StateMachine with the data_write program, WR on Pin(5), data on pin 8++
sm = rp2.StateMachine(0, data_write, freq=125_000_000,
sideset_base=Pin(2), out_base=Pin(6))
sm.active(1)
startDMA(0, ar, len(ar) - 3)