From 11921eb92863b5a54e7e95d65d6c2a0b23b7d992 Mon Sep 17 00:00:00 2001 From: Vic Date: Tue, 5 Jan 2021 10:42:50 +0100 Subject: [PATCH] One more ISR improvement --- tasmota/xdrv_47_ftc532.ino | 58 ++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index 98a7ddf18..6a50ba9b1 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -49,13 +49,41 @@ Timing of an ALL OFF frame in clock cycles T=377µs, triggering on rising edge: IDLE-2222444422224444-IDLE + + ********************* + * About this driver * + ********************* + + This driver implements the reverse engineered protocol of the FTC532 touch controller. + The protocol encodes the bitmap of touched keys in variable length pulses comprising a + fixed length frame. These frames are then sent out continuously from the FTC532 chip. + The first version of this driver was working fine on well behaved hardware. After being + released to the field and installed on crappy hardware in noisy environments it developed + a habit of random 'ghost' switchings at night, much to the chagrin of some users. + This is almost a re-write containing a lot more timing (and other) checks in order to + detect and mitigate various incarnations of noise. + If you should still experience 'ghost switching' issues a solution may be increasing + FTC532_DEBOUNCE to 2 or higher. That will enable the de-bouncing code, at the expense of + 'snappiness' of touch reactions. Higher values will accumulate more samples in 50 ms steps + before actually firing the rules trigger. It will eat a few bytes off your RAM and Flash + budget, too. + + Usage: + ------ + This driver does not actually switch anything. It is a pure "rules" driver that solely emits + {"FTC532":{"KEYS":"XX"}} JSON messages to be used in a rule or by an MQTT broker. "XX" stands + for the hexadecimal (big endian) representation of a bitmap of keys currently touched, where + e.g. "00" means "no key touched" while "03" means "keys 1 and 2 touched simultaneously". + Selecting "FTC532" on a GPIO will awake the driver. This driver can only be selected once. + + \*********************************************************************************************/ #define XDRV_47 47 +#define FTC532_DEBOUNCE 0 // no. of cycles, < 2 disables the code #define FTC532_KEYS 4 // number of key pins on chip #define FTC532_KEYS_MAX 8 // number of key slots in protocol -#define FTC532_DEBOUNCE 0 // number of consecutive cycles until key accepted #define FTC532_STATE_WAITING 0x1 #define FTC532_STATE_READING 0x2 @@ -79,15 +107,15 @@ struct FTC532 { volatile uint16_t state; // ISR state uint8_t keys = 0; // bitmap of active keys uint8_t old_keys = 0; // previously active keys + bool present = false; // driver active #if FTC532_DEBOUNCE > 1 uint8_t key_cnt = 0; // used to de-bounce #endif // FTC532_DEBOUNCE > 1 - bool present = false; // driver active #ifdef DEBUG_FTC532 - volatile uint16_t e_inv = 0; // inv. key error counter + volatile uint16_t e_inv = 0; // inverted key error counter volatile uint16_t e_frame = 0; // frame error counter volatile uint16_t e_noise = 0; // noise detection counter - volatile bool valid = 0; // did we ever receive valid data? + volatile bool valid = 0; // did we ever receive valid data? #endif // DEBUG_FTC532 } Ftc532; @@ -108,37 +136,36 @@ void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, trigger #endif // DEBUG_FTC532 } Ftc532.state = FTC532_STATE_READING; + Ftc532.tsmp = 0; } else { Ftc532.state = FTC532_STATE_WAITING; } return; } - // FTC532_STATE_READING starts here + // FTC532_STATE_READING starts here if (time_diff > FTC532_LONG + FTC532_BIT) { #ifdef DEBUG_FTC532 - ++Ftc532.e_frame; // frame error + ++Ftc532.e_frame; // frame error #endif // DEBUG_FTC532 Ftc532.state = FTC532_STATE_WAITING; return; } if (time_diff > FTC532_SHORT + FTC532_BIT) { - Ftc532.tsmp |= (1 << Ftc532.rxbit); // LONG - } else if (time_diff < FTC532_NOISE) { // noise detector + Ftc532.tsmp |= (1 << Ftc532.rxbit); // LONG + } else if (time_diff < FTC532_NOISE) { // NOISE #ifdef DEBUG_FTC532 ++Ftc532.e_noise; #endif // DEBUG_FTC532 Ftc532.state = FTC532_STATE_WAITING; return; - } else { - Ftc532.tsmp &= ~(1 << Ftc532.rxbit); // SHORT } ++Ftc532.rxbit; - if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete + if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete Ftc532.state = FTC532_STATE_COMPLETE; } } -void ftc532_init(void) { // Initialize +void ftc532_init(void) { // Initialize if (!PinUsed(GPIO_FTC532)) { return; } Ftc532.state = FTC532_STATE_WAITING; pinMode(Pin(GPIO_FTC532), INPUT_PULLUP); @@ -147,7 +174,7 @@ void ftc532_init(void) { // Initialize Ftc532.present = true; } -void ftc532_update(void) { // Usually called every 50 ms +void ftc532_update(void) { // Usually called every 50 ms if ((Ftc532.sample & 0xF0F0) == ((~Ftc532.sample & 0x0F0F) << 4) && (Ftc532.sample >> 8) == 0xF0) { Ftc532.keys = Ftc532.sample & 0xF; if (Ftc532.keys != Ftc532.old_keys) { @@ -156,7 +183,8 @@ void ftc532_update(void) { // Usually called every 50 ms #endif // FTC532_DEBOUNCE > 1 #ifdef DEBUG_FTC532 AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%X OLD=%X INV=%u NOI=%u FRM=%u OK=%u TIME=%lu Pin=%u"), - Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.e_inv, Ftc532.e_noise, Ftc532.e_frame, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); + Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.e_inv, Ftc532.e_noise, Ftc532.e_frame, + Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); #endif // DEBUG_FTC532 ftc532_publish(); Ftc532.old_keys = Ftc532.keys; @@ -171,7 +199,7 @@ void ftc532_update(void) { // Usually called every 50 ms #ifdef DEBUG_FTC532 else { ++Ftc532.e_inv; - AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X"), Ftc532.sample); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: ILL SAM=%04X"), Ftc532.sample); } #endif // DEBUG_FTC532 }