This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/MSP430FR6989: 4x4 Keypad IRQ issue

Part Number: MSP430FR6989

Tool/software: Code Composer Studio

Hi,

I have connected in my MSP430FR6989 a 4x4 keypad in order to use it as input for a calculator.

the rows of the keypad are connected in the pins p2.1 to p2.4 and these pins are configured as IRQ and enable the pull-up resistors. 

the columns of the keypad are connected in the pins p8.4 to p8.7 and these pins are configured as output and the output is low.

My first step was making a test that when a button is pressed, the microcontroller goes a attend the interrupt and in the LCD appear 543210, but not appear nothing

this is my code

#include "msp430.h"
volatile int edge =0x1E;


const unsigned char lcd_num[14] =
{       0xFC,        // 0
        0x60,        // 1
        0xDB,        // 2
        0xF3,        // 3
        0x67,        // 4
        0xB7,        // 5
        0xBF,        // 6
        0xE4,        // 7
        0xFF,        // 8
        0xF7,        // 9
        0xEF,        // a
        0x3F,       //B
        0x9C,       // C
        0x7B        // d
        };

int main(void)
{
    msp_init();
    LCD_initialize();
    Init_4_4_KeyPad();

    Init_ISR(edge);
    __enable_interrupt(); // Set global interrupt enable bit in SR register
    _BIS_SR(LPM4 | GIE);

}


#pragma vector = PORT2_VECTOR
__interrupt void Port_2() // function called when the port is interrupted (button pressed)
{
    LCDCMEMCTL = LCDCLRM;                   // Clear LCD memory
    LCDM8 = lcd_num[0];
    LCDM15 = lcd_num[1];
    LCDM19 = lcd_num[2];
    LCDM4 = lcd_num[3];
    LCDM6 = lcd_num[4];
    LCDM10 = lcd_num[5];
        //Turn LCD on
    LCDCCTL0 |= LCDON;
}

void LCD_initialize()
{
    PJSEL0 = BIT4 | BIT5; // For LFXT

    LCDCPCTL0 = 0xFFF0; // Init. LCD segments 4, 6-15
    LCDCPCTL1 = 0xF83F; // Init. LCD segments 16-21, 27-31
    LCDCPCTL2 = 0x00F8; // Init. LCD segments 35-39

    // Disable the GPIO power-on default high-impedance mode
    // to activate previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    // Configure LFXT 32kHz crystal
    CSCTL0_H = CSKEY >> 8;    // Unlock CS registers
    CSCTL4 &= ~LFXTOFF;    // Enable LFXT
    do
    {
        CSCTL5 &= ~LFXTOFFG; // Clear LFXT fault flag
        SFRIFG1 &= ~OFIFG;
    }
    while (SFRIFG1 & OFIFG); // Test oscillator fault flag
    CSCTL0_H = 0; // Lock CS registers

    // Initialize LCD_C
    // ACLK, Divider = 1, Pre-divider = 16; 4-pin MUX
    LCDCCTL0 = LCDDIV__1 | LCDPRE__16 | LCD4MUX | LCDLP | LCDSON;

    // VLCD generated internally,
    // V2-V4 generated internally, v5 to ground
    // Set VLCD voltage to 2.60v
    // Enable charge pump and select internal reference for it
    LCDCVCTL = VLCD_1 | VLCDREF_0 | LCDCPEN;

    LCDCCPCTL = LCDCPCLKSYNC;    // Clock synchronization enabled

    //LCDCMEMCTL = LCDCLRM;// Clear LCD memory

    //LCDCCTL0 |= LCDON;

}




void msp_init()
{
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    P2DIR &= ~(BIT1|BIT2|BIT3|BIT4); // Set pins P2.1- P2.4 to be an input
    P2REN |= BIT1|BIT2|BIT3|BIT4;  // Enable internal pullup/pulldown resistor on P2.1- P2.4
    P2OUT |= BIT1|BIT2|BIT3|BIT4;  // Pullup selected on P2.1- P2.4



}


