[sdiy] Coding digital waveforms

Jerry Gray-Eskue jerryge at cableone.net
Thu Dec 17 19:23:40 CET 2009


<<
1) Start the interrupt
2) Get the stored sample value from memory (in some variable called
SAMPLE_OUT or whatever).
3) Send it to the DAC
4) Start calculating the next sample
5) Finish calculating the next sample and store it in SAMPLE_OUT.
6) Finish the interrupt
>>

This is all valid but I would tend to do only steps 1-3 in the interrupt and
the rest in my "main" loop.
This keeps the interrupt as short as possible but requires using a token
(this has many names) of some sort,
basically a flag that the Main loop sets and the Interrupt clears.
This is used so the main loop can update the SAMPLE_OUT without the
interrupt missing any sample values.
In good code the main loop would always reach point where it is waiting on
the flag to clear.
If this is not happening your routine to load the next SAMPLE_OUT value is
too slow and your output is glitching.

1) Start the interrupt
if( SAMPLE_OUT Ready)
{
	 Get the stored sample value from memory
	 Send it to the DAC
	 Clear(SAMPLE_OUT Ready)
}
else
{
	/* Opps output glitched */
}
4) Finish the interrupt

In the main loop:
 	calculate the next sample
	while(SAMPLE_OUT Ready)
	{
		/* Wait on it... */
		/* You may want to software loop time out in here incase you are dead
locked... */
	}
	store it in SAMPLE_OUT.
	Set(SAMPLE_OUT Ready)


The main loop should also handle no timing critical code.

One trick you can use in the main loop is do partial code execution per
loop, for instance:

Loop #
1 Read switches start A2D conversion - calculate the next sample and store
it in SAMPLE_OUT.
2 Read A2D Update LEDs - calculate the next sample and store it in
SAMPLE_OUT.
3 Update Graphic Display - calculate the next sample and store it in
SAMPLE_OUT.


The advantage is using short interrupts is your system will keep running and
will not crash due to too much time spent in the interrupts.
This makes debugging much easier and it is more obvious what is going wrong.
Also at some point you will want to have more than one interrupt source.

-----Original Message-----
From: synth-diy-bounces at dropmix.xs4all.nl
[mailto:synth-diy-bounces at dropmix.xs4all.nl]On Behalf Of Tom Wiltshire
Sent: Thursday, December 17, 2009 9:41 AM
To: Justin Owen
Cc: SDIY List
Subject: Re: [sdiy] Coding digital waveforms


Justin,

> At the moment I'm just using a counter to increment through an
> array of values that output to a DAC. It's a fixed frequency at the
> moment - but the plan is to set up a variable to tell it how 'fast'
> to run through the array - or how many of the values to use. It's
> basic and there's loads of room for improvement - but so far it works.
>
> So firstly - considering that my code game is pretty basic - is
> there a better way of handling it than this?

Not really. What you've got is the standard method. You can improve
the frequency resolution and accuracy by adding extra bits to the low
end of the counter. So for example if you have 256 entries in your
waveform table, you use a 16-bit counter, and then only use the top 8
bits as the index into the table. This effectively gives you sub-
sample accuracy. If you do use interpolation, you can use the lower 8-
bits as the interpolation index.

In terms of how much accuracy is required, I used a 24-bit counter
and a 16-bit frequency increment in my own LFO. I've seen other
designs that get away with a 16-bit counter - it depends a bit on the
output sample rate. By the time you're up to 32-bit counters, you've
got incredible frequency resolution, and this is probably far beyond
what you need for an LFO.

> and secondly - to smooth the output (which is obviously 'stepped'
> right now) - should I be looking at some type of 'lag' circuit
> (i.e. the resistor/diode/cap combo) - or something else?

The two options are interpolation on the digital side and filtering
on the analogue side. Or some mixture of both, I guess.

Jerry mentioned execution times and latency, which he's right to
point out. The typical way to alleviate these problems is to work on
the *next* sample, not the current one. If you've got a timer
interrupt or something similar that is setting the output sample
rate, the plan looks like this:

1) Start the interrupt
2) Get the stored sample value from memory (in some variable called
SAMPLE_OUT or whatever).
3) Send it to the DAC
4) Start calculating the next sample
5) Finish calculating the next sample and store it in SAMPLE_OUT.
6) Finish the interrupt

This way, step 4 can vary in length widely and there won't be any
jitter in the sample output, since steps 1,2, & 3 will always take
the same amount of time.

HTH,
Tom
_______________________________________________
Synth-diy mailing list
Synth-diy at dropmix.xs4all.nl
http://dropmix.xs4all.nl/mailman/listinfo/synth-diy




More information about the Synth-diy mailing list