Digital Audio Sinewave Generator, a project draft

Go To Last Post
58 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
is this a test "box" that only do this, or is it a part of a product that in "test mode" can make the tones ?

In my actual application, it is a part of a product. It has to produce, if not halted, a continuous bit stream that generates a sinewave signal at a certain frequency (actually, in the audio spectrum). For the time being, there are 100 frequencies only (using 50 tables).

sparrow2 wrote:
how fast does it need to be able to change between different freq. ?

In my application, the frequency index (from 0 to 99) is sent via TWI. So when the bit stream is interrupted by TWI (as a slave) and TWDR is read (the frequency index), the starting address of the requested table and its length are read, in turn, from the general index table before re-entering the SPI loop.

Manually, 7 pins could specify the frequency index. When the state of a pin (or more) is changed, the SPI loop stops and the new frequency index could be read from the state of 7 pins.

sparrow2 wrote:
I have not seen your code but I expect that you make a delta modulator at max spi 4MHz or ?

Yes, the table data are based on Delta Modulation. I chose the SPI Prescaler of fosc/4. So the frequency of the SPI clock is 2MHz.

sparrow2 wrote:
Do you place the tables in flash or do you have a formula that can build the table(s), so it's placed in RAM ?

I wished there is a formula; this would have saved a lot of work. So the tables are placed in flash.

sparrow2 wrote:
Do you do this in C or ASM ?  

I write always my code in assembly. So I am not sure if, by using a C compiler, the exact timing could be achieved.

Brian Fairchild wrote:
If you read the stuff I mentioned about Don Lancaster you'll get a bit of the background.

By the way, since the time of ZX Spectrum microcomputer, I was familiar with delta modulation for saving/playing speech signals (300 Hz up to 3.3 KHz) digitally. One of the project, as a hobby, was scrambling the voice (on phone) by reversing the bits every 100ms (if I remember well). But, by using the ICs that I was able to get at that time, its board had to be rather too big (not practical).

Now, the existing SPI protocol has a surprise to those who will try to use its output (MOSI) as if it were the output of a delta modulator. The surprise is that MOSI pin has a break/dead time (at a constant level) between every two consecutive transmissions. This timing is emulated on LTspice (#38) and could be seen if SPI_bit_stream.asc is simulated and the PLS1 or PLS2 is plotted and magnified.

sparrow2 wrote:
but for me do we have 100% of CPU time for this, or less (same for flash and RAM). In this case I don't care about the filter (for now), what I want to know if I(OP) can do whatever as long it's a 8MHz mega8 or only have 50% or something like that.

To me in the least, I needed a reliable simple low-cost generator to produce audio sinewave signals with practical amplitudes (say around 300 mV if buffered).

There is another ATmega8 to play the role of ‘brain’ :)

sparrow2 wrote:
Is this for a sweep or one tone at the time or 2 tones for a modem  or ? 

For the time being, only one sinewave at a time is of interest to me. But the code can let it be for a sweep.

On the other hand, I believe that this technique could be applied to generate any periodic signal (below 100 KHz) in case it is not available already by one or more ready-made generators.

==============

By the way, the existing SPI protocol doesn’t have a free running mode (to eliminate the dead time after every byte transfer).

But this could be achieved by just adding a flag in SPSR and an 8-bit buffer register for SPDR in master mode (in this mode, MISO, SCK and SS could be used as I/O pins). So after transmitting the 8 bits of SPDR, the contents of its buffer will be loaded into it and the transmission goes on without interruption. It is up to the programmer to place, or not, new data in the SPDR buffer register before the end of the present transfer.

 

Edited:

But this could be achieved, by an MCU manufacturer, by just adding...

Last Edited: Thu. Mar 26, 2020 - 10:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I ask because if you can make a R2R DAC and a DDS I would expect it to be better (there is one DDS here somewhere called Jespers DDS) that do that.

The tone is made in main, and is changed in a ISR, that make noise when freq are changed but that don't seems to matter in your case.

His code make an update every 9 clk (but with same quality can be done in 8 clk ) . so an update rate of 1MHz or 50 points for a 20 KHz sine wave. 

 

