MSPLife 2 Posted December 18, 2015 Share Posted December 18, 2015 Hi everyone, I want to use both of Timer0_A0 and Timer0_A1 interrupt. I have configured as below: void TIM_TRIG_ADC_CFG(){ CCTL0 &= ~CCIE; CCTL1 &= ~CCIE; TACTL = TASSEL_2 + MC_1; // Set the timer A to SMCLCK, Continuous TACCR0 = 50000-1; TACCR1 += 25000-1; CCTL0 |= CCIE; CCTL1 |= CCIE; // Clear the timer and enable timer interrupt __enable_interrupt(); } // Timer A0 interrupt service routine #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A00 (void) { if(!((++timerCount)%16)) P1OUT ^= LED_RED; } // Timer A1 interrupt service routine #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A01 (void) { if(!((++timerCount1))) P1OUT ^= LED_GREEN; } It's only jump to Timer0A0 ISR, TImer0A1 is not. Please hlep me to explain and how I can make Timer0A1 ISR working? Thank in advance! Quote Link to post Share on other sites
Fmilburn 446 Posted December 18, 2015 Share Posted December 18, 2015 Hi @@MSPLife, Your code as submitted looks to be incomplete and you have not specified what MCU you are using. The following, derived from something I wrote for the F5529 as a programming exercise recently, may do what you are attempting. I added ACLK to slow things down but the commented out lines with SMCLK also work. // Written for the F5529 // //***** Include ********************************************************************************* #include <msp430.h> //***** Define ********************************************************************************** #define RED_LED BIT0 // P1.0 is the red LED #define GREEN_LED BIT7 // P4.7 is the green LED //***** Main ************************************************************************************ main() { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer P1DIR = RED_LED; // Set red LED to output P4DIR = GREEN_LED; // Set green LED to output TA0CCR0 = 50000; // Timer A0 counts to this number //TA0CTL = TASSEL_2 + MC_1; // Timer A0 using SMCLK, continuous TA0CTL = TASSEL_1 + MC_1; // Use ACLK to slow things down TA0CCTL0 = CCIE; // Enable the interrupt for Timer A0 TA1CCR0 = 25000; // Timer A1 counts to this number //TA1CTL = TASSEL_2 + MC_1; // Timer A1 using SMCLK, continuous TA1CTL = TASSEL_1 + MC_1; // Use ACLK to slow things down TA1CCTL0 = CCIE; // Enable the interrupt for Timer A1 _BIS_SR(GIE); // Global activation of interrupts) while(1); // Wait here for the interrupt } //***** TimerA0 ISR ****************************************************************************** #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer0_ISR (void) { P1OUT = P1OUT ^ RED_LED; // Toggle the red LED } //***** TimerA1 ISR ****************************************************************************** #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer1_ISR (void) { P4OUT = P4OUT ^ GREEN_LED; // Toggle the green LED } greeeg 1 Quote Link to post Share on other sites
greeeg 460 Posted December 18, 2015 Share Posted December 18, 2015 @@MSPLife Have you debugged the operation of the interrupts? I've assumed you are using the G2231, shouldn't really matter thought. My thinking is that since TIMER0_A1_VECTOR is a shared interrupt you generally should be checking the corresponding Interrupt Vector, to determine the exact source of the interrupt. void TIM_TRIG_ADC_CFG(){ CCTL0 &= ~CCIE; CCTL1 &= ~CCIE; TACTL = TASSEL_2 + MC_1; // Set the timer A to SMCLCK, Continuous TACCR0 = 50000-1; TACCR1 += 25000-1; CCTL0 |= CCIE; CCTL1 |= CCIE; // Clear the timer and enable timer interrupt __enable_interrupt(); } // Timer A0 interrupt service routine #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A00 (void) { if(!((++timerCount)%16)) P1OUT ^= LED_RED; } // Timer A1 interrupt service routine #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A01 (void) { switch( TAIV ) { case TAIV_NONE: break; case TAIV_TACCR1: if(!((++timerCount1))) P1OUT ^= LED_GREEN; break; case TAIV_TAIFG: break; default: break; } } This is because the TAIV is only cleared when TAIV is read, so there is a potential that the code does not signal that the interrupt was handled... This means your CPU gets stuck continuously servicing the interrupt. (I don't actually think this happens with MSP, but it could...) An except from SLAU144 [12.2.6.2 - TAIV, Interrupt Vector Generator] Any access, read or write, of the TAIV register automatically resets the highest pending interrupt flag. If another interrupt flag is set, another interrupt is immediately generated after servicing the initial interrupt. Also note, that this statement if(!((++timerCount1))) P1OUT ^= LED_GREEN; Will toggle the GREEN LED if timerCount1 == 0. Since you are incrementing it, it will not toggle again until timerCount1 overflows, and equals 0 again. So if you are relying on the LED to check if your interrupt is firing then this won't help. Quote Link to post Share on other sites
MSPLife 2 Posted December 18, 2015 Author Share Posted December 18, 2015 Dear Fmiburn I want to use : TIMER0_A1_VECTOR not timer A1 Hi @@MSPLife, Your code as submitted looks to be incomplete and you have not specified what MCU you are using. The following, derived from something I wrote for the F5529 as a programming exercise recently, may do what you are attempting. I added ACLK to slow things down but the commented out lines with SMCLK also work. // Written for the F5529 // //***** Include ********************************************************************************* #include <msp430.h> //***** Define ********************************************************************************** #define RED_LED BIT0 // P1.0 is the red LED #define GREEN_LED BIT7 // P4.7 is the green LED //***** Main ************************************************************************************ main() { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer P1DIR = RED_LED; // Set red LED to output P4DIR = GREEN_LED; // Set green LED to output TA0CCR0 = 50000; // Timer A0 counts to this number //TA0CTL = TASSEL_2 + MC_1; // Timer A0 using SMCLK, continuous TA0CTL = TASSEL_1 + MC_1; // Use ACLK to slow things down TA0CCTL0 = CCIE; // Enable the interrupt for Timer A0 TA1CCR0 = 25000; // Timer A1 counts to this number //TA1CTL = TASSEL_2 + MC_1; // Timer A1 using SMCLK, continuous TA1CTL = TASSEL_1 + MC_1; // Use ACLK to slow things down TA1CCTL0 = CCIE; // Enable the interrupt for Timer A1 _BIS_SR(GIE); // Global activation of interrupts) while(1); // Wait here for the interrupt } //***** TimerA0 ISR ****************************************************************************** #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer0_ISR (void) { P1OUT = P1OUT ^ RED_LED; // Toggle the red LED } //***** TimerA1 ISR ****************************************************************************** #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer1_ISR (void) { P4OUT = P4OUT ^ GREEN_LED; // Toggle the green LED } Quote Link to post Share on other sites
MSPLife 2 Posted December 18, 2015 Author Share Posted December 18, 2015 Dear greeeg, I put a breakpoint in TIMER0_A1_VECTOR, but it doeasn jump to that. @@MSPLife Have you debugged the operation of the interrupts? I've assumed you are using the G2231, shouldn't really matter thought. My thinking is that since TIMER0_A1_VECTOR is a shared interrupt you generally should be checking the corresponding Interrupt Vector, to determine the exact source of the interrupt. void TIM_TRIG_ADC_CFG(){ CCTL0 &= ~CCIE; CCTL1 &= ~CCIE; TACTL = TASSEL_2 + MC_1; // Set the timer A to SMCLCK, Continuous TACCR0 = 50000-1; TACCR1 += 25000-1; CCTL0 |= CCIE; CCTL1 |= CCIE; // Clear the timer and enable timer interrupt __enable_interrupt(); } // Timer A0 interrupt service routine #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A00 (void) { if(!((++timerCount)%16)) P1OUT ^= LED_RED; } // Timer A1 interrupt service routine #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A01 (void) { switch( TAIV ) { case TAIV_NONE: break; case TAIV_TACCR1: if(!((++timerCount1))) P1OUT ^= LED_GREEN; break; case TAIV_TAIFG: break; default: break; } } This is because the TAIV is only cleared when TAIV is read, so there is a potential that the code does not signal that the interrupt was handled... This means your CPU gets stuck continuously servicing the interrupt. (I don't actually think this happens with MSP, but it could...) An except from SLAU144 [12.2.6.2 - TAIV, Interrupt Vector Generator] Any access, read or write, of the TAIV register automatically resets the highest pending interrupt flag. If another interrupt flag is set, another interrupt is immediately generated after servicing the initial interrupt. Also note, that this statement if(!((++timerCount1))) P1OUT ^= LED_GREEN; Will toggle the GREEN LED if timerCount1 == 0. Since you are incrementing it, it will not toggle again until timerCount1 overflows, and equals 0 again. So if you are relying on the LED to check if your interrupt is firing then this won't help. Fmilburn 1 Quote Link to post Share on other sites
greeeg 460 Posted December 18, 2015 Share Posted December 18, 2015 @@MSPLife The only other thing I can think off is regarding your initialization of CCR's TACCR0 = 50000-1; TACCR1 += 25000-1; Suppose TACCR1 is not initialized to 0 on reset. Or is TIM_TRIG_ADC_CFG() is called multiple times. If TACCR1 > TACCR0 Since you reset the TAR when it reaches CCR0, then it will never reach CCR1. I would suggest changing these lines to TACCR0 = 50000-1; TACCR1 = 25000-1; This might not produce the desired result. Both the interrupts will fire at the same rate, just offset by half a cycle. This is how your original code operated. A0 IFG _______^________^_______ A1 IFG ___^_______^________^___ Fmilburn and MSPLife 2 Quote Link to post Share on other sites
Fmilburn 446 Posted December 18, 2015 Share Posted December 18, 2015 Dear Fmiburn I want to use : TIMER0_A1_VECTOR not timer A1 Oops @@greeeg Implementing your suggestions on my code seems to work... // Written for the F5529 // //***** Include ********************************************************************************* #include <msp430.h> //***** Define ********************************************************************************** #define RED_LED BIT0 // P1.0 is the red LED #define GREEN_LED BIT7 // P4.7 is the green LED //***** Main ************************************************************************************ main() { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer P1DIR = RED_LED; // Set red LED to output P4DIR = GREEN_LED; // Set green LED to output TA0CCR0 = 50000; // Timer A0 counts to this number TA0CCR1 = 25000; // Timer A1 counts to this number TA0CTL = TASSEL_2 + MC_1; // Timer A0 using SMCLK, continuous TA0CCTL0 = CCIE; // Enable the interrupt for Timer0_A0 TA0CCTL1 = CCIE; // Enable the interrupt for Timer0_A1 _BIS_SR(GIE); // Global activation of interrupts) while(1); // Wait here for the interrupt } //***** TimerA0 ISR ****************************************************************************** #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer0_ISR (void) { P1OUT = P1OUT ^ RED_LED; // Toggle the red LED } //***** TimerA1 ISR ****************************************************************************** #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer1_ISR (void) { switch(__even_in_range( TA0IV, 10)) { case 0x00: break; // None case 0x02: // CCR1 IFG P4OUT = P4OUT ^ GREEN_LED; // Toggle the green LED default: break; } } Snippet from a TI course.... greeeg and MSPLife 2 Quote Link to post Share on other sites
MSPLife 2 Posted December 19, 2015 Author Share Posted December 19, 2015 Dear @@greeeg, @@Fmilburn, 1.My program worked, but I want to understand, why do we need to check TA0IV in a specific ISR? If I want to use TImer0A2, I need to check TAIV in Timer0A2 ISR as well? 2. Now my program is below: void TIM_TRIG_ADC_CFG(){ CCTL0 &= ~CCIE; CCTL1 &= ~CCIE; TACTL = TASSEL_2 + MC_1; // Set the timer A to SMCLCK, Continuous TACCR0 = 50000-1; TACCR1 = 25000-1; CCTL0 |= CCIE; CCTL1 |= CCIE; // Clear the timer and enable timer interrupt __enable_interrupt(); } #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A00 (void) { if(!((++timerCount)%32)){ Toggle(1,0); //Toggle RED LED } } #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A01 (void) { switch(__even_in_range( TA0IV, 10)) { case 0x00: break; // None case 0x02: // CCR1 IFG if(!((++timerCount1)%32)) Toggle(1,6); // Toggle GREEN LED default: break; } } The LEDs blink with same period while my set up make GREEN LED blink with a shorter period (faster). Please help to explain. Thank so much! Quote Link to post Share on other sites
greeeg 460 Posted December 19, 2015 Share Posted December 19, 2015 Dear @@greeeg, @@Fmilburn, 1.My program worked, but I want to understand, why we need to check TA0IV in the specific ISR? If I want to use TImer0A2, I need to check TAIV in Timer0A2 ISR as well? ... The LEDs blink with same period while my set up make GREEN LED blink with a shorter period (faster). Please help to explain. Thank so much! Can you tell me which processor you are using, it will make this explanation more specific. Why we need to check TA0IV. First, T0A2 interrupt does not exist. This is the purpose of TA0IV (Timer A0 Interrupt Vector) Interrupts require a fair amount of hardware (priority encoders, etc). To keep this manageable, the MSP430 are conservative with their interrupts. Lets look at the interrupts inside a MSP430G2955 There is only 15 unique interrupt vectors! Note that the CPU in the G2955 supports 32 interrupt vectors. Let's look at it's timer. Timer0_A3. This means that this timer contains 3 capture/compare modules. So that means 3 interrupts right? Actually 4, the timer itself has an overflow interrupt. But this timer is only assigned 2 unique interrupt vectors. Timer0_A0 handles TACCR0 - CCIFGTimer0_A1 handles TACCR1 - CCIFG TACCR2 - CCIFG TAIFG (overflow) To differentiate we must check TA0IV to determine the exact source within Timer0_A1 Why not have all 4 separately? This might work on this particular IC, however larger MSP's include Timers with upto 7/8 CCR's There is not enough interrupt vectors to handle all those sources. Note it's easy to get confused by the vector names. You can check the header file for your MSP430 to see the available vector names. "If I want to use TImer0A2, I need to check TAIV in Timer0A2 ISR as well?" This will be part of the Timer0_A1 ISR. but yes, you need to check the TAIV. #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A01 (void) { switch(__even_in_range( TA0IV, 10)) { case 0x00: // None break; case 0x02: // CCR1 IFG if(!((++timerCount1)%32)) Toggle(1,6); // Toggle GREEN LED break; case 0x04: // CCR2 IFG if(!((++timerCount2)%32)) Toggle(1,0); // Toggle RED LED break; default: break; } } You can find in the family guide, that a value of 2 in TAIV represents CCR1, a value of 4 represents CCR2. MSPLife and Fmilburn 2 Quote Link to post Share on other sites
greeeg 460 Posted December 19, 2015 Share Posted December 19, 2015 The LEDs blink with same period while my set up make GREEN LED blink with a shorter period (faster). Your timer currently count to CCR0. CCR0 is set to 49,999 When your timer reaches 49,999 an interrupt occurs. and the next timer value is 0. CCR1 is set to 24,999 When the timer value reaches 24,999 it will cause an interrupt. Hence you're leds blink at the same rate. It takes the timer the same amount of time to count from 0 to 49,999 = 50,000 ticks and 25,000 to 24,999 = 50,000 ticks. How do you fix this. I would recommend the following. (but there are multiple ways.) Set TA0 to run in continuous mode, instead of up mode. (Your code comments mistakenly say continuous, but you've been setting it to up mode) When CCR0 ISR fires, you need to add your new period to CCR0 When CCR1 ISR fires, you need to add your new period to CCR1 void TIM_TRIG_ADC_CFG(){ CCTL0 &= ~CCIE; CCTL1 &= ~CCIE; TACTL = TASSEL_2 + MC_2; // Set the timer A to SMCLCK, Continuous TACCR0 = 50000-1; TACCR1 = 25000-1; CCTL0 |= CCIE; CCTL1 |= CCIE; // Clear the timer and enable timer interrupt __enable_interrupt(); } #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A00 (void) { CCR0 += 50000; // Return in 50,000 cycles if(!((++timerCount)%32)){ Toggle(1,0); //Toggle RED LED } } #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A01 (void) { switch(__even_in_range( TA0IV, 10)) { case 0x00: // None break; case 0x02: // CCR1 IFG CCR1 += 25000; // Return in 25,000 cycles if(!((++timerCount1)%32)) Toggle(1,6); // Toggle GREEN LED break; default: break; } } Now most of the time adding large value like this is dangerous, because of integer overflow. But it's okay here, because the timer counter itself is overflowing in exactly the same way. MSPLife 1 Quote Link to post Share on other sites
Jake 24 Posted December 23, 2015 Share Posted December 23, 2015 subd.... Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.