|
|
View previous topic :: View next topic |
Author |
Message |
hello188
Joined: 02 Jun 2010 Posts: 74
|
16bit variables and interrupts |
Posted: Wed Nov 09, 2011 6:43 am |
|
|
Hi, I have a quick question.
Let's say that we have 16bit integer variable that consists of 2 8bit registers.
Say that the variable can be changed in interrupt.
In the main routine, say we need to save the values in EEPROM.
To do it safely, we move the 16bit variable to another 16 bit buffer, and then we save it.
The problem is,
say that the variable is A = 0x16FF, and the buffer is called variable B.
First, B becomes 0x1600. Then, it should be 0x16FF. But, what if A becomes incremented by 1 in interrupt and becomes A = 0x1700. Then, B becomes 0x1600 and we save 0x1600 in EEPROM which is way wrong.
Would declaring it as volatile solve the problem? Then how does the compiler do it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Nov 09, 2011 6:48 am |
|
|
All you do, is disable interrupts, copy the value into a local temporary variable, and then enable interrupts again. Copying a value, takes just a few machine cycles, so the interrupts are off for only a tiny time.
The compiler does not do this itself, and the volatile directive at present does nothing.
Best Wishes |
|
|
mbradley
Joined: 11 Jul 2009 Posts: 118 Location: California, USA
|
|
Posted: Tue Nov 15, 2011 12:35 am |
|
|
I agree with above. I just want to post another way that I sometimes use, that is to have a flag bit set somewhere so one of my routines knows to do something or wait until something is done.
Ie, your interrupt doesn't update if flag not cleared. _________________ Michael Bradley
www.mculabs.com
Open Drivers and Projects |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Nov 15, 2011 7:37 am |
|
|
there is another way to read the variable:
"double read"
Code: |
int16 keeper;
do{ keeper=yourintvar;} while (keeper!=yourintvar);
|
the loop will never execute more than twice
and ints can be left alone |
|
|
mbradley
Joined: 11 Jul 2009 Posts: 118 Location: California, USA
|
|
Posted: Tue Nov 15, 2011 8:47 am |
|
|
Interesting, I like it. Wrap in a macro, and your good,
Code: |
#define mINTSAFEXFR(y,x) do { x=y;} while (x!=y);
int16 keeper;
int16 thevar;
// txfr the var to keeper
mINTSAFEXFR(thevar,keeper);
..
..
// now write keeper to EEPROM
..
.. |
_________________ Michael Bradley
www.mculabs.com
Open Drivers and Projects |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Nov 15, 2011 10:50 am |
|
|
Double reading is a workround that's fine for simple variables. Its not much good for more complex data structures.
One example is a "simple" circular buffer for serial data. It's filled in an isr, emptied in mainloop code. There is a count of the number of characters in the buffer, a couple of buffer pointers or indexes and the data itself: an array of char. When the main code wants to do a "kb_hit()" it has to check the buffer count. OK, but what if an interrupt happens immediately after? Now the main loop's idea of the number of characters in the buffer is wrong. We may get away with that.... Then we have to get the most recent character with a getc() type function, but another has arrived, so will we get the character we expect? Then the pointers/indexes have to be altered to reflect the character we've just got, all of which could be affected, and of course we have to alter the character count. This all means that at the least the getc() has to be ONE non-interruptable operation, not just reads or writes of single variables.
Worse happens when sending using buffers. "Worse" as in one byte transmitted out of place by 255 characters in over 100k of a packetised, byte stuffed datastream. Who has to wade through sheet after sheet of hex dump hand decoding the packet framing to prove the fault was there... yes, me
The standard way of dealing with this is the turning off interrupt(s) thing. Its called a critical section and its a key building block of operating systems:
Enter critical section (turn off interrupts, or relevant interrupt: eg serial receive)
Do stuff which must not be interrupted.
Leave critical section (turn on interrupt/s again).
They are of critical importance to any robust interrupt driven software buffering arrangement. All other locks/semaphores/mutexes/spinlocks and the like are built using critical sections as their foundation.
RF Developer |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Nov 15, 2011 1:05 pm |
|
|
what RF developer says is very well stated.
However turning off an interrupt also increases the
( sometimes not well appreciated) responsibility of the programmer
to deal with unforseen conditions that can occur.
Fortunately , management of some of the basics , like clearing the associated INT flag , are well handled by the compiler.
The example i gave was a snippet from an 18F , timer0
1 ms timer interrupt routine ,with a ' tick' range of 16 unsigned bits.
it works in an environment with RS232 serial interrupts and edge triggered port B interrupts.
For that value, as the original poster requested, there is no safer way to get the data. And the MOST up to data data at that.
Double reading is a simple , foolproof, and SAFE way to get that specific data, with NO risk to the interrupt routine that does the counting.
Ditto SISR and similar circular buffer code that i and others have posted.
So long as pointers are updated in the right order, there is no easy way it is going to fail, short of total interrupt overlap saturation. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|