Real Time Audio Processing

The built in A/D is 10 bits.
Making a home built 16 bit D/A using two ladders is an illusion and put on the web by people who frankly don’t know what they are doing and don’t know how to test it correctly. The accuracy of the resistor ratios needed is just not attainable from fixed resistors.

How can a timer function create better audio?
Pleas tell us what you actually want to do.

You can synthesize upto 16 bit accuracy from 2 8-bit PWM signals and two accurate resistors in the ratio 1:256,
which hasn't been mentioned on this thread yet.

MarkT:
You can synthesize upto 16 bit accuracy from 2 8-bit PWM signals and two accurate resistors in the ratio 1:256,
which hasn't been mentioned on this thread yet.

Would it be enough for the PWM signals to have the same frequency and phase offset? Edge-aligned or phase-correct PWM?
Or should both signals be LPF'ed first, and then combined?

I think it's probably easier to just use Timer1 for 16-bit PWM.

However, a 16-bit DAC isn't of much use if your ADC is only 10 bits or even 8 bits at higher speeds, but I don't think OP realizes this ...

But you can also combine two 5 bit PWMs to get 10 bit, and 5 bit PWM can run a lot faster for easier
low-pass filtering on the output.

MarkT:
But you can also combine two 5 bit PWMs to get 10 bit, and 5 bit PWM can run a lot faster for easier
low-pass filtering on the output.

True, I didn't think about that!

PieterP:
Would it be enough for the PWM signals to have the same frequency and phase offset? Edge-aligned or phase-correct PWM?

You should always use phase-correct PWM for audio, it has a lot less harmonic distortion.
The frequency and phase relationship is irrelevant, as the duty cycle carries the signal, but you'd
need to make sure the frequency difference didn't fall in the audio band and alias all over it - theres
no reason to do anything but use the same frequency

Or should both signals be LPF'ed first, and then combined?

Why would that make any difference? They are both linear operations. Save components and use one filter.

[ PWM and distortion: PWM Distortion Analysis | Open Music Labs ]

PieterP:
I think it's probably easier to just use Timer1 for 16-bit PWM.

Easier said than done.

At a given oscillator speed, you trade off resolution for frequency (at a power of 2).
Furthermore, timer1 makes use of all its 16 bits only in normal or CTC mode (for timed interrupts only). In PWM mode, from 8 up to 10 bits are used, being that last one the maximum possible resolution for hardware-generated PWM (at least for AVRs though).

And it makes sense, if an MCU that runs at 16 MHz could produce 16-bit PWM signals, their maximum frequency would be 16M / 65536 = 244.14 Hz. Well... even worse than timer1 and 2 at their default settings.
Faster but "cheap" alternatives (such as the "Blue Pill") aren't that much better either; somewhere close to 80 MHz would yield around 1 KHz.

To get a (single) 16-bit PWM signal that would actually produce decent-quality audio, the system would have to run at 5-6.5 GHz (good luck finding a PC CPU that fast but without overclocking).

As you can see, hi-res hi-rate PWM DACs are practically impossible, unless you combine two low-res outputs (which is the only feasible way to achieve high-quality audio merely by PWM). Resistor-ladder DACs don't have this problem since their trade-offs work differently (resolution for simplicity/cheapness, the frequency is up to how often the system is willing to toggle its digital outputs).

Lucario448:
As you can see, hi-res hi-rate PWM DACs are practically impossible.

But possible, which is what multibit sigma-delta DACs do. Its all in the noise shaping. Take
raw 5 bit PWM say, at about 1MHz, throw in multiple-order noise shaping can get you to 20 or more
bits of precision at lower audio frequencies. Think of it as an advanced version of dithering/averaging.
The quantization noise is pushed up in frequency where it can easily be filtered out. Its a trade off
of clock speed for precision. 32MHz clocked PWM generates 20kHz of clean bandwidth. The picture
in the attic is all the noise above 20kHz.

Thank you once again with all the information. I had a quick question, so the code i written in the page 1

void setup() {
  //
  cli();
 
  //
  TCCR2A = 0x00;
  TCCR2B = 0x00;
  TCNT2 = 0x00;
  OCR2A = 249;
  TCCR2A |= (1 << WGM21);
  TCCR2B |= (1 << CS21);
  TIMSK2 |= (1 << OCIE2A);
 
  //
  sei();

}

