LEDs won't turn off when using PWM

I’m new to AVR’s and messing with them is quite fun!

right now I’m doing a fade in fade out RGB LED thing as an excersize in learning AVRs and learning about PWM

I’m using a atmega168 and playing with 8bit timer 0 using both channel A and B

currently I’m having a little issue getting the LEDs to turn off completely when I set OCR0A to 0 they’re dim but not off

here’s my code:

//shorthand type def
typedef unsigned char u8;

#include <avr/io.h>
#include <avr/interrupt.h>

int main(){
	
	u8 direction_R 	= 1;	//set fade direction 0=bottom_peak_hold, 1=fadein, 2=top_peak_hold, 3=fadeout
	u8 direction_G 	= 3;
	u8 hold_length 	= 50;	//hold length
	u8 hold_R 		= 0; 
	u8 hold_G 		= 0;
	
	//OCR0A = 255;		//set initial width 0=off 255=on
	//OCR0B = 0;
	
	TCCR0B	|= (1 << CS01) | (1 << CS00);	//use internal clock with prescaler of 64
	
	DDRD	|= (1 << DDD6) | (1 << DDD5);	//set PORTD pin 6 and 5 or OC0A and OC0B for output
	
	TCCR0A	|= (1 << COM0A1) | (1 << COM0B1);	//set TCCR0A pin for non-inverted PWM clear on compare match, on at BOTTOM
	
	TCCR0A	|= (1 << WGM00) | (1 << WGM01);	//set waveform generator for fast PWM with TOP = 0xFF
	
	while(1){
		if(TIFR0 & (1 << TOV0)){
			
			if(direction_R == 0 && hold_R > 0){
				hold_R--;									//hold
			}else if(direction_R == 0 && hold_R == 0){
				direction_R++;								//start fadein
			}else if(direction_R == 1 && OCR0A < 255){
				OCR0A++;									//fadein
			}else if(direction_R == 1 && OCR0A == 255){
				direction_R++;								//start top peak hold
				hold_R = hold_length;
			}else if(direction_R == 2 && hold_R > 0){
				hold_R--;									//hold
			}else if(direction_R == 2 && hold_R == 0){
				direction_R++;								//start fadeout
			}else if(direction_R == 3 && OCR0A > 0){
				OCR0A--;									//fadeout
			}else if(direction_R == 3 && OCR0A == 0){
				direction_R = 0;							//start bottom peak hold
				hold_R = hold_length;
			}
			
			if(direction_G == 0 && hold_G > 0){
				hold_G--;									//hold
			}else if(direction_G == 0 && hold_G == 0){
				direction_G++;								//start fadein
			}else if(direction_G == 1 && OCR0B < 255){
				OCR0B++;									//fadein
			}else if(direction_G == 1 && OCR0B == 255){
				direction_G++;								//start top peak hold
				hold_G = hold_length;
			}else if(direction_G == 2 && hold_G > 0){
				hold_G--;									//hold
			}else if(direction_G == 2 && hold_G == 0){
				direction_G++;								//start fadeout
			}else if(direction_G == 3 && OCR0B > 0){
				OCR0B--;									//fadeout
			}else if(direction_G == 3 && OCR0B == 0){
				direction_G = 0;							//start bottom peak hold
				hold_G = hold_length;
			}
			
			TIFR0 = (1 << TOV0);	//reset TOV0
		}
	}
	
	return 0;
}

Messy and redundant, I know how to program properly in C++, but for some reason when I created other functions they never worked properly… was like execution skipped over them completely… (in the AVR studio simulation they did get skipped completely during execution…) however, that’s another issue for another day.

Even if I comment out my fading code block and just set OCR0A & OCR0B to 0 you can see really well that the LEDs are still being turned on dimly.

I’m guessing because when the timer resets it automatically turns on the pin for a tick before it’s turned off by the OCR0A / B compare

note that I’m probably going to add a blue and maybe a couple others to this using the other available timers so I need to keep them all synced. I’m thinking I’ll have to create a for loop and work with arrays for each of the colors so I can fade from red to orange to yellow to green to etc… and back to red.

Am I going about this the wrong way?

Thanks!

just thought I’d answer my own question for anyone who finds this.

Since PWM mode requires that the appropriate pin’s data direction register bit be set to 1 for output you simply set it to 0 to turn the LED off completely.

The reason being that while the timer’s output compare register may be set to 0, the LED will still flicker on for a brief instant after the timer counter overflows but before PWM catches that the timer is equal to the compare register and turns the LED off.

To fix this simply check to see if the timer’s output compare register is at 0 and if it is turn off pin output

//example
if(OCR0A == 0){ 
   DDRB &= ~(1 << DDB1); 
}else{
   DDRB |= (1 << DDB1);
}