Reply by Paul E. Bennett●January 17, 20042004-01-17
In article <4006935e$1@news.nb.nu>
mhsprang@NOcustomSPAMware.nl "Meindert Sprang" writes:
> "CAFxX" <cafxx@n-side.it> wrote in message
> news:bu634c$7g9$1@lacerta.tiscalinet.it...
> > what i need to do is to generate a custom-frequency sine wave to be
> > outputted at CD-quality frequency (44100 samples/second) to a DAC.
>
> If that is all you have to do, take a look at Analog Device's DDS chips.
He could also do a search on DDA routines. These are simple add and
shift routines that can often be done in a few machine cycles. John
Matthews book has an example in for this (Engineering Applications
in Forth).
--
********************************************************************
Paul E. Bennett ....................<email://peb@amleth.demon.co.uk>
Forth based HIDECS Consultancy .....<http://www.amleth.demon.co.uk/>
Mob: +44 (0)7811-639972 .........NOW AVAILABLE:- HIDECS COURSE......
Tel: +44 (0)1235-811095 .... see http://www.feabhas.com for details.
Going Forth Safely ..... EBA. www.electric-boat-association.org.uk..
********************************************************************
Reply by David F. Cox●January 17, 20042004-01-17
"CBarn24050" <cbarn24050@aol.com> wrote in message
news:20040117055417.12966.00000182@mb-m02.aol.com...
> hi, this is the simplification of the compound angle formulas, it works
very
> well and can be quite quick but not as fast as a lookup table.
in context: I had to drive a stepper motor around 1 metre diameter circles
with an accuracy of 0.1 mm using a 2K EPROM
========
original post:
I am sorry, terribly busy, but you can get there from here (I had to)
circles ( and sines, fit for your purpose) using only add and subtract
X = 100: y = 0
FOR i = 1 TO 1000
PRINT X, y
X = X - y / 256
y = y + X / 256
NEXT
If you cannot do it I will dig out the Scamp (INS8060) code, eventually.
David F. Cox
======
Reply by CBarn24050●January 17, 20042004-01-17
hi, this is the simplification of the compound angle formulas, it works very
well and can be quite quick but not as fast as a lookup table.
Reply by David F. Cox●January 16, 20042004-01-16
"CAFxX" <cafxx@n-side.it> wrote in message
news:bu49k1$125$1@lacerta.tiscalinet.it...
> does anybody know where to find some FAST sine routines to be run on an
> 8052? sdcc's math.h is just an empty file... just an #error directive!
thank
> you in advance.
I am sorry, terribly busy, but you can get there from here (I had to)
circles ( and sines, fit for your purpose) using only add and subtract
X = 100: y = 0
FOR i = 1 TO 1000
PRINT X, y
X = X - y / 256
y = y + X / 256
NEXT
If you cannot do it I will dig out the Scamp (INS8060) code, eventually.
David F. Cox
Reply by Ben Bradley●January 16, 20042004-01-16
In comp.arch.embedded, "CAFxX" <cafxx@n-side.it> wrote:
>ok i understood that i have to use a lookup table. before asking some more
>question i just want to explain what i am really trying to do.
>it will simply be a sort of musical keyboard (a synth). it takes the input
>of 24 keys (using 3 of the four raw i/o ports of the 8052) and sends 16 bit
>samples to the dac (even if it accepts only 24 bits samples - i simply leave
>the LS 8 all low).
>what i'm wondering here is how to implement the lookup table (actually the
>problem is that the sine function generate variable frequency sine waves)
This Is Not A Problem.
Use a phase accumulator running at 44.1kHz. Here's some scratch
code:
unsigned_int_24_bits phase; // yes, three bytes for each.
unsigned_int_24_bits frequency;
unsigned_int_24_bits freq_lookup [24] =
{
123445, // (SWAG approximate values)
126999, // These should each be the frequency for
131111, // the corresponding key.
...
};
int sin_lookup [256]; // this table is 256 points along a complete
sine wave of 360 degrees.
phase = 0; // init phase (not even neccesary)
frequency = freq_lookup [note]; // set output frequency based
on note
interrrupt isr_for_44100Hz_interrupt (void);
{
phase += frequency;
output_sample_to_DAC = sin_lookup [phase >> 16];
} // end ISR routine
This routine is just about that simple. When the frequency variable
is half its maximum value, the output will be (if the phase doesn't
start out at zero, but we can ignore that for this calculation) two
points at 22,050Hz. Thus the ratio between Hertz and the number in the
frequency variable (or specifically freq_lookup) is:
22050 / 2^23 = 0.0026285648345947265625
Thus, if you put a 1 in the frequnecy variable, you will get a sine
wave with 0.0026 Hz output. Let's take the reciprocal of that for
easier conversion the other way:
380.435736961451247165532879818594
Let's call it 380.436. To generate an "A" at 440Hz, use the number:
380.436 * 440 = 167391.84 or just round it to 167392.
The next note up is A# at 2^(1/12)*440 or 466.16Hz.
380.436 * 466.16 = 177344.04576 which when rounded becomes 177344.
If you follow the code carefully you may notice that at frequencies
below 44100/256 or 172Hz, some samples will have sine table entries
repeated, and at higher frequencies some entries in the sine table
will be skipped. Again, this is not a problem, unless you're making a
"real" music synthesizer for use by "real" musicians, or you're using
this for a lab instrument that needs a pure-as-possible sine wave at
arbitrary frequencies.
Another neat thing about using a lookup table in this manner is
that you can change the waveshape just by putting it into the lookup
table. Square, triangle and sawtooth immediately come to mind, and
again, skipping or repeating samples at different frequencies isn't a
problem except in truly critical applications.
>i mean:
>
>short sine (unsigned short frequency) {
> return sin[(counter % frequency) / frequency];
>}
>
>(note that long is 4 byte in sdcc) to make sure of having a *decent*
>resolution without using long and float (int and short are the same) values
>in the calculation what can i do?
>i thought of something like
> return sin[((counter % frequency) << 10) / frequency];
>(at least 10) but i think this will mess up everything. or not?
>
>"Hans-Bernhard Broeker" <broeker@physik.rwth-aachen.de> ha scritto nel
>messaggio news:bu65lp$1ls$1@nets3.rz.RWTH-Aachen.DE...
>> CAFxX <cafxx@n-side.it> wrote:
>> > what i need to do is to generate a custom-frequency sine wave to be
>> > outputted at CD-quality frequency (44100 samples/second) to a DAC.
>> > If possible i'd prefer working with 16 bit integers since float needs
>> > cpu-time-expensive libraries.
>>
>> Setting aside the recommendable option of replacing the whole kaboodle
>> you're planning now with a special-purpose chip (a digitally
>> controlled oscillator), there's still no reason to actually evaluate a
>> sine function for this.
>>
>> A table should be perfectly adequate --- subsample it in steps through
>> the table whose size is governed by the quotient of your target
>> frequency and the frequency of the tabulated signal. E.g. if you have
>> a sine table of (effectively) 44100 samples for a 1 Hz wave, a 1 kHz
>> wave would use every 1000th sample from that table, and wrap around at
>> the 45th iteration to 45*1000 - 44100 = 900. You'll want to handle
>> non-integer step sizes, too --- either using fixed-point fractional
>> arithmetic, or by Bresenham's algorithm.
>>
>> The actual table should of course store only one quadrant of the wave
>> (0 .. 90 degrees, typically), to keep it short.
>>
>> --
>> Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
>> Even if all the snow were burnt, ashes would remain.
>
Reply by John R. Strohm●January 16, 20042004-01-16
"Meindert Sprang" <mhsprang@NOcustomSPAMware.nl> wrote in message
news:40079955$1@news.nb.nu...
> "John R. Strohm" <strohm@airmail.net> wrote in message
> news:bu82f6$9mc@library2.airnews.net...
> > "CAFxX" <cafxx@n-side.it> wrote in message
> > news:bu634c$7g9$1@lacerta.tiscalinet.it...
> > > what i need to do is to generate a custom-frequency sine wave to be
> > > outputted at CD-quality frequency (44100 samples/second) to a DAC.
> > > If possible i'd prefer working with 16 bit integers since float needs
> > > cpu-time-expensive libraries.
> > > thanks to all of you for your replies.
> >
> > If your hardware design is not set in stone at this point, add two 27512
> 64Kx8
> > EPROMs, and a handful of glue logic. Feed the address pins with two 8-bit
> > latches that can WRITE from the 8051. Use some glue logic to take a pulse
> from
> > the processor, do a read cycle on the EPROMs, and latch the results into
> two
> > other 8-bit latches that you can READ from the 8051.
> >
> > Now burn the EPROMs with sin(address), and you have a dedicated hardware
> sin(x)
> > lookup table that will be scary fast compared to any algorithm for
> computing
> > sin(x).
>
> Nice idea, but you also need a DA converter.
> Now go take a look at the AD9833: A full DDS capable of outputting DC to
> 12.5MHz in 0.1Hz steps, sine, square and triangle. And if you clock it with
> 'only' 1MHz, you get DC to 500kHz in 0.004Hz resolution.
> And all this in a 10 pin package for a whopping $9.30 at Digikey....
The original poster already has a DAC.
If all you want is sine/square/triangle waves, that chip will do it. If you
want to do more interesting things, it won't.
But I think I'm going to take a longer look at it, for some radio projects I
have in mind.
Reply by Hans-Bernhard Broeker●January 16, 20042004-01-16
CAFxX <cafxx@n-side.it> wrote:
> ok i understood that i have to use a lookup table. before asking some more
> question i just want to explain what i am really trying to do.
> it will simply be a sort of musical keyboard (a synth). it takes the input
> of 24 keys (using 3 of the four raw i/o ports of the 8052) and sends 16 bit
> samples to the dac (even if it accepts only 24 bits samples - i simply leave
> the LS 8 all low).
> what i'm wondering here is how to implement the lookup table (actually the
> problem is that the sine function generate variable frequency sine waves)
> i mean:
> short sine (unsigned short frequency) {
> return sin[(counter % frequency) / frequency];
> }
Careful here, you're getting mixed up with the various frequencies
involved in this. A sampled signal being played back at a different
frequency involves *three* frequencies, or even four, depending on how
flexible you want to be:
*) the stored sample's sampling rate : r_in
*) the playback sampling rate : r_out
*) the frequency you're trying to output: f_out
*) the original frequency of the sampled: f_in
For numeric examples, I'll assume
r_in = r_out = 44100 Hz
f_in = 1 Hz
From these, the computations go as follows:
N := r_in / f_in
gives the length of the sampling table for one complete cycle of the
wave, and thus the table index after which you would wrap around.
dt := 1/r_out
is the time step of the output --- the time between two writes to your
DAC. In this time, you've covered a fraction of
dp := f_out * dt = f_out / r_out
or your output wave. Since we know that one complete cycle of that
wave is one pass through the table, the step size in the table has
to be
di := N * dp
= N * f_out / r_out
= (r_in * f_out) / (r_out * f_in)
Assuming r_in = r_out, this becomes
di = f_out / f_in
The frequency actually output will not be accurate to more than f_in
anyway, so there's no point trying to treat f_out as a fractional
number. Using this, all computations are in integers:
N = r_in / f_in;
sine_table[N] = { filled by precomputation... }
i = 0;
assert(f_out * 2 < r_out); // pay respect to Mr. Myquist...
forever {
to_DAC(sine_table[i]);
i = (i + f_out) % N;
... wait until time 1/r_out has passed ...
}
If you need frequency accuracy better than 1 Hz, you must use a
smaller f_in, but that will obviously make your table larger. If you
try to use non-integer multiples of f_in as f_out, you'll get noisy
output, i.e. more than one harmonic on output.
--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply by Robert Wessel●January 16, 20042004-01-16
"CAFxX" <cafxx@n-side.it> wrote in message news:<bu6k2g$s4s$1@lacerta.tiscalinet.it>...
> ok i understood that i have to use a lookup table. before asking some more
> question i just want to explain what i am really trying to do.
> it will simply be a sort of musical keyboard (a synth). it takes the input
> of 24 keys (using 3 of the four raw i/o ports of the 8052) and sends 16 bit
> samples to the dac (even if it accepts only 24 bits samples - i simply leave
> the LS 8 all low).
> what i'm wondering here is how to implement the lookup table (actually the
> problem is that the sine function generate variable frequency sine waves)
> i mean:
>
> short sine (unsigned short frequency) {
> return sin[(counter % frequency) / frequency];
> }
>
> (note that long is 4 byte in sdcc) to make sure of having a *decent*
> resolution without using long and float (int and short are the same) values
> in the calculation what can i do?
> i thought of something like
> return sin[((counter % frequency) << 10) / frequency];
> (at least 10) but i think this will mess up everything. or not?
Please don't top post.
If I understand you correctly, you just want to generate 1-4 sine
waves, of varying frequencies and amplitudes, then add then together
and send them out your DAC, right?
To generate a continuous sine wave, just ought to be able to use
Bresenham's circle drawing algorithm and output the X (or Y)
coordinate as you pop around the circle you're "drawing." Very fast
and you can do it all with modest resolution integer math. (The
technique is closely related to Bresenham's line drawing algorithm -
just Google for either).
Reply by Meindert Sprang●January 16, 20042004-01-16
"John R. Strohm" <strohm@airmail.net> wrote in message
news:bu82f6$9mc@library2.airnews.net...
> "CAFxX" <cafxx@n-side.it> wrote in message
> news:bu634c$7g9$1@lacerta.tiscalinet.it...
> > what i need to do is to generate a custom-frequency sine wave to be
> > outputted at CD-quality frequency (44100 samples/second) to a DAC.
> > If possible i'd prefer working with 16 bit integers since float needs
> > cpu-time-expensive libraries.
> > thanks to all of you for your replies.
>
> If your hardware design is not set in stone at this point, add two 27512
64Kx8
> EPROMs, and a handful of glue logic. Feed the address pins with two 8-bit
> latches that can WRITE from the 8051. Use some glue logic to take a pulse
from
> the processor, do a read cycle on the EPROMs, and latch the results into
two
> other 8-bit latches that you can READ from the 8051.
>
> Now burn the EPROMs with sin(address), and you have a dedicated hardware
sin(x)
> lookup table that will be scary fast compared to any algorithm for
computing
> sin(x).
Nice idea, but you also need a DA converter.
Now go take a look at the AD9833: A full DDS capable of outputting DC to
12.5MHz in 0.1Hz steps, sine, square and triangle. And if you clock it with
'only' 1MHz, you get DC to 500kHz in 0.004Hz resolution.
And all this in a 10 pin package for a whopping $9.30 at Digikey....
Meindert
Reply by John R. Strohm●January 16, 20042004-01-16
"CAFxX" <cafxx@n-side.it> wrote in message
news:bu634c$7g9$1@lacerta.tiscalinet.it...
> what i need to do is to generate a custom-frequency sine wave to be
> outputted at CD-quality frequency (44100 samples/second) to a DAC.
> If possible i'd prefer working with 16 bit integers since float needs
> cpu-time-expensive libraries.
> thanks to all of you for your replies.
If your hardware design is not set in stone at this point, add two 27512 64Kx8
EPROMs, and a handful of glue logic. Feed the address pins with two 8-bit
latches that can WRITE from the 8051. Use some glue logic to take a pulse from
the processor, do a read cycle on the EPROMs, and latch the results into two
other 8-bit latches that you can READ from the 8051.
Now burn the EPROMs with sin(address), and you have a dedicated hardware sin(x)
lookup table that will be scary fast compared to any algorithm for computing
sin(x).
It works something like this:
poke(msb(x), SIN_TABLE_ADDR_MSB);
poke(lsb(x), SIN_TABLE_ADDR_LSB);
pulse(SIN_TABLE_TRIGGER);
sinx = peek(SIN_TABLE_DATA_MSB) << 8 | peek(SIN_TABLE_DATA_LSB);
This is basically how the Yamaha DX7 synthesizer generated frequency-modulated
audio sinewaves.
The trick is realizing that you can hook EPROM (and RAM, for that matter)
address pins to other things besides microprocessor address pins.