# imports import array import time import machine #==== SIO ============================ # register adddresses for DMA # datasheet page 102 DMA_base = 0x50000000 # DMA regs # starting read address DMA_RD_ADDR0 = 0x000 + DMA_base # starting write address DMA_WR_ADDR0 = 0x004 + DMA_base # number off ITEMS (not bytes to trnasffer) DMA_TR_CNT0 = 0x008 + DMA_base # Channel control -- many fields -- see below DMA_CTRL0 = 0x00c + DMA_base # kill the channels by writing one to the bit number of thh channel DMA_Ch_ABORT = 0x444 + DMA_base # bits in ctrl register # busy during transfer DMA_BUSY = (1<<24) # bit 24 high when busy # turn off channel done IRQ DMA_IRQ_QUIET = (1<<21) # bit 21 turn off interrupt # Triggger Source table page 96 section 2.5.3.1 # More tirgger info page 114 # 0x0 to 0x3a → select DREQ n as TREQ from table above # 0x3b → Select Timer 0 as TREQ # 0x3c → Select Timer 1 as TREQ # 0x3d → Select Timer 2 as TREQ (Optional) # 0x3e → Select Timer 3 as TREQ (Optional) # 0x3f → Permanent request, for unpaced transfers. # bits 15:20 trigger request source def DMA_TREQ(trigger_source): return (trigger_source & 0x3f)<<15 # When this channel completes, it will trigger the channel # indicated by CHAIN_TO. Disable by setting CHAIN_TO = # (this channel). def DMA_CHAIN_TO (next_ch): return (next_ch & 0x0f)<<11 # bits 11:14 next chnnel # # Select whether RING_SIZE applies to read or writeaddresses. # If 0, read addresses are wrapped on a (1 << RING_SIZE) # boundary. If 1, write addresses are wrapped. DMA_RING_SEL = (1<<10) # bits 10 -- loop? # Ring sizes between 2 and 32768 bytes are possible. This # can apply to either read or write addresses, based on # value of RING_SEL. # 0x0 → RING_NONE def DMA_RING_SIZE(ring_size): return (ring_size & 0x0f)<<6 # bits 6:9 # increment or keep constant wrrite nd read addr # useful for peripheril write/read DMA_WR_INC = (1<<5) # bits 5 DMA_RD_INC = (1<<4) # bits 4 # Set the size of each bus transfer (byte/halfword/word). # READ_ADDR and WRITE_ADDR advance by this amount # (1/2/4 bytes) with each transfer. # 0x0 → SIZE_BYTE # 0x1 → SIZE_HALFWORD # 0x2 → SIZE_WORD def DMA_DATA_WIDTH(data_width): return (data_width & 0x03)<<2 # bits 2:3 # give this channel more access if several channels aare on DMA_HIGH_PRI = (1<<1) # bit 1 # turn on the channel DMA_EN = 1 # bits 0 # DMA source and destination DMA_src = array.array('i',[ 1, 2, 3, 4, 5]) DMA_dst = array.array('i',[ 0, 0, 0, 0, 0]) print('initial dest=', DMA_dst) # ==================================== @micropython.asm_thumb # passing an array name to the assembler # actually passes in the address def addressof(r0): # r0 is the output register, so address beomes output # this is really a NOP mov(r0, r0) # ==================================== DMA_src_addr = addressof(DMA_src) machine.mem32[DMA_RD_ADDR0] = DMA_src_addr DMA_dst_addr = addressof(DMA_dst) machine.mem32[DMA_WR_ADDR0] = DMA_dst_addr machine.mem32[DMA_TR_CNT0] = len(DMA_src) # this writ starts the transfer perm_trig = 0x3f # alwas go data_32 = 0x02 # 32 bit # set up control and start the DMA machine.mem32[DMA_CTRL0] = (DMA_IRQ_QUIET | DMA_TREQ(perm_trig) | DMA_WR_INC | DMA_RD_INC | DMA_DATA_WIDTH(data_32) | DMA_EN ) # print('src=', DMA_src) print('dest after DMA=', DMA_dst) # change the data and do it again machine.mem32[DMA_src_addr+4] = 10 DMA_src[0] = 20 # print('new src=', DMA_src) # have to reload, becuase end value is maintained machine.mem32[DMA_RD_ADDR0] = DMA_src_addr machine.mem32[DMA_WR_ADDR0] = DMA_dst_addr # cntl reg stays the same, so just enable machine.mem32[DMA_CTRL0] |= DMA_EN # print('new dest=', DMA_dst) #kill channel 0 DMA_CH_ABORT = 1 # set bit 0 to kill channel 0