sc7-default-firmware/dds.py

110 lines
3.3 KiB
Python

import array
import generate_wavetables
NUM_SAMPLES = const(256)
ACCUMULATOR_BITS = const(16)
X_CHANNEL = const(0)
Y_CHANNEL = const(1)
WAVEFORM_SINE = const(0)
WAVEFORM_SQUARE = const(1)
WAVEFORM_SAWTOOTH = const(2)
WAVEFORM_TRIANGLE = const(3)
class DDS():
def __init__(self, vectorscope):
""" pass it an instance of the Vectorscope module from main, it needs to write to the DMA audio registers"""
self.wave = vectorscope.wave
self.waveform = ["sine", "sine"]
self.increment = [51000, 25000]
self.amplitude = [1, 1] ## set this infrequently? -- it's an expensive calculation
self.phase = [0, 0]
self.phase_increment = [0, 0]
self.index = [0, 0]
self.accumulator = [0, 0]
self.samplesX = [0]*NUM_SAMPLES
self.samplesY = [0]*NUM_SAMPLES
self.samples = [self.samplesX, self.samplesY]
self.base_waveforms = {}
self.base_waveforms["sine"] = generate_wavetables.sine()
self.base_waveforms["square"] = generate_wavetables.square()
self.base_waveforms["sawtooth"] = generate_wavetables.sawtooth()
self.base_waveforms["triangle"] = generate_wavetables.triangle()
## init
self.waves = [[0]*256, [0]*256]
self.recalculate_waveforms() ## have to do this every time you change parameters.
def recalculate_waveforms(self): ## select 0=X, 1=Y
for i in [0,1]:
self.waves[i] = [int(self.amplitude[i]*x) for x in self.base_waveforms[self.waveform[i]]]
def initial_wait_for_buffer_sync(self):
self.wave.outBuffer_ready = False ## mark seen
while not self.wave.outBuffer_ready:
pass ## (@_@) should be async wait
@micropython.viper
def do_dds(self):
for i in [0,1]: ## X , Y
self.phase[i] = int(self.phase[i]) + int(self.phase_increment[i])
for s in range(NUM_SAMPLES):
self.index[i] = int(self.phase[i]) + (int(self.accumulator[i]) >> ACCUMULATOR_BITS) & 0xFF ## roll over sample bits
self.accumulator[i] = (int(self.accumulator[i]) + int(self.increment[i])) & 0xFFFFFF ## sample bits + accumulator bits
self.samples[i][s] = self.waves[i][self.index[i]]
def populate_buffer(self):
while not self.wave.outBuffer_ready:
pass ## (@_@) should be async wait
self.wave.packX(self.samplesX)
self.wave.packY(self.samplesY)
self.wave.outBuffer_ready = False
if __name__ == "__main__":
import vectorscope
import machine
userbutton = machine.Pin(19, machine.Pin.IN)
v = vectorscope.Vectorscope()
d = DDS(v)
d.amplitude=[0.5, 0.5]
d.recalculate_waveforms()
## but you can also write them yourself directly: 16-bit signed, 256 values
d.waves[0] = [0]*256
## but it gets overwritten if you recalculate_waveforms()
d.recalculate_waveforms()
def go(n=200):
for i in range(n):
d.do_dds()
d.populate_buffer()
d.waves[0] = d.base_waveforms["square"]
d.recalculate_waveforms()
for i in range(n):
d.do_dds()
d.populate_buffer()
go()