Interrupt Priority Structure

Hi…
Before asking this question can I simply state been designing’s Process control RTOS system for >40 years so do understand Interrupt structures but am getting a strange phenomena and wonder if its to do with the Ardunino run time libraries, don’t want to have to plow through code if I don’t need to… System current developed on a Mega Arduino Board.

  1. The system is designed with my own process run time based on time division multiplex of processes, i.e little bits of each every time round the void back ground loop…

  2. I have a Timer3 overflow Interrupt running at 20mS - latency to Interrupt ?
    ISR routine < 1mS run time as measured with logic analysis by fire output on entry and reset on exit so no chance of re-entry problems .

  3. Edge Triggered Interrupt from a sensor ISR run time between 6 and 8 mS frequency of interrupt > 4 Seconds so again re-entrancy problems non existent,but for safety I disable the triggered interrupt until data recovery completed.

System design classical, all algorithmic computations in background loop, Interrupts only provide up to date data they do not try and compute answers.

Now on this system in 99% of time brilliant, the background loop computation time gives it a cycle of 12-14 mS the two Interrupts function in collaboration, never experienced any problems, the system response to its other input/output well within the customers specifications. The 20mS time is used mainly for watchdogs on the processes and no faults provided hardware is functioning are detected.

However, in one point, during a recalibration the background is shut down to a very short internal while loop in one of the processes. I have measure and rather than the normal 12-14mS it is down to 0.4 mS.

When this happens the Edge triggered Interrupt is never getting a look in? The hardware edge occurs but the ISR is never actioned ?
If I put a 1mS delay in the background thereby stretch it to 1.4mS all comes back working?

Reading chip spec can’t come to any conclusion as to why, All I can think is something to do with the run time extras from the library. Is there some problem with tight background looks.

Code snippets show the interrupt set up, and ISR outlines

Anyone got detail knowledge of these run time additions…

This code is a test set not the actual code as the system is commercial in confidence, I have signed a full non disclosure, so can’t post but this code exhibits exactly the same fault --I am generating an edge interrupt from a touch screen
Timer 3 interrupt code

void RTInterrupt::begin(int f)
{
    _timer3_counter = CountValue(f);
    TCCR3A = 0;
    TCCR3B = 0;
    // set up interrupt on overflow..
    TCNT3 = _timer3_counter;   // preload timer
    TCCR3B |= (1 << CS12);    // 256 prescaler
    TIMSK3 |= (1 << TOIE1);   // enable timer overflow interrup
    // enable all interrupts
    _Second = 50;
    _HalfSecond = 25;
    
}
void RTInterrupt::setValue(int val) {TCNT3 = val;}

ISR(TIMER3_OVF_vect)        // interrupt service routine read all serial Ports
{
    int diff;
    int No;
    digitalWrite(2,HIGH);
    diff= RTInterrupt::GetValue();
    RTInterrupt::setValue(diff);
    _HalfSecond--;
    if (_HalfSecond<0)
    {
        _HalfSecond=25;
    }
    _Second--;
    if (_Second <0)
    {
        _Second = 50;
        if (TouchTimer > 0)
            TouchTimer--;
        else
        {
            if (Touch->TouchStatus() != NoTouch)
            {
                Touch->SetTouchStatus(NoTouch);
                Touch->TouchEnableInterrupt();
            }
        }
      }
    digitalWrite(2,LOW);
}

the digital writes on Pin two are for timing reference only.

The int4 set up

    EICRB = 0x10; // FALLING edge
    EIMSK = EIMSK | 0X10; //enable int 4
//void touchevent()
ISR(INT4_vect)
{
    if ( _TouchStatus == NoTouch)
    {
        EIMSK = EIMSK & 0xEF;  // DISABLE
        TouchTimer = 1;
        Ptr->ReadTouch();
        _TouchStatus = ScreenTouch;
    }
}

A loop of code called from the void look

    Done = false;
    while (Done == false)
    {
        if (Touch->TouchStatus()!= NoTouch)
        {
            showln("exit");
            Touch->SetTouchStatus(NoTouch);
            Touch->TouchEnableInterrupt();
            Done =true;
        }
        delay (1);
        
    }

Without the delay no interrupts with the delay works…Any run time experts…

Can live with delay but would rather loose it not a lover if fiddles to make code work

BTW the code snippets are from EmbedX code , the standard IDE is no use on systems such as this with >3 thousand lines code, but have run this test directly on 1.0.5 and 1.5 IDE same strange behavior…

Regards and happy coding 8) 8)

Before asking this question can I simply state been designing's Process control RTOS system for >40 years

Then, it's hard to believe that you can't call a function a function. IT IS NOT A VOID.

