Pages: [1]   Go Down
Author Topic: Accessing variables in ISR  (Read 695 times)
0 Members and 1 Guest are viewing this topic.
Vancouver, Canada
Offline Offline
Full Member
***
Karma: 0
Posts: 118
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,

Just wondering how do access variables "safely", that are changing inside the ISR? (My ISR is on a 1 ms period)
Is it just declaring the variable volatile enough? what would happen if I am in the middle of a read operation that accesses the variable inside the ISR, and then the ISR kicks in, pausing my read operation and... well giving false data?
Is there a way to safely access variables inside ISR?

Thank you,
Logged

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 22
Posts: 1675
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You also need to turn interrupts off breifly to take a local copy of the variable inside loop, example and background here -

http://rcarduino.blogspot.com/2012/04/how-to-read-multiple-rc-channels-draft.html

Duane B
Logged


Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 299
Posts: 26180
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
what would happen if I am in the middle of a read operation that accesses the variable inside the ISR, and then the ISR kicks in, pausing my read operation and... well giving false data?
There's only a problem if the ISR modifies the variable being read.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 480
Posts: 18719
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't think you need to worry about single-byte variables (although they need to be volatile still) because access to them is atomic. Multiple bytes (eg. int) or related variables would need to be protected by putting noInterrupts() and interrupts() around them.

I would also be cautious if the main code modified a variable in a non-atomic way (eg. changing more than one bit).
Logged


Vancouver, Canada
Offline Offline
Full Member
***
Karma: 0
Posts: 118
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for all your input.
The link that DuaneB posted was very helpful and explained it all. Thanks for that.

Thank you Nick for your comment. However in the project that I am doing, the timing of the ISR is very critical and I cannot stop it no matter what. Is there any way around that. Is there a way to let the ISR do its job (read sensors to volatile variables (ints)) and these variables can be read in the main loop? ( I am not writing to them, just read them in main loop)

Thank you,
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12631
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't know how much of a delay calling the ISR would be acceptable to you. Bearing in mind that the processor is running quite fast and you may only need to make a couple of variable assignments, the delay would be relatively short.

If you can't afford to delay the ISR at all and need the ISR to make non-atomic writes which can be read by the main code, you can implement either a circular queue or swinging buffers.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 480
Posts: 18719
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you Nick for your comment. However in the project that I am doing, the timing of the ISR is very critical and I cannot stop it no matter what. Is there any way around that. Is there a way to let the ISR do its job (read sensors to volatile variables (ints)) and these variables can be read in the main loop? ( I am not writing to them, just read them in main loop)

No-one said anything about stopping the ISR. If you have multi-byte variables, then in the main loop you need to protect them by putting noInterrupts() in front of attempts to access them.

If timing is critical, put all the relevant variables into a struct, and then make a quick copy of it. eg.

myStructType copyOfVariables;

Code:
noInterrupts ();
memcpy (&copyOfVariables, &isrVariables, sizeof copyOfVariables);
interrupts ();

Bear in mind the ISR won't fire immediately, necessarily, anyway. For example, the millis() interrupt may be processing its stuff.
Logged


Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, there are a few ways to do what you want:

1) Double read: this is the most widely used. Essentially, it reads the variable until two consecutive reads yield the same value.
2) Write flag: your isr will set a flag just before it writes to that variable. Your read routine will test that flag before reading the variable and resets the flag after a read.

The above doesn't alter the timing of your isr at all.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 480
Posts: 18719
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

After it writes the variable, I would say.

That's a good idea, and one I've used before.

The ISR checks first if the flag is set, and if so does nothing. If not set, it changes as many variables as it wants and then sets the flag last. eg.

Code:
volatile byte updatedFlag = false;
volatile int var1;
volatile int var2;

ISR (foo)
  {
  // do nothing if loop hasn't picked up previous value
  if (updatedFlag)
    return;

  var1 = whatever;
  var2 = whatever;
 
  updatedFlag = true;
  } // end of ISR

void loop ()
  {
  int copyVar1;
  int copyVar2;

  if (updatedFlag)
    {
    copyVar1 = var1;
    copyVar2 = var2;
    updatedFlag = false;  // let ISR know it can update variables again
    }

  // work with copy of variables here ...

  }   // end of loop
Logged


Pages: [1]   Go Up
Jump to: