Trying to setup a 125uS interrupt.

Status
Not open for further replies.

Pommie

Well-Known Member
Most Helpful Member
I'm trying to setup an interrupt to produce 125uS ticks.
I had the following code which doesn't work,
Code:
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t count;

ISR(TIMER2_COMPA_vect){
  count++;
}

void setup(){
  Serial.begin(115200);
  cli();                //disable interrupts
  OCR2A=249;            //set period
  TCCR2A = (1<<WGM21);  //CTC mode
  TCCR2B = (1<<CS21);   //prescaler = 8
  TIMSK2 = (1<<OCIE2A); //enable timer interrupts
  sei();                //enable all interrupts
  while(1){
    Serial.println(count);
  }
}

void loop(){
}
But, if I move the line OCR2A=249; down to just before the sei() line then it works perfectly.
It also works if I add the line OCR2A=249; to the ISR.

There must be a logical explanation for this but I can't work it out.

Any ideas anyone?

Mike.
 
This has the interrupt configuration I'm using, it's got masses of comments as it's part or a youtube multitasking tutorial I'm working on:

It's using timer 0 rather than 2.


C:
//
// Robert Jenkins Technology Channel
//
// https://www.youtube.com/@RJTC
//
// Real time interrupt example
// Part of my multitasking series
//
// This example has been tested on Arduino Uno R3 and Mega2560 R3 boards,
// and it will likely also work on other AVR based Arduinos
//
// Set the board type appropriately in the Tools > Board menu!
//
// See the "Multitasking_Periodic_Interrupt_ARM" version for ARM based Arduinos.
//

// Standardised variable type includes:
// Adding these allows variable type names to be used the same
// Across different compilers, rather than having to redefine
// for each different compiler.
// intxx_t for signed with xx bit size,
// uintxx_t for unnsigned with xx bit size.
//
#include <stdint.h>
#include <stdbool.h>


// Global variable definitions

// Time / timing related
int8_t t_xsec;            // Fractional mS, used with interrupts >1KHz
int8_t t_msec;            // Millisecond counter
int8_t t_csec;            // 1/100th second counter
int8_t t_dsec;            // 1/10th second counter
int8_t t_ssec;            // second counter

// t_min, t_hour etc. could also be added if time of day tracking is needed,
// though preferably add a section in the main program loop that checks t_secflag
// and increments counters as appropriate each time that is set, to minimise the interrupt duration.

// struct_tm xtime;       // Not used in this program; used with time.h functions for time conversions

uint32_t tick_counter;    // "ticks; count of 1mS incerments since program was started.

bool i_msecflag;          // flag bits used (set) by the interrupt
bool i_csecflag;          // routine at the various intervals
bool i_dsecflag;
bool i_ssecflag;

bool t_msecflag;          // Copies of the above, used in the main program
bool t_csecflag;          // to synchronise timed actions
bool t_dsecflag;
bool t_ssecflag;


// Plus a byte store the demo LED states
uint8_t ledbits;


void setup() {
  // put your setup code here, to run once:

  // Configure ports and any other peripherals etc.
  // Using 8 & 9 as they are close to GND for LED resistor common.
 
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);

  // Initialise and configure a timer:
  cli();          // Probably not needed, but keeps things safe if this section is re-used
  TIMSK0 = 0;     // Clear register to disable timer interrupts, also probably not needed

  // TCCR0A and TCCR0B are configuration registers for Timer 0
 
  TCCR0A = _BV(WGM01);    // Sets the counter module in counter (as opposed to PWM) mode.

  // The low three bits of TCCR0B control the prescaler for the counter input,
  // from the CPU I/O clock frequency. 001 = /1 (direct), 010 = /8, 011 = /64, 100 = /256, 101 = /1024.
  // 000 = no input, 110 & 111 set input from an MCU pin.
  // The remaining bits should be zero for a repetitive interrupt use, such as this.
 
  TCCR0B = _BV(CS01) | _BV(CS00);     // Write bit 1 and 0 to 1 = [011]. I/O clock /64 to timer.

  // OCR0A is the value that the count will be compared to, to trigger an interrupt.
 
  // The MCU clock (16MHz on a Mega2560) will be divided by the prescaler value to
  // to increment the timer0 counter & an interrupt will be triggered each time the
  // the count reaches the number in OCR0A
  // With the prescaler bits 011, prescale /64, that timer clock will be 250 KHz.
  // At that, setting OCR0A to 250 would give 1mS interrupts.

  // For approx. 10mS, use TCCR0B = _BV(CS02); giving /256 and set OCR0A to 156
  // Or use the valuse as below and ignore the t_csecflag fo 10mS indication...
 
 
  OCR0A = 250;             // 16KHz / 16 count = 1mS interrupt rate

  // Now enable the interrupt from Timer 0 when there is a compare match.
  // That interrupt is called TIMER0_COMPA_vect
 
  TIMSK0 = _BV(OCIE0A);


  // Finally, after all hardware initialisation etc. is complete,
  // enable the overall MCU interrupts
  sei();
 
}

