Timer questions

Mega 2560, new to Arduino.

I'm trying to understand how the timers work so I've written some code to do some tests.

I have Timer 2 set up as a time rate generator which triggers an interrupt every second. Within this interrupt routine I use Timer 1 Channels A and B to drive pins high for a 20 mS timed pulse . This is to be repeated every second.

The time rate generator works fine, but the Timer 1 channels aren't behaving as expected. On a logic analyzer I see when pin 13 changes state there is a 9 uS delay before pin 11 goes high. After another 6 uS delay pin 12 goes high. Pin 11 goes low after a pulse of only 15.5 uS. Pin 12 goes low after a pulse of only 20.5 uS. This is quite consistent every second.

If anyone can tell me what I'm doing wrong I'd really appreciate it.

// 16 bit timers (n = timer number) (Timers 1,3,4,5)

// Timer1 registers:

// TCCR1A - Timer/Counter 1 Control Register A:

// Bit7 - COM1A1 - Compare output mode for channel A
// Bit6 - COM1A0 - Compare output mode for channel A
// Bit5 - COM1B1 - Compare output mode for channel B
// Bit4 - COM1B0 - Compare output mode for channel B
// Bit3 - COM1C1 - Compare output mode for channel A
// Bit2 - COM1C0 - Compare output mode for channel C
// Bit2 - WGM11 - Operation Mode 
// Bit2 - WGM10 - Operation Mode

// COM1 : COM0
//  0   :   0   - Normal port operation
//  0   :   1   - Toggle on output compare
//  1   :   0   - Clear on output compare
//  1   :   1   - Set on output compare

// WGM11 : WGM10
//   0   :   0   - Normal port operation

// TCCR1B - Timer/Counter 1 Control Register B:

// Bit7 - ICNC1 - Input capture noise canceller
// Bit6 - ICES1 - Input capture edge select
// Bit5 - N/A
// Bit4 - WGM13 - Waveform generation mode
// Bit3 - WGM12 - Waveform generation mode
// Bit2 - CS12 - Clock Select
// Bit2 - CS11 - Clock Select 
// Bit2 - CS10 - Clock Select

// WGM13 : WGM12
//   0   :   0   - Normal port operation

// 16,000,000 / prescale = Frequency
// CS12:CS11:CS10
// TCR1B = B00000001: 16,000,000 / 1 = 16,000,000 Hz (16mHz) = .0625uS period * 65,536 = 4,096uS max period (4.096mS)
// TCR1B = B00000010:  16,000,000 / 8 = 2,000,000 Hz (2mHz) = .5uS period period * 65,536 = 32,768uS max period (32.768mS.)
// TCR1B = B00000011:  16,000,000 / 64 = 250,000 Hz (250kHz) = 4uS period * 65,536 = 262,144uS max period (262.144mS)
// TCR1B = B00000100:  16,000,000 / 256 = 62,500 Hz (62.5kHz) = 16uS period * 65,536 = 1,048,576uS max period (1.048576Sec)
// TCR1B = B00000101:  16,000,000 / 1024 = 15,625 Hz (15.625kHz)= 64uS period * 65,536 = 4,194,304uS max period (4.194304Sec)

// TCCR1B = B00000001; // Prescale = 1  (.0625uS increment)(max period before overflow 4.096mS)
// TCCR1B = B00000010; // Prescale = 2  (.5uS increment)(max period before overflow 32.768mS.)
// TCCR1B = B00000011; // Prescale = 3  (4uS increment)(max period before overflow 262.144mS)
// TCCR1B = B00000100; // Prescale = 4  (16uS increment)(max period before overflow 1.048576Sec)
// TCCR1B = B00000101; // Prescale = 5  (64uS increment)(max period before overflow 4.194304Sec)

// Arduino pin connections:
// ledPin13 = Arduino LED on pin 13 
// pulseApin11 = Pulse A output on pin D11, PB5, Output Compare 1A
// pulseBpin12 = Pulse B output on pin D12, PB6, Output Compare 1B

// Time Rate Generator constants:
const byte ledPin13 = 13;               // Arduino LED on pin 13

// Timed Pulse Constants:
const byte pulseApin11 = 11;     // Pulse A output on pin D11, PB5, Output Compare 1A
const byte pulseBpin12 = 12;     // Pulse B output on pin D12, PB6, Output Compare 1B

