The software FLL works just fine. Got it running last week.
SMCLK feeds TimerA and the CCR0 is used (because that is
where CCI0B is located and that's how ACLK can be used to
perform a "capture.") The PI is initialized by clearing the
integrator (i-term summation value) and preloading a latched
TACCR0 value outside the interrup code so that there is a
prior value from which to compute a delta value the next time
a capture takes place. All that is bog standard normal
stuff.
The simple approach here is to simply wait for the first
event and save it. Doesn't matter what you get, but it
should be snapped from either the rising or falling edge and
so long as you wait until the next similar edge, the next
time the capture takes place the difference should be about
right. I vaguely recalled reading something years ago that
the first capture can be "flaky" but don't recall where or
when. And I couldn't find anything in the family manual, the
datasheet, or the errata that specifically pointed out a
problem that matched by vague recollection exactly, so I
instructed that we just use the straight approach to this.
Turns out that it "worked sometimes." The first delta
computed would sometimes be approximately half of what it
should be. Not exactly half. Say, 0x800 when we should have
been getting 0xE00. But it would happen about 1/3rd the
time. And of course, that is enough to say there is a
problem!
So I found and dragged out the TI "DCI_Library.s43" file from
their site and scarfed through it. Sure enough, there it
was. A comment about "skip first short ACLK to avoid error"
on their first capture. I had previously inserted a long
startup delay which I'd already determined solved the
problem, without knowing why. But this comment in their
source code seemed to confirm there is a problem to deal
with. Using that approach instead of the delay loop works
well. So that's in place and everything runs wonderfully.
But I'd like to know if anyone recalls the exact details
here. I imagine that there is a "false edge" in the capture
input, at first, and that it might trigger oddly. I've no
problem with that. But why, exactly do I consistently
experience a value that is consistently wrong by precisely
the same amount, say 0x800 vs 0xE00 (actually more like 0x808
vs 0xE18.) It's not ox70C, for example, which would be half.
And it always nails the 0x808, plus or minus 1. Knowing
exactly why that may occur remains mysterious to me. My
instructions relative to the current phase of the 32.768kHz
crystal driving ACLK shouldn't always be quite that precise,
I'd imagine. I don't think the powerup/reset is quite that
perfect!
Does anyone remember the docs on this and where to find them?
Tossing away the first captured value works flawlessly, but I
just like to know all the details well enough to predict what
I experienced and actually calculate values before I get
them.
Thanks in advance,
Jon
G2xx devices without FLL, using DCO, ACLK, and TimerA for software FLL
Started by ●May 16, 2011
Reply by ●May 17, 20112011-05-17
Jon,
My understanding is, you need to calculate:
"delta counts" = "current latched counts" "previous latched counts";
This means, you cannot get a "delta counts" at the very first "latch" because there is no "previous". If you try to fake a "previous", you end up with a fake "delta counts".
-- OCY
--- In m..., Jon Kirwan wrote:
>
> The software FLL works just fine. Got it running last week.
> SMCLK feeds TimerA and the CCR0 is used (because that is
> where CCI0B is located and that's how ACLK can be used to
> perform a "capture.") The PI is initialized by clearing the
> integrator (i-term summation value) and preloading a latched
> TACCR0 value outside the interrup code so that there is a
> prior value from which to compute a delta value the next time
> a capture takes place. All that is bog standard normal
> stuff.
>
> The simple approach here is to simply wait for the first
> event and save it. Doesn't matter what you get, but it
> should be snapped from either the rising or falling edge and
> so long as you wait until the next similar edge, the next
> time the capture takes place the difference should be about
> right. I vaguely recalled reading something years ago that
> the first capture can be "flaky" but don't recall where or
> when. And I couldn't find anything in the family manual, the
> datasheet, or the errata that specifically pointed out a
> problem that matched by vague recollection exactly, so I
> instructed that we just use the straight approach to this.
>
> Turns out that it "worked sometimes." The first delta
> computed would sometimes be approximately half of what it
> should be. Not exactly half. Say, 0x800 when we should have
> been getting 0xE00. But it would happen about 1/3rd the
> time. And of course, that is enough to say there is a
> problem!
>
> So I found and dragged out the TI "DCI_Library.s43" file from
> their site and scarfed through it. Sure enough, there it
> was. A comment about "skip first short ACLK to avoid error"
> on their first capture. I had previously inserted a long
> startup delay which I'd already determined solved the
> problem, without knowing why. But this comment in their
> source code seemed to confirm there is a problem to deal
> with. Using that approach instead of the delay loop works
> well. So that's in place and everything runs wonderfully.
>
> But I'd like to know if anyone recalls the exact details
> here. I imagine that there is a "false edge" in the capture
> input, at first, and that it might trigger oddly. I've no
> problem with that. But why, exactly do I consistently
> experience a value that is consistently wrong by precisely
> the same amount, say 0x800 vs 0xE00 (actually more like 0x808
> vs 0xE18.) It's not ox70C, for example, which would be half.
> And it always nails the 0x808, plus or minus 1. Knowing
> exactly why that may occur remains mysterious to me. My
> instructions relative to the current phase of the 32.768kHz
> crystal driving ACLK shouldn't always be quite that precise,
> I'd imagine. I don't think the powerup/reset is quite that
> perfect!
>
> Does anyone remember the docs on this and where to find them?
> Tossing away the first captured value works flawlessly, but I
> just like to know all the details well enough to predict what
> I experienced and actually calculate values before I get
> them.
>
> Thanks in advance,
> Jon
>
My understanding is, you need to calculate:
"delta counts" = "current latched counts" "previous latched counts";
This means, you cannot get a "delta counts" at the very first "latch" because there is no "previous". If you try to fake a "previous", you end up with a fake "delta counts".
-- OCY
--- In m..., Jon Kirwan wrote:
>
> The software FLL works just fine. Got it running last week.
> SMCLK feeds TimerA and the CCR0 is used (because that is
> where CCI0B is located and that's how ACLK can be used to
> perform a "capture.") The PI is initialized by clearing the
> integrator (i-term summation value) and preloading a latched
> TACCR0 value outside the interrup code so that there is a
> prior value from which to compute a delta value the next time
> a capture takes place. All that is bog standard normal
> stuff.
>
> The simple approach here is to simply wait for the first
> event and save it. Doesn't matter what you get, but it
> should be snapped from either the rising or falling edge and
> so long as you wait until the next similar edge, the next
> time the capture takes place the difference should be about
> right. I vaguely recalled reading something years ago that
> the first capture can be "flaky" but don't recall where or
> when. And I couldn't find anything in the family manual, the
> datasheet, or the errata that specifically pointed out a
> problem that matched by vague recollection exactly, so I
> instructed that we just use the straight approach to this.
>
> Turns out that it "worked sometimes." The first delta
> computed would sometimes be approximately half of what it
> should be. Not exactly half. Say, 0x800 when we should have
> been getting 0xE00. But it would happen about 1/3rd the
> time. And of course, that is enough to say there is a
> problem!
>
> So I found and dragged out the TI "DCI_Library.s43" file from
> their site and scarfed through it. Sure enough, there it
> was. A comment about "skip first short ACLK to avoid error"
> on their first capture. I had previously inserted a long
> startup delay which I'd already determined solved the
> problem, without knowing why. But this comment in their
> source code seemed to confirm there is a problem to deal
> with. Using that approach instead of the delay loop works
> well. So that's in place and everything runs wonderfully.
>
> But I'd like to know if anyone recalls the exact details
> here. I imagine that there is a "false edge" in the capture
> input, at first, and that it might trigger oddly. I've no
> problem with that. But why, exactly do I consistently
> experience a value that is consistently wrong by precisely
> the same amount, say 0x800 vs 0xE00 (actually more like 0x808
> vs 0xE18.) It's not ox70C, for example, which would be half.
> And it always nails the 0x808, plus or minus 1. Knowing
> exactly why that may occur remains mysterious to me. My
> instructions relative to the current phase of the 32.768kHz
> crystal driving ACLK shouldn't always be quite that precise,
> I'd imagine. I don't think the powerup/reset is quite that
> perfect!
>
> Does anyone remember the docs on this and where to find them?
> Tossing away the first captured value works flawlessly, but I
> just like to know all the details well enough to predict what
> I experienced and actually calculate values before I get
> them.
>
> Thanks in advance,
> Jon
>
Reply by ●May 17, 20112011-05-17
On Tue, 17 May 2011 06:10:39 -0000, you wrote:
>Jon,
>
>My understanding is, you need to calculate:
>"delta counts" = "current latched counts" "previous latched counts";
>
> This means, you cannot get a "delta counts" at the very
> first "latch" because there is no "previous". If you try to
> fake a "previous", you end up with a fake "delta counts".
I already do the above. Here, let me show you a few steps:
; Set up CCR0 (it's required instead of CCR1 because
; CCI0B is the only way that the ACLK signal can be
; accessed for our purposes) for the PI control loop.
mov #CM_1 + CCIS_1 + SCS + CAP + OUTMOD_0, &TACCTL0
mov #MC_2 + ID_0 + TASSEL_2, &TACTL
You can assume that I've already set up the DCO at RSEL=15
and that the LFXT1 is up and running and the error bit clear.
Please note that at this point the CCIE is NOT turned on. Nor
is the GIE. The whole interrupt system is disabled. So
don't worry about it. Please. This is the very first part
that takes place quite soon after PUC.
After that point I do something like:
call await_aclk
mov r15, r14
call await_aclk
sub r14, r15
At that point the value of R15 isn't always what I expect.
That is, if I haven't inserted some kind of delay prior to
reaching the above sequence. If I have done so, then it
works just as I expect, each and every time I try it.
Note that I do wait for the ACLK to trigger a capture (the
routine returns TACCR0 in R15, always.) _THEN_ I wait again.
Then I subtract the two to get a difference. I have tried
this with either CM_1 or CM_2 for rising or falling edges,
without any difference in the results. Without the delay, I
get occasionally incorrect values. With the delay, never. It
always works fine.
Now, I have a tiny subroutine. Might as well disclose it so
that there is no doubt.
;------------------------
await_aclk ; WAIT FOR ACLK TO TRIGGER CAPTURE OF SMCLK COUNTS
;------------------------
; This routine assumes that the interrupt system is
; disabled and waits for CCIFG to go HI, indicating
; that a capture has taken place. It loads the TACCR0
; value into R15 and then returns.
await_aclk_01 bit #CCIFG, &TACCTL0
jeq await_aclk_01
mov &TACCR0, r15
bic #CCIFG, &TACCTL0
ret
Since interrupts are off, the MSP430 cannot respond using the
vector and so it is necessary to manually clear CCIFG, which
is why the last instruction is there. Okay?
Now, let's say I rewrite things. So that the calls to
await_ack go like this:
call await_aclk
call await_aclk
mov r15, r14
call await_aclk
sub r14, r15
This ALWAYS WORKS just fine. It never fails. I just toss
out the first capture.
Now, what is the value I get without the tossed first value?
Well, the subtraction either gives me the right value down to
within one count!!... or else it gives me something else that
is also quite unvarying, but wrongly so. I am supposed to
get about 0xE18 or so. Plus or minus one, let's say. But
either that happens quite well or else I sometimes get 0x808.
I might get 0x809. Once in a while, as well. But that's it.
And it's not as though that can be explained by picking up
half an ACLK cycle. It's not the right ratio for that.
In looking at the DCO_Library.s43 file from TI, guess what??
I find that they ALSO inserted a dummy read and throw away
the first value. What a surprise. Question is, why??
The logic is this. Timer_A is set up just fine with ACLK as
the capture input via CCI0B. SMCLK feeds it. When Timer_A
starts counting SMCLK cycles, relative to ACLK, is anyone's
guess. I've always known that. Never left my mind for a
second. At some point, perhaps at a very small count
number.... or not.... the selected edge of ACLK will trigger
a capture. So I read TACCR0 (the first captured value which
may be anything, large or small, who knows) in and place it
somewhere for safekeeping. It's the base. Then I clear
CCIFG and go wait again. Take another snapshot. TACCR0 will
be some other number now. BUT. But it should be one ACLK
cycle later. And in that time, some predictable number of
SMCLKs will have been counted. I shouldn't need to do THREE
reads of TACCR0. Just two. But I need three for some
reason. And if this were just a "bug" or some funky behavior
right after setting all those timer control values, I still
don't understand why the WRONG value is so repeatable. It
shouldn't be. It varies by one, so it's not a constant,
either.
I would like to know why. I would like to be able to predict
it, too. Since it is repeatable, it should be predictable.
Weird thing is, the folks at TI code their subroutine (which
has a different bug in it, by the way) to do exactly what
I've learned I need to do. But they don't say why. And
looking over the errata hasn't helped.
I'm just wondering if anyone else has seen some printed
detail about this. Something I can refer to.
I've got everything working wonderfully. It's as precise as
a beautiful clock. Locks up quickly and just ticks away.
Couldn't be better. I am trying to understand (and document)
the reason why I have just ONE extra call in my code. I
_hate_ not knowing why and not being able to fully justify it
in front of a room full of angry programmers looking for my
job.
This bothers me.
That's all. I need to know. Just curious if anyone has this
in their back pocket somewhere and can tell me so that I can
neatly document the details and refer to the right pages to
go to. All for one call statement. But yes, I have a firm
practice of being always prepared to jusstify every single
line of code I write without waffling or handwaving. And
that's why this bugs me.
Got any ideas?
Jon
>Jon,
>
>My understanding is, you need to calculate:
>"delta counts" = "current latched counts" "previous latched counts";
>
> This means, you cannot get a "delta counts" at the very
> first "latch" because there is no "previous". If you try to
> fake a "previous", you end up with a fake "delta counts".
I already do the above. Here, let me show you a few steps:
; Set up CCR0 (it's required instead of CCR1 because
; CCI0B is the only way that the ACLK signal can be
; accessed for our purposes) for the PI control loop.
mov #CM_1 + CCIS_1 + SCS + CAP + OUTMOD_0, &TACCTL0
mov #MC_2 + ID_0 + TASSEL_2, &TACTL
You can assume that I've already set up the DCO at RSEL=15
and that the LFXT1 is up and running and the error bit clear.
Please note that at this point the CCIE is NOT turned on. Nor
is the GIE. The whole interrupt system is disabled. So
don't worry about it. Please. This is the very first part
that takes place quite soon after PUC.
After that point I do something like:
call await_aclk
mov r15, r14
call await_aclk
sub r14, r15
At that point the value of R15 isn't always what I expect.
That is, if I haven't inserted some kind of delay prior to
reaching the above sequence. If I have done so, then it
works just as I expect, each and every time I try it.
Note that I do wait for the ACLK to trigger a capture (the
routine returns TACCR0 in R15, always.) _THEN_ I wait again.
Then I subtract the two to get a difference. I have tried
this with either CM_1 or CM_2 for rising or falling edges,
without any difference in the results. Without the delay, I
get occasionally incorrect values. With the delay, never. It
always works fine.
Now, I have a tiny subroutine. Might as well disclose it so
that there is no doubt.
;------------------------
await_aclk ; WAIT FOR ACLK TO TRIGGER CAPTURE OF SMCLK COUNTS
;------------------------
; This routine assumes that the interrupt system is
; disabled and waits for CCIFG to go HI, indicating
; that a capture has taken place. It loads the TACCR0
; value into R15 and then returns.
await_aclk_01 bit #CCIFG, &TACCTL0
jeq await_aclk_01
mov &TACCR0, r15
bic #CCIFG, &TACCTL0
ret
Since interrupts are off, the MSP430 cannot respond using the
vector and so it is necessary to manually clear CCIFG, which
is why the last instruction is there. Okay?
Now, let's say I rewrite things. So that the calls to
await_ack go like this:
call await_aclk
call await_aclk
mov r15, r14
call await_aclk
sub r14, r15
This ALWAYS WORKS just fine. It never fails. I just toss
out the first capture.
Now, what is the value I get without the tossed first value?
Well, the subtraction either gives me the right value down to
within one count!!... or else it gives me something else that
is also quite unvarying, but wrongly so. I am supposed to
get about 0xE18 or so. Plus or minus one, let's say. But
either that happens quite well or else I sometimes get 0x808.
I might get 0x809. Once in a while, as well. But that's it.
And it's not as though that can be explained by picking up
half an ACLK cycle. It's not the right ratio for that.
In looking at the DCO_Library.s43 file from TI, guess what??
I find that they ALSO inserted a dummy read and throw away
the first value. What a surprise. Question is, why??
The logic is this. Timer_A is set up just fine with ACLK as
the capture input via CCI0B. SMCLK feeds it. When Timer_A
starts counting SMCLK cycles, relative to ACLK, is anyone's
guess. I've always known that. Never left my mind for a
second. At some point, perhaps at a very small count
number.... or not.... the selected edge of ACLK will trigger
a capture. So I read TACCR0 (the first captured value which
may be anything, large or small, who knows) in and place it
somewhere for safekeeping. It's the base. Then I clear
CCIFG and go wait again. Take another snapshot. TACCR0 will
be some other number now. BUT. But it should be one ACLK
cycle later. And in that time, some predictable number of
SMCLKs will have been counted. I shouldn't need to do THREE
reads of TACCR0. Just two. But I need three for some
reason. And if this were just a "bug" or some funky behavior
right after setting all those timer control values, I still
don't understand why the WRONG value is so repeatable. It
shouldn't be. It varies by one, so it's not a constant,
either.
I would like to know why. I would like to be able to predict
it, too. Since it is repeatable, it should be predictable.
Weird thing is, the folks at TI code their subroutine (which
has a different bug in it, by the way) to do exactly what
I've learned I need to do. But they don't say why. And
looking over the errata hasn't helped.
I'm just wondering if anyone else has seen some printed
detail about this. Something I can refer to.
I've got everything working wonderfully. It's as precise as
a beautiful clock. Locks up quickly and just ticks away.
Couldn't be better. I am trying to understand (and document)
the reason why I have just ONE extra call in my code. I
_hate_ not knowing why and not being able to fully justify it
in front of a room full of angry programmers looking for my
job.
This bothers me.
That's all. I need to know. Just curious if anyone has this
in their back pocket somewhere and can tell me so that I can
neatly document the details and refer to the right pages to
go to. All for one call statement. But yes, I have a firm
practice of being always prepared to jusstify every single
line of code I write without waffling or handwaving. And
that's why this bugs me.
Got any ideas?
Jon
Reply by ●May 17, 20112011-05-17
Oh. Damn. I wrote the calls wrong in my sample code. Sorry.
I did use the # sign beforehand. So:
call #await_aclk
Just in case you think I made that mistake. I didn't.
Jon
I did use the # sign beforehand. So:
call #await_aclk
Just in case you think I made that mistake. I didn't.
Jon
Reply by ●May 17, 20112011-05-17
I remember that there are some silicon bugs (e.g. TA12 TA16) in MSP430
devices related to ACLK and Timer capture/compare after initialization.
Have you checked the errata of your device?
M.
Jon Kirwan :
> On Tue, 17 May 2011 06:10:39 -0000, you wrote:
>
>>Jon,
>>
>>My understanding is, you need to calculate:
>>"delta counts" = "current latched counts" "previous latched counts";
>>
>> This means, you cannot get a "delta counts" at the very
>> first "latch" because there is no "previous". If you try to
>> fake a "previous", you end up with a fake "delta counts".
>
> I already do the above. Here, let me show you a few steps:
>
> ; Set up CCR0 (it's required instead of CCR1 because
> ; CCI0B is the only way that the ACLK signal can be
> ; accessed for our purposes) for the PI control loop.
>
> mov #CM_1 + CCIS_1 + SCS + CAP + OUTMOD_0, &TACCTL0
> mov #MC_2 + ID_0 + TASSEL_2, &TACTL
>
> You can assume that I've already set up the DCO at RSEL
> and that the LFXT1 is up and running and the error bit clear.
> Please note that at this point the CCIE is NOT turned on. Nor
> is the GIE. The whole interrupt system is disabled. So
> don't worry about it. Please. This is the very first part
> that takes place quite soon after PUC.
>
> After that point I do something like:
>
> call await_aclk
> mov r15, r14
> call await_aclk
> sub r14, r15
>
> At that point the value of R15 isn't always what I expect.
> That is, if I haven't inserted some kind of delay prior to
> reaching the above sequence. If I have done so, then it
> works just as I expect, each and every time I try it.
>
> Note that I do wait for the ACLK to trigger a capture (the
> routine returns TACCR0 in R15, always.) _THEN_ I wait again.
> Then I subtract the two to get a difference. I have tried
> this with either CM_1 or CM_2 for rising or falling edges,
> without any difference in the results. Without the delay, I
> get occasionally incorrect values. With the delay, never. It
> always works fine.
>
> Now, I have a tiny subroutine. Might as well disclose it so
> that there is no doubt.
>
> ;------------------------
> await_aclk ; WAIT FOR ACLK TO TRIGGER CAPTURE OF SMCLK COUNTS
> ;------------------------
> ; This routine assumes that the interrupt system is
> ; disabled and waits for CCIFG to go HI, indicating
> ; that a capture has taken place. It loads the TACCR0
> ; value into R15 and then returns.
>
> await_aclk_01 bit #CCIFG, &TACCTL0
> jeq await_aclk_01
> mov &TACCR0, r15
> bic #CCIFG, &TACCTL0
> ret
>
> Since interrupts are off, the MSP430 cannot respond using the
> vector and so it is necessary to manually clear CCIFG, which
> is why the last instruction is there. Okay?
>
> Now, let's say I rewrite things. So that the calls to
> await_ack go like this:
>
> call await_aclk
> call await_aclk
> mov r15, r14
> call await_aclk
> sub r14, r15
>
> This ALWAYS WORKS just fine. It never fails. I just toss
> out the first capture.
>
> Now, what is the value I get without the tossed first value?
> Well, the subtraction either gives me the right value down to
> within one count!!... or else it gives me something else that
> is also quite unvarying, but wrongly so. I am supposed to
> get about 0xE18 or so. Plus or minus one, let's say. But
> either that happens quite well or else I sometimes get 0x808.
> I might get 0x809. Once in a while, as well. But that's it.
> And it's not as though that can be explained by picking up
> half an ACLK cycle. It's not the right ratio for that.
>
> In looking at the DCO_Library.s43 file from TI, guess what??
> I find that they ALSO inserted a dummy read and throw away
> the first value. What a surprise. Question is, why??
>
> The logic is this. Timer_A is set up just fine with ACLK as
> the capture input via CCI0B. SMCLK feeds it. When Timer_A
> starts counting SMCLK cycles, relative to ACLK, is anyone's
> guess. I've always known that. Never left my mind for a
> second. At some point, perhaps at a very small count
> number.... or not.... the selected edge of ACLK will trigger
> a capture. So I read TACCR0 (the first captured value which
> may be anything, large or small, who knows) in and place it
> somewhere for safekeeping. It's the base. Then I clear
> CCIFG and go wait again. Take another snapshot. TACCR0 will
> be some other number now. BUT. But it should be one ACLK
> cycle later. And in that time, some predictable number of
> SMCLKs will have been counted. I shouldn't need to do THREE
> reads of TACCR0. Just two. But I need three for some
> reason. And if this were just a "bug" or some funky behavior
> right after setting all those timer control values, I still
> don't understand why the WRONG value is so repeatable. It
> shouldn't be. It varies by one, so it's not a constant,
> either.
>
> I would like to know why. I would like to be able to predict
> it, too. Since it is repeatable, it should be predictable.
>
> Weird thing is, the folks at TI code their subroutine (which
> has a different bug in it, by the way) to do exactly what
> I've learned I need to do. But they don't say why. And
> looking over the errata hasn't helped.
>
> I'm just wondering if anyone else has seen some printed
> detail about this. Something I can refer to.
>
> I've got everything working wonderfully. It's as precise as
> a beautiful clock. Locks up quickly and just ticks away.
> Couldn't be better. I am trying to understand (and document)
> the reason why I have just ONE extra call in my code. I
> _hate_ not knowing why and not being able to fully justify it
> in front of a room full of angry programmers looking for my
> job.
>
> This bothers me.
>
> That's all. I need to know. Just curious if anyone has this
> in their back pocket somewhere and can tell me so that I can
> neatly document the details and refer to the right pages to
> go to. All for one call statement. But yes, I have a firm
> practice of being always prepared to jusstify every single
> line of code I write without waffling or handwaving. And
> that's why this bugs me.
>
> Got any ideas?
>
> Jon
>
devices related to ACLK and Timer capture/compare after initialization.
Have you checked the errata of your device?
M.
Jon Kirwan :
> On Tue, 17 May 2011 06:10:39 -0000, you wrote:
>
>>Jon,
>>
>>My understanding is, you need to calculate:
>>"delta counts" = "current latched counts" "previous latched counts";
>>
>> This means, you cannot get a "delta counts" at the very
>> first "latch" because there is no "previous". If you try to
>> fake a "previous", you end up with a fake "delta counts".
>
> I already do the above. Here, let me show you a few steps:
>
> ; Set up CCR0 (it's required instead of CCR1 because
> ; CCI0B is the only way that the ACLK signal can be
> ; accessed for our purposes) for the PI control loop.
>
> mov #CM_1 + CCIS_1 + SCS + CAP + OUTMOD_0, &TACCTL0
> mov #MC_2 + ID_0 + TASSEL_2, &TACTL
>
> You can assume that I've already set up the DCO at RSEL
> and that the LFXT1 is up and running and the error bit clear.
> Please note that at this point the CCIE is NOT turned on. Nor
> is the GIE. The whole interrupt system is disabled. So
> don't worry about it. Please. This is the very first part
> that takes place quite soon after PUC.
>
> After that point I do something like:
>
> call await_aclk
> mov r15, r14
> call await_aclk
> sub r14, r15
>
> At that point the value of R15 isn't always what I expect.
> That is, if I haven't inserted some kind of delay prior to
> reaching the above sequence. If I have done so, then it
> works just as I expect, each and every time I try it.
>
> Note that I do wait for the ACLK to trigger a capture (the
> routine returns TACCR0 in R15, always.) _THEN_ I wait again.
> Then I subtract the two to get a difference. I have tried
> this with either CM_1 or CM_2 for rising or falling edges,
> without any difference in the results. Without the delay, I
> get occasionally incorrect values. With the delay, never. It
> always works fine.
>
> Now, I have a tiny subroutine. Might as well disclose it so
> that there is no doubt.
>
> ;------------------------
> await_aclk ; WAIT FOR ACLK TO TRIGGER CAPTURE OF SMCLK COUNTS
> ;------------------------
> ; This routine assumes that the interrupt system is
> ; disabled and waits for CCIFG to go HI, indicating
> ; that a capture has taken place. It loads the TACCR0
> ; value into R15 and then returns.
>
> await_aclk_01 bit #CCIFG, &TACCTL0
> jeq await_aclk_01
> mov &TACCR0, r15
> bic #CCIFG, &TACCTL0
> ret
>
> Since interrupts are off, the MSP430 cannot respond using the
> vector and so it is necessary to manually clear CCIFG, which
> is why the last instruction is there. Okay?
>
> Now, let's say I rewrite things. So that the calls to
> await_ack go like this:
>
> call await_aclk
> call await_aclk
> mov r15, r14
> call await_aclk
> sub r14, r15
>
> This ALWAYS WORKS just fine. It never fails. I just toss
> out the first capture.
>
> Now, what is the value I get without the tossed first value?
> Well, the subtraction either gives me the right value down to
> within one count!!... or else it gives me something else that
> is also quite unvarying, but wrongly so. I am supposed to
> get about 0xE18 or so. Plus or minus one, let's say. But
> either that happens quite well or else I sometimes get 0x808.
> I might get 0x809. Once in a while, as well. But that's it.
> And it's not as though that can be explained by picking up
> half an ACLK cycle. It's not the right ratio for that.
>
> In looking at the DCO_Library.s43 file from TI, guess what??
> I find that they ALSO inserted a dummy read and throw away
> the first value. What a surprise. Question is, why??
>
> The logic is this. Timer_A is set up just fine with ACLK as
> the capture input via CCI0B. SMCLK feeds it. When Timer_A
> starts counting SMCLK cycles, relative to ACLK, is anyone's
> guess. I've always known that. Never left my mind for a
> second. At some point, perhaps at a very small count
> number.... or not.... the selected edge of ACLK will trigger
> a capture. So I read TACCR0 (the first captured value which
> may be anything, large or small, who knows) in and place it
> somewhere for safekeeping. It's the base. Then I clear
> CCIFG and go wait again. Take another snapshot. TACCR0 will
> be some other number now. BUT. But it should be one ACLK
> cycle later. And in that time, some predictable number of
> SMCLKs will have been counted. I shouldn't need to do THREE
> reads of TACCR0. Just two. But I need three for some
> reason. And if this were just a "bug" or some funky behavior
> right after setting all those timer control values, I still
> don't understand why the WRONG value is so repeatable. It
> shouldn't be. It varies by one, so it's not a constant,
> either.
>
> I would like to know why. I would like to be able to predict
> it, too. Since it is repeatable, it should be predictable.
>
> Weird thing is, the folks at TI code their subroutine (which
> has a different bug in it, by the way) to do exactly what
> I've learned I need to do. But they don't say why. And
> looking over the errata hasn't helped.
>
> I'm just wondering if anyone else has seen some printed
> detail about this. Something I can refer to.
>
> I've got everything working wonderfully. It's as precise as
> a beautiful clock. Locks up quickly and just ticks away.
> Couldn't be better. I am trying to understand (and document)
> the reason why I have just ONE extra call in my code. I
> _hate_ not knowing why and not being able to fully justify it
> in front of a room full of angry programmers looking for my
> job.
>
> This bothers me.
>
> That's all. I need to know. Just curious if anyone has this
> in their back pocket somewhere and can tell me so that I can
> neatly document the details and refer to the right pages to
> go to. All for one call statement. But yes, I have a firm
> practice of being always prepared to jusstify every single
> line of code I write without waffling or handwaving. And
> that's why this bugs me.
>
> Got any ideas?
>
> Jon
>
Reply by ●May 17, 20112011-05-17
On Tue, 17 May 2011 14:08:16 +0000 (UTC), you wrote:
>I remember that there are some silicon bugs (e.g. TA12 TA16) in MSP430
>devices related to ACLK and Timer capture/compare after initialization.
>
>Have you checked the errata of your device?
Oh, yes. In fact, I not only mentioned the fact that I had
checked the errata in the very post you are replying to, but
I also mentioned that fact in the original post, as well. I
looked closely at them and am following those rules. I also
searched for ACLK in them and checked anything mentioning it.
Jon
>I remember that there are some silicon bugs (e.g. TA12 TA16) in MSP430
>devices related to ACLK and Timer capture/compare after initialization.
>
>Have you checked the errata of your device?
Oh, yes. In fact, I not only mentioned the fact that I had
checked the errata in the very post you are replying to, but
I also mentioned that fact in the original post, as well. I
looked closely at them and am following those rules. I also
searched for ACLK in them and checked anything mentioning it.
Jon
Reply by ●May 17, 20112011-05-17
>
> You can assume that I've already set up the DCO at RSEL
> and that the LFXT1 is up and running and the error bit clear.
>
Okay, I assume that you did the following:
main: MOV.W #0x280,SP
MOV.W #WDTPW+WDTHOLD,&WDTCTL
MOV.B #XCAP_3,&BCSCTL3
MOV.W #0,R15
L1: BIC.B #OFIFG,&IFG1
L2: SUB.W #1,R15
JNZ L2
BIT.B #OFIFG,&IFG1
JNZ L1
MOV.B #XT2OFF+15,&BCSCTL1
After that I copied your code:
mov #CM_1 + CCIS_1 + SCS + CAP + OUTMOD_0, &TACCTL0
mov #MC_2 + ID_0 + TASSEL_2, &TACTL
call #await_aclk
mov r15, r14
call #await_aclk
sub r14, r15
And added an infinity loop followed by your subroutine.
JMP $
await_aclk
await_aclk_01
bit #CCIFG, &TACCTL0
jeq await_aclk_01
mov &TACCR0, r15
bic #CCIFG, &TACCTL0
ret
What I found is, r14 is kind of random and r15 is always what I expected.
Using one G2211, I always get 0x01B6 or 0x01b7. Using a different G2211, I always get 0x01D4 or 0x01D5. They correspond to DCO frequency of ~14.4 MHz and ~15.4 MHz respectively.
> You can assume that I've already set up the DCO at RSEL
> and that the LFXT1 is up and running and the error bit clear.
>
Okay, I assume that you did the following:
main: MOV.W #0x280,SP
MOV.W #WDTPW+WDTHOLD,&WDTCTL
MOV.B #XCAP_3,&BCSCTL3
MOV.W #0,R15
L1: BIC.B #OFIFG,&IFG1
L2: SUB.W #1,R15
JNZ L2
BIT.B #OFIFG,&IFG1
JNZ L1
MOV.B #XT2OFF+15,&BCSCTL1
After that I copied your code:
mov #CM_1 + CCIS_1 + SCS + CAP + OUTMOD_0, &TACCTL0
mov #MC_2 + ID_0 + TASSEL_2, &TACTL
call #await_aclk
mov r15, r14
call #await_aclk
sub r14, r15
And added an infinity loop followed by your subroutine.
JMP $
await_aclk
await_aclk_01
bit #CCIFG, &TACCTL0
jeq await_aclk_01
mov &TACCR0, r15
bic #CCIFG, &TACCTL0
ret
What I found is, r14 is kind of random and r15 is always what I expected.
Using one G2211, I always get 0x01B6 or 0x01b7. Using a different G2211, I always get 0x01D4 or 0x01D5. They correspond to DCO frequency of ~14.4 MHz and ~15.4 MHz respectively.
Reply by ●May 17, 20112011-05-17
Very similar code. I happen to set up some port I/O
directions and I also set the ACLK for a divisor of 8.
Otherwise, looks similar. Here's the prior instructions:
mov #SFE(CSTACK), SP
mov #WDTPW+WDTHOLD, &WDTCTL
bis.b #01000011b, &P1DIR
clr.b &DCOCTL
mov.b #XT2OFF + DIVA_3 + 15, &BCSCTL1
mov.b #01111111b, &DCOCTL
I knew that 1k-word of flash _might_ be tight (it won't be),
so I decided to rely upon stated initial conditions of the
various registers. The datasheet for the provided capacitor,
the Microcrystal MS3V-T1R was in hand, but it supports 7, 9,
and 12.5pF. The parts list for the LaunchPad was not in
hand, so I permitted the 6pF default to stand, above. I
could always change that when I took the extra time.
The documentation regarding the errata sheet on changing RSEL
from the default 7 to 15 is followed in the above code. Note
that there is a different process going in the other
direction. But they provide examples in the TLV chapter of
the x2xx Family manual, which I chose to follow per
instructions in the errata.
Your code, however, does something which inherently does what
I did to make things work before making those two calls.
However, that doesn't tell me __WHY__. So let's look at your
code, again:
>main: MOV.W #0x280,SP
> MOV.W #WDTPW+WDTHOLD,&WDTCTL
> MOV.B #XCAP_3,&BCSCTL3
> MOV.W #0,R15
>L1: BIC.B #OFIFG,&IFG1
>L2: SUB.W #1,R15
> JNZ L2
> BIT.B #OFIFG,&IFG1
> JNZ L1
> MOV.B #XT2OFF+15,&BCSCTL1
I'm going to skip over the dead-obvious first two
instructions. Nothing needs be said there.
The XCAP_3 setting to BCSCTL3 is different than the power up
case. But I don't think it's important, for now. It only
means the xtal gets pulled a little. It doesn't address
itself, unless you wish to say so, towards the question at
hand. But if you think that's it, I'd be happy to test it
here.
The last instruction modifies RSEL after those waiting for
the crystal to show "good." That's an interesting approach,
but I don't think it is a necessary one. I should be able to
transition to RSEL without regard to whether or not the
crystal is up and running. So I'll ignore that unless you
have a theory about why LFXT1 and setting RSEL are
necessarily tethered to each other.
So that gets us to these:
> MOV.W #0,R15
>L1: BIC.B #OFIFG,&IFG1
>L2: SUB.W #1,R15
> JNZ L2
> BIT.B #OFIFG,&IFG1
> JNZ L1
Here you clear OFIFG, wait a LONG TIME (R15 delay loop), and
then test OFIFG. If OFIFG is in error, you clear it again,
wait a LONG TIME again (R15 is back to zero, again), and then
repeat the process.
My code works perfectly well without most of that. If I
_only_ apply your R15 delay loop and NOTHING ELSE AT ALL, it
works perfectly.
My problem isn't getting right results. It's knowing ALL of
the details why.
In the case you provide above, you are ensuring that the
crystal is running before proceeding. I do that, too. And
it is. But my testing for that excluded the LONG DELAY part.
I just sat in a dead loop (which, by the way, was never
needed because by the time the processor was running it seems
that the crystal was also always running before I could even
start testing it.
So, of course you get good results with the above code. You
perform a LONG DELAY at least one time. Without the rest of
your OFIFG testing code (and mine deleted as well) it always
works perfectly, delay loop only.
It's still not an understanding. I know it works. But I
need to know why in terms of the electronics design of the
cpu. The details are important to me.
Jon
On Tue, 17 May 2011 18:41:45 -0000, OCY wrote:
>>
>> You can assume that I've already set up the DCO at RSEL
>> and that the LFXT1 is up and running and the error bit clear.
>>Okay, I assume that you did the following:
>
>main: MOV.W #0x280,SP
> MOV.W #WDTPW+WDTHOLD,&WDTCTL
> MOV.B #XCAP_3,&BCSCTL3
> MOV.W #0,R15
>L1: BIC.B #OFIFG,&IFG1
>L2: SUB.W #1,R15
> JNZ L2
> BIT.B #OFIFG,&IFG1
> JNZ L1
> MOV.B #XT2OFF+15,&BCSCTL1
>
>After that I copied your code:
>
> mov #CM_1 + CCIS_1 + SCS + CAP + OUTMOD_0, &TACCTL0
> mov #MC_2 + ID_0 + TASSEL_2, &TACTL
> call #await_aclk
> mov r15, r14
> call #await_aclk
> sub r14, r15
>
>And added an infinity loop followed by your subroutine.
>
> JMP $
>await_aclk
>await_aclk_01
> bit #CCIFG, &TACCTL0
> jeq await_aclk_01
> mov &TACCR0, r15
> bic #CCIFG, &TACCTL0
> ret
>
>What I found is, r14 is kind of random and r15 is always what I expected.
>
>Using one G2211, I always get 0x01B6 or 0x01b7. Using a different G2211, I always get 0x01D4 or 0x01D5. They correspond to DCO frequency of ~14.4 MHz and ~15.4 MHz respectively.
>
>
directions and I also set the ACLK for a divisor of 8.
Otherwise, looks similar. Here's the prior instructions:
mov #SFE(CSTACK), SP
mov #WDTPW+WDTHOLD, &WDTCTL
bis.b #01000011b, &P1DIR
clr.b &DCOCTL
mov.b #XT2OFF + DIVA_3 + 15, &BCSCTL1
mov.b #01111111b, &DCOCTL
I knew that 1k-word of flash _might_ be tight (it won't be),
so I decided to rely upon stated initial conditions of the
various registers. The datasheet for the provided capacitor,
the Microcrystal MS3V-T1R was in hand, but it supports 7, 9,
and 12.5pF. The parts list for the LaunchPad was not in
hand, so I permitted the 6pF default to stand, above. I
could always change that when I took the extra time.
The documentation regarding the errata sheet on changing RSEL
from the default 7 to 15 is followed in the above code. Note
that there is a different process going in the other
direction. But they provide examples in the TLV chapter of
the x2xx Family manual, which I chose to follow per
instructions in the errata.
Your code, however, does something which inherently does what
I did to make things work before making those two calls.
However, that doesn't tell me __WHY__. So let's look at your
code, again:
>main: MOV.W #0x280,SP
> MOV.W #WDTPW+WDTHOLD,&WDTCTL
> MOV.B #XCAP_3,&BCSCTL3
> MOV.W #0,R15
>L1: BIC.B #OFIFG,&IFG1
>L2: SUB.W #1,R15
> JNZ L2
> BIT.B #OFIFG,&IFG1
> JNZ L1
> MOV.B #XT2OFF+15,&BCSCTL1
I'm going to skip over the dead-obvious first two
instructions. Nothing needs be said there.
The XCAP_3 setting to BCSCTL3 is different than the power up
case. But I don't think it's important, for now. It only
means the xtal gets pulled a little. It doesn't address
itself, unless you wish to say so, towards the question at
hand. But if you think that's it, I'd be happy to test it
here.
The last instruction modifies RSEL after those waiting for
the crystal to show "good." That's an interesting approach,
but I don't think it is a necessary one. I should be able to
transition to RSEL without regard to whether or not the
crystal is up and running. So I'll ignore that unless you
have a theory about why LFXT1 and setting RSEL are
necessarily tethered to each other.
So that gets us to these:
> MOV.W #0,R15
>L1: BIC.B #OFIFG,&IFG1
>L2: SUB.W #1,R15
> JNZ L2
> BIT.B #OFIFG,&IFG1
> JNZ L1
Here you clear OFIFG, wait a LONG TIME (R15 delay loop), and
then test OFIFG. If OFIFG is in error, you clear it again,
wait a LONG TIME again (R15 is back to zero, again), and then
repeat the process.
My code works perfectly well without most of that. If I
_only_ apply your R15 delay loop and NOTHING ELSE AT ALL, it
works perfectly.
My problem isn't getting right results. It's knowing ALL of
the details why.
In the case you provide above, you are ensuring that the
crystal is running before proceeding. I do that, too. And
it is. But my testing for that excluded the LONG DELAY part.
I just sat in a dead loop (which, by the way, was never
needed because by the time the processor was running it seems
that the crystal was also always running before I could even
start testing it.
So, of course you get good results with the above code. You
perform a LONG DELAY at least one time. Without the rest of
your OFIFG testing code (and mine deleted as well) it always
works perfectly, delay loop only.
It's still not an understanding. I know it works. But I
need to know why in terms of the electronics design of the
cpu. The details are important to me.
Jon
On Tue, 17 May 2011 18:41:45 -0000, OCY wrote:
>>
>> You can assume that I've already set up the DCO at RSEL
>> and that the LFXT1 is up and running and the error bit clear.
>>Okay, I assume that you did the following:
>
>main: MOV.W #0x280,SP
> MOV.W #WDTPW+WDTHOLD,&WDTCTL
> MOV.B #XCAP_3,&BCSCTL3
> MOV.W #0,R15
>L1: BIC.B #OFIFG,&IFG1
>L2: SUB.W #1,R15
> JNZ L2
> BIT.B #OFIFG,&IFG1
> JNZ L1
> MOV.B #XT2OFF+15,&BCSCTL1
>
>After that I copied your code:
>
> mov #CM_1 + CCIS_1 + SCS + CAP + OUTMOD_0, &TACCTL0
> mov #MC_2 + ID_0 + TASSEL_2, &TACTL
> call #await_aclk
> mov r15, r14
> call #await_aclk
> sub r14, r15
>
>And added an infinity loop followed by your subroutine.
>
> JMP $
>await_aclk
>await_aclk_01
> bit #CCIFG, &TACCTL0
> jeq await_aclk_01
> mov &TACCR0, r15
> bic #CCIFG, &TACCTL0
> ret
>
>What I found is, r14 is kind of random and r15 is always what I expected.
>
>Using one G2211, I always get 0x01B6 or 0x01b7. Using a different G2211, I always get 0x01D4 or 0x01D5. They correspond to DCO frequency of ~14.4 MHz and ~15.4 MHz respectively.
>
>
Reply by ●May 17, 20112011-05-17
Let me add a note. I'm working on other things, but I went
back and double-checked some details.
When the G2231 starts up, OFIFG=1 but LFXT1OF=0. The LFXT1
is up and running, no errors, but by default the OFIFG=1 and
that is done because they want to MAKE SURE that the
processor __uses__ the DCO, at POR. That's clear enough.
Clearing OFIFG doesn't impact the LFXT1 oscillator system. It
merely permits the use of it for MCLK, if you might want
that. It is LFXT1OF, which is a combinatorial signal and not
a latch, that tells you the story.
Without a delay inserted at the top, and running the same
code today that yesterday gave me 1 error in 3 or 4 tries, is
now giving me fewer errors. Mostly, it happens right after
downloading code via the TI USB FET tool. If I reset and run
again, it almost always works. Yesterday, it would fail more
often. But I still do see the rare case where it "fails"
(according to my criteria), unless I insert a delay loop. It
also occasionally (still rarely) fails if I wait on LFXT1OF,
whether or not I first clear OFIFG.
I need to insert some code to manually reset the cpu and set
a breakpoint that only takes place on failures (so I will
need code to test against a tight range and go somewhere else
where the breakpoint is at should the value go outside the
range.) If it "succeeds" (again, according to my rules),
then I will reset the CPU and force a restart. In this way,
the debugger can be used to see if there are ANY single
failures at all, regardless of how many thousands or tens of
thousands of tries it takes to find one.
I'll try that now. Bulletproof and full understanding is
required.
By the way, OCY, your example code for starting things up
with the R15 delay loop comes almost straight out of the x2xx
Family Guide (I'm using SLAU144H) on page 279, section
heading 5.2.7.1. But they use 255 for the loop. Not the
very long period you use. Turns out, I had tried out the
small timing loop of 255 as a precursor to doing the rest and
that didn't always work. If I expanded it to about 1000, it
did always work.
Anyway, I know what works. In fact, I know quite a few ways
that work. And I have some vague ideas about possible
reasons for the occasional failure. Problem is, I want it
nailed down hard. Without the theory behind it, no matter
what I do and no matter how perfectly all my testing verifies
that it does work, the code generated from my ignorance
remains a potential risk. I don't like that feeling.
And very sincere thanks OCY for even bothering to think and
try anything to help me. I sincerely appreciate it and need
to say so. It means a lot.
Jon
back and double-checked some details.
When the G2231 starts up, OFIFG=1 but LFXT1OF=0. The LFXT1
is up and running, no errors, but by default the OFIFG=1 and
that is done because they want to MAKE SURE that the
processor __uses__ the DCO, at POR. That's clear enough.
Clearing OFIFG doesn't impact the LFXT1 oscillator system. It
merely permits the use of it for MCLK, if you might want
that. It is LFXT1OF, which is a combinatorial signal and not
a latch, that tells you the story.
Without a delay inserted at the top, and running the same
code today that yesterday gave me 1 error in 3 or 4 tries, is
now giving me fewer errors. Mostly, it happens right after
downloading code via the TI USB FET tool. If I reset and run
again, it almost always works. Yesterday, it would fail more
often. But I still do see the rare case where it "fails"
(according to my criteria), unless I insert a delay loop. It
also occasionally (still rarely) fails if I wait on LFXT1OF,
whether or not I first clear OFIFG.
I need to insert some code to manually reset the cpu and set
a breakpoint that only takes place on failures (so I will
need code to test against a tight range and go somewhere else
where the breakpoint is at should the value go outside the
range.) If it "succeeds" (again, according to my rules),
then I will reset the CPU and force a restart. In this way,
the debugger can be used to see if there are ANY single
failures at all, regardless of how many thousands or tens of
thousands of tries it takes to find one.
I'll try that now. Bulletproof and full understanding is
required.
By the way, OCY, your example code for starting things up
with the R15 delay loop comes almost straight out of the x2xx
Family Guide (I'm using SLAU144H) on page 279, section
heading 5.2.7.1. But they use 255 for the loop. Not the
very long period you use. Turns out, I had tried out the
small timing loop of 255 as a precursor to doing the rest and
that didn't always work. If I expanded it to about 1000, it
did always work.
Anyway, I know what works. In fact, I know quite a few ways
that work. And I have some vague ideas about possible
reasons for the occasional failure. Problem is, I want it
nailed down hard. Without the theory behind it, no matter
what I do and no matter how perfectly all my testing verifies
that it does work, the code generated from my ignorance
remains a potential risk. I don't like that feeling.
And very sincere thanks OCY for even bothering to think and
try anything to help me. I sincerely appreciate it and need
to say so. It means a lot.
Jon
Reply by ●May 18, 20112011-05-18
Jon Kirwan :
> On Tue, 17 May 2011 14:08:16 +0000 (UTC), you wrote:
>
>>I remember that there are some silicon bugs (e.g. TA12 TA16) in MSP430
>>devices related to ACLK and Timer capture/compare after initialization.
>>
>>Have you checked the errata of your device?
>
> Oh, yes. In fact, I not only mentioned the fact that I had
> checked the errata in the very post you are replying to, but
> I also mentioned that fact in the original post, as well. I
> looked closely at them and am following those rules. I also
> searched for ACLK in them and checked anything mentioning it.
Sorry, life is short, I just did not really read your very long article, just
fly over it. Keep it as short as possible and simple. :-)
M.
> On Tue, 17 May 2011 14:08:16 +0000 (UTC), you wrote:
>
>>I remember that there are some silicon bugs (e.g. TA12 TA16) in MSP430
>>devices related to ACLK and Timer capture/compare after initialization.
>>
>>Have you checked the errata of your device?
>
> Oh, yes. In fact, I not only mentioned the fact that I had
> checked the errata in the very post you are replying to, but
> I also mentioned that fact in the original post, as well. I
> looked closely at them and am following those rules. I also
> searched for ACLK in them and checked anything mentioning it.
Sorry, life is short, I just did not really read your very long article, just
fly over it. Keep it as short as possible and simple. :-)
M.