Tool/software: TI C/C++ Compiler
Hello, We have an issue with the Quadrature encoder input. There is no problem in interrupt Edge Detection, but there are multiple detection. Due to this it is causing multiple detriment or increment to the counter. Code shows the arrangement of connection between the Quadrature encoder and the MSP430G2553 TSSOP-28 pin version. Attaching the Code here: [code] // Button Input from Quadrature Encoder // // MSP430G2xx3 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // | | // TXD-----|P1.2/UCA0TXD | LED 150E // | P1.6|--|>|---/\/\/\---- // RXD-----|P1.1/UCARXD | | // | | --- // | | /// // | | // | | // | P1.3/A3| #include // Encoder Line A #define LINE_A BIT3 // Encoder Line B #define LINE_B BIT4 // Get the Status of the Input Lines from Encoder #define GETLINESTATE() (P2IN & (LINE_A + LINE_B)) // Check if the button is in Pressed State #define BtnRead_Pressed() ((P1IN&BIT3) == 0) // Check if the Button is in Released State #define BtnRead_Released() ((P1IN&BIT3) == BIT3) // Button in Idle State #define BtnSTATE_IDLE 0 // Button Detected and Now Debouncing sensing loop #define BtnSTATE_SENSE 1 // Button Action being performed #define BtnSTATE_ACTION 2 // Button Waiting for Release #define BtnSTATE_TRANS 4 // Button Debounce Delay in Milliseconds #define MAX_Btn_Debounce_mS 50 // Button Start / Dection condition from Interrupt volatile uint16_t button_detect = 0; // Button Timing counter uint32_t button_counter = 0; // Button State Storage uint16_t button_state = BtnSTATE_IDLE; // Counter for Encoder volatile uint8_t encoder_pos = 0; // Encoder Time Stamp volatile uint32_t encoder_ts = 0; // Encoder Click - Indicate that there has been movement volatile uint16_t encoder_click = 0; // Milliseconds Counter volatile uint32_t millis = 0; // Time stamp for delay volatile uint32_t timer_delay_ts = 0; // Time Delay needed volatile uint32_t timer_delay_ms = 0; //****************************************************************************** // Device Initialization ******************************************************* //****************************************************************************** void initClockTo16MHz() { if (CALBC1_16MHZ == 0xFF) // If calibration constant erased { while (1) __bis_SR_register(LPM4_bits);// do not load, trap CPU!! } DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_16MHZ; // Set DCO DCOCTL = CALDCO_16MHZ; } void initGPIO() { __disable_interrupt(); P1SEL = BIT1 + BIT2; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2; // Low Power P1DIR = ~(BIT3); // P1.3 as input P1OUT = BIT3; // P1.3 Pull-up P1REN = BIT3; // P1.3 Enable Pull-up P2DIR = ~(LINE_A | LINE_B); // LINE A and B as Input P2OUT = (LINE_A | LINE_B); // LINE A and B Pull-up P2REN = (LINE_A | LINE_B); // LINE A and B Enable Pull-up P3DIR = 0xFF; P3OUT = 0; // Configure Interrupt P1IE |= BIT3; // P1.3 interrupt enabled P1IES |= BIT3; // P1.3 Hi/lo edge P1IFG &= ~BIT3; // P1.3 IFG cleared // Configure Encoder Interrupt P2IE |= (LINE_A + LINE_B); // LINE A and B Interrupt Enabled P2IES |= LINE_A; // Configure the Edge based on current input state P2IFG = 0; // Clear the IFG } void initUART() { UCA0CTL1 |= UCSSEL_1; // ACLK UCA0BR0 = 3; // 32768Hz 9600 UCA0BR1 = 0; // 32768Hz 9600 UCA0MCTL = UCBRS_3; // Modulation UCBRSx = 3 UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** } void initTIMERA() { // 1 Millisecond Pulse with ACLK/8 and Dual CCR interrupts // Timer in Up-count mode MC_1 // Clock input as ACLK TASSEL_1 // Input clock divided by 8 as ID_3 // --- // Final Frequency Fs = ACLK / 8 = 32768 / 8 = 4096Hz // Time Unit Ts = 1/(ACLK / 8) = 1/4096 = 244.1440uS // 1Ms = Counts * Ts, or // Counts = 1Ms / Ts = 1Ms / (1 / (ACLK/8) ) = 1MS * ACLK / 8 , or // Counts = 1MS * 32768 / 8 = 4096 / 1000 = 4.096 ~ 4 // CCR0 (TA0CCR0) = 4-1 = 3 // --- // Both Interrupts for TA0CCTL0 // CCR0 = 4 - 1; // PWM Period for 1 Ms CCTL0 = CCIE; // Enable TA0CCTL0 - Compare Interrupt millis = 0; // Clear the Counter TACTL = TASSEL_1 + MC_1 + ID_3; // ACLK/8, up mode } uint16_t button_process() { uint16_t ret = 0; switch(button_state) { case BtnSTATE_IDLE: if (button_detect == 1 && BtnRead_Pressed()) { button_state = BtnSTATE_SENSE; button_counter = millis; } break; case BtnSTATE_SENSE: if ((millis - button_counter) >= MAX_Btn_Debounce_mS) { if (BtnRead_Pressed()) { button_state = BtnSTATE_ACTION; button_counter = millis; // Restart for Release } else // Debounce Failed { __disable_interrupt(); button_detect = 0; button_counter = 0; __enable_interrupt(); button_state = BtnSTATE_IDLE; } } break; case BtnSTATE_ACTION: ret = 1; button_state = BtnSTATE_TRANS; break; case BtnSTATE_TRANS: if (((millis - button_counter) >= (MAX_Btn_Debounce_mS*2)) || BtnRead_Released()) { __disable_interrupt(); button_detect = 0; button_counter = 0; __enable_interrupt(); button_state = BtnSTATE_IDLE; } break; } return ret; } void delay(uint32_t ms) { __disable_interrupt(); timer_delay_ts = millis; timer_delay_ms = ms; __enable_interrupt(); __bis_SR_register(LPM3_bits + GIE); // Sleep the MCU } //****************************************************************************** // Main ************************************************************************ //****************************************************************************** int main(void) { //uint32_t ts; WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer initClockTo16MHz(); initGPIO(); initUART(); initTIMERA(); __enable_interrupt(); //ts = millis; while (1) { //if( (millis - ts) >= 1000) if (button_process()) { P1OUT ^= BIT6; while (!(IFG2 & UCA0TXIFG)) ; // USCI_A0 TX buffer ready? UCA0TXBUF = 0x00; __no_operation(); while (!(IFG2 & UCA0TXIFG)) ; // USCI_A0 TX buffer ready? UCA0TXBUF = millis; __no_operation(); } if (encoder_click == 1) { while (!(IFG2 & UCA0TXIFG)) ; // USCI_A0 TX buffer ready? UCA0TXBUF = 0x01; __no_operation(); while (!(IFG2 & UCA0TXIFG)) ; // USCI_A0 TX buffer ready? UCA0TXBUF = encoder_pos; __no_operation(); __disable_interrupt(); encoder_click = 0; __enable_interrupt(); } __delay_cycles(400000); } } // Timer A0 interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) Timer_A (void) #else #error Compiler not supported! #endif { ++millis; if (timer_delay_ms != 0) { if ((millis - timer_delay_ts) >= timer_delay_ms) { timer_delay_ts = 0; // WAKE-UP! __bic_SR_register_on_exit(LPM3_bits); // Clear LPM3 bits from 0(SR) } } } // Port 1 interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void) #else #error Compiler not supported! #endif { if(BtnRead_Pressed()) button_detect = 1; // Indicate Button press P1IFG &= ~BIT3; // P1.3 IFG cleared } // Port 2 interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=PORT2_VECTOR __interrupt void Port_2(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(PORT2_VECTOR))) Port_2 (void) #else #error Compiler not supported! #endif { uint8_t state = GETLINESTATE(); uint8_t ifg = P2IFG; ifg &= (LINE_A | LINE_B); encoder_ts = millis; // Time Stamp if( (ifg & LINE_A) == LINE_A ) // Interrupt on LINE A { if (P2IES & LINE_A) { // if falling edge on Line A if (state & LINE_B) { // Transitioned from State 3 to State 1 encoder_pos -= 1; } else { encoder_pos += 1; // Transitioned from State 2 to State 0 } } else { // else rising edge on Line A if (state & LINE_B) { // Transitioned from State 1 to State 3 encoder_pos += 1; } else { // Transitioned from State 0 to State 2 encoder_pos -= 1; } } P2IES ^= LINE_A; encoder_click = 1; } if( (ifg & LINE_B) == LINE_B ) // Interrupt on LINE B { if (P2IES & LINE_B) { // if falling edge on Line B if (state & LINE_A) { // Transitioned from State 3 to State 2 encoder_pos += 1; } else { encoder_pos -= 1; // Transitioned from State 1 to State 0 } } else { // else rising edge on Line B if (state & LINE_A) { // Transitioned from State 2 to State 3 encoder_pos -= 1; } else { // Transitioned from State 0 to State 1 encoder_pos += 1; } } P2IES ^= LINE_B; encoder_click = 1; }// P2IFG = 0; // LINE_A and LINE B IFG cleared } [/code] Please help with this, Thanking you, Regards, Ab