// Time Rate Generator variables:
volatile int count100ms;              // Counter to signal 100mS events (1000 of 100uS interrupts)
volatile int  countSec;               // Counter to signal 1 second events (10,000 of 100uS interrupts)
volatile byte state ;                 // Used to blink ledPin13 just for a visual indication that the program is running.

// Timed Pulse variables
volatile unsigned int timeDelayOff;  // Time to delay to pin LOW (microseconds x 2)
volatile unsigned int temp1;
volatile unsigned int temp2;


// Interrupt Service Routines:

// Time rate generator ISR:
// Timer2 Overflow Interrupt Vector, called when the timer overflows every 1mS
// Every 1mS Increment the 100 mS counter and the seconds counter
// Every 100 mS reset the 100mS counter
// Every second reset the 100mS counter, reset the seconds counter, toggle ledPin13

ISR(TIMER2_OVF_vect)
{ // Start of TIMER2_OVF_vect ISR 
  count100ms++;  // Increment the 100 mS counter
  countSec++;    // Increment the Seconds counter 

// Loop executed every 100mS (1mS x 100 = 100mS). Anything inside this if statement will run every 100mS.
      if(count100ms == 100) 
      { // Start of if(count100ms == 100)
        count100ms = 0; // Reset the 100mS counter.
        // 100mS code goes here
      } // End of if(count100ms == 100)

// Loop executed every 1 second (1mS x 1,000 = 1Sec). Anything inside this if statement will run every second.
        if(countSec == 1000) 
        { // Start of if(countSec == 1000)
          count100ms = 0; // Reset the 100mS counter.
          countSec = 0;   // Reset the seconds counter.

          digitalWrite(ledPin13, state); // Toggle the on board LED every second just to show the time rate generator is working
          state = !state;                // Toggle state

// Test timed pulse operation:
          timeDelayOff = 40000;             // 20 mS (.02Sec x 1,000,000 = 20,000uS x 2 = 40,000uS)

// Read Timer1 counter register, add timeDelayOff to it and write it into OCR1A
          noInterrupts();                   // Disable interrupts
          temp1 = TCNT1;                    // Read TCNT1 into temp1
          temp2 = temp1;                    // Read TCNT1 into temp2
          temp1 = (temp1 + timeDelayOff);   // Add timeDelayOff with TCNT1
          temp2 = (temp2 + timeDelayOff);   // Add timeDelayOff with TCNT1
          digitalWrite(pulseApin11, HIGH);  // pulseApin11 on
          OCR1A = temp1;                    // Copy result to OCR1A
          digitalWrite(pulseBpin12, HIGH);  //pulseBpin12 on
          OCR1B = temp2;                    // Copy result to OCR1B
          interrupts();                     // Enable interrupts
       //   TIMSK1 = TIMSK1 | B00000010;      // Enable OCR1A match interrupt 
       //   TIMSK1 = TIMSK1 | B00000100;      // Enable OCR1B match interrupt
          TIMSK1 = TIMSK1 | B00000110;      // Enable OCR1A and OCR1B match interrupts 
        } // End of if(countSec == 1000)

//Reset Timer2 to trigger in another ~100uS 
    TCNT2 = 131;     // Timer/Counter 2: //Preload timer2 with 131 cycles, leaving 125 till overflow. Testing shows this to be very close to a 1mS interrupt. 
    TIFR2 = 0x00;    // Timer/Counter 2 Interrupt Flag Register:  //Timer2 INT Flag Reg: Clear Timer Overflow Flag
} // End of TIMER2_OVF_vect ISR

// Timer1 Output Compare channel A ( Output compare flag is cleared automaticlly when ISR is executed) 
ISR(TIMER1_COMPA_vect) // Timer1 OC1A ISR vector
{
  digitalWrite(pulseApin11, LOW);         // pulseApin11 off
  TIMSK1 = (TIMSK1 & B11111101);          // Disable Timer1 output compare A match interrupt
}

// Timer1 Output Compare channel B (Output compare flag is cleared automaticlly when ISR is executed) 
ISR(TIMER1_COMPB_vect)  // Timer1 OC1B ISR vector
{
  digitalWrite(pulseBpin12, LOW);         //  pulseBpin12 off
  TIMSK1 = (TIMSK1 & B11111011);          // Disable Timer1 output compare B match interrupt
}

