Jump to content
43oh

How to deal with LPM and ISRs in a clean way?


Recommended Posts

Hi,

This is really about basics, however if I don't ask I won't know the answer ;-) 

How do you deal with LPM and ISRs in a clean and readable way?

 

Say you have a product that does measurements on multiple sensors; one are I2C ones, the other are ADC-based, yet the other are simple timer-capture-based impulse counters. They basically should  work sequentially, not simultaneously.

 

The problem I have is like this (pseudo code):

0: {
1: setUpSensor();
2: enterLPM0();
3: startMeasurement();
4: enterLPM0();
5: }

ISR1() { .....; exitLPM(); }
ISR2() { .....; exitLPM(); }

Now, at line 2 we enter LPM0 and wait for the sensor to return from the setup procedure, say we assume it triggers some specific ISR that shall do something and exit the LPM at the end causing the program resume (as of line 3).

Then it goes into startMeasurement and the LPM, waiting for the other ISR to do something and then exit LPM.

 

Now, without any conditions after enterLPM() the program will resume with any exitLPM() routine call, any ISR can trigger it.

We can have ISR1() to set some variable to be checked to proceed, like:

0: {
1: setUpSensor();
2: enterLPM0();
3: while (!setup) 
4: {
5:   startMeasurement();
6:   enterLPM0();
7: }
8: }

ISR1() { setup = 1; exitLPM(); }
ISR2() { .....; exitLPM(); }

This is going to keep the program running until the setup is false or 0, but it can eventually kill the program if the setup is never set for any reason (e.g sensor defect).

 

Having just checked the condition:

0: {
1: setUpSensor();
2: enterLPM0();
3: if (setup > 0)
4: {
5:   startMeasurement();
6:   enterLPM0();
7: }
8: }

ISR1() { setup = 1; exitLPM(); }
ISR2() { .....; exitLPM(); }

makes it necessary to put the conditions to all other code so the program does not continues from line 7 when  exitLPM() is called (when the program was paused at 2) but the setup = 0 

 

This all makes it more and more complex as we add another ISRs, checking the conditions becomes a nightmare.

 

What I do in my program is indeed checking the flags set up in the corresponding ISRs and disabling the interrupt enable of the particular modules when their support is completed, this way they don't trigger ISRs when they are not expected (i.e when I finished measuring the pressure at I2C I disable the I2C interrupts and simply enable them when I want to do the measurement).

The last one is tricky, it does work for me but doesn't protect me from the situation when I forget to disable some interrupt.

 

What is your way?

How is it done in the complex systems (yet not having the operating systems?).

Is it disabling all interrupts at start and having them enabled just when they are used and disabled right after they are not used until next measurement, or is it using these flags set within ISRs and then checking them in the code? I don't believe my solution is correct.

Link to post
Share on other sites
volatile unsigned int flags;

main()
{
  init();
  while(1)
  {
    if (flags & 0x01)
    {
      function1()
      flags &= ~0x01;
    }

    if (flags & 0x02)
    {
      function2()
      flags &= ~0x02;
    }

    if (flags & 0x04)
    {
      function3()
      flags &= ~0x04;
    }

    //...


    if (!flags)
    {
      enterLPM();
    }
  }
}

LPM1(){flags |= 0x01; exitLPM;}
LPM2(){flags |= 0x02; exitLPM;}
LPM3(){flags |= 0x04; exitLPM;}

How is this? You could even pack the if() block in a macro, passing the function to call to it.

 

Also, you are in control of which interrupts are enabled at what time; make sure that only the setup interrupt can trigger during setup, after setup, disable the setup interrupt and enable the other interrupt.

Link to post
Share on other sites

OK, thanks! So this looks like what I was refering to in my last code snippet.

Is there any reason for clearing the flag after the execution of the function() - provided this function doesn't check the flags? Like the interrupt flags, they are very often cleared upon ISR entry before any other interrupt is queued.

Link to post
Share on other sites

Yes, if you do not clear the flag, then the next time any interrupt is triggered, that function will be called again, even if the corresponding interrupt did not occur.

Say ISR1 is triggered, then function1 is executed, then back to low power.

A while later ISR2 is triggered, then function1 is executed, because its flag is still set, then function2 is executed.

To prevent function1 to be executed on the second interrupt, you must clear the flag once you've served it; then a second trigger to that specific interrupt will again call that function correctly.

Link to post
Share on other sites

Yes, if you do not clear the flag, then the next time any interrupt is triggered, that function will be called again, even if the corresponding interrupt did not occur.

Say ISR1 is triggered, then function1 is executed, then back to low power.

A while later ISR2 is triggered, then function1 is executed, because its flag is still set, then function2 is executed.

To prevent function1 to be executed on the second interrupt, you must clear the flag once you've served it; then a second trigger to that specific interrupt will again call that function correctly.

@@roadrunner84, thank you for your extraordinary patience while explaining these really basic stuff  :)

I should have been more precise: what I meant was: "Is there any reason for clearing the flag after instead of before execution of the function() "

I guess it does not matter, anyway.

Link to post
Share on other sites

@@roadrunner84, thank you for your extraordinary patience while explaining these really basic stuff  :)

I should have been more precise: what I meant was: "Is there any reason for clearing the flag after instead of before execution of the function() "

I guess it does not matter, anyway.

You're right, it is not really important, clearing the flag before calling the function might give you a little higher chance of catching a second interrupt while still handling the first.

If the function does some long term delaying (note that serial communication is delaying too, unless you're doing that on ISR basis too) that might indeed be preferable.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...