void Init_ISR(int f)
{


    P2IES = f;   // edge selection PxIFG flag is set with a high-to-low (f==1)
                 // or low-to-high (f==0) transition
    P2IFG &= ~(BIT1|BIT2|BIT3|BIT4); // Clear the P2.0 interrupt flag
    P2IE = 0x1E; // 2.1to2.4 port's interrupt eneable set

}


void Init_4_4_KeyPad()
{
    P8DIR |= (BIT4 | BIT5 | BIT6 | BIT7);       // P8.4 to P8.7 pins output
    P8OUT &= ~(BIT4 | BIT5 | BIT6 | BIT7);       // P8.4 to P8.7 Level output as 0
}

Thank you for help me

  • For the LCD you use the ACLK right? ACLK is not work under LPM4, You can try LPM3. By the way, can you get the GPIO interrupt?

  • I could fix the problem. I can see the values of the keypad in the LCD.

    Now I have a new problem

    I want to do shift numbers each time that I push a button. (for example when I press in the following order the buttons 3 - 7 -8 in the LCD has to appear 873) that is done with the LCD_Display() function. The function has an LCD_index variable that increases each time that I push any button. and should enter within of each case of the switch statement. But the behavior when I press a button and the code entrees to the switch statement, the LCD_index has increased a lot and goes directly to the default option.

    That is the new code:

    #include "msp430.h"
    
    volatile int edge = 0xff;
    volatile unsigned int LCD_index = 1;
    volatile unsigned int interrupFlag = 0;
    volatile unsigned int index_press = 0;
    volatile unsigned int index_press2 = 0;
    volatile unsigned int value_row = 0;
    volatile unsigned int value_column = 0;
    volatile unsigned int catch_frecuency = 0;
    void LCD_initialize();
    void LCD_Display();
    void LCD_Clear();
    void LCD_turnOn();
    
    void Configure_buzzer();
    
    void msp_init();
    void Init_ISR(int f);
    void Init_4_4_KeyPad();
    
    #define TIMER_CFG_STOP TASSEL__ACLK | MC__STOP | TACLR;
    #define TIMER_CFG_UP TASSEL__ACLK | MC__UP | TACLR;
    
    unsigned int matrix_keypad[4][4] =
            { { 0x01, 0x02, 0x03, 0x0A }, { 0x04, 0x05, 0x06, 0x0B },
              { 0x07, 0x08, 0x09, 0x0C }, { 0x0E, 0x00, 0x0F, 0x0D } };
    
    const unsigned char lcd_num[14] = { 0xFC,        // 0
            0x60,        // 1
            0xDB,        // 2
            0xF3,        // 3
            0x67,        // 4
            0xB7,        // 5
            0xBF,        // 6
            0xE4,        // 7
            0xFF,        // 8
            0xF7,        // 9
            0xEF,        // a
            0x3F,       //B
            0x9C,       // C
            0x7B        // d
            };
    
    int main(void)
    {
        msp_init();
        LCD_initialize();
        Init_4_4_KeyPad();
        Configure_buzzer();
        Init_ISR(edge);
        __enable_interrupt(); // Set global interrupt enable bit in SR register
    
        LCD_Clear();
        while (1)
        {
    
            if (interrupFlag == 1)
            {
                LCD_Display();
                interrupFlag = 0;
                LCD_turnOn();
            }
    
        }
    
    }
    void Configure_buzzer(){
        P2DIR |= BIT4;      //p2.4 as Output
        P2SEL0 |= BIT4;     //Select module
        P2SEL0 &= ~BIT4;     //Select module
        // set output mode to reset/set (see page 459 in user's guide - slau367f)
         TB0CCTL3 = TB0CCTL4 = TB0CCTL5 = TB0CCTL6 = OUTMOD_7;
        // clock source = SMCLK divided by 8, put timer in UP mode, clear timer register
         TB0CTL = TBSSEL__SMCLK  | ID__8| MC__UP | TBCLR;
    
    }
    
    void Configure_Frecuency_buzzer(unsigned int frecuency){
    
        unsigned int value_ticks = 125000/frecuency;
        TB0CCR0 = value_ticks;              // (1000 KHz / 8) / frecuency ticks
        TB0CCR3 = value_ticks*4/5;               // 80 / 100 = 80% duty cycle
        __delay_cycles(1000000);
        TB0CCR3 = 0;
    
    }
    
    void Test_frecuency(){
    
        Configure_Frecuency_buzzer(212);
        Configure_Frecuency_buzzer(325);
        Configure_Frecuency_buzzer(450);
    }
    void LCD_Clear()
    {
        LCDCMEMCTL = LCDCLRM;                   // Clear LCD memory
        LCD_index = 0;
        catch_frecuency=0;
    }
    
    void LCD_turnOn()
    {
        LCDCCTL0 |= LCDON;
    }
    void LCD_Display() // Display function
    {
    
        if(LCD_index*matrix_keypad[value_row][value_column]==0x0A){
            Configure_Frecuency_buzzer(catch_frecuency);
            return;
        }
        if(LCD_index*matrix_keypad[value_row][value_column]==0x0B){
            LCD_Clear();
            return;
        }
    
        switch (LCD_index)
        {
        case 1:
            LCDM8 = lcd_num[matrix_keypad[value_row][value_column]];
            catch_frecuency = catch_frecuency + matrix_keypad[value_row][value_column];
            break;
        case 2:
            LCDM15 = lcd_num[matrix_keypad[value_row][value_column]];
            catch_frecuency = catch_frecuency + 10*matrix_keypad[value_row][value_column];
            break;
        case 3:
            LCDM19 = lcd_num[matrix_keypad[value_row][value_column]];
            catch_frecuency = catch_frecuency + 100*matrix_keypad[value_row][value_column];
            break;
    
        default:
            LCDM8 = lcd_num[matrix_keypad[0][0]];
            LCDM15 = lcd_num[matrix_keypad[0][0]];
            LCDM19 = lcd_num[matrix_keypad[0][0]];
            LCDM4 = lcd_num[matrix_keypad[0][0]];
            LCDM6 = lcd_num[matrix_keypad[0][0]];
            LCDM10 = lcd_num[matrix_keypad[0][0]];
            break;
        }
    }
    
    #pragma vector = PORT2_VECTOR
    __interrupt void Port_2() // function called when the port is interrupted (button pressed)
    {
        P2IES ^= (BIT1 | BIT2 | BIT3 | BIT4);
        P2IE = 0X00;           //disable the interrupts on port 2
        TA2CCTL0 = CCIE;       // Enable debounce timer interrupt
    
        index_press2 = (P2IFG & 0x1E) >> 1;
        P8DIR &= ~(BIT4 | BIT5 | BIT6 | BIT7);       // P8.4 to P8.7 pins input
    
        TA2CTL = TIMER_CFG_UP; // Start debounce timer
    }
    
    #pragma vector = TIMER2_A0_VECTOR
    __interrupt void debounce_ISR()
    {
        if (P2IES & BIT1)
        {
            return;
        }
        LCD_index++;
        TA2CCTL0 = 0;            // Disable debounce timer interrupt
        TA2CTL = TIMER_CFG_STOP
        ; // Stop debounce timer
    
        index_press = (P8IN & 0xF0) >> 4;
    
        switch (index_press)
        {
        case 0x01:
            value_row = 0;
            break;
        case 0x02:
            value_row = 1;
            break;
        case 0x04:
            value_row = 2;
            break;
        case 0x08:
            value_row = 3;
            break;
        }
    
        switch (index_press2)
        {
        case 0x01:
            value_column = 0;
            break;
        case 0x02:
            value_column = 1;
            break;
        case 0x04:
            value_column = 2;
            break;
        case 0x08:
            value_column = 3;
            break;
        }
    
    
        P2IE |= (BIT1 | BIT2 | BIT3 | BIT4); // Re-enable interrupt after debouncing
        P2IFG &= ~(BIT1 | BIT2 | BIT3 | BIT4); // Clear the interrupt flag
    
        P8DIR |= (BIT4 | BIT5 | BIT6 | BIT7);       // P8.4 to P8.7 pins output
        P8OUT &= ~(BIT4 | BIT5 | BIT6 | BIT7);     // P8.4 to P8.7 Level output as 0
        interrupFlag = 1;
    }
    
    void LCD_initialize()
    {
        PJSEL0 = BIT4 | BIT5; // For LFXT
    
        LCDCPCTL0 = 0xFFF0; // Init. LCD segments 4, 6-15
        LCDCPCTL1 = 0xF83F; // Init. LCD segments 16-21, 27-31
        LCDCPCTL2 = 0x00F8; // Init. LCD segments 35-39
    
        // Disable the GPIO power-on default high-impedance mode
        // to activate previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
    
        // Configure LFXT 32kHz crystal
        CSCTL0_H = CSKEY >> 8;    // Unlock CS registers
        CSCTL4 &= ~LFXTOFF;    // Enable LFXT
        do
        {
            CSCTL5 &= ~LFXTOFFG; // Clear LFXT fault flag
            SFRIFG1 &= ~OFIFG;
        }
        while (SFRIFG1 & OFIFG); // Test oscillator fault flag
        CSCTL0_H = 0; // Lock CS registers
    
        // Initialize LCD_C
        // ACLK, Divider = 1, Pre-divider = 16; 4-pin MUX
        LCDCCTL0 = LCDDIV__1 | LCDPRE__16 | LCD4MUX | LCDLP | LCDSON;
    
        // VLCD generated internally,
        // V2-V4 generated internally, v5 to ground
        // Set VLCD voltage to 2.60v
        // Enable charge pump and select internal reference for it
        LCDCVCTL = VLCD_1 | VLCDREF_0 | LCDCPEN;
    
        LCDCCPCTL = LCDCPCLKSYNC;    // Clock synchronization enabled
    
        //LCDCMEMCTL = LCDCLRM;// Clear LCD memory
    
        //LCDCCTL0 |= LCDON;
    
    }
    
    void msp_init()
    {
        WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
        P2DIR &= ~(BIT1 | BIT2 | BIT3 | BIT4); // Set pins P2.1- P2.4 to be an input
        P2REN |= BIT1 | BIT2 | BIT3 | BIT4; // Enable internal pullup/pulldown resistor on P2.1- P2.4
        P2OUT |= (BIT1 | BIT2 | BIT3 | BIT4);  // Pulldown selected on P2.1- P2.4
        P2IES |= (BIT1 | BIT2 | BIT3 | BIT4); // edge selection PxIFG flag is set with a high-to-low (f==1)
        // or low-to-high (f==0) transition
        P2IE |= (BIT1 | BIT2 | BIT3 | BIT4);
        ; // 2.1to2.4 port's interrupt eneable set
        P2IFG &= ~(BIT1 | BIT2 | BIT3 | BIT4); // Clear the P2.0 interrupt flag
        // Timers A2/3 are good for debouncing since they don't have external pins
        TA2CCR0 = 1620;             // 25 ms * 32768 Hz = 819.2 ticks debounce delay
        TA2CTL = TASSEL__ACLK | MC__STOP | TACLR; // Configure debounce timer but don't start it
    
        //PM5CTL0 &= ~LOCKLPM5; // Unlock ports from power manager
    
    }
    
    void Init_ISR(int f)
    {
    
        P2IES = f;   // edge selection PxIFG flag is set with a high-to-low (f==1)
                     // or low-to-high (f==0) transition
        P2IFG &= ~(BIT1 | BIT2 | BIT3 | BIT4); // Clear the P2.0 interrupt flag
        P2IE = 0x1E; // 2.1to2.4 port's interrupt eneable set
    
    }
    
    void Init_4_4_KeyPad()
    {
        //P8REN &= ~(BIT4 | BIT5 | BIT6 | BIT7);   // Disable internal pullup/pulldown resistor on P8.4 to P8.7
        P8DIR |= (BIT4 | BIT5 | BIT6 | BIT7);       // P8.4 to P8.7 pins output
        P8OUT &= ~(BIT4 | BIT5 | BIT6 | BIT7);     // P8.4 to P8.7 Level output as 0
    }
    
    


    I would like to know what is the issue in my code

    When I press a button, the interrupt flag is set and I change the pull up configuration to pull down in order to avoid problems when the user maintaining press the button, when the user releases the button configuration change to pull up again.

  • Hi Dario

    Sorry for the late response, does your problem been solved, I have time to look into it?

**Attention** This is a public forum