ISR(TIMER2_COMPA_vect) {
  //
  analogWrite(10, map(analogRead(0), 0, 1023, 0, 255);
}

void loop() {
 
}

-This code allowed fairly some music to play, unfortunately applying that now, we do not get the same result. Im a mic amplifier which thus goes to A0 an a 8 bit R2R resistor ladder. Reading some forums i see that the same voltage from the same audrino sometimes causes problems could that be the case. I tried giving the mic a separate voltage source and the ground connected to the Dac of the audrino. May someone know what the problem may be

Reading some forums i see that the same voltage from the same audrino sometimes causes problems could that be the case.

That is very vague. Can you post a link to those forum threads you talk of.

Unfortunately, I dont remember exactly. I apologize. Also because I am trying to finish in about 2 days with some listenable audio that can you can hear from a 8 bit R2R ladder. Is there a way tall know of?

This code allowed fairly some music to play, unfortunately applying that now, we do not get the same result.

Are you saying that this code used to work and now it does not?

If so then your circuit is not what it was. It has changed or you have loose intermittent connections.

I have one more question. So how could i increase the sampling rate to 8Hz and send the data to the R2R Dac -- the code below.

I know that atmeag328 rums at 16MHZ so if we use a prescaler of 128 it would equal to 125KHZ and it takes 13 cycles therefore 125/13 = 9615 Hz. With nyquist theorem that would be about half the quality i could reproduce.

How can i change my code to get 8KHZ sampling rate and as well as sending that data to the R2R Dac. I believe i can do PORTD = ADCH;

However, there are a few details. I will want to left justify the ADC read value, and I will to use only the high byte.
Then i will want to connect the R-2R ladder to PORTD in the right order. The most significant bit will be output on pin PD7 and the least bit will be on PD0.

I need help with Setting the sample rate and the other configuration details needed for this task. Thank you Again for all the help

void setup() {
  //
  cli();
 
  //
  TCCR2A = 0x00;
  TCCR2B = 0x00;
  TCNT2 = 0x00;
  OCR2A = 249;
  TCCR2A |= (1 << WGM21);
  TCCR2B |= (1 << CS21);
  TIMSK2 |= (1 << OCIE2A);
 
  //
  sei();

}

ISR(TIMER2_COMPA_vect) {
  //
  analogWrite(10, map(analogRead(0), 0, 1023, 0, 255);
}

void loop() {
 
}

I will want to left justify the ADC read value, and I will to use only the high byte.

Shift to the right by two places.

aIn = analogueRead(pin);
justified = aIn >> 2;

I need help with Setting the sample rate

From the looks of that code you do not have a framework that anybody can help you with yet, unless help means doing it for you.

This code allowed fairly some music to play

No it didn’t.

The prescaler defaults to 128 so the sample rate is already at about 10K.

Hang an ISR off the ADC converter compleate interrupt. Have it read the ADC results registers and do the shift then output to port D.
See Arduino Reference - Arduino Reference for examples of how to write to ports.
Why does it have to be exactly 8KHz?

Like this ? Thank you

void setup()
{
  Serial.begin(115200);
  
  DDRD = 0xFF;
  ADCSRA = 0;             // clear ADCSRA register
  ADCSRB = 0;             // clear ADCSRB register
  ADMUX |= (0 & 0x07);    // set A0 analog input pin
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX |= (1 << ADLAR);  // left align ADC value to 8 bits from ADCH register
  
  ADCSRA |= (1 << ADPS2); // 16 prescaler for 76.9 KHz
  ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect)
{
  PORTD = ADCH; // output ot Port D
}

void loop(){
  
}
ISR(ADC_vect)
{
  PORTD = ADCH; // output ot Port D
}

You'll barely hear anything like this; only the two most significant bits are retrieved. The right way to narrow down ADC readings is this:

ISR(ADC_vect)
{
  PORTD = (ADCL >> 2) | (ADCH << 6);
}

Also, don't worry about bit order; the MSB of the register is indeed wired to PD7 (pin 7); as well as the LSB to PD0 (pin 0 / hardware USART RX).

PD: by the way, if you started with the idea of a R-2R DAC, then why you showed us an example of PWM DAC at some point?

I've forgot to point out another mistake.

If you call Serial.begin(), you set up the USART port; and if you set up the USART port, it will override PD0 and PD1. This will make those pins unresponsive to any write attempt to PORTD and DDRD.

Thank you so much. However the quality is still pretty tough.any suggestions in increasing quality. Can I do a 5 bit dac two of them to get a 10 bit dac as previously stated in this forum? Or what other methods can I do to improve the quality? I know it's a bit which can only get good sound quality but still wanted to know. Thank you for helping.

However the quality is still pretty tough.any suggestions in increasing quality.

Make sure that the audio input is a 5V peak to peak signal, this makes the most of every bit you have.

This is the sort of quality you can expect from 8 bits using a PWM modulated output.
https://youtu.be/WShVFcrFpwU and the full range of the 8 bit D/A it produces.

Make sure that the audio input is a 5V peak to peak signal, this makes the most of every bit you have.

How can I make sure? Thank you again