If thats your only contribution a mistake in a comment then I feel sad for you ............

A loop of code called from the void look

As far as we're concerned, "look" really is a void, because you didn't post it.

Once again its meaningless typo I have Parkingsons so odd typo do occur..
If you can't look beyond typos in words which should have said Called from main Sketch void loop ....

Its not important, the question related to why does a tight background loop inhibit the Interrupts perhaps thats more to your liking..

BTW in true C++ the only form EmbedXcode accepts there are no functions. every thing is based as it should be re ISO standard ( a committee I was a member of for a number of years ), on Object Methods.

The Arduino IDE is a great starting point for turning on/off LED's but to do something serious the fiddles it automatically generates hide the true nature of large system development. including the true structure of a C++ solution. However I applaud its simplicity for the newbie IDE's such as VStudio or Xcode are far to complex and syntax and semantics demanding for people with little or no formal programming skills.

I think the problem I am seeing relates to the hidden nature of the arduino fiddles, in this case within the run time library, what I am trying to do is

a. highlight the problem
b. Ensure my solutions do not have fiddle delays I do not understand simply to cover short coming..

It isn't a typo, it's a complete omission of the code for a function called "look".
Unless you can post a sketch that demonstrates your problem, it's all just hand-waving.

What more do you want .. without the external interrupt stimulus such sketch would be meaningless, my question related to an understanding of the run time library .. have you got any references to that you can offer, I have started to pick it apart but that's a long slow process.

Any attempt to run a stand alone sketch without the external event generation would change the dynamics of the Interrupt structure, I built one trying to use one output to feed another input as the external event, but the extra timing to drive the output in the background loop was enough to alter the dynamics so it worked.

Obviously I have no idea of your understanding of Interrupt driven systems they require a great deal of thought in design, the timing dynamics alter dependent on code run times both of the ISR the latency to ISR after event, finally the latency to return from ISR. Interrupting Interrupts create a further dimension to the problem, this is where I believe the problem resides..

Anyone have any discussion reference to Interrupt priority run time library ?
8) 8)

I am re posting this since the original thread got right off topic, it also did not have a Sketch that demonstrated how the problem manifests itself.

This Trivial example using only a single OVF interrupt locks out the Interrupt ISR without the delay (currently commented out in the background loop) nothing appears to be running…

Un comment the delay, the Serial output as expected prints out the seconds…

// Simple Sketch to demonstrate Interrupt lock out problem 
// The background void loop is so tight it apparently locks the ability to get Interrupts, which according to the chip spec is not a // // //function unless you use masks or the Global Interrupt enable flag..
// The sketch sets up a Timer 3 interrupt at 20mS 
//The ISR only counts the interrupts and at 50 count = 1 second increments a variable
// The background loop  compares the counted variable to the last Printed value when different prints the new value
//  Then Updates the held value..

#define RTCFREQ 50  // try 20ms seems reasonable
#define CountValue(freq)  65536- ((16000000/256)/freq)  // simple macro to calculate counter value

int SecondCounter;
int IntCounter;
int DisplayCounter;
int timer3counter;

// Interrupt set Up Function

void RTCInit(int f)
{
  timer3counter = CountValue(f);
  TCCR3A = 0;
  TCCR3B = 0;
  // set up interrupt on overflow.. 
  TCNT3 = timer3counter;   // preload timer
  TCCR3B |= (1 << CS12);    // 256 prescaler      
  TIMSK3 |= (1 << TOIE1);   // enable timer overflow interrupt
  SecondCounter= 50;    // Initialise count of 1 secxond
}
/// ISR for timer3 overflow
ISR(TIMER3_OVF_vect)      
{ 
  TCNT3 = timer3counter; // Reload counter
  SecondCounter --;
  if (SecondCounter == 0)
  {
    SecondCounter = 50;  // had required number Interrupts so reset and update data
    IntCounter ++;
  }
}
void setup()
{
  Serial.begin (9600);
  IntCounter = 0;
  DisplayCounter =0;
  RTCInit(RTCFREQ);    // simple initialise of variables
}

// Back Ground loop
void loop()
{
  int a;
  while (true)  // force a tight loop within Background
  {
    if (IntCounter == DisplayCounter)  // check if two variables the same
      a =1;  // effectively do nothing real.. in that condition
    else
    {
      Serial.println( IntCounter);  // display via Serial value
      DisplayCounter = IntCounter; // update display value
    }
    //delay(1);  // without this the above Serial output does not occur..
  }
}

Yes this is very contrived example, but in my real world example the background loop is stopped during a phase of calibration and this condition occurs not only on the timer interrupt but also on an edge triggered input on INT 4

My question is why ? What aspect of the run time is locking the interrupts

