stm32 keypad 4x4 IDR register always set

143 Views Asked by At

I am trying to interface stm32 nucleo microcontroler with 4x4 keypad. Rows are set with a pull-up resistor, interruptions triggered on a falling edge. The interruption is correctly triggered when a key is pressed (I use EXTI, NVIC and TIM3 - for vibration detection). Columns and rows linked through GPIOC, column ports: PC0, PC1, PC2, PC3, row ports: PC6, PC7, PC8, PC9.

Example GPIO configuration:

// COL4 - PC3
    GPIOoutConfigure(GPIOC, 
                      3,
                      GPIO_OType_PP, 
                      GPIO_Low_Speed,
                      GPIO_PuPd_NOPULL);


    // Configure rows
    // ROW1 - PC6
    GPIOinConfigure(GPIOC, 6, GPIO_PuPd_UP,
                    EXTI_Mode_Interrupt,
                    EXTI_Trigger_Falling)

In order to check the button pressed, I set column outputs to 0 (one column is set to 0, the rest is set to 1).

void set_low_state(int col_row_pin) {
    GPIOC->BSRR = 1 << (col_row_pin + 16);
}

void set_high_state(int col_row_pin) {
    GPIOC->BSRR = 1 << col_row_pin;
}

As I check ODR register for columns when set high or low, it seems to be correctly set.

However I have noticed, that whether interruption is triggered or not (first noticed it in TIM3_IRQ handler, then checked it in main before pressing the key) the IDR registers for ALL rows are ALWAYS set:

if ((GPIOC->IDR >> 6) & 1) {
 // 6: ROW1_PIN, that is PC6
// always true

Is there any mistake? Which register and how should I check in order to get to know the row state? Are there any bottlenecks I should pay attention to? I have found some library docs over the Internet and I can't find the difference between my approach and the library.

1

There are 1 best solutions below

0
fgh On

In this type of keypad button press detection - with a pull-up resistor - input ports are set to 1, therefore I need to check for logical zero:

if (!((GPIOC->IDR >> 6) & 1)) {
...
}