Reply by jonk...@infinitefactors.org February 3, 20082008-02-03
> TACTL= MC_0 | TASSEL_1 | ID_0 | TACLR;
> TACCTL0= CM_0 | CCIS_2 | SCS | OUTMOD_1 | CCIE;
> TACCR0= 19999;
> TACTL= MC_1 | TASSEL_1 | ID_0;

The OP used CCR0, so the above 19999 is only an example. Also, I
provided some examples for other facets of CTL0 above that I might use
instead of just setting it to CCIE.

Jon

Beginning Microcontrollers with the MSP430

Reply by old_cow_yellow February 3, 20082008-02-03
When I wrote, "I found that LPM0_EXIT actually ***clears*** the LPM0
bits of the saved SR in the stack." I was also a victim of the header
file that says:

#define LPM0_bits (CPUOFF)
#define LPM0_EXIT _BIC_SR_IRQ(LPM0_bits)

Sorry for that!
Reply by jonk...@infinitefactors.org February 3, 20082008-02-03
> --- In m..., jonk@... wrote:
>>
>> Let me add a comment to what I just wrote, namely:
>>
>> > I take it that you mean that SCG1 and SCG0 and OSCOFF are 0?
>> > But isn't that exactly what it takes to get INTO LPM0 mode??
>> > If so, the return from interrupt will do what I feared and
>> > pointed out, earlier.
>>
>> Also, CPUOFF is '1', I should have added. It's been my
>> experience with LPM0 that it disables the CPU. Isn't that
>> right?
>
> As I said, I got the "free" KickStart from TI.
> I found that it compiles "LPM0_EXIT" into "bic.w #0x10,0(SP)"
> It simply clears CPUOFF.
> SCG1, SCG0, OSCOFF, etc, are unchanged.

Well, I didn't gather that's what you said, when you wrote, "I found that
LPM0_EXIT actually ***clears*** the LPM0 bits of the saved SR in the
stack." But thanks to your kick here, I went and looked at the
instruction generated, too. And it just clears one bit (bic #0x10), which
is indeed just the CPUOFF bit.

Okay. So the last thing done in the interrupt routine is to _enable_ the
cpu and to leave the rest of the LPM mode bits on the stack alone. Which
should leave the cpu operational _after_ the return.

However, your forcing me to go look at the actual assembly generation
produced another effect. The posted code did not have a #pragma such as
this:

#pragma vector= TIMERA1_VECTOR

before the interrupt code, itself. As a result, the compiler doesn't
place a vector pointer. And because it doesn't do that, the interrupt
code itself doesn't appear in the resulting binary, so far as I can tell.

Also, now that I'm looking closer at the code than before, I also notice
that the original poster sets up the timer bits in TACTL all at once.
It's been my practice to first reset it with the TACLR, using MC_0, then
set up CTL0 and CCR0, and then go back and set TACTL with, say, MC_1 after
that. So I'd modify the poster's code on that part to say:

TACTL= MC_0 | TASSEL_1 | ID_0 | TACLR;
TACCTL0= CM_0 | CCIS_2 | SCS | OUTMOD_1 | CCIE;
TACCR0= 19999;
TACTL= MC_1 | TASSEL_1 | ID_0;

Something like that, instead. Not sure if ID_0 is the desired one, right
now. But whatever it should be, I'd include it, too, as shown above.

But the #pragma is vital.

Jon
Reply by old_cow_yellow February 3, 20082008-02-03
As I said, I got the "free" KickStart from TI.
I found that it compiles "LPM0_EXIT" into "bic.w #0x10,0(SP)"
It simply clears CPUOFF.
SCG1, SCG0, OSCOFF, etc, are unchanged.

--- In m..., jonk@... wrote:
>
> Let me add a comment to what I just wrote, namely:
>
> > I take it that you mean that SCG1 and SCG0 and OSCOFF are 0?
> > But isn't that exactly what it takes to get INTO LPM0 mode??
> > If so, the return from interrupt will do what I feared and
> > pointed out, earlier.
>
> Also, CPUOFF is '1', I should have added. It's been my
> experience with LPM0 that it disables the CPU. Isn't that
> right?
>
> Jon
>
Reply by jonk...@infinitefactors.org February 3, 20082008-02-03
Let me add a comment to what I just wrote, namely:

> I take it that you mean that SCG1 and SCG0 and OSCOFF are 0? But isn't
> that exactly what it takes to get INTO LPM0 mode?? If so, the return
> from interrupt will do what I feared and pointed out, earlier.

Also, CPUOFF is '1', I should have added. It's been my experience with
LPM0 that it disables the CPU. Isn't that right?

Jon
Reply by jonk...@infinitefactors.org February 3, 20082008-02-03
> I do not use LPM0_EXIT either. For that matter, I do not use c period.

Just to make my position clear, I try to do what is in the client's better
interest, generally. Often, that will include c for many cpus, but
usually also with some assembly included. In some cases, assembly only is
called for. In the MSP430 case, I've only used the cpu for educational
and small scale personal purposes so I haven't paid for a commercial
license to use a c compiler for the chip, as yet. If that changes and a
customer's requirements included c as a better way to go, I'd go buy a
license, as appropriate for them. However, just so you know my use so
far, it has entirely been with IAR's free version for educational use and
for personal use has included both IAR's Kickstart and Imagecraft's ICC
(with permission.) I very much, as a personal matter, enjoy working with
either assembly or c or both. Just depends on what I'm doing.

> I dislike layers and layers of syntax and semantics wrapped around
> lousy ideas or algorithms. For example:
>
> for(;;)
> {
> _BIS_SR(LPM0_bits + GIE);
> P1OUT ^= 0x01;
> }
>
> #pragma vector= TIMERA0_VECTOR
> __interrupt void Timer_A0(void)
> {
> LPM0_EXIT;
> }
>

Yeah. That is basically trivial assembly, which is clear to read, cast
into obscure and specialized coding that only makes complete sense if you
go and dig things up, which is actually more work to me. In fact, as I
already admitted, I had to google LPM0_EXIT to even get a clue about it
(the IAR help didn't find it for me.) With assembly, everything would
have been clearer and not more wordy.

> I totally agree with you that this is a lousy way to toggle P1.0
> output. But I think it does toggle P1.0 output periodically (if
> Timer_A0 is set up correctly).

I didn't think so, though, given my perhaps wrong assumption about what
that macro did. And I'll point out the reason, again, just after your
next comment.

> I use (IAR) KickStart to compile the above segment of c code and
> examined the object code generated. I found that LPM0_EXIT actually
> ***clears*** the LPM0 bits of the saved SR in the stack.

I take it that you mean that SCG1 and SCG0 and OSCOFF are 0? But isn't
that exactly what it takes to get INTO LPM0 mode?? If so, the return from
interrupt will do what I feared and pointed out, earlier.

Not so?

Jon
Reply by old_cow_yellow February 3, 20082008-02-03
I do not use LPM0_EXIT either. For that matter, I do not use c period.
I dislike layers and layers of syntax and semantics wrapped around
lousy ideas or algorithms. For example:

for(;;)
{
_BIS_SR(LPM0_bits + GIE);
P1OUT ^= 0x01;
}

#pragma vector= TIMERA0_VECTOR
__interrupt void Timer_A0(void)
{
LPM0_EXIT;
}


I totally agree with you that this is a lousy way to toggle P1.0
output. But I think it does toggle P1.0 output periodically (if
Timer_A0 is set up correctly).

I use (IAR) KickStart to compile the above fragment of c code and
examined the object code generated. I found that LPM0_EXIT actually
***clears*** the LPM0 bits of the saved SR in the stack.

--- In m..., jonk@... wrote:
>
> > I think you may have been misled by LPM0_EXIT when you said:
> > "(4) Your interrupt routine modifies the saved stack status
> > to LPM0, but of course it already is that way so there is no
> > real change caused by that."
>
> That could be. Thanks for bringing my attention here. I don't
> use LPM0_EXIT, at all, so I just looked it up on the web and
> noted that it appears to modify the saved stack status and went
> with that.
>
> Regardless (because it doesn't matter to what I was pointing out),
> I think the rest of the logic holds, though. Or?
>
> > What do you think is the resulting x after the statement:
> > x = ADD_ONE_TO(2);
> >
> > where:
> > int ADD_ONE_TO(int i) {return (i-1);}
>
> Since I'm on shaky ground regarding my knowledge of LPM0_EXIT,
> not using it myself, I'll hold short of trying to interpret
> your question in that context. I'm more likely than not of
> getting myself into trouble doing that.
>
> The main point I had wanted to get across, and I don't think
> LPM0_EXIT affects the point, is that the design appears flawed
> at the outset. The fact that there is no toggling going on is
> more an issue of approach, I've think.
>
> In the past, I've done the toggle (xor) in the interrupt
> function itself. The main code (assuming the simple case here
> of just toggling an LED) can just go into LPM0 mode and sit a
> "return 0;" statement, if it wanted to. The return would never
> actually get to execute, the interrupt would operate just fine
> and toggle the LED and no modification of the stack would be
> required since the LPM0 was properly saved there when the
> interrupt took place. I've done it that way, in fact, with
> some educational programs for a 1st year class in programming
> at a local college here, using the MSP430. Worked very easy
> and was easy to explain, too. (Can provide source, if you want
> to see the 10 project series I developed for them.)
>
> Jon
>



Reply by jonk...@infinitefactors.org February 2, 20082008-02-02
> I think you may have been misled by LPM0_EXIT when you said: "(4) Your
> interrupt routine modifies the saved stack status to LPM0, but of
> course it already is that way so there is no real change caused by that."

That could be. Thanks for bringing my attention here. I don't use
LPM0_EXIT, at all, so I just looked it up on the web and noted that it
appears to modify the saved stack status and went with that.

Regardless (because it doesn't matter to what I was pointing out), I think
the rest of the logic holds, though. Or?

> What do you think is the resulting x after the statement:
> x = ADD_ONE_TO(2);
>
> where:
> int ADD_ONE_TO(int i) {return (i-1);}

Since I'm on shaky ground regarding my knowledge of LPM0_EXIT, not using
it myself, I'll hold short of trying to interpret your question in that
context. I'm more likely than not of getting myself into trouble doing
that.

The main point I had wanted to get across, and I don't think LPM0_EXIT
affects the point, is that the design appears flawed at the outset. The
fact that there is no toggling going on is more an issue of approach, I've
think.

In the past, I've done the toggle (xor) in the interrupt function itself.
The main code (assuming the simple case here of just toggling an LED) can
just go into LPM0 mode and sit a "return 0;" statement, if it wanted to.
The return would never actually get to execute, the interrupt would
operate just fine and toggle the LED and no modification of the stack
would be required since the LPM0 was properly saved there when the
interrupt took place. I've done it that way, in fact, with some
educational programs for a 1st year class in programming at a local
college here, using the MSP430. Worked very easy and was easy to explain,
too. (Can provide source, if you want to see the 10 project series I
developed for them.)

Jon
Reply by old_cow_yellow February 2, 20082008-02-02
Jon,

I think you may have been misled by LPM0_EXIT when you said: "(4) Your
interrupt routine modifies the saved stack status to LPM0, but of
course it already is that way so there is no real change caused by that."

What do you think is the resulting x after the statement:
x = ADD_ONE_TO(2);

where:
int ADD_ONE_TO(int i) {return (i-1);}
Reply by jonk...@infinitefactors.org February 2, 20082008-02-02
> I have programmed the MSP430F149 to toggle the p1.0 pin every 1000ns
> using a 12.288 mhz crystal clock connect to XT2IN. The ISR will wake the
> CPU up every 1000ns after toggling, it will put it to sleep. However,
> the code does not entered the interrupt routine and IAR cannot compile
> when include the __interrupt [TimerA Vector] void Timer_A(void).

I don't see a definition for 'x' in the code. But I'm sure you must have
merely missed including it, because I'm pretty sure it wouldn't compile
without one and you'd know it.

Have you considered this scenario?

(1) You enter LPM0 in your main for loop, just before the LED XOR.
(2) CPU is now sitting on, but not executing yet, the XOR.
(3) Interrupt takes place, saving the current LPM0 status on the
stack, changing the mode, and entering the interrupt.
(4) Your interrupt routine modifies the saved stack status to
LPM0, but of course it already is that way so there is no
real change caused by that.
(5) Interrupt routine returns, causing the CPU to enter LPM0 and
thus sit once again waiting on, but not yet executing that
XOR.
(6) Another interrupt takes place later on, saving again the LPM0
mode, etc., and getting to the interrupt code, and we go back
to step (4).

The result is that you never ever get to the XOR.

Jon