【RPi PICO】DDS sine generator and dual PWM output
[Copy link]
From: https://forum.micropython.org/viewtopic.php?t=9945&p=55587#p55587
The sine generator of the DDS is generated using the second core. To achieve higher resolution and higher frequency, it adds 2 PWM signals, each 6 bits.
# DDS Sine Generator in second core by CWE
# Example using Double PWM
# http://www.openmusiclabs.com/learning/digital/pwm-dac/dual-pwm-circuits/index.html 100k and 1.5k + 4.7nF
import time, _thread, sys
from machine import Pin, PWM
import math
import uarray
# Construct PWM object, with LED on Pin(25).
pwmA = PWM(Pin(15, Pin.OUT)) # upper 6 bits
pwmB = PWM(Pin(14, Pin.OUT)) # low 6 bits
# Set the PWM frequency.
pwmFreq= int(125_000_000/64) # 6 bit
pwmA.freq(pwmFreq)
pwmB.freq(pwmFreq)
pwmA.duty_u16(31<<10)
pwmB.duty_u16(31<<10)
sineBufLen= 6249 #1kHz: 6249
sineBuf=uarray.array("H",range(0,sineBufLen))
for x in range(0,sineBufLen):
xr= x/sineBufLen*2*math.pi
sineBuf[x]= 2047+int(2047*math.sin(xr)) # 12 bit resolution
#print(sineBuf[x])
pwmA.duty_u16(0<<10)
pwmB.duty_u16(0<<10)
ddsCtrl = uarray.array('i',[
0x40050000 + 0x98, # 0 cc7
sineBufLen, # 4
1, # 8
int((1<<16)*1.0) # 12 1=run, step in half
])
@micropython.asm_thumb
def dds(r0, r1): # Buffer, ctrl-array
mov(r2,r0) # Buffer Start Address
ldr(r5, [r1,4]) # buffer length
ldr(r4, [r1,0]) # pwm counter compare register
ldr(r7, [r1,12]) # step index fine
mov(r3,0) # Buffer Index fine
label(nextVal)
lsr(r0,r3,16) # index coarse
lsl(r0,r0,1) # index coarse half words
add(r0,r0,r2)
ldrh(r0,[r0,0]) # read buffer regPoke(0x40050000 + 0x98, ((a>>6)<<16) + (a&63))
lsl(r6,r0,26) # get the lowest 6 bit
lsr(r0,r0,6) # shift bits right (upper)
lsl(r0,r0,16)
lsr(r6,r6,26) # lower 6 bits
add(r0,r0,r6)
str(r0,[r4,0])
#b(retu)
add(r3,r3,r7) # next buffer index fine
lsr(r0,r3,16)
cmp(r5,r0) # end not yet reached
bhi(nextVal)
lsl(r0,r5,16)
sub(r3,r3,r0)
mov(r0,r3)
ldr(r7, [r1,12]) # reload step index repeat?
cmp(r7,0)
bne(nextVal)
label(retu)
@micropython.asm_thumb
def regPeek(r0): # Address
mov(r1,r0)
ldr(r0,[r1,0])
@micropython.asm_thumb
def regPoke(r0, r1): # Address, Data
str(r1,[r0,0])
mov(r0,r1)
def regSet(adress, mask):
regPoke(adress, regPeek(adress) | mask)
def setF(f):
ddsCtrl[3]=int(f/1000*(1<<16))
#sineBuf[0]=1<<6
#print(dds(sineBuf, ddsCtrl))
_thread.start_new_thread(dds, (sineBuf, ddsCtrl))
try:
while True:
f=10
while f<25_000:
setF(f)
time.sleep(.2)
print(f, end=" ")
f=f*1.5849 #math.sqrt(10)
except KeyboardInterrupt:
ddsCtrl[3]=0
sys.exit()
"""
x=0
delta=10
while True:
x+= delta
if x>(sineBufLen-1):
x-=sineBufLen
a= sineBuf[x]
#pwmA.duty_u16( (a<<4) & (255<<8)) # upper 6 bit
#pwmB.duty_u16( (a<<10) & (255<<8)) # lower 6 bit
regPoke(0x40050000 + 0x98, ((a>>6)<<16) + (a&63))
#regPoke(0x40050000 + 0x98, ((a>>6)<<16))
"""
|