Graeme Winter

µPython access to bytes in RAM

RAM access by pointer

To do anything non-trivial needs DMA, which is work in progress, but had a quick moment at accessing RAM from µPython and turns out to be pretty easy…

from uctypes import addressof
from machine import mem16
from array import array

# initialise array
scratch = array("H", [0xffff for _ in range(1024)])

# grab address and overwrite
address = addressof(scratch)

for j in range(0, 2048, 2):
    mem16[address + j] = j // 2

for j, s in enumerate(scratch):
    assert j == s

ADC

Useful if you are driving stuff from e.g. ADC to DMA by writing the right registers… driving the ADC for one shot is at least relatively simple:

from machine import mem32

# prepare the pin (set the function to NULL which is 0b11111, needed for ADC)
IO_BANK_BASE = 0x40014000
GPIO26_CTRL = IO_BANK_BASE + 0xD4
mem32[GPIO26_CTRL] = 0b11111

# configure the ADC inc. FIFO - registers
ADC_BASE = 0x4004C000
ADC_CS = ADC_BASE + 0x0
ADC_RESULT = ADC_BASE + 0x4

# trigger ADC for one read
mem32[ADC_CS] = 0x4 + 0x1

# read value
result = mem32[ADC_RESULT]

# report the value remembering that the range is 12 but not 16
print(result)

DMA

Now this is where things get a whole bunch more involved. Much more involved: FIFO control and status register, enabling DREQ for DMA, not chaining (because I don’t want to go that fast) and setting up a scratch array to copy the data into.

Job list:

I think that should be enough…

Data array and pointer

Easy -> as above, has to be type uint16_t also known as “H” in µPython. Just make sure that this is allocated to be sufficiently large for however many measurements I will need. Looks like using ~ 100kB will be fine as gc.mem_free() shows about 170kB.

ADC in free running mode

Register pointers:

# configure the ADC inc. FIFO - registers
ADC_BASE = 0x4004c000
ADC_CS = ADC_BASE + 0x0
ADC_FCS = ADC_BASE + 0x8
ADC_FIFO = ADC_BASE + 0xC

N.B. for this using DREQ not IRQ so want to operate in “quiet” mode. The ADC DREQ value is 0x24. Need to set the FIFO threshold to 1, enable the DREQ, enable the FIFO. ADC CS register needs to be set to 9: START_MANY|EN. Set up the DMA to read from the ADC_FIFO address.

DMA

Should really do something simple with this first like using DMA to fill an array with a specific byte pattern from a single word -> do that next. Setting that up should be simple and equivalent and … easy to debug. No DREQ as will be as fast as possible => 0x3f. INCR_WRITE 👍 but INCR_READ 👎.

from machine import mem32
from uctypes import addressof
from array import array

COUNT = 1024

target = array("H", [0 for j in range(COUNT)])
source = array("H", [0xFFFF])

# DMA registers
DMA_BASE = 0x50000000
CH0_READ_ADDR = DMA_BASE + 0x0
CH0_WRITE_ADDR = DMA_BASE + 0x4
CH0_TRANS_COUNT = DMA_BASE + 0x8
CH0_CTRL_TRIG = DMA_BASE + 0xC

QUIET = 0x1 << 21
DREQ = 0x3F << 15
WRITE_INCR = 0x1 << 5
DATA_SIZE = 0x1 << 2
ENABLE = 1

mem32[CH0_READ_ADDR] = addressof(source)
mem32[CH0_WRITE_ADDR] = addressof(target)
mem32[CH0_TRANS_COUNT] = COUNT
mem32[CH0_CTRL_TRIG] = QUIET + DREQ + WRITE_INCR + DATA_SIZE + ENABLE

BUSY = 0x1 << 24

while mem32[CH0_CTRL_TRIG] & BUSY:
    continue

for t in target:
    assert t == 0xFFFF

That seems easy enough (lots of 65535). Rest will wait until tomorrow.

Previous Next