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.
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: