• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

wav to pwm


Well-Known Member
Thread starter #1
I have found the tone function for arduino which is able to produce tones like this:

for (int ctr = 0; ctr < 20000; ctr++)
int word = recording11[ctr] ;
tone(8, word, 100);
where 8 is the pin, word is the frequency, and 100 is the duration length (which is override when calling next tone loop), the speaker is running off HDW pwm, and matches frequency, since i stop hearing it at about 17khz

I have also successfully decoded a uploaded a wav file on arduino, with the lowest possible settings, so bitrate of 8k, mono, 8bit data

but the data that is encoded in 8-bit is made for a DAC, which i dont have,

..... so is there a way i can convert ADC data to PWM? or plan B without extra circuitry?

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
If you output an audio signal on PWM ( an yes its very possible ) Then the signal will need filtering and finally a small amp so you can hear it..

The "WAV" file is raw... So just take each byte and load it into the pwm... You WILL need to set the PWM frequency to the sampled WAV file.. so if it was sampled at 19khz then set the PWM to the same..


Well-Known Member
Thread starter #4
thanks guys, but few problems seem to have arisen:

TCCR0B = TCCR0B & 0b11111000 | 0x01; // <------ compiler shows error, says there is semicolon required at the binary value,,, but seems to compile , so maybe we dont need to worry, plus my delay is timed out by ear with original track and even though only 5 or 6 seconds long in total offset is only 1second, so close enough that i should be able to make out words
TCCR0B = TCCR0B & 0b11111000;// | 0x01; // <----- even if i do this


but also I should have mentioned mega2560, it seems analog write is not an option for me, but thanks for pointer as i read a bit about it but didnt realize it was for pwm pins,
maybe a capacitor for filter(?), amp not required, since its very tiny speaker, and seems to resonate better at 700hz, as it gets loud enough to bother me enough to unplug, although i think about it maybe i pulled a speaker out of junk box that has no chance:

My BIGGER problem now is that just for test i decided to output word values to serial port:
Serial.println((String)ctr + " " + word + "\r\n");
but it seems there are alot of false values coming out , such as a series of:
10941 44
10942 44
10943 44
10944 44
10945 44
10946 44
10947 44
10948 44
10949 44


6466 0
6467 0
6468 2
6469 0
6470 0
6471 2
6472 2
6473 0
6474 0
6475 2

but nothing like that in the recording1.H ....?

Also it is to my understanding that wav value is instantaneous , while pwm is over time.,, ie

a 60hz square wave would look like this:
in PWM : 60
in ADC: 0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,


Last edited:

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
You build the filter to suit the wave If the PWM is around 22kHz a low pass filter with a 10k resister decoupled with a 10nf cap to ground will retrieve the audio... You will need to amplify to hear it though..


Well-Known Member
Thread starter #7
ya, sorry , i know you mentioned that, but i only half believed it!, could you post link for a suitable amp?


Well-Known Member
Thread starter #9
OK! i think i am getting smoother, rounder waves now but only on the +ve slope, when the slope goes negative i see a fast and sharp dip,, as with what discharging capacitors do .. but now how can i smooth that part off?

also i cannot get the sound file to play through yet .... not even close to coherent yet!>? ... wav file data is in analog form right??
Last edited:
I think you may need to oversample the output to the PWM, running it at eg. 4 or 8 times (or more) the audio sample rate, so the filtering can take out the PWM carrier frequency without filtering all the higher frequencies from the wanted audio.

Either feed the same audio value that many time or interpolate somewhat between samples at each transition, taking the average of the last output value and present sample value.

It's a very different output from a PWM than from a DAC and it needs a lot! more filtering.
OK, it sounds like a data format problem.

eg. If it's signed data in a twos-complement sample format, just copying that to a normal DAC will keep switching between extreme limits as 0 and -1 are 0000 and ffff (at 16 bit); the low level signal range drives the DAC to its extreme limits.

Invert the high bit of the value, if that's the case. That's in effect adding half the total range and making the zero point half scale on the DAC.
eg. 0000 > 8000 and FFFF > 7FFF so no extreme stepping.

Or it may be a mismatch in data size, so you are not outputting a coherent single waveform?
What bit size are the samples and DAC? 8, 12, 16 etc.

Also, you mention a .WAV file earlier on - how are you extracting the raw audio data from that? There is a lot of other junk at the start of such a file.

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
When you set up your PWM it will most probably be 19khz and 8 bit..

You have to wait for the PWM timer refresh ( On the pic we use timer 2... So TMR2IF )
Then put the raw data in the pwm (CCPR1L ) !! You need the lower two bits as well..

Every time TMR2 spills refresh with the next data ... I used a 10k / 0.1uf filter..
The first amp I used was a simple push pull using NPN and PNP into a 8 ohm, but it was rubbish.. So I used an LM386

If you need a tad of help... Looky here... This guy used to post on the forum.. Gone now ( I think he had a spat with Nigel )
http://www.moty22.co.uk/sd.php.. Ardunio version aswell..


Well-Known Member
Thread starter #14
on a bit of a different note today I am attempting pwm on a pic 18f1230 .. there are dedicated pwm pins on port B 0 & 1 & 4 & 5
but all the examples for pwm are for ccp and timer interrupts .... is there example code for the pwm0 pin?


Well-Known Member
Thread starter #16
just general pwm for LED, rgb if you have! ... im using TIMER0 interrupt for now.

back to the music thing.... i have made some hardware adjustments... i have feed the output to my mic jack in my pc and running my samples under a spectrum .... I see now the difference between a square wave and a clean sine wave... which making has been my new obsession.. my dac is spi ... any chance in code for a sine/sawtooth generator? ... broad range if possible?

as for the other hump ... i think we are right about the zero point .. also my dac is 12bit .. but still working on that

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
If you use hardware PWM you do not get to choose timer0.. Its either 2, 4, or 6 I believe..

If you use tables to output to a DAC via SPI... If you run it at over 1 Mhz ( I have run close to 16Mhz ) you could get a really good wave output at 44Khz.... This is at 8 bit.... You could get 16bit with a little overhead.... But running an interrupt to output a constant wave form requires little room for manoeuvre within the ISR... Me Nigel and Eric were pushing SPI to the entire limits to get a TFT to run smoothly!!


Well-Known Member
Thread starter #19
if im not mistaking the datasheet there are 6pwm's but only have 3 clocks to run them... either way i couldnt get even one working but it would be better than using the timer

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Pick one.... Using the pic18f1230 PWM

On this chip they have just renamed and shifted operation to support BLDC motors and deadtime..

There are 3 PWM modules but there are 3 extra complemenary outputs.. PWM1 is the one to use for a "free running pwm" to get sound

PWMCON0 = 0x22; sets the PWM to the mode you need PWM will be on RB1 and the inverse will be on RB0 ( just use RB1 )
PTER = 1; and PTDIR = 0; Is needed to be set PWM going.

The PTPER needs to be set to 19khz so I need your OSC frequency.. The Duty cycle is the key.. ie if you run it at 10Mhz then PTPER = 0x3F; for 8 bit resolution... If you want 12 bit resolution you'll need to use the PLL and crank the frequency up..

The Duty cycle ( music data ) is placed every time PTMR is overrun ( flag is set ).. PDC0... Most registers have a High and a Low so two writes may be needed..

PDC1 is for PWM 3 and PDC2 is for PWM 5. The Time base seems to be a constant all three modules have a different duty cycle but the base and period is the same... This chip was designed for motor control..

Latest threads

EE World Online Articles