Atomic access to volatile long

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello

I am working with volatile long variables, which are beeing modified in ISRs.

To ensure an atomic access to these variables outside of the ISRs, I am using a function which is making a copy of the value, while interrupts are disabled.

u32 ATOMIC32(volatile u32 *var)
//---------------------------------------------
// avoid ISR during access to the 4 bytes of a 
// volatile long, which might be modified in ISR
// => Atomic volatile access oustide of ISR
//---------------------------------------------
{
  u32 temp;
  cli();
  temp=*var;
  sei();
  return(temp);
}

My question is, if anybody knows a smarter (respectively more efficient) way to do this, (e.g. with a macro- or inline-definition)?

Thanks for any hint!

Pater

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think some macro or "direct code":

cli; temp = long_var; sei

would be faster... but your idea is good if you have many accesses in your app., even if it looks (very) slow...

Real men don't use backups, they post their stuff on a public ftp server and let the rest of the world make copies.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The downside to having the atomic read in a separate function is that, when you call it, the compiler has to treat it as such: The registers a subroutine is allowed to trash are considered trashed, so the variables it kept in those registers have to be reloaded afterwards. In the end, moving it to a separate function costs more code than it saves.
Depending on how smart your compiler is, you can declare your routine 'static inline'; A smart compiler will then generate groenhen's code. A less smart one will prefer
#define ATOMICMOVE32(dst,src) {cli(); dst=(src); sei();}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!

But I am afraid, that with a macro it is not possible to use statements like:

if (ATOMIC32(MyVar)==0) DoSomething();
while(ATOMIC32(MyVar)) DoSomethingElse();

Basically, it would be sufficient, if I could check with a macro, whether MyVar is zero or not!

n.b. I am using WinAvr...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I expect WinAVR will do a good job on this if you declare it "static __inline__".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I have more than one reference to the important variable, or if I want to do something like your comparison, I use a temporary variable, make the copy with interrupts off, then turn interrupts on to let important work proceed.

A lot of the "solution" depends on the particular needs of the app, and what is most important. Is the variable going to be repeatedly (like every main loop scan) looked at to see if 0 or not? Then have the ISR make another bit flag, read-only from the main loop, that indicates whether it is 0 or not. At some point when the ISR is manipulating it it probably "knows" if it keeps track of Z whehter it is zero; or it can do the test in one spot and set the flag for repeated testing in the main loop.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also, I would suggest saving the state of the interrupt flag, and then disabling it and finally restoring it after reading the var. Instead of blindly disabling and enabling interrupts. This way you don't inadvertently turn interrupts back on when they should be off. While most if the time it may be obvious, it may not be if you're doing this from within a subroutine that may be called in either condition. It's easy to forget, and can cause a whole slew of problems that can be hard to find.

Another solution may be to only disable the particular interrupt that will change that var for the duration of the read, and then re-enabling it. This has the added advantage of not starving other potentially critical interrupts, and avoids potential deadlock. If all you do is disable the interrupt source, it will still fire once you re-enable it, just as if CLI/SEI are used. In addition this method works regardless of whether or not global interrupts are enabled or disabled. Though technically you should still do the save/restore method here, unless you can guarantee that this interrupt will never be disabled on entry. If in a multitasking environment you need to do the save/restore, in case another thread tries to access the same variable.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@glitch:
Thanks for your hint, I will consider your point of storing the SREG! So far it is not a problem, because I have interrupts always enabled outsie of the ISR, but it could be a trap in a later and bigger project.

@mckenney
I am not familiar with using "static __inline__". Will I have do declaire my function-body and/or function-prototype with this attribuet?

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Peter, yes.

static __inline__ void Banana(void)
   {
      // ...
   }

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!