CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

16bit variables and interrupts

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hello188



Joined: 02 Jun 2010
Posts: 74

View user's profile Send private message

16bit variables and interrupts
PostPosted: Wed Nov 09, 2011 6:43 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Nov 09, 2011 6:48 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Tue Nov 15, 2011 12:35 am     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Tue Nov 15, 2011 7:37 am     Reply with quote

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

View user's profile Send private message Visit poster's website

PostPosted: Tue Nov 15, 2011 8:47 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Nov 15, 2011 10:50 am     Reply with quote

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 Twisted Evil

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

View user's profile Send private message AIM Address

PostPosted: Tue Nov 15, 2011 1:05 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Nov 15, 2011 1:17 pm     Reply with quote

This post has sample code which shows how to disable interrupts while
reading an int16 or int32 in main(), that is updated inside an isr routine:
http://www.ccsinfo.com/forum/viewtopic.php?t=27666&start=1
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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