RoTo
November 29, 2016, 3:21pm
1
Hello,
I am new on Adruino and I want to generate a PWM Signal on any digital pin of the Arduino UNO board.
To get full control and complete understanding of the PWM I don´t want to use a existingl PWM library.
In the following code I use Pin 9 as a PWM output, which should be toggled by compare register A interrupt.
But it doesn´t work, and I don´t understand why.
I set following for timer 2:
reset all registers to zero
choose fast PWM
disconnect PWM pins (not needed if interrupt is used)
compare register A set to a value for duty cycle (e.g. 200)
activate timer interrupt for CompA and OVF (compare and timer overflow)
prescaler 64
The timer overflow is needed to preload the timer 2 to get 1kHz frequency.
I get no signal on pin 9 with this setup.
Perhaps anyone can give me a hint, how to get it to work.
Thank you in advance!
#include <avr/io.h>
#include <avr/interrupt.h>
//******* Variable Declaration *******
int value;
boolean toggle = 0; //storage variables
//-----------------------------------------------------------------------------------------
void setup()
{
//set pins as outputs
pinMode(9, OUTPUT); // PWM Interrupt Output
pinMode(11, OUTPUT); // OC2A
pinMode(3, OUTPUT); // OC2B
//setup all timers
noInterrupts(); // disable all interrupts
//****** Register Reset ******
TCNT2 = 0x00;
TCCR2A = 0x00;
TCCR2B = 0x00;
TIMSK2 = 0x00;
TIFR2 = 0x00;
//****** Select PWM Mode by WGM Bits *******
TCCR2B |= (0 << WGM22);
TCCR2A |= (1 << WGM21) | (1 << WGM20); // fast pwm
//****** Chose Signal Mode *******
TCCR2A |= (0 << COM2A1) | (0 << COM2A0); // OC2A disconnected
TCCR2A |= (0 << COM2B1) | (0 << COM2B0); // OC2B disconnected
//****** Set Compare Register *******
OCR2A = 200;
OCR2B = 100;
//****** Activate Interrupt *******
TIMSK2 |= (0 << OCIE2B) | (1 << OCIE2A) | (1 << TOIE2) ; //activate Timer 2 Interrupts
//****** Set Prescaler and start PWM *******
TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20); //prescaler 64
interrupts(); // enable all interrupts
}
//-----------------------------------------------------------------------------------------
ISR(TIMER2_CompA_vect)
{
if (toggle){
digitalWrite(9,LOW);
toggle = 0;
}
else{
digitalWrite(9,HIGH);
toggle = 1;
}
TIFR2 = 0x00;
}
//-----------------------------------------------------------------------------------------
ISR(TIMER2_OVF_vect) //timer2 interrupt at timer overflow
{
TCNT2 = 6; //load timer
TIFR2 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
}
//-----------------------------------------------------------------------------------------
void loop()
{
}
toggle should be volatile
Or, you could just read the state:
digitalWrite(pin, !digitalRead(pin))
or read and set the real register yourself
RoTo
November 29, 2016, 4:53pm
4
Thanks for the fast reply!
I updated the code. But the main issue is the interrupt. It is not called, so there is no PWM signal on pin 9.
#include <avr/io.h>
#include <avr/interrupt.h>
//******* Variable Declaration *******
int value;
//-----------------------------------------------------------------------------------------
void setup()
{
//Serial.begin(9600);
//set pins as outputs
pinMode(9, OUTPUT); // PWM Interrupt Output
pinMode(11, OUTPUT); // OC2A
pinMode(3, OUTPUT); // OC2B
//setup all timers
noInterrupts(); // disable all interrupts
//****** Register Reset ******
TCNT2 = 0x00;
TCCR2A = 0x00;
TCCR2B = 0x00;
TIMSK2 = 0x00;
TIFR2 = 0x00;
//****** Select PWM Mode by WGM Bits *******
TCCR2B |= (0 << WGM22);
TCCR2A |= (1 << WGM21) | (1 << WGM20); // fast pwm
//****** Chose Signal Mode *******
TCCR2A |= (0 << COM2A1) | (0 << COM2A0); // OC2A disconnected
TCCR2A |= (0 << COM2B1) | (0 << COM2B0); // OC2B disconnected
//****** Set Compare Register *******
OCR2A = 200;
OCR2B = 100;
//****** Activate Interrupt *******
TIMSK2 |= (0 << OCIE2B) | (1 << OCIE2A) | (1 << TOIE2) ; //activate Timer 2 Interrupts
//****** Set Prescaler and start PWM *******
TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20); //prescaler 64
interrupts(); // enable all interrupts
}
//-----------------------------------------------------------------------------------------
ISR(TIMER2_CompA_vect)
{
digitalWrite(9, !digitalRead(9));
TIFR2 = 0x00;
}
//-----------------------------------------------------------------------------------------
ISR(TIMER2_OVF_vect) //timer2 interrupt at timer overflow
{
TCNT2 = 6; //load timer
TIFR2 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
}
//-----------------------------------------------------------------------------------------
void loop()
{
}
RoTo
November 29, 2016, 5:23pm
6
Sorry, I was blocked for a few minutes, because I answered too fast. :
Now it´s updated, see above.
Syntax is case sensitive
//ISR(TIMER2_CompA_vect)
ISR(TIMER2_COMPA_vect)
RoTo
November 29, 2016, 5:38pm
8
I can´t belive it ... I am searching since hours for the root cause and you did it within minutes!! :o
Now it is running well! Thank you so much!
Hopefully this code helps other beginners too. I think it is easy to understand.
Here the final code:
#include <avr/io.h>
#include <avr/interrupt.h>
//******* Variable Declaration *******
int value;
//-----------------------------------------------------------------------------------------
void setup()
{
//set pins as outputs
pinMode(9, OUTPUT); // PWM Interrupt Output
pinMode(11, OUTPUT); // OC2A
pinMode(3, OUTPUT); // OC2B
//setup all timers
noInterrupts(); // disable all interrupts
//****** Register Reset ******
TCNT2 = 0x00;
TCCR2A = 0x00;
TCCR2B = 0x00;
TIMSK2 = 0x00;
TIFR2 = 0x00;
//****** Select PWM Mode by WGM Bits *******
TCCR2B |= (0 << WGM22);
TCCR2A |= (1 << WGM21) | (1 << WGM20); // fast pwm
//****** Choose Signal Mode *******
TCCR2A |= (1 << COM2A1) | (0 << COM2A0); // OC2A disconnected
TCCR2A |= (0 << COM2B1) | (0 << COM2B0); // OC2B disconnected
//****** Set Compare Register *******
OCR2A = 128;
OCR2B = 200;
//****** Activate Interrupt *******
TIMSK2 |= (0 << OCIE2B) | (1 << OCIE2A) | (1 << TOIE2) ; //activate Timer 2 Interrupts
//****** Set Prescaler and start PWM *******
TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20); //prescaler 64
interrupts(); // enable all interrupts
}
//-----------------------------------------------------------------------------------------
ISR(TIMER2_COMPA_vect)
{
digitalWrite(9, !digitalRead(9));
TIFR2 = 0x00;
}
//-----------------------------------------------------------------------------------------
ISR(TIMER2_OVF_vect) //timer2 interrupt at timer overflow
{
TCNT2 = 6; //load timer to adjust frequency
TIFR2 = 0x00; //Timer2 INT Flag Reg: Clear Timer Overflow Flag
}
//-----------------------------------------------------------------------------------------
void loop()
{
}