Fw: [jallib] Advice regarding variable access from interrupt routines

18 views
Skip to first unread message

Alun

unread,
Jan 7, 2013, 1:34:27 PM1/7/13
to jal...@googlegroups.com


Begin forwarded message:

Date: Mon, 7 Jan 2013 17:22:58 +0000
From: Alun <alun....@ty-penguin.org.uk>
To: Oliver Seitz <karl...@yahoo.com>
Subject: Re: [jallib] Advice regarding variable access from interrupt
routines
[Also here for the list]

On Mon, 7 Jan 2013 09:05:04 -0800 (PST)
Oliver Seitz <karl...@yahoo.com> wrote:

>
> Just imagine, routine 2 always writes shortly after routine 1 does.
> The value of routine 1 will never be read back, the easiest way then
> would be not to implement routine 1 at all.

Well that would certainly save some time :-)

Thanks for your thoughts. I was worried I might be missing some simple
way to bypass the difficulty.

It's easy enough to build, by hand, safe access for each specific case
but, if I submit a library called "safe_concurrent_access.jal" and it's
not safe under all conditions I'm sure someone will manage to trigger
corruption and, rightly enough, call it a bug in the library.

Cheers,
Alun.

Karin Willers

unread,
Jan 8, 2013, 1:00:26 AM1/8/13
to jal...@googlegroups.com
What about disabling interrupts in the mainline code, making
a copy of the variable and then enabling interrupts again?
Working with the copy should be safe ...

Greetings,  Karin

Alun Jones

unread,
Jan 8, 2013, 2:29:43 AM1/8/13
to jal...@googlegroups.com

Isn't there then a risk missing an interrupt? I'm not sure about this, but if we turn off interrupts I don't think they'd queue until turned back on.

Last night, I thrashed out what I think is a "thread safe variable" library, but getting all the corner cases made it huge (costing at least 300 words) and when I wrote a test case for it I realised it provided no way of safely incrementing a variable! So I'm coming to the conclusion that a general solution isn't practical.

As part of doing that, though, I *did* write routines for acquiring a lock atomically. I need to do some testing, but will probably submit that instead.

Cheers,
Alun.

Oliver Seitz

unread,
Jan 8, 2013, 3:42:44 AM1/8/13
to jal...@googlegroups.com


On Tuesday, 8 January 2013 06:00:26 UTC, ScannerPrincess wrote:
On 01/07/2013 07:34 PM, Alun wrote:
What about disabling interrupts in the mainline code, making
a copy of the variable and then enabling interrupts again?
Working with the copy should be safe ...

Greetings,  Karin


Isn't there then a risk missing an interrupt? I'm not sure about this, but if we turn off interrupts I don't think they'd queue until turned back on.

No, no Interrupt will be missed. The IF flags are set regardless of the GIE flag setting, and as soon as GIE is enabled again, the interrupt is triggered.



Last night, I thrashed out what I think is a "thread safe variable" library, but getting all the corner cases made it huge (costing at least 300 words) and when I wrote a test case for it I realised it provided no way of safely incrementing a variable! So I'm coming to the conclusion that a general solution isn't practical.

That's why I prefer to only put complex, tedious tasks in a library, like converting numbers to decimal strings for output. Some tasks are easily done by the main program, but can be very complex and often inefficient to be done by a general-purpose-library. There exist libs for A/D-conversion, I believe. I have never had a look at them, as I need to look in the datasheet to find the analog inputs anyway. The three or four needed commands and assignments for the real conversion can quickly be typed. Furthermore, I like to use the spare cycles while the conversion is in progress, using the lib, those cycles are probably always wasted.

Greets,
Kiste

Alun Jones

unread,
Jan 8, 2013, 4:41:32 AM1/8/13
to jal...@googlegroups.com, Oliver Seitz


On Tuesday, 8 January 2013 08:42:44 UTC, Kiste wrote:
On Tuesday, 8 January 2013 06:00:26 UTC, ScannerPrincess wrote:

What about disabling interrupts in the mainline code, making
a copy of the variable and then enabling interrupts again?
Working with the copy should be safe ...
Isn't there then a risk missing an interrupt? I'm not sure about this, but if we turn off interrupts I don't think they'd queue until turned back on.
No, no Interrupt will be missed. The IF flags are set regardless of the GIE flag setting, and as soon as GIE is enabled again, the interrupt is triggered.

Thank you, both, for helping me to understand all this. In that case, it's all trivially easy - that bit of inspiration I was hoping someone out there had!

Making it general is presumably as simple as having two functions and scattering those throughout the code where needed:

oldstate = maskinterrupts() -- returns previous GIE value
...
restoreinterrupts(oldstate)   -- puts it back.

I take your point about libraries potentially wasting space and cycles, but I think I'd still do it this way, *and* use the functions from inside an ISR, just to keep things easy to understand. I'm quite happy to optimise stuff away when space becomes a premium (got some code I'm particularly proud of on a 12f615...), but readability 2 years later is also worthwhile :-)

Does anyone think there's any use at all for that atomic lock library I mentioned earlier? I'm happy to test, document and release it, but I'm not sure there's any particular usage scenario, given the above.

Cheers,
Alun.

Oliver Seitz

unread,
Jan 8, 2013, 5:04:45 AM1/8/13
to jal...@googlegroups.com

Making it general is presumably as simple as having two functions and scattering those throughout the code where needed:

oldstate = maskinterrupts() -- returns previous GIE value
...
restoreinterrupts(oldstate)   -- puts it back.

var bit GIE_savestate

GIE_savestate=INTCON_GIE
INTCON_GIE=false
...
INTCON_GIE=GIE_savestate

Well, without the lib it's one line more. Is it worth the effort? Your decision.

Greets,
Kiste

Sebastien Lelong

unread,
Jan 8, 2013, 6:16:50 AM1/8/13
to jal...@googlegroups.com

Hi Kiste
When interrupts are disabled, there won't be interrupt anymore, they won't queue until you enable them again. Right? Am I missing something ?
Cheers
Seb

--
You received this message because you are subscribed to the Google Groups "jallib" group.
To post to this group, send email to jal...@googlegroups.com.
To unsubscribe from this group, send email to jallib+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/jallib?hl=en.

Oliver Seitz

unread,
Jan 8, 2013, 6:31:05 AM1/8/13
to jal...@googlegroups.com



When interrupts are disabled, there won't be interrupt anymore, they won't queue until you enable them again. Right? Am I missing something ?

The IF flag will be set, even if GIE is not set. For GIE is not set, no interrupt will be triggered.

As soon as GIE becomes set, and the corresponding IE (and possibly PEIE) for a set IF flag are also set, an interrupt is triggered. At least this is how I've always read the datasheets. So the interrupts are not literally queued, but latched. If one interrupt source would trigger two interrupts while GIE is unset, only one interrupt will result. Therefore, GIE should not be unset for too long, but copying a single variable of two or four bytes should never take longer than two interrupts of the same kind.

The period in which GIE is unset should be kept as short as possible, of course.

Greets,
Kiste

Sebastien Lelong

unread,
Jan 8, 2013, 7:05:26 AM1/8/13
to jal...@googlegroups.com

OK great thanks for the clarifacation
Cheers
Seb

--

Joep Suijs

unread,
Jan 8, 2013, 7:09:53 AM1/8/13
to jal...@googlegroups.com
Hi guys,

Interesting discussion! I always use global vars to make data availble
to the i2c isr and have to take care when non-byte variables are used.

2013/1/8 Oliver Seitz <karl...@yahoo.com>:
> The IF flag will be set, even if GIE is not set. For GIE is not set, no
> interrupt will be triggered.
>
> As soon as GIE becomes set, and the corresponding IE (and possibly PEIE) for
> a set IF flag are also set, an interrupt is triggered. At least this is how
> I've always read the datasheets.

Correct afaik.

My view on the matter:

IMHO disabling interrupts is a good way to handle the issue in
specific spaces. User space might be a good place. A procedure might
be an option, but I don't know what the overhead would be when it is
inline. The overhead when it is not inline will be significant.

Downside is that disabling interrupts might cause missing interrupts
and at least will delayed interrupts. Missing interrupts are generally
not acceptable, and delay is not acceptable in some cases (like timing
of intterupt-on-change pins). So disabling interrupts is not an
universal sollution.

The use of a flag and two variables (or maybe a more generic way with
a pool of variables so prevent doubling of the ram used) would be a
nice 'libraray' sollution with no global impact like changing
interrupt timing.

Regards,
Joep
Reply all
Reply to author
Forward
0 new messages