I have tried running interrupts disabled both Global and specific Interrupt masking whilst doing the comparison to create mutual exclusion so value can’t be updated by interrupt during comparison no difference, the collision possibility in this example is remote the ISR takes only a few micro Seconds in this case…i.e.s it could happen but not every time you run the sketch.

With the 1mS delay in the background 100% success had this demo running for several hours…

Any ideas …

Both IntCounter and DisplayCounter are modified by the interrupt routine and should therefore be declared volatile so that the compiler doesn't try to optimize them into registers.

volatile int IntCounter;
volatile int DisplayCounter;

Pete

Agreed but try it it makes no difference..

I did try it, that’s why I posted. But I do not have a Mega - I tried it on a Teensy2 which fails without the volatile and works fine with it.
Even if specifying volatile in that specific doesn’t work for you, you must use it.

Pete

In the real system its a class based system compiled using EmbedXcode

All the data is private within the class so optimization to registers would not be a problem..

Will have a play with volatile but never considered it necessary in full OO compilation.. It used to be true in C ..

cheers anyway..

Just tried to volatile specify data in loop which fails no success.

Is there a switch within ide to get assembler listing ?

Would like to review output for context switch .. can't see how register optimization effect context since register values must be stacked to create the ISR return stack frame...

Just tried to volatile specify data in loop

I don’t know what that means.

Does this code work?

// Simple Sketch to demonstrate Interrupt lock out problem 
// The background void loop is so tight it apparently locks the ability to get Interrupts, which according to the chip spec is not a // // //function unless you use masks or the Global Interrupt enable flag..
// The sketch sets up a Timer 3 interrupt at 20mS 
//The ISR only counts the interrupts and at 50 count = 1 second increments a variable
// The background loop  compares the counted variable to the last Printed value when different prints the new value
//  Then Updates the held value..

#define RTCFREQ 50  // try 20ms seems reasonable
#define CountValue(freq)  65536- ((16000000/256)/freq)  // simple macro to calculate counter value

volatile int SecondCounter;
volatile int IntCounter;
int DisplayCounter;
int timer3counter;

// Interrupt set Up Function

void RTCInit(int f)
{
  timer3counter = CountValue(f);
  TCCR3A = 0;
  TCCR3B = 0;
  // set up interrupt on overflow.. 
  TCNT3 = timer3counter;   // preload timer
  TCCR3B |= (1 << CS12);    // 256 prescaler      
  TIMSK3 |= (1 << TOIE1);   // enable timer overflow interrupt
  SecondCounter= 50;    // Initialise count of 1 secxond
}
/// ISR for timer3 overflow
ISR(TIMER3_OVF_vect)      
{ 
  TCNT3 = timer3counter; // Reload counter
  SecondCounter --;
  if (SecondCounter == 0)
  {
    SecondCounter = 50;  // had required number Interrupts so reset and update data
    IntCounter ++;
  }
}
void setup()
{
  Serial.begin (9600);
  IntCounter = 0;
  DisplayCounter =0;
  RTCInit(RTCFREQ);    // simple initialise of variables
}

// Back Ground loop
void loop()
{
  int a;
  while (true)  // force a tight loop within Background
  {
    if (IntCounter == DisplayCounter)  // check if two variables the same
      a =1;  // effectively do nothing real.. in that condition
    else
    {
      Serial.println( IntCounter);  // display via Serial value
      DisplayCounter = IntCounter; // update display value
    }
    //delay(1);  // without this the above Serial output does not occur..
  }
}

Pete

Is there a switch within ide to get assembler listing ?

Not a switch, a utility... You pass the ELF file to it...
General porocessshown here:

Cheers just what i needed now some serious detective work on why the problem
8) 8)

Pete..
No that was what I tried ..

just generate the assembler some strange quirks need to investigate more fully tomorrow.. off to bed know..

cheers

Update
Having spent several hours on Assembler listing..

  1. As I suspected use of Volatile has no significance .. It does alter the declaration of the data but actual access in this case is the same both in background and in ISR.. it may be difference in other scenarios.

  2. Reviewing the ISO standard, Volatile was included fundamentally for Memory Mapped devices for instance the 8086 I/O page

  3. The two solutions with / without Volatile are there for fundamentally the same, the difference comes with / without the delay call, in back ground, there is a difference in the ISR stack frame which is most strange, obviously the auto stacking must take place at context switch, but with the delay theres additional stacking before the delay call .. probably to be expected, but also extra unstacking on ISR exit.?

I am at a loss to explain, without an understanding of the linkage requirements of the run time libraries..

I can live with the delay call in this instance so I am not going to pursue. Is it a bug> who knows.. is it related to GCC or the library who knows >

I thought I should at the least identify it can happen..