// Set up function (called only on initial power up or after a reset):
void setup()
{
  pinMode(ledPin13, OUTPUT);           // Declare  LED_BUILTIN an output
  digitalWrite(ledPin13, LOW);         // Initialize LED_BUILTIN LOW
  pinMode(pulseApin11, OUTPUT);        // Declare Pulse A output on pin D11, PB5, Output Compare 1A
  digitalWrite(pulseApin11, LOW);      // Initialize pulseApin11 low
  pinMode(pulseBpin12, OUTPUT);        // Declare Pulse B output on pin D12, PB6, Output Compare 1B
  digitalWrite(pulseBpin12, LOW);      // Initialize pulseBpin12 low

// Set up for Time Rate Generator ISR:
//Configure 8 bit Timer2 to interrupt every 100 microseconds: 
   TCCR2B = 0x00;  // Timer/Counter 2 Control Register B:      //Disable Timer2 while we set it up
   TCNT2  = 131;   // Timer/Counter 2: //Preload timer2 with 131 cycles, leaving 125 till overflow. Testing shows this to be very close to a 1mS interrupt. 
   TIFR2  = 0x00;  // Timer/Counter 2 Interrupt Flag Register: //Timer2 INT Flag Reg: Clear Timer Overflow Flag
   TIMSK2 = 0x01;  // Timer/Counter 2 Interrupt Mask Register: //Timer2 Set Overflow Interrupt enabled.
   TCCR2A = 0x00;  // Timer/Counter 2 Control Register A:      //Timer2 Control Reg A: Wave Gen Mode normal

   // 8 bit timers (n = timer number) (Timers 0 and 2)
   // 16,000,000 / prescale = Frequency
   // TCCRnB = B00000001: 16,000,000 / 1 = 16,000,000 Hz (16mHz) = .0625uS period * 256 = 16uS interrupt period
   // TCCRnB = B00000010: 16,000,000 / 8 = 2,000,000 Hz (2mHz) = .5uS period period * 256 = 128uS interrupt period
   // TCCRnB = B00000011: 16,000,000 / 32 = 500,000 Hz (500kHz) = 2uS period period * 256 = 512uS interrupt period * (50/256) = 100uS
   // TCCRnB = B00000100: 16,000,000 / 64 = 250,000 Hz (250kHz) = 4uS period = * 256 = 1,024uS interrupt period
   // TCCRnB = B00000101: 16,000,000 / 128 = 125,000 Hz (125kHz) = 8uS period = * 256 = 2,048uS interrupt period * (125/256) = 1mS
   // TCCRnB = B00000110: 16,000,000 / 256 = 62,500 Hz (62.5kHz) = 16uS period = * 256 = 4,096uS interrupt period
   // TCCRnB = B00000111: 16,000,000 / 1024 = 15,625 Hz (15.625kHz)= 64uS period = * 256 = 16,384uS interrupt period

   // TCCR2B = B00000001; // Prescale = 1  (16uS interrupt)
   // TCCR2B = B00000010; // Prescale = 2  (128uS interrupt)
   // TCCR2B = B00000011; // Prescale = 3  (512uS interrupt)
   // TCCR2B = B00000100; // Prescale = 4  (1024uS interrupt)
   // TCCR2B = B00000101; // Prescale = 5  (2048uS interrupt)
   // TCCR2B = B00000110; // Prescale = 6  (4096uS interrupt)
   // TCCR2B = B00000111; // Prescale = 7  (16,384uS interrupt)

// Now configure the prescaler to CPU clock divided by 128 = 125Khz 
   TCCR2B = B00000101; // Prescale = 5  (2048uS interrupt)

// Configure 16 bit Timer1 for pin D11 (OC1A) and pin D12 (OC1B) time delay off control:
  TCCR1B = B00000000;               // Disable Timer1 while we set it up
  TCNT1  = 0;                       // Zero Timer Count Register
  TIFR1  = B00000000;               // Timer1 INT Flag Register: Clear Timer Overflow Flag register
  TCCR1A = B00000000;               // Timer1 Control Register A: Wave Gen Mode normal  
  TIMSK1 = B00000000;               // Timer1 Interrupt Mask Register: Timer1 Overflow Interrupts disabled
// Now configure the prescaler to CPU clock divided by 2 = 2mHz and start the timer/counter 
  TCCR1B = B00000010;               // Prescale = 2  (.5uS increment)(max period before overflow 32.768mS.) 

}// End of setup()

