Thursday, 21 June 2018

Handling timer overflow and compare interrupts in ATMega328 (Arduino)


I'm trying to simulate PMW mode on multiple pins in software by controlling a Timer2.


I'm using maximum prescaler value to get approximately 60 pulses per second when timer counts to its maximum value. Value of OCR2A is used to trigger the actual moment within full timer cycle. Overflow interrupt is used to set the LED (PIN13) on and compare interrupt is used to reset LED off.


When I run it, I see that LED blinks but very dimly and its brightness is not affected by CUT_OFF value. If I disable LED off in compare interrupt and just toggle LED in overflow I see it blinks at a reasonable rate which match the final report printed to serial port (number of interrupts in 5 sec). Final report also shows that both interrupts are being called correct number of times.


Here's the code that I use:


#include 
#include


#define LED_PORT (13)

#define CUT_OFF (100)

volatile unsigned long time1 = 0;
volatile unsigned long time2 = 0;

ISR(TIMER2_OVF_vect) {
PORTB |= 0x20;
time1++;

}

ISR(TIMER2_COMPA_vect) {
PORTB &= ~0x20;
time2+=2;
}

void startTimer() {
cli();
// enable timer interrupt overflow + reg a

TIMSK2 = _BV(OCIE2A) | _BV(TOIE2);
// counter
TCNT2 = 0x00;
// cut off value
OCR2A = CUT_OFF;
// mode - normal + prescaler 1024
TCCR2A = 0x00;
TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
// async mode off
ASSR &= ~(_BV(AS2) | _BV(EXCLK));

sei();
}

void stopTimer() {
cli();
// disable interrupts
TIMSK2 = 0x00;
// mode (disconnect clock source)
TCCR2A = 0x00;
TCCR2B = 0x00;

// async mode off
ASSR &= ~((1< sei();
}

void blinkLed(uint8_t times) {
for(uint8_t i=0;i digitalWrite(LED_PORT, HIGH);
delay(500);
digitalWrite(LED_PORT, LOW);

delay(500);
}
}

void setup() {
pinMode(LED_PORT, OUTPUT);
Serial.begin(9600);
}

unsigned long iterations = 0;


#define MAX_ITERATIONS (1000000)

void loop() {
blinkLed(3);
startTimer();
delay(5000);
stopTimer();
blinkLed(2);


Serial.println("Iterations finished!");
Serial.print("Timer1=");
Serial.println(time1);
Serial.print("Timer2=");
Serial.println(time2);

while(1);
}

Is there something wrong with my understanding of when interrupts are called:




  • COM2A - when we reach CUT_OFF value

  • OVF when counter reaches 255 and flips to 0


or there's a problem with setting up timer/or handling interrupts?


Update: Could the problem be in digitalWrite() usage in interrupts? Update2: Changing digitalWrite to direct PORTB bit manipulation produces single flash probably on initial interrupt and subsequent very dim LED so it is not the only problem.


P.S. blinking LED is just a test so using built in PWM is not an option.




No comments:

Post a Comment

arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...