[Icc-430] Reading MSP-430 status register from C....
Kris Heidenstrom
kris at abbey.co.nz
Tue Apr 15 14:47:38 PDT 2008
Kirk Bailey (bailey at peak.org) wrote:
> For the current issue I need to read the GIE bit, but
> there are other situations where it is useful to be
> able to examine other status bits.
>
> Basically what I'm trying to do is implement two
> primitives:
>
> 1. Enter-Monitor (read current GIE status, set GIE
> to 0)
> This primitive is where I need to be able to read the
> SR, followed by a _DINT() /* or _BIC_SR(GIE) */.
> Depending on the application it may also be useful to
> isolate the GIE bit by itself in the saved copy to
> avoid over-writing some of the other flags in the SR
> during the later execution of the "exit" primitive.
>
> 2. Exit-Monitor (restore saved GIE status)
> This translates into a _BIS_SR(saved_GIE_status)
Yes we have the same issue with icc430. It's common in
embedded programming to do exactly what you describe.
You need to make sure that interrupts are disabled during
certain critical sections, but you don't want to lock out
interrupts unnecessarily.
If your function just enables interrupts explicitly at
the end of each critical section, then you have to ensure
that the function will never be called in a situation
where interrupts are disabled and must stay disabled,
because the function will explicitly enable them. This
might be a workable approach as long as it's clearly
documented and explained.
But of course the cleanest solution is the traditional one:
push (or otherwise save) the status register
explicitly disable interrupts
do the critical stuff
restore the status register from the saved value.
With this approach it doesn't matter whether interrupts
were disabled on entry to the function or not, because
the code never enables them if they weren't already
enabled, but only forces interrupts off during critical
section(s).
We have tried to convince icc430 to do this efficiently
by defining an automatic local variable to hold the status
register value, and accessing it using asm statements, but
it doesn't work because the compiler thinks the local
variable has no scope (because it is only accessed from
asm statements and the compiler just passes those on to
the assembler without looking at them) so the compiler
will reuse the register allocated to the local variable
for other variables. This was the general idea:
void myfunction(void) {
auto saved_sr;
asm ("mov r2,saved_sr"); /* Save SR */
/* Non-critical code can go here */
asm ("dint");
asm ("nop"); /* (if needed) */
/* Critical code */
asm ("mov saved_sr,r2"); / Restore SR */
/* Non-critical code */
asm ("dint");
asm ("nop"); /* (if needed) */
/* Critical code */
asm ("mov saved_sr,r2");
/* Non-critical code */
/* ... more if wanted ... */
/* Must exit with interrupt flag as on entry */
asm ("mov saved_sr,r2");
/* Non-critical code */
return;
}
This would be fairly efficient and would have the
advantage that you only need to save the status register
in the local variable _once_, near the start of the
function (which would be an improvement over the common
approach of pushing SR onto the stack before _each_ DINT
and popping it to restore the interrupt flag), but we
haven't been able to make it work.
At the moment we're using function calls to get and
set the status register. This is inefficient, and
ironically that inefficiency affects the very code
that you want to be as efficient as possible. :-(
I would appreciate a formally sanctioned way to deal
with this common embedded programming situation.
Kris
--
Kris Heidenstrom Embedded systems designer / programmer
kris at abbey.co.nz Abbey Systems Ltd - Telemetry Specialists
Wellington NEW ZEALAND Voice +64-4-385-6611 Fax +64-4-385-6848
More information about the Icc-430
mailing list