Attiny10 PWM for LED fade in

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I have the following code for LED fade in with PWM. Something is not working fine and it's making me crazy. I've been debugging the code with atmelstudio 7, putting brakepoints here and there and I realised that putting a breakpoint in the while the debugger never stops, never goes into the while. On the contrary, putting a breakpoint in the ISR does stop the debugger, so the counter/pwm seems to be well defined...

 

Please any idea? 

 

#define F_CPU 2000000

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

int dutyCycle = 0;

int main(void)
{
	DDRB |= 0x01;  //PB0 as an output
	TIMSK0 = (1 << TOIE0); //overflow interrupt enable

	TCCR0A = (( 1 << WGM00) | (1 << COM0A1));  //Set timer as fast PWM non-inverting mode
	
	OCR0A = dutyCycle/100*255; //The Output Compare Register OCR storage the value when the signal is going to change from high to low. 255 bc is 16-bits timer

	sei();
	
	TCCR0B = (1 << CS00) | ( 1 << WGM02); //Prescaler set to 1. The timer starts. Set timer as fast PWM and non-inverting mode
	
	while (1)
	{
		_delay_ms(100);
		
		dutyCycle += 10;
		
		if (dutyCycle >= 100)
		{
			dutyCycle=0;
		}
	}
}

ISR(TIM0_OVF_vect)
{
	OCR0A = dutyCycle/100*255; // We change the dutycycle here
}

Thanks!

Manuel

This topic has a solution.
Last Edited: Sun. Dec 3, 2017 - 12:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You should not enable the interrupts until the timer is fully configured.

 

Changing the duty cycle in the ISR is not necessary.
 

David (aka frog_jr)

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OCR0A will always get set to 0 - integer math!  Why not just use dutyCycle directly?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kk6gm wrote:

OCR0A will always get set to 0 - integer math!  Why not just use dutyCycle directly?


Why? Because of the decimals?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'll try your both proposals, thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

M3one wrote:
kk6gm wrote:

OCR0A will always get set to 0 - integer math!  Why not just use dutyCycle directly?

Why? Because of the decimals?

With integer math, if x < 100, then x/100 will always be 0.  0/100 = 0.  1/100 = 0.  99/100 = 0.  100/100 = 1.  If you wanted to scale, do (dutyCycle*255)/100 (and making sure that dutyCycle*255 can't overflow an integer, which it can't in your case).  But those operations, especially the division, are expensive for small uCs.  Unless you have a good reason, better to use a 0-255 dutyCycle value directly.

 

Also, you should declare any variables shared between main and ISR code as 'volatile'.  And unless you need negative values, it's better to use unsigned int rather than int.  Keep this in mind (especially for 8-bit micros)

Don't use floats if longs will work
Don't use longs if ints will work
Don't use ints if bytes will work
Don't use signed if unsigned will work
And get to know the various types in stdint.h

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks kk6gm, now it's working fine. Sometimes I forget how small these little things are and the special care we should take. I'm still amazed what they can do...

 

I leave the code (working) so it may help other newbies:

 

#define F_CPU 2000000

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

volatile unsigned int dutyCycle = 0; //Variables share with ISR shall be volatile


int main(void)
{
	DDRB |= 0x01;  //PB0 as an output
	TIMSK0 = (1 << TOIE0); //overflow interrupt enable

	TCCR0A = (( 1 << WGM00) | (1 << COM0A1));  //Set timer as fast PWM non-inverting mode
	
	OCR0A = dutyCycle; //The Output Compare Register OCR storage the value when the signal is going to change from high to low. 255 bc is 16-bits timer
	
	TCCR0B = ( 1 << WGM02); //Set timer as fast PWM and non-inverting mode
	sei();
	
	TCCR0B = (1 << CS00) ; //Prescaler set to 1. The timer starts.
	
	while (1)
	{

		
		_delay_ms(50);
		
		dutyCycle += 25;
		
		if (dutyCycle >= 255)
		{
			dutyCycle=0;
		}
	}
}

ISR(TIM0_OVF_vect)
{
	OCR0A = dutyCycle; // We change the dutycycle here
}

Manuel