This is an output bit rate of 8 megabit compared to your 2. (I know it's not 4 times better but I would into it)

 

Since you don't need same resolution it can be done down to 6 clk. so 4/3 MHz update.

 

For the SPI way, a easy way would be to look at each byte as a value between 0 and 8 and (or perhaps 2 bytes 0 to 16), and than make a DDS around that.

But first point I would make sure that there is no space between bytes.

 

  

    

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, sparrow2, for your interesting hints. I will revise Jespers DDS carefully to find out if it is better in term of simplicity and cost in my case (covering from 20 Hz to 20 KHz).

By the way, I usually try avoiding R2R DAC because the best tolerance of the available resistors here is 5% (if genuine); not suitable for producing many sets having similar low THDs. But this may not be a problem when the actual crisis will be over and I can produce my boards in China again.

 

Last Edited: Thu. Mar 26, 2020 - 01:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you make the R2R out of 24 resistors from the same batch, the unbalance is very small.

 

 

add:

here is a link to Jespers code:

 

https://www.avrfreaks.net/commen...

 

here is the "real" DDS part:

 

; main loop
;
;	r28,r29,r30 is the phase accumulator
;  	r24,r25,r26 is the adder value determining frequency
;
; 	add value to accumulator
;	load byte from current table in ROM
;	output byte to port
;	repeat 
;
LOOP1:
		add		r28,r24			; 1
		adc		r29,r25			; 1
		adc		r30,r26			; 1
		lpm						; 3
		out		PORTB,r0		; 1
		rjmp	LOOP1			; 2 => 9 cycles

 And comments :

move table to RAM save one clk.

and because rjmp is two clk's one clk can be saved by having the code two times, just make sure there is the same time between the two out instructions.

so in your case 7 clk with a good resolution.

And from the numbers you have given you should be able to go down to 16 bit fraction, so that would be 6 clk. 

 

Last Edited: Thu. Mar 26, 2020 - 05:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I noticed now your add: , thank you.

 

By the way, I drew a schematic on LTspice to emulate DDS with 8-bit ladder. So now I can see the effects on the output THD when using real resistances having a certain tolerance for the R2R ladder. And it helps me adjust its output (as AC and DC) because I have to use, as a buffer, a low-cost opamp, as LM324/LM358, which is not rail-to-rail.

 

About R2R, I added a function which could be activated at boot to compensate, when necessary and to some degree, its non-linearity. This is done by using ADC to adjust the 256 entries of the ideal sine table. The new table is saved on the MCU EEPROM.

 

I guess the SPI technique is good only if applied by an MCU manufacturer as an added function (after giving it another name, I guess) since it uses just one pin. In this case, before enabling this function, the programmer needs just to set the first address (an internal memory space) and the data length that generates the required signal. The MCU will be free as before while it acts as a signal generator (though for relatively low frequencies). But perhaps, this was done already in a certain MCU family.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

KerimF wrote:

I guess the SPI technique is good only if applied by an MCU manufacturer as an added function (after giving it another name, I guess) since it uses just one pin. In this case, before enabling this function, the programmer needs just to set the first address (an internal memory space) and the data length that generates the required signal. The MCU will be free as before while it acts as a signal generator (though for relatively low frequencies). But perhaps, this was done already in a certain MCU family.

 

DMA controller?

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

re: gaps in the SPI output stream

 

Many years ago I needed to generate video on an AVR. And I needed real full CCIR spec compliant video. I also couldn't accept the gaps in the output that using SPI would cause.

 

So I used this technique...

 

OUT VideoPort, R1
LSR R1
NOP
NOP
OUT VideoPort, R1
LSR R1
NOP
NOP
...

 

...which gives a bit stream on Videoport bit 0 at Fcpu/4. Obviously this ties up a complete port, you just uses bit 0 as your output.

 

The 'clever' bit was to then put useful code in place of the NOPs and tracking flags across the video opcodes. IIRC BLD and BST came in handy there. By unrolling the loop for the length of the active part of a video line I was able to keep something like 60% of the CPU cycles available for other work.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

Pages