The assembly code given here was written to see what it would take to make an AT90S1200 generate 8 channels of proper PWM. In this case, by proper, I mean with the maximum high frequency content consistent with the needed duty cycle and give clock. Take a look at the scope shots below and notice that when the data value is =$02, there pulse frequency is twice that which occurs when the data value is =$01. The significance of this is that the percent of ripple voltage out of the low pass filter stays much more constant as the data values change than they would with a conventional PWM that merely varies the width of a single pulse (see the auto zero code for the RF Field Strength Probe for an example of code that does this). Take a look at the pictures below to see the effect.
When running with a 4 MHz clock, this code provides 8 channels of 8 bit resolution with a 60 Hz minimum frequency (which occur at data values of $01 and $FF. By adjusting the interrupt timer reload value, the minimum frequency can be taken to 100 Hz, but at the cost of time available for other tasks. Of course, changing the clock oscillator frequency is another way to increase the minimum frequency.
The code was originally written for and tested on an AT90S1200A, I also merged it with a monitor program and tested it on an AT90S2313. Thus, it can be adapted to a variety of AVR chips, including those with really limited resources such as the ATTiny12 easily.
The code
Here is theĀ assembly codeĀ for the PWM routine. This code is an example program with the routines necessary to make the PWM machine work, but it only drives values that are preprogrammed in as constants at assembly time. Adding an interface so the PWM values can be adjusted in real time is left as an exercize for the student.
Read more: 8 Channel PWM using AVR microcontroller