avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] "Volatile"


From: David Brown
Subject: Re: [avr-gcc-list] "Volatile"
Date: Mon, 18 Apr 2005 16:25:57 +0200

> On Mon, 18 Apr 2005, David Brown wrote:
> > Note that the assignment is atomic even if the assembly consists of more
> > than one instruction (e.g., something like ldi r16, #1; st r16, flag ).
The
> > point of an "atomic" access is that there is no way to break the
statement
> > into a "half-done" step, as viewed by interrupt functions or external
> > accesses of some sort.  Even if an interrupt occured between these two
> > instructions, the flag change itself would not be affected - thus it is
> > atomic.
> >
>  I think I missed something here.  Why would :
>
> ldi r16, #1;
> st r16, flag
>
> Necessarily be atomic?  If an interrupt occured between these 2
> instructions, and the interrupt changed the state of flag, wouldn't there
> still be the original problem?
>

No, the flag change is still atomic.  There is no sequence of events that
does not have the same effect as either:
    < interrupt >
    flag = 1
or
    flag = 1
    < interrupt >

If the interrupt occurs in the middle of the two instructions, it has
exactly the same effect as if it had occured *before* the two instuctions,
both from the point of view of the interrupt code, and from the point of
view of the interrupted code.  Since there is no distinction between the
effect on "flag" of an interrupt before the instruction pair and an
interrupt during the instruction pair, the setting of "flag" is atomic.

This is very different from your code which uses "cFlags &= ~x", which is
most definitely not atomic (and thus requires interrupts to be disabled).
That is because it must be implemented (on an avr) as a read, followed by a
logic operation, followed by a write, and an interrupt occuring during that
sequence could result in a different effect than either the interrupt
occuring after or before the sequence.

Of course, using a single byte per flag also gives very much faster and
smaller code than using bit masks and extra function calls, at the expense
of more data space.

> On to a solution, since disabling interrupts is not portable, would
> something like the following be an OK solution?
>
> void Flags_Clear(unsigned char x)
> {
>     CRITICAL_SECTION_BEGIN
>     cFlags &= ~x;
>     CRITICAL_SECTION_END
> }
>
> Where the CRITICAL_SECTION stuff are macros, defined on a per machine
> basis?
>

When using bit masks like this to clear the flags, you are doing a
read-modify-write operation, and therefore must turn off interrupts (or at
least, all *relevant* interrupts) around the change.  And yes, macros are a
good idea here for portability - but you must be careful to *restore* the
state of the interrupts at the end of the function, which means checking
whether they were on or not at the start.  The msp430 port of gcc has a very
nice "critical" function attribute which does exactly that.

mvh.,

David

> Thanks to everyone for all their help on this issue!
> Keith
>
>





reply via email to

[Prev in Thread] Current Thread [Next in Thread]