// Main program loop function (runs in a continuous loop):  
void loop()
{ // Start of loop()
  // No code in here
} // End of loop()
      

I have no instant solution to your problem but here are some insights.

  1. You should know that ISR should be as short as it is possible.
  2. Interrupts are disabled automatically before enter into ISR.
  3. To enable the interrupts inside of ISR take a risk of immediate jump into another ISR of possible pending interrupt.
2 Likes

Thanks for the replies. I should have added that both pins are high at the same time for 9.5uS.

Its understandable that there will be delays getting both pins to go high, but why am I not getting the 20mS on delay that I am looking for? I can do another capture and take a screen shot if I am able to post it.

I don't think I'm making myself clear. The pins are only on for microseconds, not milliseconds. When I change the output compare value it makes no difference to the on time.

What is WGM?

Because I am using both channel A and channel B and will eventually be using them separately. I didn't want to stop the counter because that would affect the output compare times if they overlap. That's the reason I was adding the on time to the timer counter. Maybe there is a better way.

Waveform Generation Mode bits in Timer/Counter Control Register.
See the datasheet for 2560 and also in your code, right at the beginning.

@efinut
Few queries:
1 You have three outputs at DPins-11, 12, 13. What kind of signals you want to see on them? What is the timing relationship among them.

2. You are talking about Ch-A (DPin-9) and Ch-B (DPin-10) of TC1. What kind of signals you want to see on these channels - PWM? What is the relation of these signals with the signals of Step-1?*

3. TC2 is working as "Time Rate Generator"? Is it generating signals or 1-sec interval that will be used as an interrupting signal? What is the relation of this signal with other signals of Step-1, 2?

TC2 toggles Pin D13 every second in an interrupt. TC1 channels A and B are initiated within this interrupt. It's purpose is to create a time reference that I can see on my digital signal analyzer. I want to see pins 11 and 12 go high very shortly after pin 13 changes state and stay high for 20 milliseconds. I realize that there will be a short delay from the time pin 13 changes state to the time that pin 11 goes high, and another short delay until pin 12 goes high. I am seeing this, but both pins don't stay high for the commanded 20 mS.

Referring to my copy of A000067-full-pinout.PDF pin D12 should be OC1B and pin D11 should be OC1A

Does that answer your questions?

1. Does the diagram of Fig-1 describe in time scale (not to scale) what you have expressed in post #10?
tc1Mega
Figure-1:

2. Assuming that Step-1 is true, then the four signals are synchronized and could be created manually by bit-bang. I am not sure if TC1's PWM hardware could be used to achive these requirements!

3. You will not be able to generate 1 Hz signal using 8-bit TC2 (with fosc = 16 MHz and N = 1024). I wold recommend to use 16-bit TC3 for this purpose.

4. Possible solution using bit-bang.
(1) Use the 1 Hz output of TC3 to interrupt MEGA on INT0-pin on RISING edge.

(2) In the ISRINT0(), assert HIGH on DPin-11, 12, 13. Change the triggering mode of INT0 to FALLING edge.

(3) In the ISRINT0(), configure TC4 to generate 20 ms time delay. Keep monitoring if 20 ms has elapsed and then assert LOW on DPin-11, 12. Return from ISRINT0() to loop() and wait for interrupt.

(4) When next falling edge interrupt arrives, enter into ISRINT0(), assert LOW on DPin-13 and HIGH onDPin-11 & 12.

(5) Repeat the process.

5. If you like, you can convert the above steps into sketch/codes, run the sketch, chcek the timing relationship among the signals using scope, and report the result.

Unfortunately it does not. Is there anyway I can take a screen shot of my logic capture and post it?

How about that, it worked!. Anyway, the screen shot shows 3 traces. The bottom one is for D13, the middle one is D12 ands the top is D11. Cursor A1 aligns with the point in time that D13 changes state. D11 goes high approximately 9 microseconds later. D12 goes high approximately 9 microseconds after that. D11 goes low approximately 15 microseconds after it has gone high. D12 goes low approximately 18 microseconds after it has gone high. Total time from the point at which D13 changes state to when both D11 and D12 are low is only 36 microseconds. I am supposed to be getting a 20 millisecond on time. I'm completely baffled. I think it has something to do with the fact that I have the time rate generator running in the background that uses interrupts, but I haven't been able to track the problem down any more than that.

I re-wrote the test program to make it simpler and tried just setting a flag in the time reference interrupt so I could arm the timer in the main loop. Essentially no change from before so This will require a lot more thought.

// Arduino pin connections:
// ledPin13 = Arduino LED on pin 13 

// 80mS 50% duty square wave constants:
const byte ledPin13 = 13;               // Arduino LED on pin 13

// 80mS 50% duty square wave variables:
volatile int count16ms;              // Counter to signal 16mS events (5 of 16S interrupts = 80 mS)
volatile byte state ;                // Used to blink ledPin13 just for a visual indication that the program is running.

// Timed Pulse Constants:
const byte pulseApin11 = 11;     // Pulse A output on pin D11, PB5, Output Compare 1A

// Timed Pulse variables
volatile unsigned int timeDelayOff;  // Time to delay to pin LOW (microseconds x 2)
volatile unsigned int temp1;
volatile bool flag;

// Interrupt Service Routines:

// 80mS 50% duty square wave ISR:
// Timer2 Overflow Interrupt Vector, called when the timer overflows every 16mS
// Every 16mS Increment the 16mS counter
// Every 80 mS reset the 16mS counter and toggle ledPin13

ISR(TIMER2_OVF_vect)
{ // Start of (TIMER2_OVF_vect ISR) 
  count16ms++;  // Increment the 16 mS counter

// Loop executed every 800mS (16mS x 5 = 80mS). Anything inside this if statement will run every 80mS.
      if(count16ms == 5) 
      { // Start of if(count16ms == 5)
        count16ms = 0; // Reset the 16mS counter.
        digitalWrite(ledPin13, state); // Toggle the on board LED every 80 milliseconds just to show the time PWM generator is working
        state = !state;                // Toggle state
        flag = true;                   // Set flag true
      } // End of if(count16ms == 5)

//Reset Timer2 to trigger in another 16,384uS 
 
    TCNT2 = 6;     // Timer/Counter 2: //Preload timer2 with 6 cycles, leaving 250 till overflow. Testing shows this to be very close to a 16mS interrupt.
    TIFR2 = 0x00;    // Timer/Counter 2 Interrupt Flag Register:  //Timer2 INT Flag Reg: Clear Timer Overflow Flag

} // End of (TIMER2_OVF_vect ISR)

// Timer1 Output Compare channel A ( Output compare flag is cleared automaticlly when ISR is executed) 
ISR(TIMER1_COMPA_vect) // Timer1 OC1A ISR vector
{ // Start of TIMER1_COMPA_vect 
  digitalWrite(pulseApin11, LOW);         // pulseApin11 off
  TIMSK1 = (TIMSK1 & B11111101);          // Disable Timer1 output compare A match interrupt

} // End of TIMER1_COMPA_vect

// Set up function (called only on initial power up or after a reset):
void setup()
{ // Start of setup()
  pinMode(ledPin13, OUTPUT);         // Declare  LED_BUILTIN an output
  digitalWrite(ledPin13, LOW);       // Initialize LED_BUILTIN LOW
  pinMode(pulseApin11, OUTPUT);      // Declare Pulse A output on pin D11, PB5, Output Compare 1A
  digitalWrite(pulseApin11, LOW);    // Initialize pulseApin11 low

  flag = false;                      // Initialize flag false
  timeDelayOff = 40000;             // 20 mS (.02Sec x 1,000,000 = 20,000uS x 2 = 40,000uS)

// Set up for 80mS 50% duty square wave ISR:
//Configure 8 bit Timer2 to interrupt every 16 microseconds: 
   TCCR2B = 0x00;  // Timer/Counter 2 Control Register B:      //Disable Timer2 while we set it up
   TCNT2  = 6;   // Timer/Counter 2: //Preload timer2 with 6 cycles, leaving 250 till overflow. Testing shows this to be very close to a 16mS interrupt. 
   TIFR2  = 0x00;  // Timer/Counter 2 Interrupt Flag Register: //Timer2 INT Flag Reg: Clear Timer Overflow Flag
   TIMSK2 = 0x01;  // Timer/Counter 2 Interrupt Mask Register: //Timer2 Set Overflow Interrupt enabled.
   TCCR2A = 0x00;  // Timer/Counter 2 Control Register A:      //Timer2 Control Reg A: Wave Gen Mode normal

   // 8 bit timers (n = timer number) (Timers 0 and 2)
   // 16,000,000 / prescale = Frequency
   // TCCRnB = B00000001: 16,000,000 / 1 = 16,000,000 Hz (16mHz) = .0625uS period * 256 = 16uS interrupt period
   // TCCRnB = B00000010: 16,000,000 / 8 = 2,000,000 Hz (2mHz) = .5uS period period * 256 = 128uS interrupt period
   // TCCRnB = B00000011: 16,000,000 / 32 = 500,000 Hz (500kHz) = 2uS period period * 256 = 512uS interrupt period * (50/256) = 100uS
   // TCCRnB = B00000100: 16,000,000 / 64 = 250,000 Hz (250kHz) = 4uS period = * 256 = 1,024uS interrupt period
   // TCCRnB = B00000101: 16,000,000 / 128 = 125,000 Hz (125kHz) = 8uS period = * 256 = 2,048uS interrupt period * (125/256) = 1mS
   // TCCRnB = B00000110: 16,000,000 / 256 = 62,500 Hz (62.5kHz) = 16uS period = * 256 = 4,096uS interrupt period
   // TCCRnB = B00000111: 16,000,000 / 1024 = 15,625 Hz (15.625kHz)= 64uS period = * 256 = 16,384uS interrupt period

   // TCCR2B = B00000001; // Prescale = 1  (16uS interrupt)
   // TCCR2B = B00000010; // Prescale = 2  (128uS interrupt)
   // TCCR2B = B00000011; // Prescale = 3  (512uS interrupt)
   // TCCR2B = B00000100; // Prescale = 4  (1024uS interrupt)
   // TCCR2B = B00000101; // Prescale = 5  (2048uS interrupt)
   // TCCR2B = B00000110; // Prescale = 6  (4096uS interrupt)
   // TCCR2B = B00000111; // Prescale = 7  (16,384uS interrupt)

// Now configure the prescaler to CPU clock divided by 1024 = 15,625Khz (64uS period) 
   TCCR2B = B00000111; // Prescale = 7  (2048uS interrupt)

// Configure 16 bit Timer1 for pin D11 (OC1A) time delay off control:
  TCCR1B = B00000000;               // Disable Timer1 while we set it up
  TCNT1  = 0;                       // Zero Timer Count Register
  TIFR1  = B00000000;               // Timer1 INT Flag Register: Clear Timer Overflow Flag register
  TCCR1A = B00000000;               // Timer1 Control Register A: Wave Gen Mode normal  
  TIMSK1 = B00000000;               // Timer1 Interrupt Mask Register: Timer1 Overflow Interrupts disabled
// Now configure the prescaler to CPU clock divided by 2 = 2mHz and start the timer/counter 
  TCCR1B = B00000010;               // Prescale = 2  (.5uS increment)(max period before overflow 32.768mS.) 

}// End of setup()

// Main program loop function (runs in a continuous loop):  
void loop()
{ // Start of loop()
 if(flag == true)
 { // Start of if(flag == true) 
// Read Timer1 counter register, add timeDelayOff to it and write it into OCR1A
  noInterrupts();                   // Disable interrupts
  temp1 = TCNT1;                    // Read TCNT1 into temp1
  temp1 = (temp1 + timeDelayOff);   // Add timeDelayOff with TCNT1
  OCR1A = temp1;                    // Copy result to OCR1A
  digitalWrite(pulseApin11, HIGH);  // pulseApin11 on
  interrupts();                     // Enable interrupts
  TIMSK1 = TIMSK1 | B00000010;      // Enable OCR1A match interrupt 
  flag = false;

 } // End of if(flag == true)
} // End of loop()
      

1. Do you agree that the timing relationships among your four signals (as depicted in Fig-1 of post #11) are alright?

2. The algorithm that I have provided in post #11 does not provide the expected realionship -- correct?

The timing relationships in post 11 are not correct. Hopefully my screen shots will clear that up. I did not try the algorithm you posted because I'm assuming that it would depend on the relationships in post 11 being correct.

I was under the impression that the interrupt flag was cleared automatically when the ISR is serviced, but I'll see if I can do it manually. What you are saying makes sense to me though.

Can you hand draw a timing digram (clearly showing cause and effect) and post it here?

If it is a polled interrupt, then the interrupt flag is to be cleared manually. In vectored interrupt, the interrupt flag is automatically cleared when the processor makes a return to mainline program.

It looks like your suggestion worked so far. I'll keep working to try and refine it. Thanks so much for your efforts, I really was bogged down with this. Here is the modified code:

// TimedPulseTest-05-20-24.ino
// Modified 05-21-24 interrupt flag cleared manually line 116.  This code is working 


// Arduino pin connections:
// ledPin13 = Arduino LED on pin 13 

// 80mS 50% duty square wave constants:
const byte ledPin13 = 13;               // Arduino LED on pin 13

// 80mS 50% duty square wave variables:
volatile int count16ms;              // Counter to signal 16mS events (5 of 16S interrupts = 80 mS)
volatile byte state ;                // Used to blink ledPin13 just for a visual indication that the program is running.

// Timed Pulse Constants:
const byte pulseApin11 = 11;     // Pulse A output on pin D11, PB5, Output Compare 1A

// Timed Pulse variables
volatile unsigned int timeDelayOff;  // Time to delay to pin LOW (microseconds x 2)
volatile unsigned int temp1;
volatile bool flag;

// Interrupt Service Routines:

// 80mS 50% duty square wave ISR:
// Timer2 Overflow Interrupt Vector, called when the timer overflows every 16mS
// Every 16mS Increment the 16mS counter
// Every 80 mS reset the 16mS counter and toggle ledPin13

ISR(TIMER2_OVF_vect)
{ // Start of (TIMER2_OVF_vect ISR) 
  count16ms++;  // Increment the 16 mS counter

// Loop executed every 800mS (16mS x 5 = 80mS). Anything inside this if statement will run every 80mS.
      if(count16ms == 5) 
      { // Start of if(count16ms == 5)
        count16ms = 0; // Reset the 16mS counter.
        digitalWrite(ledPin13, state); // Toggle the on board LED every 80 milliseconds just to show the time PWM generator is working
        state = !state;                // Toggle state
        flag = true;                   // Set flag true
      } // End of if(count16ms == 5)

//Reset Timer2 to trigger in another 16,384uS 
 
    TCNT2 = 6;     // Timer/Counter 2: //Preload timer2 with 6 cycles, leaving 250 till overflow. Testing shows this to be very close to a 16mS interrupt.
    TIFR2 = 0x00;    // Timer/Counter 2 Interrupt Flag Register:  //Timer2 INT Flag Reg: Clear Timer Overflow Flag

} // End of (TIMER2_OVF_vect ISR)

// Timer1 Output Compare channel A ( Output compare flag is cleared automaticlly when ISR is executed) 
ISR(TIMER1_COMPA_vect) // Timer1 OC1A ISR vector
{ // Start of TIMER1_COMPA_vect 
  digitalWrite(pulseApin11, LOW);         // pulseApin11 off
  TIMSK1 = (TIMSK1 & B11111101);          // Disable Timer1 output compare A match interrupt

} // End of TIMER1_COMPA_vect

// Set up function (called only on initial power up or after a reset):
void setup()
{ // Start of setup()
  pinMode(ledPin13, OUTPUT);         // Declare  LED_BUILTIN an output
  digitalWrite(ledPin13, LOW);       // Initialize LED_BUILTIN LOW
  pinMode(pulseApin11, OUTPUT);      // Declare Pulse A output on pin D11, PB5, Output Compare 1A
  digitalWrite(pulseApin11, LOW);    // Initialize pulseApin11 low

  flag = false;                      // Initialize flag false
  timeDelayOff = 40000;             // 20 mS (.02Sec x 1,000,000 = 20,000uS x 2 = 40,000uS)

// Set up for 80mS 50% duty square wave ISR:
//Configure 8 bit Timer2 to interrupt every 16 microseconds: 
   TCCR2B = 0x00;  // Timer/Counter 2 Control Register B:      //Disable Timer2 while we set it up
   TCNT2  = 6;   // Timer/Counter 2: //Preload timer2 with 6 cycles, leaving 250 till overflow. Testing shows this to be very close to a 16mS interrupt. 
   TIFR2  = 0x00;  // Timer/Counter 2 Interrupt Flag Register: //Timer2 INT Flag Reg: Clear Timer Overflow Flag
   TIMSK2 = 0x01;  // Timer/Counter 2 Interrupt Mask Register: //Timer2 Set Overflow Interrupt enabled.
   TCCR2A = 0x00;  // Timer/Counter 2 Control Register A:      //Timer2 Control Reg A: Wave Gen Mode normal

   // 8 bit timers (n = timer number) (Timers 0 and 2)
   // 16,000,000 / prescale = Frequency
   // TCCRnB = B00000001: 16,000,000 / 1 = 16,000,000 Hz (16mHz) = .0625uS period * 256 = 16uS interrupt period
   // TCCRnB = B00000010: 16,000,000 / 8 = 2,000,000 Hz (2mHz) = .5uS period period * 256 = 128uS interrupt period
   // TCCRnB = B00000011: 16,000,000 / 32 = 500,000 Hz (500kHz) = 2uS period period * 256 = 512uS interrupt period * (50/256) = 100uS
   // TCCRnB = B00000100: 16,000,000 / 64 = 250,000 Hz (250kHz) = 4uS period = * 256 = 1,024uS interrupt period
   // TCCRnB = B00000101: 16,000,000 / 128 = 125,000 Hz (125kHz) = 8uS period = * 256 = 2,048uS interrupt period * (125/256) = 1mS
   // TCCRnB = B00000110: 16,000,000 / 256 = 62,500 Hz (62.5kHz) = 16uS period = * 256 = 4,096uS interrupt period
   // TCCRnB = B00000111: 16,000,000 / 1024 = 15,625 Hz (15.625kHz)= 64uS period = * 256 = 16,384uS interrupt period

   // TCCR2B = B00000001; // Prescale = 1  (16uS interrupt)
   // TCCR2B = B00000010; // Prescale = 2  (128uS interrupt)
   // TCCR2B = B00000011; // Prescale = 3  (512uS interrupt)
   // TCCR2B = B00000100; // Prescale = 4  (1024uS interrupt)
   // TCCR2B = B00000101; // Prescale = 5  (2048uS interrupt)
   // TCCR2B = B00000110; // Prescale = 6  (4096uS interrupt)
   // TCCR2B = B00000111; // Prescale = 7  (16,384uS interrupt)

// Now configure the prescaler to CPU clock divided by 1024 = 15,625Khz (64uS period) 
   TCCR2B = B00000111; // Prescale = 7  (2048uS interrupt)

// Configure 16 bit Timer1 for pin D11 (OC1A) time delay off control:
  TCCR1B = B00000000;               // Disable Timer1 while we set it up
  TCNT1  = 0;                       // Zero Timer Count Register
  TIFR1  = B00000000;               // Timer1 INT Flag Register: Clear Timer Overflow Flag register
  TCCR1A = B00000000;               // Timer1 Control Register A: Wave Gen Mode normal  
  TIMSK1 = B00000000;               // Timer1 Interrupt Mask Register: Timer1 Overflow Interrupts disabled
// Now configure the prescaler to CPU clock divided by 2 = 2mHz and start the timer/counter 
  TCCR1B = B00000010;               // Prescale = 2  (.5uS increment)(max period before overflow 32.768mS.) 

}// End of setup()

// Main program loop function (runs in a continuous loop):  
void loop()
{ // Start of loop()
 if(flag == true)
 { // Start of if(flag == true) 
// Read Timer1 counter register, add timeDelayOff to it and write it into OCR1A
  noInterrupts();                   // Disable interrupts
  TIFR1 = TIFR1 |= B00000010;       // Set OCF1A to 1 to clear interrupt flag
  temp1 = TCNT1;                    // Read TCNT1 into temp1
  temp1 = (temp1 + timeDelayOff);   // Add timeDelayOff with TCNT1
  OCR1A = temp1;                    // Copy result to OCR1A
  digitalWrite(pulseApin11, HIGH);  // pulseApin11 on
  TIMSK1 = TIMSK1 | B00000010;      // Enable OCR1A match interrupt
  interrupts();                     // Enable interrupts 
  flag = false;

 } // End of if(flag == true)
} // End of loop()
      

Thanks. I've seen that used before but I don't speak C or C++ and I am struggling to learn the Arduino language. Looking at it now it does make sense. Thanks again for all your help.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.