LCD and encoder modules - button events

Hi,
I have encountered one “not very bright” design decission on LCD module making trouble using it together with encoder module.

Encoder has it’s button connected to BOOT signal in standard way. On LCD module, 2 buttons below display are connected to I2C expander (so far so good). But for some reason, there are double diode (D1) connecting both buttons to BOOT signal as well, resulting in each of display buttons generating 2 events, second event acting as encoder button push. That makes it quite difficult to distinguish between LCD and encoder buttons.

What is preferred way of solving this problem? I can think of 2 solutions:

  1. solder out D1 from LCD module. But that would void warranty and it is not very easy with my simple equipment.

  2. on button events just set some flags which button triggered event and fire scheduller task for ~10ms later. In this schedulled task I would analyze which button flags were triggered and in case LCD module was pressed, i would ignore encoder button.

And if I can have suggestion, leave out D1 on LCD module at all, probability that someone would need to use LCD module as push button is rather low and it can even be easily done in push button firmware.

Thanks for suggestions,
Mixi

Hi, we have some code solution to that. We’ll give you an update in a few days.

Hi, I stumbled over this issue again… do you have some fix for this?

Hi, at first look it seemed easy to me to solve. But after consultation with colleague it turned out it will be much more work to get this done in the SDK.

The events from the two LCD buttons are checked separately (initialized in bc_module_lcd_set_event_handler). If they would be managed together in a single module, the you can decide if the button press was right or left button (by reading I2C gpio expander) or if there is no signal from expander, it must be separate button/encoder.

I created a simple workaround without any SDK changes which works only when you react to PRESS ir HOLD event on encoder. It checks, whether in the same time the encoder PRESS event arrives there isn’t any LCD button pressed.

#include <application.h>

void event_encoder(twr_module_encoder_event_t event, void *param)
{
    (void) param;

    // Get LCD button driver instance
    const twr_button_driver_t *driver = twr_module_lcd_get_button_driver();
    // Fake virtual buttons 0 & 1, which is then used in get_input below
    static twr_button_t left = {._channel.virtual = 0};
    static twr_button_t right = {._channel.virtual = 1};

    // Check if also LCD buttons are pressed, this works only on PRESS or HOLD event of the encoder
    if ((event == TWR_MODULE_ENCODER_EVENT_PRESS || event == TWR_MODULE_ENCODER_EVENT_HOLD) && driver->get_input(&left) == 0 && driver->get_input(&right) == 0)
    {
        twr_log_debug("Encoder event: %d", event);
    }
}

void event_lcd(twr_module_lcd_event_t event, void *param)
{
    (void) param;

    twr_log_debug("LCD event: %d", event);
}

// Application initialization function which is called once after boot
void application_init(void)
{
    // Initialize logging
    twr_log_init(TWR_LOG_LEVEL_DUMP, TWR_LOG_TIMESTAMP_ABS);

    twr_module_encoder_init();
    twr_module_encoder_set_event_handler(event_encoder, NULL);

    twr_module_lcd_init();
    twr_module_lcd_set_event_handler(event_lcd, NULL);
}


And the output :

# 144.20 <D> Encoder event: 1
# 145.28 <D> LCD event: 18
# 145.88 <D> LCD event: 34

Let me know if this works for you.

Thanks for reply, I was considering similar solution myself (after your last reply I was hoping it could be done in SDK to make it easier for firmware developers though :wink: ).

This works for me. It has one downside though as it cannot properly detect simultaneous press of encoder and display button (I don’t need it, but it could be handy for example for resetting firmware configuration to defaults after some wrong setting “brick” it). So if you can please pass back to HW guys to not fit D1 on LCD modules, it would make life simpler for future firmware developers. :slight_smile:

LCD Module has also event of two pressed and holding buttons TWR_MODULE_LCD_EVENT_BOTH_HOLD, so you can do factory reset there. Or you can use Menu or AT serial interface, see menu.c or at.c in LoRa project https://github.com/hardwario/twr-lora-tester-lcd-gps-ttnmapper/tree/master/src

Diode D1 is not any mistake. It is intentionally there so we are not polling I2C expanders and wasting energy in the battery applications. We react to the GPIO level and only after that we sample all the I2C GPIO expanders the firmware knows about.

Oh, I see, suddenly it makes much more sense now! :grinning:

Thanks for clarification, it looks like it’s in fact design gap on encoder module, which should use I2C expander as well, instead of directly connect to the BOOT + 2× GPIO pins. It even uses same GPIO as sensor module making them mutually exclusive as well (I never realized this until now).

That makes me wonder, why is this not mentioned anywhere in the documentation? If there are some mutually exclusive modules (using same GPIO or I2C addresses like encoder vs. sensor module) or some potentially problematic module combinations (like LCD vs. encoder buttons), it should be explicitly mentioned in the documentation for each of affected modules. You should also have some module compatability matrix.