Skip to content

Instantly share code, notes, and snippets.

@azechi
Created October 21, 2022 11:08
Show Gist options
  • Save azechi/9f6a5b76747accc6826df5ef57c8ce3f to your computer and use it in GitHub Desktop.
Save azechi/9f6a5b76747accc6826df5ef57c8ce3f to your computer and use it in GitHub Desktop.
Raspberry Pi Pico Micropython PWM DMA CHAIN LED fade
from uctypes import *
from machine import Pin, PWM, mem32
from sys import byteorder
# control register structure
DMA_CTRL_LAYOUT = {
"AHB_ERROR": 31<<BF_POS | 1<<BF_LEN | BFUINT32,
"READ_ERROR": 30<<BF_POS | 1<<BF_LEN | BFUINT32,
"WRITE_ERROR": 29<<BF_POS | 1<<BF_LEN | BFUINT32,
"BUSY": 24<<BF_POS | 1<<BF_LEN | BFUINT32,
"SNIFF_EN": 23<<BF_POS | 1<<BF_LEN | BFUINT32,
"BSWAP": 22<<BF_POS | 1<<BF_LEN | BFUINT32,
"IRQ_QUIET": 21<<BF_POS | 1<<BF_LEN | BFUINT32,
"TREQ_SEL": 15<<BF_POS | 6<<BF_LEN | BFUINT32,
"CHAIN_TO": 11<<BF_POS | 4<<BF_LEN | BFUINT32,
"RING_SEL": 10<<BF_POS | 1<<BF_LEN | BFUINT32,
"RING_SIZE": 6<<BF_POS | 4<<BF_LEN | BFUINT32,
"INCR_WRITE": 5<<BF_POS | 1<<BF_LEN | BFUINT32,
"INCR_READ": 4<<BF_POS | 1<<BF_LEN | BFUINT32,
"DATA_SIZE": 2<<BF_POS | 2<<BF_LEN | BFUINT32,
"HIGH_PRIORITY": 1<<BF_POS | 1<<BF_LEN | BFUINT32,
"EN": 0<<BF_POS | 1<<BF_LEN | BFUINT32
}
DMA_BASE = const(0x5000_0000)
# channel offset
DMA_CH = 0x040
# alias CSRs offset address
DMA_0_READ_ADDR = const(0x000)
DMA_0_WRITE_ADDR = const(0x004)
DMA_0_TRANS_COUNT = const(0x008)
DMA_0_CTRL_TRIG = const(0x00c)
DMA_1_CTRL = const(0x010)
DMA_3_READ_ADD_TRIG = const(0x03c)
# raw intrrupt status register
DMA_INTR = const(0x400)
PWM_BASE = const(0x4005_0000)
#channel offset (PWM_BASE + (CH * ch) + CC)
PWM_CH = const(0x14)
PWM_CSR = const(0x00) # control and status register
PWM_DIV = const(0x04) # divider
PWM_CTR = const(0x08) # counter
PWM_CC = const(0x0c) # counter compare
PWM_TOP = const(0x10) # counter wrap value
@micropython.viper
def fade():
fade = bytearray(4*256)
p = ptr32(fade)
for i in range(0, 256, 1):
p[i] = uint(i * i << 16) # cc channel B
return fade
fade = fade()
# pwm slice 4
DREQ_PWM_WRAP4 = 28
pwm_ch = PWM_BASE + (PWM_CH * 4)
pwm_cc = pwm_ch + PWM_CC
# PWM slice=4, channel=1
led = PWM(Pin(25))
# clkdiv 8.0
mem32[pwm_ch + PWM_DIV] = (0x8 << 4)
# start pwm
mem32[pwm_ch + PWM_CSR] |= 1
dma_ch_pwm = DMA_BASE + (DMA_CH * 1)
dma_ch_config = DMA_BASE + (DMA_CH * 2)
config = addressof(fade).to_bytes(4, byteorder)
mem32[dma_ch_config + DMA_0_READ_ADDR] = addressof(config)
mem32[dma_ch_config + DMA_0_WRITE_ADDR] = dma_ch_pwm + DMA_3_READ_ADD_TRIG
mem32[dma_ch_config + DMA_0_TRANS_COUNT] = 1
ctrl = struct(dma_ch_config + DMA_1_CTRL, DMA_CTRL_LAYOUT)
ctrl.TREQ_SEL = 0x3f # permanent request
ctrl.CHAIN_TO = (dma_ch_pwm - DMA_BASE) // DMA_CH
ctrl.INCR_WRITE = 0
ctrl.INCR_READ = 0
ctrl.DATA_SIZE = 0x2 # SIZE_WORD: 4 bytes
ctrl.EN = 1
# dma channel for pwm
mem32[dma_ch_pwm + DMA_0_READ_ADDR] = addressof(fade)
mem32[dma_ch_pwm + DMA_0_WRITE_ADDR] = pwm_cc
mem32[dma_ch_pwm + DMA_0_TRANS_COUNT] = 256
ctrl = struct(dma_ch_pwm + DMA_0_CTRL_TRIG, DMA_CTRL_LAYOUT)
ctrl.TREQ_SEL = DREQ_PWM_WRAP4
ctrl.CHAIN_TO = (dma_ch_config - DMA_BASE) // DMA_CH
ctrl.INCR_WRITE = 0
ctrl.INCR_READ = 1
ctrl.DATA_SIZE = 0x2 # SIZE_WORD: 4 bytes
ctrl.EN = 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment