Behavior of interrupt handler?

I have a sketch for testing timers on Due. Timer8 generates an interrupt when RA is loaded. The interrupt handler is

void TC8_Handler()                                // ISR TC8 (TC2 Channel 2)
{
  if (TC2->TC_CHANNEL[2].TC_SR & TC_SR_LDRAS)     // Check for RA load condition
  {
    introk = 1;
    frequ = TC2->TC_CHANNEL[2].TC_RA;
  }
}

In loop variable freq is displayed on the Serial Monitor:

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

  if (introk) {   // in case of interrupts
    introk=0;
    Serial.print("f=");Serial.println(frequ);
  }
}

This works well.

But when I comment the if statement within interrupt handler there are'nt any interrupts at all.

void TC8_Handler()                                // ISR TC8 (TC2 Channel 2)
{
//  if (TC2->TC_CHANNEL[2].TC_SR & TC_SR_LDRAS)     // Check for RA load condition
//  {
    introk = 1;
    frequ = TC2->TC_CHANNEL[2].TC_RA;
//  }
}

Condition "RA load" is the only condition to generate interrupts.
Why are interrupts stopping?

(if anybody wants to test it on its Due I could provide the complete sketch)

Is introk declared as volatile?

yes it is declared as volatile.


Is introk a single byte data type?


Why not go ahead and

provide the complete sketch

or a deuces yet complete example sketch that demonstrates your issue?

a7

Here is the complete sketch for measuring frequency on a Due.
Explanations at the beginning of code in English in short:
" Timer7 generates a 1 sec gate signal on TIOA7 output (D3). This output shall be connected with TIOA8 input (D11) of Timer8. Timer8 is counting the frequency on TCLK8 input (D30). The signal on TIOA7 is triggering the counter in Timer8. Falling edge of this signal loads RA which then contains frequency in Hz."

#include <Arduino.h>

#define PROCTIME (15000)    // time between measurements
volatile uint8_t introk=0;
volatile uint32_t frequ=0;

void setup() {
  Serial.begin(19200);

  /* Timer7 erzeugt ein 1 sec Gatesignal auf TIOA7, das mit dem
     Eingang TIOA8 von Timer8 verbunden wird.
   Timer8 zählt die Takte der Eingangsfrequenz an TCLK8 waehrend
    der Gatezeit von 1 sec.
   Der Counter von Timer8 wird vom TIOA8-Eingang so gesteuert, dass
    er jeweils mit der positiven Flanke getriggert wird (zuruecksetzen
    und starten). Mit der negativen Flanke an TIOA8 wird der Counterwert
    nach Register A uebernommen und ein Interrupt ausgeloest, der den
    Inhalt von Register A in die Variable frequ speichert.
   TIOA7 auf D3/PC28/peripheral B, TIOA8 auf D11/PD7/peripheral B,
   TCLK8 auf D30/PD9/peripheral B. 
  */
  
  // Clocks fuer TC7 und TC8 aktivieren:
  PMC->PMC_PCER1 |= PMC_PCER1_PID34 | PMC_PCER1_PID35;  // clock Timer Counter Channel 7 & 8
  
  // Pin fuer TIOA7 konfigurieren:
  PIOC->PIO_ABSR |= PIO_ABSR_P28;     // Switch the multiplexer on pin PC28 to peripheral B (TIOA7)
  PIOC->PIO_PDR |= PIO_PDR_P28;       // Disable the GPIO on pin PC28
  // Pins fuer TCLK8 und TIOA8 konfigurieren:
  PIOD->PIO_ABSR |= PIO_ABSR_P7;     // Switch the multiplexer on pin PD7 to peripheral B (TIOA8)
  PIOD->PIO_PDR |= PIO_PDR_P7;       // Disable the GPIO on TIOA8
  PIOD->PIO_ABSR |= PIO_ABSR_P9;     // Switch the multiplexer on pin PD9 to peripheral B (TCLK8)
  PIOD->PIO_PDR |= PIO_PDR_P9;       // Disable the GPIO on pin PD9
  
  // TC7 (Modul 2, Channel 1) auf Wave Mode :
  TC2->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK4 |  // MCK/128 = 656250 Hz
                              TC_CMR_WAVSEL_UP_RC |         // cnt up, RC compare triggers
                              TC_CMR_WAVE |                 // set wave mode
                              TC_CMR_ACPA_SET |             // RA compare sets TIOA to high
                              TC_CMR_ACPC_CLEAR |           // RC compare sets TIOA to low
                              TC_CMR_ASWTRG_CLEAR;          // SW trigger sets TIOA to low
  TC2->TC_CHANNEL[1].TC_RA = PROCTIME;
  TC2->TC_CHANNEL[1].TC_RC = 656250 + PROCTIME;

//  TC8 (Modul 2, Channel 2) auf Capture Mode:
  TC2->TC_BMR = TC_BMR_TC2XC2S_TCLK2;                   // TCLK2 of TC-Modul2 to XC2
  TC2->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_XC2 |       // clock TCLK8 on XC2
                              TC_CMR_ETRGEDG_RISING |   // rising edge on TIOA triggers counter
                              TC_CMR_ABETRG |           // TIOA is external trigger
                              TC_CMR_LDRA_FALLING ;     // RA load on falling edge on TIOA
  TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_CLKEN;             // enable clock
  NVIC_EnableIRQ(TC8_IRQn);         // Connect TC8 to Nested Vector Interrupt Controller (NVIC)
  NVIC_SetPriority(TC8_IRQn, 8);    // Set the NVIC priority for TC8 to 8 (medium) 
  TC2->TC_CHANNEL[2].TC_IER |= TC_IER_LDRAS;  // enable interrupt of TC8 on RA loading
  TC2->TC_CHANNEL[2].TC_IMR |= TC_IER_LDRAS;  // set interrupt mask of TC8 on RA loading

  // Enable clock and trigger Timer7:
  TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;
}

void TC8_Handler()                                // ISR TC8 (TC2 Channel 2)
{
  if (TC2->TC_CHANNEL[2].TC_SR & TC_SR_LDRAS)     // Check for RA load condition
  {
    introk = 1;
    frequ = TC2->TC_CHANNEL[2].TC_RA;
  }
}

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

  if (introk) {   // in case of interrupts
    introk=0;
    Serial.print("f=");Serial.println(frequ);
  }
}

If you have a Due you can measure frequency very accurately, but only if the if statement in TC8_Handler() is not commented.
IMO the if statement should not be necessary, but really it is necessary - who knows why?

Why did you decide that there are no interrupts? Due to the lack of freq value?

I think that the interrupts still firing, but without condition you get the freq value at the wrong moment.

A good rule that if you don't understand the code - do not "optimize" it :slight_smile:

With the if statement commented there are no outputs to the Serial Monitor. Without such outputs there are no interrupts.

If the interrupt fires then variable introk will be set to 1. And within loop() there will be an output to the Serial Monitor only if introk is set, i.e. if there was an interrupt. Repetition period of interrupts is about 1 sec. Therefore loop() will easyly get every interrupt.

Concerning

wrong moment

The interrupt is defined to fire in the moment when RA is loaded with the counter value at that moment. RA will keep this value for little bit more than a second before the next load will happen. loop() has a lot of time to check if introk is set. How could this checking happen at a wrong moment?

Meantime I added toggling the built in LED within TC8_Handler():

void TC8_Handler()                                // ISR TC8 (TC2 Channel 2)
{
  if (TC2->TC_CHANNEL[2].TC_SR & TC_SR_LDRAS)     // Check for RA load condition
  {
    introk = 1;
    frequ = TC2->TC_CHANNEL[2].TC_RA;
  }
  LEDon = !LEDon;
  digitalWrite(13, LEDon);
}

LEDon is declared volatile boolean. In the version as shown above the LED is blinking.
With the if statement commented the LED is constantly on but with low brightness as if it were toggled with PWM with long low period.

My interpretation of this effect is that the Due controller is busy with interrupts.
Or what else could happen?

My assumption that the Due controller is busy with interrupts now is confirmed.
I measured with an oscilloscope at the LED pin and saw a 188 kHz on/off.

Finally reading the Due manual got the solution. Explanations for the status register say: LDRAS: RA Loading Status (cleared on read)
The bit LDRAS is cleared when read and remains on when not read !

1 Like

Good catch :slight_smile:
But your initial idea that there are no interrupts without condition was wrong :slight_smile: Interrupts still firing.

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