void loop() {
  // put your main code here, to run repeatedly:

  // As the interrupts could occur at any time in the main program,
  // check and copy the time flag bits here so they are consistent all
  // the way through the main program loop.
  // This can be done a bit more efficiently, but this is a demo
  // to explain the overall methodology!
  // See the Arduino Due example for the faster version

  cli(); // temporarily disable interrupts to nothing changes while testing the bits!

  if(i_msecflag) {
    t_msecflag = true;
    i_msecflag = false;
  }
  else {
    t_msecflag = false;
  }

  if(i_csecflag) {
    t_csecflag = true;
    i_csecflag = false;
  }
  else {
    t_csecflag = false;
  }

  if(i_dsecflag) {
    t_dsecflag = true;
    i_dsecflag = false;
  }
  else {
    t_dsecflag = false;
  }

  if(i_ssecflag) {
    t_ssecflag = true;
    i_ssecflag = false;
  }
  else {
    t_ssecflag = false;
  }

  // The t_ flag bits above will be set for one pass through the main program loop
  // at their respective intervals.
  // eg. If you want to do something ten times per second, check for the t_dsecflag being set
 
  // Or test (t_flags & F_DSEC), in the fast version of the flag update routine as in the Arduino Duo example.

sei(); // Re-enable the interrupts

// The rest of the program from here on.


// This demo is just going to toggle a couple of outputs at 10Hz and 1Hz
// (so flashing cycles at 5Hz and 0.5Hz)

if(t_dsecflag)
 
  // Toggle LED on pin 9, bit 1 of store
  if(ledbits & 0x02) // LED is on
  {
    digitalWrite(9, LOW);
    ledbits &= 0xFD;  // turn off bit 1
  }
  else
  {
    digitalWrite(9, HIGH);
    ledbits |= 0x02;  // turn on bit 1
  }


if(t_ssecflag)
 
  // Toggle LED on pin 8, bit 0 of store
  if(ledbits & 0x01) // LED is on
  {
    digitalWrite(8, LOW);
    ledbits &= 0xFE; // turn off bit 0
  }
  else
  {
    digitalWrite(8, HIGH);
    ledbits |= 0x01; // turn on bit 0
  }


  // Add to the program here, as you wish.


  // End of main program loop
}



// This is the function that will be called each time the timer 0 periodic interrupt occurs:
ISR(TIMER0_COMPA_vect)
{
  // The code in an interrupt routine must be minimal,
  // to do only what is absoluetly essential - no waiting
  // or delays of any type!

  // With the settings above, this will be called at 1KHz, every 1mS.
 

  // Count milliseconds through to seconds
 
  t_msec++;
  i_msecflag = true;
 
  if(t_msec > 9) {
    // 10 counts, reset and increment 1/100sec
    t_msec = 0;

    t_csec++;
    i_csecflag = true;

    if(t_csec > 9) {
      // Same for each decade used
      t_csec = 0;

      t_dsec++;
      i_dsecflag = true;

      if(t_dsec > 9) {
        t_dsec = 0;

        t_ssec++;
        i_ssecflag = true;
      }
    }
  }

  // Counters done, any other stuff such as serial
  // port & buffer checks for up to 9600 baud
  // could also go in here.

  // My software timer library would also be called from here

 
}
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…