Using timer2 problem

Hi,

I am trying to use timer2 on an Arduino UNO but I am having some unexpected behaviour which I would like to understand and fix. I have attached the library I have created and which I have been using.

Basically the problem lies with when I am trying to set the timer period using either the EnableTimerInterrupt(void (*isr)(), unsigned long microseconds=0) or EnablePWM(uint8_t pin, uint8_t duty, unsigned long microseconds=0) functions.

Setting microseconds to 2000 or less, the resulting period is close enough to the target value.

However I cannot seem to get anything higher than that. for example if I try to set microseconds to 4000 or more, I end up with a period of 2ms or less! :o

any ideas on what's gone wrong here?

TimerTwo.cpp (4.63 KB)

TimerTwo.h (811 Bytes)

any ideas on what's gone wrong here?

#define RESOLUTION 256    // Timer2 is 8 bit

RESOLUTION*prescaler in setPeriod is defaulting to an integer and overflowing.

Try

#define RESOLUTION 256UL    // Timer2 is 8 bit

Thanks Cattle dog. that solved the problem.

However I now found another problem this time with the PWM function.

the duty cycle and period is off in some cases (for example using EnablePWM(11, 30, 1000), I get a 30% duty, period approx 1ms, but changing the period to 9000 duty is now 60%! and period >10ms).

I think understand why this is happening but am wondering if there is a way of fixing it.

Is it because using the OCR register, counter counts from 0-255 unlike when using the overflow interrupt where it is possible to reset TCNT2.

Is there way of doing the same thing while using the compare match output for pwm purposes? should I use be the COMPA or B ISR to fix the PWM?

I am not comfortable with your whole approach of controlling frequency with TCNT2 in the pwm mode.

I would give up on one hardware pin for output and use one of the pwm modes to OCR2A which will control the frequency. Then use OCR2B will control the duty cycle. For pin3 you can directly use the hardware outputs. For any other pin use a compare match interrupt on OCR2B and toggle the desired pin.

I followed you suggestion and changed the PWM code as below:

void TimerTwo::EnablePWM(uint8_t duty, unsigned long microseconds)
{
	uint8_t temp;
	uint16_t dutyCycle;
  
	if(microseconds > 0){
		setPeriod(microseconds); 
		
		temp = period;
		
		OCR2A = temp;		//initialise OCR2A register
		
		pinMode(PWM_PIN,OUTPUT);
		TCCR2A = 0;                 // clear control register A
		TCCR2A |= ((1<<COM2B1)|(1<<WGM21)|(1<<WGM20)); //mode 7: Fast PWM, Clear OC2B on Compare Match. Set OC2B at BOTTOM
		TCCR2B |= (1<<WGM22);
		
		dutyCycle = ((temp*duty)/100);
		
		OCR2B = dutyCycle;	//initialise OCR2B register
			
		TCNT2 = 0; //reset TCNT2
	
		TCCR2B |= clockSelectBits; //set prescale bits
    }
}

Though the duty cycle is correct, my period is still off. what did I do wrong here?

Though the duty cycle is correct, my period is still off. what did I do wrong here?

I can see the period is correct when I test at certain fixed points--for example microseconds = 9000, so I don't think there is anything fundamentally wrong with what you have done.

I think what might be going on is that in the way you set clock select bits in setPeriod() and then use
TCCR2B |= clockSelectBits; is that you never clear any bits which have been set when you define a new period.

Try clearing TCCR2B in EnablePWM like you do with TCCR2A

TCCR2A = 0; // clear control register A
TCCR2B = 0;//clear control register B

Thanks cattledog. your suggestions really helps! :slight_smile: