alex@alex... wrote: > The following program has been used to verify the Timer A TAIFG operation. > It is a modified version of > a TI supplied sample code. > <big snip> > #include <msp430x16x.h> > int temp; > void main(void) > { > temp=0; > WDTCTL = WDTPW + WDTHOLD; // Stop WDT > P1DIR |= 0x01; // P1.0 output > CCTL0 = CCIE; // CCR0 interrupt enabled > CCR0 = 0x7fff; > CCR1 = 0x9000; > CCR2 = 0xa000; > TACTL = TASSEL_1 + MC_1; // ACLK, upmode > > //_BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/ interrupt > _BIS_SR(GIE); > > while(1) > {}; > } > > // Timer A0 interrupt service routine > #pragma vector=TIMERA0_VECTOR > __interrupt void Timer_A (void) > { > > P1OUT ^= 0x01; > > if( (TACTL & TAIFG)== 0x0000) // count how many times we > temp++; // do not find the TAIFG > set > > TACTL &= ~TAIFG; > TACCTL2 &= ~CCIFG; > TACCTL1 &= ~CCIFG; > } > Alex, The TAIFG is used to indicate that TimerA has overflowed. TimerA will never overflow since you are using the CCR0 register and the timer in UP mode. Every time it reaches the CCR0 value, the CCIFG will be set and the timer will get reset back to zero. When the the vector to TIMER_A0 is taken, your CCIFG will get reset. Hope this helps, Greg
TAIFG
Started by ●September 7, 2005
Reply by ●September 9, 20052005-09-09
Reply by ●September 9, 20052005-09-09
Did you run the program, Greg? Just try it out :)O Alex ----- Original Message ----- From: "Greg Maki" <gmaki@gmak...> To: <msp430@msp4...> Sent: Friday, September 09, 2005 2:39 PM Subject: Re: Fw: [msp430] TAIFG Take 3. > alex@alex... wrote: > > > The following program has been used to verify the Timer A TAIFG operation. > > It is a modified version of > > a TI supplied sample code. > > > <big snip> > > > #include <msp430x16x.h> > > int temp; > > void main(void) > > { > > temp=0; > > WDTCTL = WDTPW + WDTHOLD; // Stop WDT > > P1DIR |= 0x01; // P1.0 output > > CCTL0 = CCIE; // CCR0 interrupt enabled > > CCR0 = 0x7fff; > > CCR1 = 0x9000; > > CCR2 = 0xa000; > > TACTL = TASSEL_1 + MC_1; // ACLK, upmode > > > > //_BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/ interrupt > > _BIS_SR(GIE); > > > > while(1) > > {}; > > } > > > > // Timer A0 interrupt service routine > > #pragma vector=TIMERA0_VECTOR > > __interrupt void Timer_A (void) > > { > > > > P1OUT ^= 0x01; > > > > if( (TACTL & TAIFG)== 0x0000) // count how many times we > > temp++; // do not find the TAIFG > > set > > > > TACTL &= ~TAIFG; > > TACCTL2 &= ~CCIFG; > > TACCTL1 &= ~CCIFG; > > } > > > > Alex, > > The TAIFG is used to indicate that TimerA has overflowed. TimerA will > never overflow since you are using the CCR0 register and the timer in UP > mode. Every time it reaches the CCR0 value, the CCIFG will be set and > the timer will get reset back to zero. When the the vector to TIMER_A0 > is taken, your CCIFG will get reset. > > Hope this helps, > > Greg > > > > . > > > Yahoo! Groups Links > > > > > > > > > > > --- > avast! Antivirus: Inbound message clean. > Virus Database (VPS): 0536-0, 09/05/2005 > Tested on: 9/9/2005 2:41:38 PM > avast! - copyright (c) 1988-2005 ALWIL Software. > http://www.avast.com > > >
Reply by ●September 9, 20052005-09-09
As my insurance companys slogan goes" We can't help but help", even when the people you're trying to help are too thick headed to accept it, or believe it. Perhaps he's baiting me in some perverse way, who cares, well I do when he starts sucking others into his delusions. alex@alex... wrote: >>The following program has been used to verify the Timer A TAIFG >> >> >operation. > > >>>It is a modified version of >>>a TI supplied sample code. >>> >>> >>> >>> >><big snip> >> >> >> >>>#include <msp430x16x.h> >>>int temp; >>>void main(void) >>>{ >>> temp=0; >>> WDTCTL = WDTPW + WDTHOLD; // Stop WDT >>> P1DIR |= 0x01; // P1.0 output >>> CCTL0 = CCIE; // CCR0 interrupt enabled >>> CCR0 = 0x7fff; >>> 1 second roll over with a watch crystal in Up Mode >>> >>> CCR1 = 0x9000; >>> CCR2 = 0xa000; >>> Pointless values since the timer rolls over to 0000 from 7FFF it can never reach these values. >>> TACTL = TASSEL_1 + MC_1; // ACLK, upmode >>> UP MODE is set. TAR will roll over twhen it equals 7FFF to 0000, it will generate a CCR0 interrupt on mathc and a TimerA overflow interrupt on the very next clock cycle. Not an overly useful thing to do, but TAIFG isn't used. >>> //_BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/ interrupt >>> _BIS_SR(GIE); >>> >>> while(1) >>> {}; >>>} >>> >>>// Timer A0 interrupt service routine >>>#pragma vector=TIMERA0_VECTOR >>>__interrupt void Timer_A (void) >>>{ >>> >>> P1OUT ^= 0x01; >>> >>> if( (TACTL & TAIFG)== 0x0000) // count how many times we >>> temp++; // do not find the >>> >>> >TAIFG > > >>>set >>> Well we won't find TAIFG set the first time around, because it sets on the rollover. You should never find TACCTL1 or 2 set, and, because TAR has continued counting after TACCTL0 CCIFG was set to get to this ISR you will never have TAIFG set if MCLK = ACLK, but may see it set if MCLK and ACLK are asynchronous and MCLK is much faster than ACLK. And this behaviour will be sporadic because occasionally you will meet a situation where the CCR0 flag is set, and the check point in the ISR is reached after TAIFG gets set, while on others you will reach it before this point, in which case it won't be seen by your software, as The flag gest reset before exit from the ISR. Cheers Al >>> >>> TACTL &= ~TAIFG; >>> TACCTL2 &= ~CCIFG; >>> TACCTL1 &= ~CCIFG; >>>} >>> >>> >>> >>Alex, >> >>The TAIFG is used to indicate that TimerA has overflowed. TimerA will >>never overflow since you are using the CCR0 register and the timer in UP >>mode. Every time it reaches the CCR0 value, the CCIFG will be set and >>the timer will get reset back to zero. When the the vector to TIMER_A0 >>is taken, your CCIFG will get reset. >> >>Hope this helps, >> >>Greg >> >> >> >>. >> >> >>Yahoo! Groups Links >> >> >> >> >> >> >> >> >> >> >>--- >>avast! Antivirus: Inbound message clean. >>Virus Database (VPS): 0536-0, 09/05/2005 >>Tested on: 9/9/2005 2:41:38 PM >>avast! - copyright (c) 1988-2005 ALWIL Software. >>http://www.avast.com >> >> >> >> >> > > > > >. > > >Yahoo! Groups Links > > > > > > > > > >
Reply by ●September 9, 20052005-09-09
Greg, I happen to think that the word "overflow" is missused here
TAIFG will be set anytime TAR is zero. This means that one clock
after the count reaches CCR0 the TAR is reset to zero thus setting the
TAIFG! This much is clear. But now an other problem occurs.
I can not see the CCIFG set although TAR is equal to CCR0!
And so, I am full circle where I started :(
I can see the timing drawing in the UM whereCCIG is depicted as a
very narrow pulse, much smaller that a clock cycle. Is this meaning
that CCIFG is reset immediately and I really can not see it set once
in the ISR. If this is so, why describe it as a user accessible flag?
Alex.
----- Original Message -----
From: "Greg Maki" <gmaki@gmak...>
To: <msp430@msp4...>
Sent: ay, September 09, 2005 2:39 PM
Subject: Re: Fw: [msp430] TAIFG Take 3.
>
> The TAIFG is used to indicate that TimerA has overflowed. TimerA will
> never overflow since you are using the CCR0 register and the timer in UP
> mode. Every time it reaches the CCR0 value, the CCIFG will be set and
> the timer will get reset back to zero. When the the vector to TIMER_A0
> is taken, your CCIFG will get reset.
>
> Hope this helps,
>
> Greg
>
>
>
> .
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
>
>
>
> ---
> avast! Antivirus: Inbound message clean.
> Virus Database (VPS): 0536-0, 09/05/2005
> Tested on: 9/9/2005 2:41:38 PM
> avast! - copyright (c) 1988-2005 ALWIL Software.
> http://www.avast.com
>
>
>
Reply by ●September 9, 20052005-09-09
Greg, I am starting to think that the docs should be annotated as follows: "Timer A in Up Mode uses a single dedicated Vector to witch the ISR jumps when CCR0 == TAR. No IFG are available during ISR execution." This would have been much more simple! Is this a good synthesis of the much discussed problem? Alex
Reply by ●September 9, 20052005-09-09
The best way to test it is using the interrupt handler itself. It isn't immediately obvious, but in "up" mode you generate 2 interrupts. One when TAR reaches CCR0 (ie TACCR0 IFG) and one when the timer overflows from CCR0 to 0 (ie TAIFG). This means you can use either interrupt, but it is usual in this case to disable the TAIFG via TAIE since TACCR0 is faster to process. If they are both left enabled - this is a common mistake - you get a spurious TAIFG interrupt which in fact does nothing other than cause an interrupt - every single time TAR rolls over from CCR0 to 0. This of course wastes power. Note the use of the intermediary LocalTAIV variable; this allows multiple interrupts to be processed within one interrupt function overhead, should such a situation ever occur. That does not include the TACCR0 interrupt, which as you note has a separate vector. This doesn't actually help much, unless you expect interrupts close together, since it means all interrupts then have the additional overhead of first latching this value. However, it can stop you missing such an event entirely, since the first read of TAIV clears all the interrupt flags. A line such as "if (TAIV & mask) ,,," therefore clears all the flags currently set, but you only get to process just one of them. Here is a typical interrupt handler pair for Timer_A. Note how the TAIE bit is cleared in case it ever happens as a precaution, since our real code is in the other handler. Initialise: This is a mistake, but try it: // Select ACLK in continuous up mode with overflow interrupt enabled TACTL = TASSEL0 | MC_1 | TAIE; This is what we really wanted: // Select ACLK in continuous up mode with overflow interrupt disabled TACTL = TASSEL0 | MC_1; CCTL0 = CCIE; // Enable CCR0 interrupt CCR1 = Trip_1; CCTL1 = CCIE; CCR2 = Trip_2; CCTL2 = CCIS0 | CCIE; // 0xFFF2 Timer A CC0 void isr_timerA_cc0(void) __interrupt[TIMERA0_VECTOR] { /* * Timer A0 interrupt * * TimerA Up Mode * ============= * The up mode is used if the timer period must be different from 0FFFFh * counts. * The timer repeatedly counts up to the value of compare register TACCR0, * which defines the period. The number of timer counts in the period is * TACCR0+1. When the timer value equals TACCR0 the timer restarts * counting from zero. If up mode is selected when the timer value is * greater than TACCR0, the timer immediately restarts counting from zero. * * The TACCR0 CCIFG interrupt flag is set when the timer equals the TACCR0 * value. The TAIFG interrupt flag is set when the timer counts from TACCR0 to * zero. */ // blah blah LPM3_EXIT; // Exit Low Power Mode 3 } // 0xFFF0 Timer A3 CC1-2, TA void isr_timerA_cc1_2(void) __interrupt[TIMERA1_VECTOR] /* * Timer A3 interrupts * * The TAIFG interrupt flag is set in up mode when the timer counts from TACCR0 * to zero. */ { uint16 LocalTAIV; // Only read TAIV once per interrupt action within the switch since the // read of the register clears the hardware flags while (LocalTAIV = TAIV) { switch(LocalTAIV) // Timer A Interrupt Vector Word { default: case 0: // no interrupt ready // blah blah // LPM3_EXIT; // Exit Low Power Mode 3 if required break; case 2: // CCR1 - ADC time-to-read interrupt // blah blah // LPM3_EXIT; // Exit Low Power Mode 3 if required break; case 4: // CCR2 - RTC interrupt, typically every 1 second // blah blah // LPM3_EXIT; // Exit Low Power Mode 3 if required break; case 10: // TAIFG NaughtyNaughty++; TACTL &= ~TAIE; // Disable timer A overflow interrupt to reduce power // LPM3_EXIT; // Exit Low Power Mode 3 if required break; } } } Hugh At 15:59 09/09/2005 -0400, you wrote: Greg, I happen to think that the word "overflow" is missused here TAIFG will be set anytime TAR is zero. This means that one clock after the count reaches CCR0 the TAR is reset to zero thus setting the TAIFG! This much is clear. But now an other problem occurs. I can not see the CCIFG set although TAR is equal to CCR0! And so, I am full circle where I started :( I can see the timing drawing in the UM whereCCIG is depicted as a very narrow pulse, much smaller that a clock cycle. Is this meaning that CCIFG is reset immediately and I really can not see it set once in the ISR. If this is so, why describe it as a user accessible flag? Alex. ----- Original Message ----- From: "Greg Maki" <gmaki@gmak...> To: <msp430@msp4...> Sent: ay, September 09, 2005 2:39 PM Subject: Re: Fw: [msp430] TAIFG Take 3. > > The TAIFG is used to indicate that TimerA has overflowed. TimerA will > never overflow since you are using the CCR0 register and the timer in UP > mode. Every time it reaches the CCR0 value, the CCIFG will be set and > the timer will get reset back to zero. When the the vector to TIMER_A0 > is taken, your CCIFG will get reset. > > Hope this helps, > > Greg
Reply by ●September 9, 20052005-09-09
Hi Hugh, good post except the first read of TAIV does NOT clear all the
pending interrupt flags. Only the highest pending one that is enabled.
Al
Hugh Molesworth wrote:
>The best way to test it is using the interrupt
handler itself. It isn't
>immediately obvious, but in "up" mode you generate 2 interrupts.
One when
>TAR reaches CCR0 (ie TACCR0 IFG) and one when the timer overflows from CCR0
>to 0 (ie TAIFG). This means you can use either interrupt, but it is usual
>in this case to disable the TAIFG via TAIE since TACCR0 is faster to
>process. If they are both left enabled - this is a common mistake - you get
>a spurious TAIFG interrupt which in fact does nothing other than cause an
>interrupt - every single time TAR rolls over from CCR0 to 0. This of course
>wastes power.
>
>Note the use of the intermediary LocalTAIV variable; this allows multiple
>interrupts to be processed within one interrupt function overhead, should
>such a situation ever occur. That does not include the TACCR0 interrupt,
>which as you note has a separate vector. This doesn't actually help
much,
>unless you expect interrupts close together, since it means all interrupts
>then have the additional overhead of first latching this value. However, it
>can stop you missing such an event entirely, since the first read of TAIV
>clears all the interrupt flags. A line such as "if (TAIV & mask)
,,,"
>therefore clears all the flags currently set, but you only get to process
>just one of them.
>
>Here is a typical interrupt handler pair for Timer_A. Note how the TAIE bit
>is cleared in case it ever happens as a precaution, since our real code is
>in the other handler.
>
>Initialise:
>
>This is a mistake, but try it:
> // Select ACLK in continuous up mode with overflow interrupt enabled
> TACTL = TASSEL0 | MC_1 | TAIE;
>This is what we really wanted:
> // Select ACLK in continuous up mode with overflow interrupt disabled
> TACTL = TASSEL0 | MC_1;
>
> CCTL0 = CCIE; // Enable CCR0 interrupt
> CCR1 = Trip_1;
> CCTL1 = CCIE;
> CCR2 = Trip_2;
> CCTL2 = CCIS0 | CCIE;
>
>// 0xFFF2 Timer A CC0
>
>void isr_timerA_cc0(void) __interrupt[TIMERA0_VECTOR]
>{
>/*
> * Timer A0 interrupt
> *
> * TimerA Up Mode
> * =============> * The up mode is used if the timer period must be
different from 0FFFFh
> * counts.
> * The timer repeatedly counts up to the value of compare register TACCR0,
> * which defines the period. The number of timer counts in the period is
> * TACCR0+1. When the timer value equals TACCR0 the timer restarts
> * counting from zero. If up mode is selected when the timer value is
> * greater than TACCR0, the timer immediately restarts counting from zero.
> *
> * The TACCR0 CCIFG interrupt flag is set when the timer equals the TACCR0
> * value. The TAIFG interrupt flag is set when the timer counts from TACCR0
to
> * zero.
> */
>
> // blah blah
> LPM3_EXIT; // Exit Low Power Mode 3
>}
>
>// 0xFFF0 Timer A3 CC1-2, TA
>
>void isr_timerA_cc1_2(void) __interrupt[TIMERA1_VECTOR]
>/*
> * Timer A3 interrupts
> *
> * The TAIFG interrupt flag is set in up mode when the timer counts from
>TACCR0
> * to zero.
> */
>{
> uint16 LocalTAIV;
>
> // Only read TAIV once per interrupt action within the switch since the
> // read of the register clears the hardware flags
> while (LocalTAIV = TAIV)
> {
> switch(LocalTAIV) // Timer A Interrupt Vector Word
> {
> default:
> case 0: // no interrupt ready
> // blah blah
> // LPM3_EXIT; // Exit Low Power Mode 3 if required
> break;
>
> case 2: // CCR1 - ADC time-to-read interrupt
> // blah blah
> // LPM3_EXIT; // Exit Low Power Mode 3 if required
> break;
>
> case 4: // CCR2 - RTC interrupt, typically every 1 second
> // blah blah
> // LPM3_EXIT; // Exit Low Power Mode 3 if required
> break;
>
> case 10: // TAIFG
> NaughtyNaughty++;
> TACTL &= ~TAIE; // Disable timer A overflow interrupt
to
>reduce power
> // LPM3_EXIT; // Exit Low Power Mode 3 if required
> break;
> }
> }
>}
>
>Hugh
>
>
>At 15:59 09/09/2005 -0400, you wrote:
>
>Greg, I happen to think that the word "overflow" is missused here
>TAIFG will be set anytime TAR is zero. This means that one clock
>after the count reaches CCR0 the TAR is reset to zero thus setting the
>TAIFG! This much is clear. But now an other problem occurs.
>I can not see the CCIFG set although TAR is equal to CCR0!
>And so, I am full circle where I started :(
>
>I can see the timing drawing in the UM whereCCIG is depicted as a
>very narrow pulse, much smaller that a clock cycle. Is this meaning
>that CCIFG is reset immediately and I really can not see it set once
>in the ISR. If this is so, why describe it as a user accessible flag?
>
>Alex.
>
>----- Original Message -----
>From: "Greg Maki" <gmaki@gmak...>
>To: <msp430@msp4...>
>Sent: ay, September 09, 2005 2:39 PM
>Subject: Re: Fw: [msp430] TAIFG Take 3.
> >
> > The TAIFG is used to indicate that TimerA has overflowed. TimerA will
> > never overflow since you are using the CCR0 register and the timer in
UP
> > mode. Every time it reaches the CCR0 value, the CCIFG will be set and
> > the timer will get reset back to zero. When the the vector to TIMER_A0
> > is taken, your CCIFG will get reset.
> >
> > Hope this helps,
> >
> > Greg
>
>
>
>
>
>.
>
>
>Yahoo! Groups Links
>
>
>
>
>
>
>
>
>
>
Reply by ●September 9, 20052005-09-09
Good point, I forgot that. The next highest interrupt gets read inside the while loop. Hugh At 08:00 10/09/2005 +0930, you wrote: Hi Hugh, good post except the first read of TAIV does NOT clear all the pending interrupt flags. Only the highest pending one that is enabled. Al Hugh Molesworth wrote: >The best way to test it is using the interrupt handler itself. It isn't >immediately obvious, but in "up" mode you generate 2 interrupts. One when >TAR reaches CCR0 (ie TACCR0 IFG) and one when the timer overflows from CCR0 >to 0 (ie TAIFG). This means you can use either interrupt, but it is usual >in this case to disable the TAIFG via TAIE since TACCR0 is faster to >process. If they are both left enabled - this is a common mistake - you get >a spurious TAIFG interrupt which in fact does nothing other than cause an >interrupt - every single time TAR rolls over from CCR0 to 0. This of course >wastes power. > >Note the use of the intermediary LocalTAIV variable; this allows multiple >interrupts to be processed within one interrupt function overhead, should >such a situation ever occur. That does not include the TACCR0 interrupt, >which as you note has a separate vector. This doesn't actually help much, >unless you expect interrupts close together, since it means all interrupts >then have the additional overhead of first latching this value. However, it >can stop you missing such an event entirely, since the first read of TAIV >clears all the interrupt flags. A line such as "if (TAIV & mask) ,,," >therefore clears all the flags currently set, but you only get to process >just one of them. > >Here is a typical interrupt handler pair for Timer_A. Note how the TAIE bit >is cleared in case it ever happens as a precaution, since our real code is >in the other handler. > >Initialise: > >This is a mistake, but try it: > // Select ACLK in continuous up mode with overflow interrupt enabled > TACTL = TASSEL0 | MC_1 | TAIE; >This is what we really wanted: > // Select ACLK in continuous up mode with overflow interrupt disabled > TACTL = TASSEL0 | MC_1; > > CCTL0 = CCIE; // Enable CCR0 interrupt > CCR1 = Trip_1; > CCTL1 = CCIE; > CCR2 = Trip_2; > CCTL2 = CCIS0 | CCIE; > >// 0xFFF2 Timer A CC0 > >void isr_timerA_cc0(void) __interrupt[TIMERA0_VECTOR] >{ >/* > * Timer A0 interrupt > * > * TimerA Up Mode > * ============= > * The up mode is used if the timer period must be different from 0FFFFh > * counts. > * The timer repeatedly counts up to the value of compare register TACCR0, > * which defines the period. The number of timer counts in the period is > * TACCR0+1. When the timer value equals TACCR0 the timer restarts > * counting from zero. If up mode is selected when the timer value is > * greater than TACCR0, the timer immediately restarts counting from zero. > * > * The TACCR0 CCIFG interrupt flag is set when the timer equals the TACCR0 > * value. The TAIFG interrupt flag is set when the timer counts from TACCR0 to > * zero. > */ > > // blah blah > LPM3_EXIT; // Exit Low Power Mode 3 >} > >// 0xFFF0 Timer A3 CC1-2, TA > >void isr_timerA_cc1_2(void) __interrupt[TIMERA1_VECTOR] >/* > * Timer A3 interrupts > * > * The TAIFG interrupt flag is set in up mode when the timer counts from >TACCR0 > * to zero. > */ >{ > uint16 LocalTAIV; > > // Only read TAIV once per interrupt action within the switch since the > // read of the register clears the hardware flags > while (LocalTAIV = TAIV) > { > switch(LocalTAIV) // Timer A Interrupt Vector Word > { > default: > case 0: // no interrupt ready > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 2: // CCR1 - ADC time-to-read interrupt > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 4: // CCR2 - RTC interrupt, typically every 1 second > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 10: // TAIFG > NaughtyNaughty++; > TACTL &= ~TAIE; // Disable timer A overflow interrupt to >reduce power > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > } > } >} > >Hugh > > >At 15:59 09/09/2005 -0400, you wrote: > >Greg, I happen to think that the word "overflow" is missused here >TAIFG will be set anytime TAR is zero. This means that one clock >after the count reaches CCR0 the TAR is reset to zero thus setting the >TAIFG! This much is clear. But now an other problem occurs. >I can not see the CCIFG set although TAR is equal to CCR0! >And so, I am full circle where I started :( > >I can see the timing drawing in the UM whereCCIG is depicted as a >very narrow pulse, much smaller that a clock cycle. Is this meaning >that CCIFG is reset immediately and I really can not see it set once >in the ISR. If this is so, why describe it as a user accessible flag? > >Alex. > >----- Original Message ----- >From: "Greg Maki" <gmaki@gmak...> >To: <msp430@msp4...> >Sent: ay, September 09, 2005 2:39 PM >Subject: Re: Fw: [msp430] TAIFG Take 3. > > > > The TAIFG is used to indicate that TimerA has overflowed. TimerA will > > never overflow since you are using the CCR0 register and the timer in UP > > mode. Every time it reaches the CCR0 value, the CCIFG will be set and > > the timer will get reset back to zero. When the the vector to TIMER_A0 > > is taken, your CCIFG will get reset. > > > > Hope this helps, > > > > Greg
Reply by ●September 9, 20052005-09-09
Hugh, tanks. You have posted much more information than I was looking for :) I have a much more simple question which is: Are TAIFG and CCR0 IFG flags visible with the C-SPY as set when I breakpoint on first instruction in my ISR? This instruction is a simple "i++:" This is ALL I need to know ;) A simple yes or no will suffice :) Alex. inal Message ----- From: "Hugh Molesworth" <nzbackpackers@nzba...> To: <msp430@msp4...> Sent: Friday, September 09, 2005 5:30 PM Subject: Re: [msp430] TAIFG > The best way to test it is using the interrupt handler itself. It isn't > immediately obvious, but in "up" mode you generate 2 interrupts. One when > TAR reaches CCR0 (ie TACCR0 IFG) and one when the timer overflows from CCR0 > to 0 (ie TAIFG). This means you can use either interrupt, but it is usual > in this case to disable the TAIFG via TAIE since TACCR0 is faster to > process. If they are both left enabled - this is a common mistake - you get > a spurious TAIFG interrupt which in fact does nothing other than cause an > interrupt - every single time TAR rolls over from CCR0 to 0. This of course > wastes power. > > Note the use of the intermediary LocalTAIV variable; this allows multiple > interrupts to be processed within one interrupt function overhead, should > such a situation ever occur. That does not include the TACCR0 interrupt, > which as you note has a separate vector. This doesn't actually help much, > unless you expect interrupts close together, since it means all interrupts > then have the additional overhead of first latching this value. However, it > can stop you missing such an event entirely, since the first read of TAIV > clears all the interrupt flags. A line such as "if (TAIV & mask) ,,," > therefore clears all the flags currently set, but you only get to process > just one of them. > > Here is a typical interrupt handler pair for Timer_A. Note how the TAIE bit > is cleared in case it ever happens as a precaution, since our real code is > in the other handler. > > Initialise: > > This is a mistake, but try it: > // Select ACLK in continuous up mode with overflow interrupt enabled > TACTL = TASSEL0 | MC_1 | TAIE; > This is what we really wanted: > // Select ACLK in continuous up mode with overflow interrupt disabled > TACTL = TASSEL0 | MC_1; > > CCTL0 = CCIE; // Enable CCR0 interrupt > CCR1 = Trip_1; > CCTL1 = CCIE; > CCR2 = Trip_2; > CCTL2 = CCIS0 | CCIE; > > // 0xFFF2 Timer A CC0 > > void isr_timerA_cc0(void) __interrupt[TIMERA0_VECTOR] > { > /* > * Timer A0 interrupt > * > * TimerA Up Mode > * =============> * The up mode is used if the timer period must be different from 0FFFFh > * counts. > * The timer repeatedly counts up to the value of compare register TACCR0, > * which defines the period. The number of timer counts in the period is > * TACCR0+1. When the timer value equals TACCR0 the timer restarts > * counting from zero. If up mode is selected when the timer value is > * greater than TACCR0, the timer immediately restarts counting from zero. > * > * The TACCR0 CCIFG interrupt flag is set when the timer equals the TACCR0 > * value. The TAIFG interrupt flag is set when the timer counts from TACCR0 to > * zero. > */ > > // blah blah > LPM3_EXIT; // Exit Low Power Mode 3 > } > > // 0xFFF0 Timer A3 CC1-2, TA > > void isr_timerA_cc1_2(void) __interrupt[TIMERA1_VECTOR] > /* > * Timer A3 interrupts > * > * The TAIFG interrupt flag is set in up mode when the timer counts from > TACCR0 > * to zero. > */ > { > uint16 LocalTAIV; > > // Only read TAIV once per interrupt action within the switch since the > // read of the register clears the hardware flags > while (LocalTAIV = TAIV) > { > switch(LocalTAIV) // Timer A Interrupt Vector Word > { > default: > case 0: // no interrupt ready > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 2: // CCR1 - ADC time-to-read interrupt > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 4: // CCR2 - RTC interrupt, typically every 1 second > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 10: // TAIFG > NaughtyNaughty++; > TACTL &= ~TAIE; // Disable timer A overflow interrupt to > reduce power > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > } > } > } > > Hugh > > > At 15:59 09/09/2005 -0400, you wrote: > > Greg, I happen to think that the word "overflow" is missused here > TAIFG will be set anytime TAR is zero. This means that one clock > after the count reaches CCR0 the TAR is reset to zero thus setting the > TAIFG! This much is clear. But now an other problem occurs. > I can not see the CCIFG set although TAR is equal to CCR0! > And so, I am full circle where I started :( > > I can see the timing drawing in the UM whereCCIG is depicted as a > very narrow pulse, much smaller that a clock cycle. Is this meaning > that CCIFG is reset immediately and I really can not see it set once > in the ISR. If this is so, why describe it as a user accessible flag? > > Alex. > > ----- Original Message ----- > From: "Greg Maki" <gmaki@gmak...> > To: <msp430@msp4...> > Sent: ay, September 09, 2005 2:39 PM > Subject: Re: Fw: [msp430] TAIFG Take 3. > > > > The TAIFG is used to indicate that TimerA has overflowed. TimerA will > > never overflow since you are using the CCR0 register and the timer in UP > > mode. Every time it reaches the CCR0 value, the CCIFG will be set and > > the timer will get reset back to zero. When the the vector to TIMER_A0 > > is taken, your CCIFG will get reset. > > > > Hope this helps, > > > > Greg > > > > > > . > > > Yahoo! Groups Links > > > > > > > > > > --- > avast! Antivirus: Inbound message clean. > Virus Database (VPS): 0536-0, 09/05/2005 > Tested on: 9/9/2005 7:27:32 PM > avast! - copyright (c) 1988-2005 ALWIL Software. > http://www.avast.com > > >
Reply by ●September 9, 20052005-09-09
Actually I'm not sure about CCR0 IFG; TAIFG should however be visible until TAIV is read. The problem here is that although you don't read TAIV before you break, C-Spy probably does read TAIV after the breakpoint when it updates it's register display, and any read of TAIV will clear TAIFG if it is the highest priority bit set. Does C-Spy display the latched value? Hmm. Question for Anders. My IAR stuff is older, since I didn't care to pay the update fees. However, the work-around for TAIFG is to copy TAIV it into a register as below, then break. I think CCR0 IFG may be indeterminate, but of course it must have been set for the CCR0 interrupt to have been triggered. So any breakpoint which goes active inside the CCR0 interrupt indicates CCR0 IFG was set. So, Yes and No. However ... enable TAIE, disable CCR0 IE, break on i++ in interrupt function CCR1-2 and both will be visible, since TAIFG will be set (generating the interrupt) and CCR0 IFG will have been already set but won't generate an interrupt. Hugh At 19:40 09/09/2005 -0400, you wrote: Hugh, tanks. You have posted much more information than I was looking for :) I have a much more simple question which is: Are TAIFG and CCR0 IFG flags visible with the C-SPY as set when I breakpoint on first instruction in my ISR? This instruction is a simple "i++:" This is ALL I need to know ;) A simple yes or no will suffice :) Alex. inal Message ----- From: "Hugh Molesworth" <nzbackpackers@nzba...> To: <msp430@msp4...> Sent: Friday, September 09, 2005 5:30 PM Subject: Re: [msp430] TAIFG > The best way to test it is using the interrupt handler itself. It isn't > immediately obvious, but in "up" mode you generate 2 interrupts. One when > TAR reaches CCR0 (ie TACCR0 IFG) and one when the timer overflows from CCR0 > to 0 (ie TAIFG). This means you can use either interrupt, but it is usual > in this case to disable the TAIFG via TAIE since TACCR0 is faster to > process. If they are both left enabled - this is a common mistake - you get > a spurious TAIFG interrupt which in fact does nothing other than cause an > interrupt - every single time TAR rolls over from CCR0 to 0. This of course > wastes power. > > Note the use of the intermediary LocalTAIV variable; this allows multiple > interrupts to be processed within one interrupt function overhead, should > such a situation ever occur. That does not include the TACCR0 interrupt, > which as you note has a separate vector. This doesn't actually help much, > unless you expect interrupts close together, since it means all interrupts > then have the additional overhead of first latching this value. However, it > can stop you missing such an event entirely, since the first read of TAIV > clears all the interrupt flags. A line such as "if (TAIV & mask) ,,," > therefore clears all the flags currently set, but you only get to process > just one of them. > > Here is a typical interrupt handler pair for Timer_A. Note how the TAIE bit > is cleared in case it ever happens as a precaution, since our real code is > in the other handler. > > Initialise: > > This is a mistake, but try it: > // Select ACLK in continuous up mode with overflow interrupt enabled > TACTL = TASSEL0 | MC_1 | TAIE; > This is what we really wanted: > // Select ACLK in continuous up mode with overflow interrupt disabled > TACTL = TASSEL0 | MC_1; > > CCTL0 = CCIE; // Enable CCR0 interrupt > CCR1 = Trip_1; > CCTL1 = CCIE; > CCR2 = Trip_2; > CCTL2 = CCIS0 | CCIE; > > // 0xFFF2 Timer A CC0 > > void isr_timerA_cc0(void) __interrupt[TIMERA0_VECTOR] > { > /* > * Timer A0 interrupt > * > * TimerA Up Mode > * ============= > * The up mode is used if the timer period must be different from 0FFFFh > * counts. > * The timer repeatedly counts up to the value of compare register TACCR0, > * which defines the period. The number of timer counts in the period is > * TACCR0+1. When the timer value equals TACCR0 the timer restarts > * counting from zero. If up mode is selected when the timer value is > * greater than TACCR0, the timer immediately restarts counting from zero. > * > * The TACCR0 CCIFG interrupt flag is set when the timer equals the TACCR0 > * value. The TAIFG interrupt flag is set when the timer counts from TACCR0 to > * zero. > */ > > // blah blah > LPM3_EXIT; // Exit Low Power Mode 3 > } > > // 0xFFF0 Timer A3 CC1-2, TA > > void isr_timerA_cc1_2(void) __interrupt[TIMERA1_VECTOR] > /* > * Timer A3 interrupts > * > * The TAIFG interrupt flag is set in up mode when the timer counts from > TACCR0 > * to zero. > */ > { > uint16 LocalTAIV; > > // Only read TAIV once per interrupt action within the switch since the > // read of the register clears the hardware flags > while (LocalTAIV = TAIV) > { > switch(LocalTAIV) // Timer A Interrupt Vector Word > { > default: > case 0: // no interrupt ready > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 2: // CCR1 - ADC time-to-read interrupt > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 4: // CCR2 - RTC interrupt, typically every 1 second > // blah blah > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > > case 10: // TAIFG > NaughtyNaughty++; > TACTL &= ~TAIE; // Disable timer A overflow interrupt to > reduce power > // LPM3_EXIT; // Exit Low Power Mode 3 if required > break; > } > } > } > > Hugh > > > At 15:59 09/09/2005 -0400, you wrote: > > Greg, I happen to think that the word "overflow" is missused here > TAIFG will be set anytime TAR is zero. This means that one clock > after the count reaches CCR0 the TAR is reset to zero thus setting the > TAIFG! This much is clear. But now an other problem occurs. > I can not see the CCIFG set although TAR is equal to CCR0! > And so, I am full circle where I started :( > > I can see the timing drawing in the UM whereCCIG is depicted as a > very narrow pulse, much smaller that a clock cycle. Is this meaning > that CCIFG is reset immediately and I really can not see it set once > in the ISR. If this is so, why describe it as a user accessible flag? > > Alex. > > ----- Original Message ----- > From: "Greg Maki" <gmaki@gmak...> > To: <msp430@msp4...> > Sent: ay, September 09, 2005 2:39 PM > Subject: Re: Fw: [msp430] TAIFG Take 3. > > > > The TAIFG is used to indicate that TimerA has overflowed. TimerA will > > never overflow since you are using the CCR0 register and the timer in UP > > mode. Every time it reaches the CCR0 value, the CCIFG will be set and > > the timer will get reset back to zero. When the the vector to TIMER_A0 > > is taken, your CCIFG will get reset. > > > > Hope this helps, > > > > Greg