firing timers with overflow enabled inside ISR

Hello, i want to first explain what i need to do:

Board: Arduino Micro

The hardware is setup like this: INT2 and INT3 pins are Tied together
Digital output 13 is: interrupt monitor, so i can know software is working .
Digital output 10 is: controlled pulse output
OLED 20X4 Screen controlled by lcd library.

The software has to do this:
software has to measure the time between interrupt pulse rise and pulse falling, brake in 4 parts the time stored in tcnt1 so this value can be used later to calculate the timing to fire the digital output 10
The attachment has a photo wich describes what is needed.

The software:

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int led = 13;
int led2 = 10;
int PRESCALER =1; // Prescaler seleccionado 4 para pines 9 y 10 salida 125 Hz
int PRESCALER2=1; // Prescaler seleccionado 4 para pines 9 y 10 salida 125 Hz
float TIMER1 = 0; // VARIABLE TIMER
float TEMP1 = 0; // VARIABLE TEMP1
int TEMP2 = 0; // VARIABLE TEMP2
float TEMP3 = 0; // VARIABLE TEMP3
float TEMP4X3= 0; // VARIABLE TEMP4 MULTIPLICADA X 3
float TEMP5 = 0; // VARIABLE TEMP5
volatile byte testbit = 0;
volatile float TempLduration = 0; // COMIENZO DE TIMER LOAD
volatile float TEMP4 = 0; // VARIABLE TEMP4
volatile float TEMP4X2= 0; // VARIABLE TEMP4 MULTIPLICADA X 2
int FREQ=0; // FRECUENCIA
volatile byte INTR2 = 2;
volatile byte INTR3 = 3;
unsigned int onTime = 0;
unsigned int offTime =0;
unsigned long int period = 1000000 / (2 * FREQ);//

