This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Sometimes nrf51822 not respond to pins toggle

Hello,

We have a RCU on the chip nrf51822-qfaa s110.
Sometimes (the period is not deterministic) occurs a situation
that the remote stop responding to key presses.
But at the same time, the bluetooth connection is not broken.
Also if you send a command via bluetooth, you can make sure,
that the LEDs and buzzer are still working.
After about 120 to 180 seconds, the buttons start working again.
And then the remote works as if nothing had happened.
What could be the reason for this behavior?

Part of the code of processing buttons:

#define KP_ROW_COUNT 3
#define KP_COL_COUNT 4
#define KP_ROW_PINS { KEYPAD_ROW_1, KEYPAD_ROW_2, KEYPAD_ROW_3 }
#define KP_COL_PINS { KEYPAD_COL_A, KEYPAD_COL_B, KEYPAD_COL_C, KEYPAD_COL_D }

#define KP_ROW_MASK 0x7

// number of RTC timer ticks for debounce delay
#define KP_DEBOUNCE_DELAY_TICKS 20

// delay during key scan, in microseconds
#define KEYPAD_SCAN_DELAY_US 1

typedef void (*keypad_handler_fn)(uint32_t keycode);

static uint32_t keypad_row_pins[KP_ROW_COUNT] = KP_ROW_PINS;
static uint32_t keypad_col_pins[KP_COL_COUNT] = KP_COL_PINS;
static uint8_t keypad_code_map[KP_ROW_COUNT * KP_COLS_COUNT] = KP_CODE_MAP;

#define KP_ROW(i) (~(1 << i))
#define KP_ROWS_ALL KP_ROW_MASK
#define KP_ROWS_NONE 0

static keypad_handler_fn s_handler = 0;
static uint32_t          s_keys_state = 0;
static uint32_t          s_debounce_filter_state = 0;
static app_timer_id_t    s_debounce_timer_id;

void keypad_init(keypad_handler_fn handler)
{
    if (!nrf_drv_gpiote_is_init())
        nrf_drv_gpiote_init();

    app_timer_create(&s_debounce_timer_id,
                    APP_TIMER_MODE_SINGLE_SHOT,
                    &debounce_timer_handler);

    s_handler = handler;

    keypad_rows_init();
    keypad_rows_activate(KP_ROWS_NONE);
    keypad_cols_init();

    keypad_cols_int_enable();
    keypad_rows_activate(KP_ROWS_ALL);
}

static void keypad_cols_init()
{
    nrf_drv_gpiote_in_config_t col_config = {
        .is_watcher = false,
        .hi_accuracy = false,
        .pull = NRF_GPIO_PIN_PULLUP,
        .sense = NRF_GPIOTE_POLARITY_TOGGLE,
    };

    for (int i = 0; i < KP_COL_COUNT; ++i) {
        nrf_drv_gpiote_in_init(keypad_col_pins[i], &col_config, &gpiote_event_handler);
    }
}


static void keypad_cols_int_enable()
{
    for (int i = 0; i < KP_COL_COUNT; ++i) {
        nrf_drv_gpiote_in_event_enable(keypad_col_pins[i], true);
    }
}

static void keypad_cols_int_disable()
{
    for (int i = 0; i < KP_COL_COUNT; ++i) {
        nrf_drv_gpiote_in_event_disable(keypad_col_pins[i]);
    }
}

static void keypad_rows_init()
{
    for (int row = 0; row < KP_ROW_COUNT; ++row) {
        // init row pins in S0D1 mode
        NRF_GPIO->PIN_CNF[keypad_row_pins[row]] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                      | (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
                                      | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                      | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                      | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    }
}

static void keypad_rows_activate(uint32_t mask)
{
    for (uint32_t row = 0; row < KP_ROW_COUNT; ++row) {
        if (mask & 1) {
            nrf_gpio_pin_clear(keypad_row_pins[row]);
        } else {
            nrf_gpio_pin_set(keypad_row_pins[row]);
        }
        mask >>= 1;
    }
}

static uint32_t keypad_scan()
{
    keypad_rows_activate(KP_ROWS_NONE);

    uint32_t res = 0;
    uint32_t key_index = 0;

    for (uint32_t row = 0; row < KP_ROW_COUNT; ++row) {

        nrf_gpio_pin_clear(keypad_row_pins[row]);
        nrf_delay_us(KEYPAD_SCAN_DELAY_US);
        uint32_t state = nrf_gpio_pins_read();
        uint32_t colmask = 0;

        for (uint32_t col = 0; col < KP_COL_COUNT; ++col, ++key_index) {
            colmask |= (1 << keypad_col_pins[col]);

            if ((state & (1 << keypad_col_pins[col])) == 0) {
                res = res | (1 << (KP_ROW_COUNT * KP_COL_COUNT - 1 - key_index));
            }
        }
        nrf_gpio_pin_set(keypad_row_pins[row]);
    }

    keypad_rows_activate(KP_ROWS_ALL);
    return res;
}

static void gpiote_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    uint32_t state = keypad_scan();
    if (state != s_keys_state) {
        app_timer_stop(s_debounce_timer_id);
        s_keys_state = state;
        uint32_t err_code = app_timer_start(s_debounce_timer_id, KP_DEBOUNCE_DELAY_TICKS, NULL);
        APP_ERROR_CHECK(err_code);
    }
}

static void debounce_timer_handler(void* arg)
{
    uint32_t state = s_keys_state;
    if (state == s_debounce_filter_state)
        return;

    uint32_t change = state ^ s_debounce_filter_state;
    s_debounce_filter_state = state;

    for (uint32_t key_index = 0; change && key_index < KP_ROW_COUNT * KP_COL_COUNT; ++key_index)
    {
        if (change & 1)
        {
            uint32_t code = (1 << (keypad_code_map[key_index])) | ((state & 1) ? KF_DOWN : KF_UP);
            (*s_handler)(code);
        }
        change >>= 1;
        state >>= 1;
    }
}

And schema for buttons:

Related