Interrupt help - need a second set of eyes

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

EDIT: Being tired never helps, it was a silly typo that I corrected in the code below.  Mods feel free to delete this post.  If not, it's a simple example of a timer overflow interrupt.

 

I'm having trouble getting my Timer0 overflow interrupt to trigger on an Atmega1284 running at 16mhz.  I've had similar code working on other Atmel chips, but I'm at a loss here.  It could be because I'm super tired, but I'm obviously missing something simple and need a second set of eyes.

 

My approach is basically:

 

  1. Enable interrupts
  2. configure Timer0 for no pre-scale and enable the overflow interrupt
  3. wait a short period of time, but long enough to get lots of overflows on the 8 bit timer
  4. print out my overflow count

 

Trouble is, I never get any overflows - so my ISR is never firing.  The LCD code is just Peter Fleury's code adapted to run using an MCP23008 I/O extender, I've tested it with lots of projects and it's bug free.

 

//REQUIRED HEADERS-------------------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <avr/sfr_defs.h>
#include "MCP23008_lcd.h"
#include "MCP23008.h"
#include "i2cmaster.h"

//DEFINITIONS-------------------------------------------------------------
#define BV(bit)			(1<<(bit))
#define cbi(reg,bit)	reg &= ~(BV(bit))
#define sbi(reg,bit)	reg |= (BV(bit))

//VARIABLES-------------------------------------------------------------
char buffer[33];		//buffer to store the strings of converted numbers
volatile uint8_t tOverflow = 0;				//counter for timer0 overflows, used for ultrasonic distance calcs

//INTERRUPTS--------------------------------------------------------------
ISR(TIMER0_OVF_vect)
{
	tOverflow++;			//increment timer overflow counter every time overflow ISR executes
}

int main(void)
{
	_delay_ms(1000);			//small delay to allow lcd and MCP2008 to startup
	i2c_init();				//initialize the i2c software/hardware
	lcd_init(LCD_DISP_ON);			//initialize lcd, display on, cursor on
	lcd_clrscr();
	sei();
	sbi(TIMSK0, TOIE0);			//enable timer overflow interrupt for timer0
	sbi(TCCR0B, CS00);			//timer prescaler set to 1 & STARTS TIMER0
	_delay_ms(2);
	lcd_gotoxy(0,0);			//move LCD cursor to origin
	sprintf(buffer, "%-3u", tOverflow);	//prints unsigned integer, left aligned, always uses 3 spaces
	lcd_puts(buffer);
}

 

Last Edited: Wed. Apr 15, 2015 - 10:40 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, at first glance I didn't see you have include TCCR0B register for prescaler but still I suggest you better write separate function to initialize timer and first try to implement timer overflow interrupt separately by simply toggling LED and then combine your rest of code for LCD and I2C. 

Last Edited: Wed. Apr 15, 2015 - 12:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Where to start?!?

 

First, what do you expect to happen?  What >>is<< happening?

 

-- A microcontroller program must have an infinite loop.  What do you expect to happen after the lcd_puts()?  With GCC, an infinit catch loop will be entered, with interrupts off.

-- Indeed, at a normal AVR clock rate, I guess I'd expect the timer to overflow within two milliseconds, and 1 be displayed.  However, we don't see F_CPU definition so who knows if the delays are accurate.

-- Once F_CPU is properly set to the speed your AVR is really running at, what results do you get if you delkay e.g. 200 ms instead of 2ms?

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Wed. Apr 15, 2015 - 01:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And another thing do you want to display tOverflow repeatedly after every ISR?

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

Thanks for the input guys.  I'll clarify some stuff now that I've slept.  This code is just a grossly simplified code that doesn't really do anything because I was lost as to why the ISR wasn't firing.  The I removed the infinite loop because don't care to loop this code, once through is enough to see if the ISR was firing.  F_CPU is specified as a symbol in AVR studio, I should have noted that.  The code works in that the ISR fires the typo was using cbi instead of sbi to enable the timer overflow interrupt.  Like I said in the edit - silly typo that I didn't see until I posted and I couldn't figure out how to delete the post after the fact.  The TCCR0B config is in there, its only a single line to start the timer and one to stop it.

 

 

 

 

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

 The TCCR0B config is in there, its only a single line to start the timer and one to stop it.

If one wants to set an I/O register to a value--why not just do it?  (I guess some don't like (1<<xxx) but you sidestepped that with BV() ... )

 

So:

TCCR0B = BV(CS00);

 

And =, not |=.  Set up an AVR peripheral with the mindset that you have no idea what the register value might be.  (Sometimes, we see register setup with a whole series of your sbi()/cbi() or equivalent doing |=/&=~ .  Again, it does nothing to do a "clean" job of it, and in the end uses more flash space and cycles and typing [which can lead to more typos].)

 

Just my opinion, based on my experience.  YMMV.

 

 

This code is just a grossly simplified code that doesn't really do anything because I was lost as to why the ISR wasn't firing.

Understood.  However, it is very useful to us to see a complete small test program with expected and actual results given.  In your code, for example, the symptoms could well be explained by an F_CPU value such that the timer would never have overflowed in 2ms.  Sent us off on a wrong track.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.