void loop()
{
sei();
TIMSK3 |= (1 << TOIE3); // enable timer overflow interrupt
lcd.setCursor(79, 1);
lcd.print(" “);
lcd.setCursor(79, 1);
lcd.print(TEMP2);
TEMP3=TEMP2/2;
TEMP4=TEMP3/2;
TEMP4X2=(TEMP4)* 2;
TempLduration= 65535-TEMP4X2;
lcd.setCursor(35,1);
lcd.print(” “);
lcd.setCursor(35,1);
lcd.print(TEMP4X2);
lcd.setCursor(84,1);
lcd.print(” ");
lcd.setCursor(84,1);
lcd.print(TCNT3);
}

void INTR()
{
Timer1.initialize();
Timer3.initialize(65534-(TEMP4));
Timer1.start();
Timer3.start();
digitalWrite(13, HIGH);
testbit = 1;

}

void tempLstart()
{
switch (testbit) {
case 1:
//do something when MyVar equals 1
Timer3.stop();
Timer3.initialize(4000+TEMP3);
digitalWrite(10,HIGH);
Timer3.start();
testbit = 0;
break;
case 0: //do something when MyVar equals 2

testbit = 2;
break;
default: // if nothing else matches, do the default default is optional
Timer3.stop();
digitalWrite(10,LOW);

}
}

void INTF()
{
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
Timer1.stop();
TEMP2= TCNT1;

}

The problem:
Timer 1 and Timer 3 , even when changing TCCR1B AND TCCR3B doesnt change the behavior towards desired behavior.
Adding constant values to the count off timer 3 (first overflow so pin 10 can be fired and end up centered and in the middle between interrupts )
Adding constant values in the order of 4000s to the second Time firing of timer3 and starting at the same time output on OUTPUT 10 does the job but code is not working as intended, because pulse output 10 does not get even closer to the desired behavior, if the constant value 3500 to 4000 is not added. I know from a lot of googling that working inside interrupts is difficult, im posting because this is my last resourse.

Would be glad if anyone can helpme figure this out.

Hi, welcome to the forum. It is very confusing for me, I'm looking at the code, but I have no clue what it is doing. Please put the sketch between code tags in a post, and show the whole sketch and tell which special libraries are used (where did you get them, which version).

You don't need the sei(), the Arduino startup code does that for you. I have never use that Timer library, so I don't know what to say about it.

Could you create a new sketch and use attachInterrup(). In the ISR you could set a global variable to the number of micros(). In the main loop, calculate the difference between the variables.

There is also a pulseIn() function, it might be just what you need.

And there are good frequency measure and timing measure libraries. I think at the teensy site is the newest version.

The output of the H11L1 will not be centered with the positive cycle of the sine wave. It has hysteresis where its output triggers high at 1.6mA and triggers low at 1mA.

I would consider another approach that should yield better accuracy and performance. If you used just one interrupt on the rising edge, then:

The duration between interrupts would determine the sine wave frequency. A constant could be determined that would be used to determine the true zero crossing time.

The interrupt routine would only set a flag and read micros() into a variable. The main code would then detect the flag and run a while loop that creates the pulse. Just after the pulse goes low, the while loop completes (based on time condition).

Now there's ample time to update "previous" variables and do calculations and printing prior to the next interrupt.

In summary, the while loop code creates the desired signal, which would be as accurate as the micros() function (within 4µs).

A bunch of code is missing. Where is the include of LiquidCrystal? Where is the setup() function?

here is the whole code.

#include <avr/io.h>
#include <PinChangeInt.h>
#include <PinChangeIntConfig.h>
#include <LiquidCrystal.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <math.h>
#include <TimerOne.h>
#include <TimerThree.h>
#define LED2 10 // pulse at peak of sine wave.
#define LED 13 // LED INTEGRADO EN TARJETA PARA MONITOREAR PIN 13.

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int led = 13;
int led2 = 10;
int PRESCALER =1; // Prescaler seleccionado
int PRESCALER2=1; // Prescaler seleccionado
float TIMER1 = 0; // VARIABLE TIMER
float TEMP1 = 0; // VARIABLE TEMP1
int TEMP2 = 0; // VARIABLE TEMP2
float TEMP3 = 0; // VARIABLE TEMP3
float TEMP4X3= 0; // VARIABLE TEMP4 MULTIPLICADA X 3
float TEMP5 = 0; // VARIABLE TEMP5
volatile byte testbit = 0;
volatile float TempLduration = 0; // COMIENZO DE TIMER LOAD
volatile float TEMP4 = 0; // VARIABLE TEMP4
volatile float TEMP4X2= 0; // VARIABLE TEMP4 MULTIPLICADA X 2
int FREQ=0; // FRECUENCIA
volatile byte INTR2 = 2;
volatile byte INTR3 = 3;
unsigned int onTime = 0; // Ton
unsigned int offTime =0; //Toff
unsigned long int period = 1000000 / (2 * FREQ);//The Timerone PWM period in uS, 60Hz = 8333 uS

byte customChar[8] = {
0b01110,
0b01110,
0b01110,
0b01110,
0b01110,
0b11111,
0b01110,
0b00100
};
// FLECHA HACIA ABAJO CREDITOS

byte customChar1[8] = {
0b11000,
0b01100,
0b00110,
0b11111,
0b11111,
0b00110,
0b01100,
0b11000
};
// FLECHA HACIA LA DERECHA
byte customChar2[8] = {
0b00110,
0b01100,
0b11000,
0b11111,
0b11111,
0b11000,
0b01100,
0b00110
};
// FLECHA HACIA LA IZQUIERDA
byte customChar3[8] = {
0b01110,
0b01010,
0b01010,
0b01010,
0b01010,
0b01010,
0b01010,
0b11011
};
// simbolo de pulso
byte customChar4[8] = {
0b00000,
0b00000,
0b00001,
0b00010,
0b00100,
0b01000,
0b11000,
0b10000
};
//sinewave 1
byte customChar5[8] = {
0b01110,
0b10001,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000
};

//sinewave 2
byte customChar6[8] = {
0b00000,
0b00000,
0b10000,
0b01000,
0b00100,
0b00010,
0b00011,
0b00001
};

//sinewave 3
byte customChar7[8] = {
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b00000,
0b11111
};
//PULSE BEGIN AND END

void setup() {

lcd.begin(20,4);
lcd.clear();
lcd.createChar(0, customChar);
lcd.createChar(1, customChar1);
lcd.createChar(2, customChar2);
lcd.createChar(3, customChar3);
lcd.createChar(4, customChar4);
lcd.createChar(5, customChar5);
lcd.createChar(6, customChar6);
lcd.createChar(7, customChar7);
lcd.setCursor(0, 1);
lcd.print(“SISTEMA DE CONTROL”);
lcd.setCursor(65, 1);
lcd.print(“find midle sine wave”);
lcd.setCursor(20,1);
lcd.print(“FABRICADO POR :”);
lcd.write((uint8_t)0);
lcd.write((uint8_t)0);
lcd.write((uint8_t)0);
lcd.write((uint8_t)0);
lcd.write((uint8_t)0);
lcd.setCursor(84,1);
lcd.write(byte(1));
lcd.print(“ALONSO AVILA CETINA”);
delay(2000);
lcd.clear();
lcd.setCursor(8, 1);
lcd.print((char)34);
lcd.print(“X4uSEG”);
lcd.print((char)34);
lcd.write((uint8_t)0);
lcd.setCursor(64, 1);
lcd.write((uint8_t)4);
lcd.write((uint8_t)5);
lcd.write((uint8_t)6);
lcd.setCursor(67, 1);
lcd.write((uint8_t)1);
lcd.print(“SINEWTIMER=”);
lcd.setCursor(20,1);
lcd.write((uint8_t)7);
lcd.write((uint8_t)3);
lcd.write((uint8_t)7);
lcd.setCursor(23,1);
lcd.write((uint8_t)1);
lcd.print(“LOAD TIMER=”);
Serial1.end();
pinMode(0, INPUT);
pinMode(1, INPUT);
pinMode(10, OUTPUT); // Pulse at middle of sine wave
pinMode(13, OUTPUT);
TEMP2= TCNT1;
TCNT3=0;
Timer1.initialize();
TCCR1A =0 ;
TCCR1B =PRESCALER; // Prescaler seleccionado
TCCR3B =PRESCALER2;
attachInterrupt(INTR2, INTR, FALLING);
attachInterrupt(INTR3, INTF, RISING);
Timer3.attachInterrupt(tempLstart); // attaches templstop() as a timer overflow interrupt
digitalWrite(10,LOW);
noInterrupts(); // disable all interrupts

}

void loop()
{
sei();
TIMSK3 |= (1 << TOIE3); // enable timer overflow interrupt
lcd.setCursor(79, 1);
lcd.print(" “);
lcd.setCursor(79, 1);
lcd.print(TEMP2);
TEMP3=TEMP2/2;
TEMP4=TEMP3/2;
TEMP4X2=(TEMP4)* 2;
TempLduration= 65535-TEMP4X2;
lcd.setCursor(35,1);
lcd.print(” “);
lcd.setCursor(35,1);
lcd.print(TEMP4X2);
lcd.setCursor(84,1);
lcd.print(” ");
lcd.setCursor(84,1);
lcd.print(TCNT3);
}

void INTR()
{
Timer1.initialize();
Timer3.initialize(65534-(TEMP4));
Timer1.start();
Timer3.start();
digitalWrite(13, HIGH);
testbit = 1;

}

void tempLstart()
{
switch (testbit) {
case 1:
//when MyVar equals 1
Timer3.stop();
Timer3.initialize(TEMP3+(4000));
digitalWrite(10,HIGH);
Timer3.start();
testbit = 0;
break;
case 0: //do something when MyVar equals 2

testbit = 2;
break;
default: // if nothing else matches, do the default default is optional
Timer3.stop();
digitalWrite(10,LOW);

}
}

void INTF()
{
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
Timer1.stop();
TEMP2= TCNT1;

}

@dlloyd

Yes i know about the hysteresis on the opto , and as showed on the picture the interesting part is the middle of the sine wave.

The time between interrupts is measured using timer1, and the time the pulse centered in the middle of the sine wave is calculated using timer3, (Output 10) the first time timer3 is fired inside intR its the time it takes to end up in the middle of sine wave, the second time timer3 is reloaded after its first overflow, the value should be enough to be close to the peak of the sine wave, i tried before using if, but ended up in an infinite loop, so instead i changed to switch, and a testcondition bit called testbit, to control the flow of the program.

Timer3 inside ISR intR when fired for the first time, seems to not be running or running too fast, you can even add constant values at intR , example Timer3.initialize(65534-(TEMP4+4000)); and does not reflects the change desired. This weird behavior is making me nuts, any help is welcome, Thanks in advance

also i forgot , to explain that the time between interrupts, intRising and intfalling, is done using timer one, the measured values showed on display at a fixed sine wave signal, does not reflects change when moving the prescalers of timer1 or timer3 or both.

I googled a lot, and timers inside interrupts is not something i could find on google.

Here are the libraries used.

TimerThree.zip (7.6 KB)

TimerOne-master.zip (7.34 KB)

Yes i know about the hysteresis on the opto , and as showed on the picture the interesting part is the middle of the sine wave.

What I’m pointing out is that your green waveform will be shifted a small amount to the right because of this. Therefore midpoint calculations will have a small error.

Here is an example that all you need to do is set the offset and width. The ouput will be centered exactly to the positive 1/2 cycle of the sine wave. Adding offset will shift the output to the left to cancel out the small timing delay of the interrupt. You can use print monitor to view results.

volatile unsigned long now = 0;
volatile boolean flag = LOW;
unsigned long previous = 0;

const unsigned short offset = 0;  // zero crossing to interrupt µS
unsigned long width = 500;        // output width µS

unsigned long duration = 0;       // sine wave period µS
float sineHz = 0.0;               // sine wave frequency Hz
float centerPoint = 0.0;
float onPoint = 0.0;
float offPoint = 0.0;
byte printCount = 0;
boolean printFlag = LOW;

void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Serial.begin(115200);
  attachInterrupt(0, pulseCapture, RISING);
}

void loop() {
  calculate();
  outputSignal();
//printResults();
  previous = now;
  flag = LOW;
}

void pulseCapture() {
  now = micros();
  flag = HIGH;
}

void calculate() {
  if (flag == HIGH) {
    duration = now - previous;
    sineHz = 1000000 / duration;
    centerPoint = duration * 0.25 - offset;
    onPoint = centerPoint - (width * 0.5) - offset;
    offPoint = centerPoint + (width * 0.5) - offset;
  }
}

void outputSignal() {
  while (micros() <  (now + duration * 0.5)) {
    if ((micros() >= (now + onPoint)) && (micros() < (now + offPoint))) {
      digitalWrite(13, HIGH);
      printFlag = HIGH;
    }
    else {
      digitalWrite(13, LOW);
    }
  }
}

void printResults() {
  if (printFlag == HIGH) {
    if (printCount % 51 == 1) {
      Serial.print("sineHz:\t\t");
      Serial.println(sineHz);
      Serial.print("now:\t\t");
      Serial.println(now);
      Serial.print("duration:\t");
      Serial.println(duration);
      Serial.print("onPoint:\t");
      Serial.println(onPoint);
      Serial.print("centerPoint:\t");
      Serial.println(centerPoint);
      Serial.print("offPoint:\t");
      Serial.println(offPoint);
      Serial.println();
    }
    printFlag = LOW;
    printCount++;
  }
}

ended up working on my code since i need to use interrupts to find the time difference when a pulse starts and when it ends , so im willing to save my own code to find the error.

Here is what i have found: seems to be that there is some trouble with Timers runing inside interrupts, i have used the LCD screen to print the value of TCNT1 AND TCNT3, and if both overflow, and found that as soon as i enter interrupt INTR Timer1 and Timer3 instantly overflow.

Also as long as the pulse lasts the interruption keeps entering, the ISR routine, thats why i ended using switch, so i can execute the code only once.

Any one knows how to stabilize this issue?

Why are you stopping and starting the timer1? Why not leave it running and grab timestamps from them as you need to? An interval is the difference of two timestamps.

Give you variables names that describe their meaning, not TEMP1, TEMP2, etc, because they are not temporary at all, they seem to be the heart of your code.

Try and separate concerns - all the time measuring with timer1 should be in separate functions from the code that plays with pin 10 and timer3...

Timer1 is being started and stopped in order to read its value later, move it to TEMP2 and perform the half cycle calculation with a large posibility of offset and accuracy between INTR and INTF. The idea when timers behave steady, is basically T1CALCULATED=T1INITIALVALUE-TIFINALVALUE;

Also have tried: not the actual code , but the general idea. It does compiles , but not accurate due to timer1 getting overflows as long as INTR is enabled. The only thing needed is that timer1 does not overflows while INTR lasts. void INTR Timer1.initialize(50000); T1INITIALVALUE= TCNT1; Timer1.start();

void INTR Timer1.stop T1FINALVALUE=TCNT1;

Here is another attempt i did : But the result is that i cant make to date timers to work ok inside interrupts void INTR() { switch (testbit) { case 0: Timer1.initialize(100000); TCNT1INITIAL=TCNT1; Timer3.initialize(8000); Timer1.start(); Timer3.start(); digitalWrite(13, HIGH); testbit2= 2; break; case 1: testbit = 2; break;

Hey MarkT, do you suggest that i move my hardware functions to another pins even when im not using PWM or pulsecounter? im still thinking that , since the timer1 and timer3 source is internal, using the pins related to the functions should not cause any trouble since they are isolated when the timers 1 and 3 got configured in void setup. Am I wrong about it?

Using the OLED screen, instead serial prints inside isr, I started the direct monitoring of TCNT1 TCNT3 and overflows of both of them, What i have found is the problem not the solution.

When INT0 or INT1 happens, instantly timers overflow, calling its ISRs , clearing the value of the TCNT1 AND TCNT0.

NOW, THE QUESTION IS: why is this happening?