The key question here is how fast and how many steps should be the PWM.
All depends in how much processing time you need for other tasks, and how many PWMs to run.
A good aproach that works for me is doing a 64 steps, 200 uS per step PWM for around 50 PWM channels.
This give us a total time of 50*200=12800 uS = 12.8 mS => 78.125 Hz.
Getting less than 10% of processing time.
I ussually do it with Timer0, this creates a 200 uS Timer0 CompA Interrupt.
I think it works for most AVR, but you can choose the part you need depending on wich registers your mcu uses:
```c // For 16 MHz clock #define T0Top_Avr 50 #define T0PresAvr 3 #if defined( OCR0 ) OCR0 = T0TOP_Avr; TCCR0 = 64 + TMR0PresAvr; // CTC mode: TOP = OCR0 #elif defined( OCR0A ) OCR0A = T0TOP_Avr; TCCR0A = 2; // CTC mode: TOP = OCR0A TCCR0B = TMR0PresAvr; #endif // enable Timer 0 compare_A interrupt #if defined( TIMSK0 ) TIMSK0 = 0; TIMSK0 |= (1 << OCIE0A); #elif defined( TIMSK ) TIMSK = 0; TIMSK |= (1 << OCIE0A); #endif sei(); // Enable interrupts // Now in the interrupt routine: #define numPWM 32 // Number of PWM Channels uint8_t pwmChannel[ numPWM ]; // Array containing pwm values uint8_t pwmCounter=0; ISR(TIMER0_COMPA_vect) // Timer 0 compare_A interrupt { for( uint8_t i=0; ipwmCounter ) { // Set the output line "i" HIGH // This depends on the hardware you are using } else { // Set the output line "i" LOW } } pwmCounter++; if( pwmCounter > 63 ) pwmCounter = 0; { ```