This is a way to play audio on a speaker connected to the PWM pin as a DAC.

I used audio recorded at 62.5 kHz with 8-bit unsigned integer samples. The sampling rate was chosen to match the frequency at which the PWM is operated. If you are working on GNU/Linux, arecord is a useful application to record audio at arbitrary sampling rates.

You can record 120 seconds of audio using 8-bit unsigned int sampling at 62.5 kHz, using the following command:

arecord -d 120 -r 62500 -f U8 output.wav

I used python's inbuilt wave and serial modules to read the samples from the file and send them to arduino.

On arduino runs a program which reads a sample from UART at the beginning of every PWM cycle, which sets the duty cycle.

Since the PWM frequency is 62.5 kHz, it will be filtered by our ears, and we will hear only the audio.


audio.c


  1. include <avr/io.h>
  2. include <util/delay.h>
  3. include <avr/interrupt.h>

int main() {

	DDRD = 0xff;
	TCCR0A = (1<<COM0B1) | (1<<WGM01) | (1<<WGM00);
	TIMSK0 |=(1<<TOIE0);
	TCCR0B = (1<<CS00);
	OCR0B = 200;
	TCNT0 = 0;
	sei();
	UCSR0B = (1<<RXEN0) | (1<<TXEN0);
	UBRR0H = 0; //set baud rate of 1000000
	UBRR0L = 0;		
	UCSR0C = (0<<UMSEL00) | (1<<UPM01) | (1<<UCSZ01) | (1<<UCSZ00); // 8,1,E

	for(;;)
	{	
	}		

}

ISR(TIMER0_OVF_vect) {

	OCR0B = UDR0;

}


audio.py


import wave,serial,time
s=serial.Serial('/dev/ttyACM0',1000000)
f=wave.open('test.wav','r')
x=f.readframes(f.getnframes())
s.write(x)

Share