From 0e5659400ae952d2b7ed546ac4d87766551d6c7c Mon Sep 17 00:00:00 2001 From: Niklas Dusenlund Date: Mon, 22 Sep 2025 13:28:16 +0200 Subject: [PATCH 1/6] qtouch: switch PTC to 8Mhz clock from 12 Mhz 8Mhz is recommended by the tooling and can be divided down to the required 2Mhz with the ADC prescaler --- external/asf4-drivers/Config/hpl_gclk_config.h | 8 ++++---- external/asf4-drivers/Config/peripheral_clk_config.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/external/asf4-drivers/Config/hpl_gclk_config.h b/external/asf4-drivers/Config/hpl_gclk_config.h index e62eab55bc..331ec261e2 100644 --- a/external/asf4-drivers/Config/hpl_gclk_config.h +++ b/external/asf4-drivers/Config/hpl_gclk_config.h @@ -387,7 +387,7 @@ // Indicates whether generic clock 5 configuration is enabled or not // enable_gclk_gen_5 #ifndef CONF_GCLK_GENERATOR_5_CONFIG -#define CONF_GCLK_GENERATOR_5_CONFIG 0 +#define CONF_GCLK_GENERATOR_5_CONFIG 1 #endif // Generic Clock Generator Control @@ -404,7 +404,7 @@ // This defines the clock source for generic clock generator 5 // gclk_gen_5_oscillator #ifndef CONF_GCLK_GEN_5_SOURCE -#define CONF_GCLK_GEN_5_SOURCE GCLK_GENCTRL_SRC_GCLKGEN1 +#define CONF_GCLK_GEN_5_SOURCE GCLK_GENCTRL_SRC_DFLL #endif // Run in Standby @@ -446,7 +446,7 @@ // Indicates whether Generic Clock Generator Enable is enabled or not // gclk_arch_gen_5_enable #ifndef CONF_GCLK_GEN_5_GENEN -#define CONF_GCLK_GEN_5_GENEN 0 +#define CONF_GCLK_GEN_5_GENEN 1 #endif // @@ -454,7 +454,7 @@ // Generic clock generator 5 division <0x0000-0xFFFF> // gclk_gen_5_div #ifndef CONF_GCLK_GEN_5_DIV -#define CONF_GCLK_GEN_5_DIV 62 +#define CONF_GCLK_GEN_5_DIV 6 #endif // // diff --git a/external/asf4-drivers/Config/peripheral_clk_config.h b/external/asf4-drivers/Config/peripheral_clk_config.h index d557fe9e81..8e6eb0cf22 100644 --- a/external/asf4-drivers/Config/peripheral_clk_config.h +++ b/external/asf4-drivers/Config/peripheral_clk_config.h @@ -33,7 +33,7 @@ // Select the clock source for ADC. #ifndef CONF_GCLK_ADC0_SRC -#define CONF_GCLK_ADC0_SRC GCLK_PCHCTRL_GEN_GCLK2_Val +#define CONF_GCLK_ADC0_SRC GCLK_PCHCTRL_GEN_GCLK5_Val #endif /** @@ -41,7 +41,7 @@ * \brief ADC0's Clock frequency */ #ifndef CONF_GCLK_ADC0_FREQUENCY -#define CONF_GCLK_ADC0_FREQUENCY 12000000 +#define CONF_GCLK_ADC0_FREQUENCY 8000000 #endif /** From d98e5c3a004bc8ee8b247963bd2afb55fac9c73f Mon Sep 17 00:00:00 2001 From: Niklas Dusenlund Date: Mon, 22 Sep 2025 13:38:32 +0200 Subject: [PATCH 2/6] qtouch: Remove binding layer and unused header file The qtouch configurator has changed the default output to not use the binding layer. Let's remove it to be more in sync with the configurator. No functionality is lost. All changes come from the new templates. --- external/CMakeLists.txt | 1 - .../include/qtm_binding_layer_0x0005_api.h | 226 ---------------- .../qtouch/include/qtm_scroller_0x000b_api.h | 151 ----------- .../qtouch/include/touch_api_ptc.h | 4 +- .../lib/gcc/libqtm_binding_layer_cm4_0x0005.a | Bin 4142 -> 0 bytes src/CMakeLists.txt | 4 +- src/qtouch/qtouch.c | 247 +++--------------- 7 files changed, 44 insertions(+), 589 deletions(-) delete mode 100644 external/asf4-drivers/qtouch/include/qtm_binding_layer_0x0005_api.h delete mode 100644 external/asf4-drivers/qtouch/include/qtm_scroller_0x000b_api.h delete mode 100644 external/asf4-drivers/qtouch/lib/gcc/libqtm_binding_layer_cm4_0x0005.a diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 6caaa3d4ad..17b767ec89 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -154,7 +154,6 @@ if(CMAKE_CROSSCOMPILING) set_property(TARGET asf4-drivers PROPERTY INTERFACE_LINK_LIBRARIES "") find_library(QTOUCHLIB_A qtm_acq_samd51_0x000f PATHS asf4-drivers/qtouch/lib/gcc NO_CMAKE_FIND_ROOT_PATH) - find_library(QTOUCHLIB_B qtm_binding_layer_cm4_0x0005 PATHS asf4-drivers/qtouch/lib/gcc NO_CMAKE_FIND_ROOT_PATH) find_library(QTOUCHLIB_T qtm_touch_key_cm4_0x0002 PATHS asf4-drivers/qtouch/lib/gcc NO_CMAKE_FIND_ROOT_PATH) add_library(cryptoauthlib diff --git a/external/asf4-drivers/qtouch/include/qtm_binding_layer_0x0005_api.h b/external/asf4-drivers/qtouch/include/qtm_binding_layer_0x0005_api.h deleted file mode 100644 index 7e4950e1c9..0000000000 --- a/external/asf4-drivers/qtouch/include/qtm_binding_layer_0x0005_api.h +++ /dev/null @@ -1,226 +0,0 @@ -/*============================================================================ -Filename : qtm_binding_layer_api.h -Project : QTouch Modular Library -Purpose : Binds the acquisition and post processing modules and provides callback ------------------------------------------------------------------------------- -Copyright (c) 2017 Microchip. All rights reserved. ------------------------------------------------------------------------------- -============================================================================*/ - -/** @file */ - -/** \defgroup Misra Misra Compliance report */ - -/** - * \addtogroup Misra - * Complaiance:
- * the module code is compiled using IARs Embedded workbench for AVR
- * MISRA 2004 compliance is selected with all required options selected
- * any rule which has been violated will be documented and the rule switched off
- *
- *
- */ - -#ifndef TOUCH_API_BINDING_LAYER_H -#define TOUCH_API_BINDING_LAYER_H - -/* Include files */ -#include -#include "qtm_common_components_api.h" - -/*---------------------------------------------------------------------------- -manifest constants -----------------------------------------------------------------------------*/ -#define null '\0' - -/*---------------------------------------------------------------------------- - * type definitions - *----------------------------------------------------------------------------*/ - -/* Modular Library state */ -typedef enum QT_Modular_lib_state_tag { uninitialised, config_initialised, ready, busy, processing, error } qtm_state_t; - -typedef enum QT_ModLib_Status_flags { - time_to_measure_touch, - node_pp_request, - reburst_request, - reserved_flag_pos_3, - - reserved_flag_pos_4, - reserved_flag_pos_5, - reserved_flag_pos_6, - reserved_flag_pos_7, -} qtm_flags; - -typedef void (*qtm_measure_complete_t)(void); -typedef void (*qtm_library_init_complete_t)(void); -typedef void (*qtm_pre_process_callback_t)(uint8_t *callback); -typedef void (*qtm_error_callback_t)(uint8_t error_code); -typedef void (*qtm_post_process_callback_t)(void); - -typedef void *(*module_init_t)(void *data_model); -typedef void *(*module_proc_t)(void *data_model); -typedef void *(*module_init_inline_t)(void *data_model); -typedef void *(*module_inline_t)(void *data_model); -typedef void *(*module_conf_t)(void *data_model); -typedef void *(*module_acq_t)(void *data_model, void (*callback)(void)); - -/* this should take an arqument */ -typedef touch_ret_t(qtm_acq_pp_t)(void); - -typedef void *module_arg_t; - -/*---------------------------------------------------------------------------- - * Structure Declarations - *----------------------------------------------------------------------------*/ - -/* ---------------------------------------------------------------------------------------- */ -/* Key sensor run-time data - api common */ -/* ---------------------------------------------------------------------------------------- */ - -/* Container */ -/** - * @brief a collection of controls for the binding layer - */ -typedef struct qtm_control_tag /*!< Control structure for the bonsding layer */ -{ - uint8_t binding_layer_flags; /*!< Some Flags */ - - module_init_t *library_modules_init; /*!< List of function pointers to acquisition sets */ - module_proc_t *library_modules_proc; /*!< List of function pointers to post processing modules */ - module_acq_t * library_modules_acq; - - module_arg_t *library_module_init_data_model; /*!< Data Model for Acquisition modules */ - module_arg_t *library_module_proc_data_model; /*!< Data Model for post processing modules */ - module_arg_t *library_modules_acq_dm; /*!< Data model for inline module processes */ - - qtm_acq_pp_t *qtm_acq_pp; /*!< Post porcessing pointer */ - - /*******************************/ - /* Callbacks for Binding layer */ - /*******************************/ - qtm_library_init_complete_t qtm_init_complete_callback; - qtm_error_callback_t qtm_error_callback; - qtm_measure_complete_t qtm_measure_complete_callback; - qtm_pre_process_callback_t qtm_pre_process_callback; - qtm_post_process_callback_t qtm_post_process_callback; - -} qtm_control_t; - -/*---------------------------------------------------------------------------- - * prototypes - *----------------------------------------------------------------------------*/ - -/** - * @brief Returns a pointer to the binding layer control structure - * - * This function is never used in the example code, but it is included here - * in case the user would like to get a (qtm_control_t) - * - * This function accepts no inputs - * - * @return &qtm_control, this is a pointer to the binding layer control structure - */ -qtm_control_t *qmt_get_binding_layer_ptr(void); - -/** - * Initialises the binding layer, there are two possible outcomes - * - * - * 1). There were no errors - * \msc - * a [label="User Application"],b [label="Modular Library"]; - * a=>>b [label="qtm_lib_init(&qtm_control);"]; - * b=>b; - * a<<=b [label="qtm_init_complete_callback();"]; - * \endmsc - * - * 2). There were errors detected - * \msc - * a [label="User Application"],b [label="Modular Library"]; - * a=>>b [label="qtm_lib_init(&qtm_control);"]; - * b=>b; - * a<<=b [label="qtm_error_callback(error_code);"]; - * \endmsc - */ - -/** - * @see qtm_state_t for a state diagram - * @param qtm_control This is the control structure to the binding layer - */ - -/** - * Typical Application flow. - * - * @msc - * a [label="User Application"],b [label="Modular Library"]; - * a=>>b [label="qtm_lib_init(&qtm_control);"]; - * b=>b; - * a<<=b [label="qtm_init_complete_callback();"]; - * a=>>b [label="qtm_calibrate_hardware();"]; - * --- [ label = "library setup, Start normal acquisition" ]; - * a=>>b [label="qtm_lib_start_acquisition();"]; - * b=>b; - * a<<=b [label="qtm_measure_complete_callback();"]; - * ...; - * a=>>b [label="qtm_lib_start_acquisition();"]; - * b=>b; - * a<<=b [label="qtm_measure_complete_callback();"]; - * ...; - * a=>>b [label="qtm_lib_start_acquisition();"]; - * b=>b; - * a<<=b [label="qtm_measure_complete_callback();"]; - * ...; - * a=>>b [label="qtm_lib_start_acquisition();"]; - * b=>b; - * a<<=b [label="qtm_measure_complete_callback();"]; - * ...; - * @endmsc - */ - -void qtm_binding_layer_init(qtm_control_t *qtm_control); - -/** - * @brief Starts the Modular library on the first acquisition set - * - * An Acquisition set is defined in the Acquisition Module documentation, but - * essentially an acquisition set is a group of node with a common property, - * the common property can be, Acquisition Type: Self or Mutual, or proximity or - * spatial displacement to or from another. - * - * @return the library state, @see qtm_state_t - */ -touch_ret_t qtm_lib_start_acquisition(uint8_t set_id); - -/*qtm_state_t qtm_post_process(void);*/ -touch_ret_t qtm_lib_post_process(void); - -/** - * @brief Gets the library state - * - * some tasks cannot happen if the library is not in the correct state - * if the library is requesting a start acquisition when there is an - * ongoing acquisition then the binding layer will move to the error - * state, checking the library state before acquisition will prevent - * errors like this. - * - * @return the library state, - * @see qtm_state_t - */ -qtm_state_t qtm_lib_get_state(void); - -touch_ret_t qtm_lib_acq_process(void); - -uint16_t qtm_get_binding_layer_module_id(void); - -/*============================================================================ -uint8_t get_qtm_m328pb_acq_module_version(void) ------------------------------------------------------------------------------- -Purpose: Returns the module Firmware version -Input : none -Output : Module ID - Upper nibble major / Lower nibble minor -Notes : none -============================================================================*/ -uint8_t qtm_get_binding_layer_module_version(void); - -#endif /* TOUCH_API_BINDING_LAYER_H */ diff --git a/external/asf4-drivers/qtouch/include/qtm_scroller_0x000b_api.h b/external/asf4-drivers/qtouch/include/qtm_scroller_0x000b_api.h deleted file mode 100644 index 3079b90362..0000000000 --- a/external/asf4-drivers/qtouch/include/qtm_scroller_0x000b_api.h +++ /dev/null @@ -1,151 +0,0 @@ -/*============================================================================ -Filename : qtm_scroller_api.h -Project : QTouch Modular Library -Purpose : Structs and definitions for use within modules ------------------------------------------------------------------------------- -Copyright (c) 2017 Microchip. All rights reserved. ------------------------------------------------------------------------------- -============================================================================*/ - -#ifndef TOUCH_API_SCROLLER_H -#define TOUCH_API_SCROLLER_H - -/* Include files */ -#include -#include "qtm_common_components_api.h" - -/* Scroller status bits */ -#define TOUCH_ACTIVE (uint8_t)((uint8_t)1 << 0u) /* Bit 0 */ -#define POSITION_CHANGE (uint8_t)((uint8_t)1 << 1u) /* Bit 1 */ -#define SCROLLER_REBURST (uint8_t)((uint8_t)1 << 7u) /* Bit 7 */ - -/* Extract Resolution / Deadband */ -#define SCR_RESOLUTION(m) (uint8_t)(((m)&0xF0u) >> 4u) -#define SCR_DEADBAND(m) (uint8_t)((m)&0x0Fu) - -/* Combine Resolution / Deadband */ -#define SCR_RESOL_DEADBAND(r, p) (uint8_t)(((r) << 4u) | (p)) - -/* scroller resolution setting */ -typedef enum tag_resolution_t { - RESOL_2_BIT = 2, - RESOL_3_BIT, - RESOL_4_BIT, - RESOL_5_BIT, - RESOL_6_BIT, - RESOL_7_BIT, - RESOL_8_BIT, - RESOL_9_BIT, - RESOL_10_BIT, - RESOL_11_BIT, - RESOL_12_BIT -} scr_resolution_t; - -/* scroller deadband percentage setting */ -typedef enum tag_deadband_t { - DB_NONE, - DB_1_PERCENT, - DB_2_PERCENT, - DB_3_PERCENT, - DB_4_PERCENT, - DB_5_PERCENT, - DB_6_PERCENT, - DB_7_PERCENT, - DB_8_PERCENT, - DB_9_PERCENT, - DB_10_PERCENT, - DB_11_PERCENT, - DB_12_PERCENT, - DB_13_PERCENT, - DB_14_PERCENT, - DB_15_PERCENT -} scr_deadband_t; - -/*---------------------------------------------------------------------------- - * Structure Declarations - *----------------------------------------------------------------------------*/ - -/* Configuration - Group of scrollers */ -typedef struct { - qtm_touch_key_data_t *qtm_touch_key_data; - uint8_t num_scrollers; -} qtm_scroller_group_config_t; - -/* Data - Group of scrollers */ -typedef struct { - uint8_t scroller_group_status; -} qtm_scroller_group_data_t; - -/* Configuration - Each slider / wheel */ -typedef struct { - uint8_t type; - uint16_t start_key; - uint8_t number_of_keys; - uint8_t resol_deadband; - uint8_t position_hysteresis; - uint16_t contact_min_threshold; -} qtm_scroller_config_t; - -/* Data Each - slider / wheel */ -typedef struct { - uint8_t scroller_status; - uint8_t right_hyst; - uint8_t left_hyst; - uint16_t raw_position; - uint16_t position; - uint16_t contact_size; -} qtm_scroller_data_t; - -/* Container */ -typedef struct { - qtm_scroller_group_data_t * qtm_scroller_group_data; - qtm_scroller_group_config_t *qtm_scroller_group_config; - qtm_scroller_data_t * qtm_scroller_data; - qtm_scroller_config_t * qtm_scroller_config; -} qtm_scroller_control_t; - -/*---------------------------------------------------------------------------- - * prototypes - *----------------------------------------------------------------------------*/ - -/*============================================================================ -touch_ret_t qtm_init_scroller_module(qtm_scroller_control_t *qtm_scroller_control) ------------------------------------------------------------------------------- -Purpose: Initialize a scroller -Input : Pointer to scroller group control data -Output : TOUCH_SUCCESS -Notes : none -============================================================================*/ -touch_ret_t qtm_init_scroller_module(qtm_scroller_control_t *qtm_scroller_control); - -/*============================================================================ -touch_ret_t qtm_scroller_process(qtm_scroller_control_t *qtm_scroller_control) ------------------------------------------------------------------------------- -Purpose: Scroller position calculation and filtering -Input : Pointer to scroller group control data -Output : TOUCH_SUCCESS -Notes : none -============================================================================*/ -touch_ret_t qtm_scroller_process(qtm_scroller_control_t *qtm_scroller_control); - -/*============================================================================ -uint16_t qtm_get_scroller_module_id(void) ------------------------------------------------------------------------------- -Purpose: Returns the module ID -Input : none -Output : Module ID -Notes : none -============================================================================*/ -uint16_t qtm_get_scroller_module_id(void); - -/*============================================================================ -uint8_t qtm_get_scroller_module_ver(void) ------------------------------------------------------------------------------- -Purpose: Returns the module Firmware version -Input : none -Output : Module ID - Upper nibble major / Lower nibble minor -Notes : none -============================================================================*/ -uint8_t qtm_get_scroller_module_ver(void); - -#endif /* TOUCH_API_SCROLLER_H */ diff --git a/external/asf4-drivers/qtouch/include/touch_api_ptc.h b/external/asf4-drivers/qtouch/include/touch_api_ptc.h index 15f693cf42..2364b371e7 100644 --- a/external/asf4-drivers/qtouch/include/touch_api_ptc.h +++ b/external/asf4-drivers/qtouch/include/touch_api_ptc.h @@ -32,11 +32,9 @@ extern "C" { #include "hal_timer.h" -#include "qtm_common_components_api.h" -#include "qtm_binding_layer_0x0005_api.h" #include "qtm_acq_samd51_0x000f_api.h" +#include "qtm_common_components_api.h" #include "qtm_touch_key_0x0002_api.h" -#include "qtm_scroller_0x000b_api.h" /*---------------------------------------------------------------------------- * prototypes diff --git a/external/asf4-drivers/qtouch/lib/gcc/libqtm_binding_layer_cm4_0x0005.a b/external/asf4-drivers/qtouch/lib/gcc/libqtm_binding_layer_cm4_0x0005.a deleted file mode 100644 index c6658cc462a2e9646314552732afbd2400561114..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4142 zcmds3O>7fK6n^Wqoy3IHgak}d=#n2bV6y&+<5H-qKngBOpomg6DykfNy z)jaQ0No^*k7DGN?$X<93R-Uypk#IO3k1NVZJdS%tGVQx?VDg|ONw`6_NH7F-3m`yy z2jGdZZU}lI0G_^<3IBYL;hpHso;VFbcLi43s{RFO0TNG^?;K=M{0SuP9Be_%jnn>l z2)Yo}UX_=|6nO$xS{%HHl_mmN19Qk{%qx@1k^XXc+7t9tq@esjD?@NgWpD`wbt96U z$bJJirXcvJ(w4hC1uLN{c%j2p(aO?@W=Nx2dDuJL0m0uZzb(7^`;C!oFIGx5^i(}d z9`v~P!V+PL*HeN1i;8A=urgoOU^A)DgX*EV81r6$!Ob|MpR-@Xl_}UESENxI=kfAq zr(wtD%569{1v@uZZsew>VCbdF`a`g?t?Kp;bgY|@7v;XsjUGcbTM*H;xV7F-Lh2^vcjeaV(;s66=R@(?^(HSa)TD1m38%+G>H zF%n(aATd6^M;S^Sc~3cBEapqf$)c(3J9bz(Fq76Z89k#MwLkEpS=ynDs!=tfM8lEM zNHiQ(hD<%Lr%L(`g^2Q7kCYk;v}Y?hj#K2sa|7r_wo) z22u53-fPF-I(!Jcu2!i{>U4KW-O^?`AZ?L)q-}0-+n6qXM{fB0sR)o8zA^wATw)k) zxyg1zOM}Nvf2oXRC-yFI!^_w!*le-!L)^r;C^CL7jeK5s1p!pE&F5|6v+;F4{1ya} zp|y#xmF2hAFm;VwGFIO>zK`KA)$n%wnqb#dmfzl#-_G(gHIN;*1iPlP{Envl4wm0l z1KII_VAoWZ?{CWYv;4a?kRAU~uxl#I?`+ENWcl?~>J;I)UR_Q2dZh%Ep}Q&G&G_mh zGQ5rk?XTTr7(<;-9k)@fi42=+Iw>-2hIg^2Q$%e8{PXmE>?yY$TPN=SS;zjE**>`J z*kxw7!%fHTVRi?6@7VX5?S~&6+ve+pUmTmp>%{s0+hBJ?9}VvKHeiKxA*&h;*v|po zG>c|3n<`}Tx(NdrIHebKGp8lBR6d_hX=jorXA2s8BQR(Qv{}>C3$+)4bH)EZA0rB` zn+q3qfO-{x+1N81KTJA@NCwc^YSo_SF5a#K^5W#-bemR`b* zc`@ll7=4EPHi$K)@mp=XgX6baGtT*x;Z?-Z*${DDCu)uhJGwaTE&@10M~j4fZP>=J zkyP>Q`mx`FjWE<`yh&{0Jf_iJi|=jpi+rt^%=xGm&S#)5@?Ax{9UB*3UmhJIUjX^2 z9;%Oe&i5(mBHwki$;XBBT|zv!uf8aL*(0yd3NqimHINxK`MZP;|&^^J0^F2a`$Tuy_m-dD8 zZNhw!?>ZjLwf3VEK_XvSsE=-B&Zjo<-9kQI6V=Gi{qZK;SI@v*aByKtM)?kLMO$UR z7-scfMg_kII$lhA(cn4cARNgCY~puw5$AE82QkJ~>UpiG!XzeL#71{C{(ZAK(K^za Ph0`X diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 93daee2cf7..4d0f99fc56 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -506,7 +506,7 @@ if(CMAKE_CROSSCOMPILING) foreach(bootloader ${DEVDEVICE-BOOTLOADERS} ${BOOTLOADERS-BITBOX02PLUS}) set(elf ${bootloader}.elf) - target_link_libraries(${elf} PRIVATE ${QTOUCHLIB_A} ${QTOUCHLIB_B} ${QTOUCHLIB_T}) + target_link_libraries(${elf} PRIVATE ${QTOUCHLIB_A} ${QTOUCHLIB_T}) target_sources(${elf} PRIVATE ${QTOUCH-SOURCES}) endforeach(bootloader) @@ -571,7 +571,7 @@ if(CMAKE_CROSSCOMPILING) target_link_libraries(${elf} PRIVATE -Wl,--defsym=STACK_SIZE=${STACK_SIZE} -Wl,-defsym=HEAP_SIZE=${HEAP_SIZE}) target_link_libraries(${elf} PRIVATE secp256k1) - target_link_libraries(${elf} PRIVATE ${QTOUCHLIB_A} ${QTOUCHLIB_B} ${QTOUCHLIB_T}) + target_link_libraries(${elf} PRIVATE ${QTOUCHLIB_A} ${QTOUCHLIB_T}) # Select the smaller version of libc called nano. target_compile_options(${elf} PRIVATE --specs=nano.specs) diff --git a/src/qtouch/qtouch.c b/src/qtouch/qtouch.c index f6ad8f57eb..fe8fb45f53 100644 --- a/src/qtouch/qtouch.c +++ b/src/qtouch/qtouch.c @@ -36,26 +36,14 @@ Copyright (c) 2017 Microchip. All rights reserved. * prototypes *----------------------------------------------------------------------------*/ -/*! \brief configure binding layer config parameter - */ -static void build_qtm_config(qtm_control_t* qtm); - /*! \brief configure keys, wheels and sliders. */ static touch_ret_t touch_sensors_config(void); -/*! \brief Init complete callback function prototype. - */ -static void init_complete_callback(void); - /*! \brief Touch measure complete callback function example prototype. */ static void qtm_measure_complete_callback(void); -/*! \brief Touch post process complete callback function prototype. - */ -static void qtm_post_process_complete(void); - /*! \brief Touch Error callback function prototype. */ static void qtm_error_callback(uint8_t err); @@ -68,13 +56,14 @@ static void qtouch_process_scroller_positions(void); * Global Variables *----------------------------------------------------------------------------*/ -/* Binding layer control */ -qtm_control_t qtm_control; -qtm_control_t* p_qtm_control; -qtm_state_t qstate; +/* Flag to indicate time for touch measurement */ +volatile uint8_t time_to_measure_touch_flag = 0; + +/* postporcess request flag */ +volatile uint8_t touch_postprocess_request = 0; /* Measurement Done Touch Flag */ -volatile bool measurement_done_touch = false; +volatile uint8_t measurement_done_touch = 0; /* Error Handling */ uint8_t module_error_code = 0; @@ -171,76 +160,6 @@ qtm_touch_key_control_t qtlib_key_set1 = { * fast responsiveness. */ -/**********************************************************/ -/**************** Binding Layer Module ******************/ -/**********************************************************/ -#define LIB_MODULES_INIT_LIST {(module_init_t) & qtm_ptc_init_acquisition_module, null} - -#define LIB_MODULES_PROC_LIST {(module_proc_t) & qtm_key_sensors_process, null} - -#define LIB_INIT_DATA_MODELS_LIST {(void*)&qtlib_acq_set1, null} - -#define LIB_DATA_MODELS_PROC_LIST {(void*)&qtlib_key_set1, null} - -#define LIB_MODULES_ACQ_ENGINES_LIST {(module_acq_t) & qtm_ptc_start_measurement_seq, null} - -#define LIB_MODULES_ACQ_ENGINES_LIST_DM {(void*)&qtlib_acq_set1, null} - -/* QTM run time options */ -module_init_t library_modules_init[] = LIB_MODULES_INIT_LIST; -module_proc_t library_modules_proc[] = LIB_MODULES_PROC_LIST; -module_arg_t library_module_init_data_models[] = LIB_INIT_DATA_MODELS_LIST; -module_acq_t library_modules_acq_engines[] = LIB_MODULES_ACQ_ENGINES_LIST; - -module_arg_t library_module_acq_engine_data_model[] = LIB_MODULES_ACQ_ENGINES_LIST_DM; -module_arg_t library_module_proc_data_model[] = LIB_DATA_MODELS_PROC_LIST; - -/*---------------------------------------------------------------------------- - * function definitions - *----------------------------------------------------------------------------*/ - -/*============================================================================ -static void build_qtm_config(qtm_control_t *qtm) ------------------------------------------------------------------------------- -Purpose: Initialization of binding layer module -Input : Pointer of binding layer container data structure -Output : none -Notes : -============================================================================*/ -static void build_qtm_config(qtm_control_t* qtm) -{ - /* Initialise the Flags by clearing them */ - qtm->binding_layer_flags = 0x00U; - - /*!< List of function pointers to acquisition sets */ - qtm->library_modules_init = library_modules_init; - - /*!< List of function pointers to post processing modules */ - qtm->library_modules_proc = library_modules_proc; - - /*!< List of Acquisition Engines (Acq Modules one per AcqSet */ - qtm->library_modules_acq = library_modules_acq_engines; - - /*!< Data Model for Acquisition modules */ - qtm->library_module_init_data_model = library_module_init_data_models; - - /*!< Data Model for post processing modules */ - qtm->library_module_proc_data_model = library_module_proc_data_model; - - /*!< Data model for inline module processes */ - qtm->library_modules_acq_dm = library_module_acq_engine_data_model; - - /*!< Post porcessing pointer */ - qtm->qtm_acq_pp = qtm_acquisition_process; - - /* Register Binding layer callbacks */ - qtm->qtm_init_complete_callback = init_complete_callback; - qtm->qtm_error_callback = qtm_error_callback; - qtm->qtm_measure_complete_callback = qtm_measure_complete_callback; - qtm->qtm_pre_process_callback = null; - qtm->qtm_post_process_callback = qtm_post_process_complete; -} - /*============================================================================ static touch_ret_t touch_sensors_config(void) ------------------------------------------------------------------------------ @@ -256,6 +175,9 @@ static touch_ret_t touch_sensors_config(void) uint16_t sensor_nodes; touch_ret_t touch_ret = TOUCH_SUCCESS; + /* Init acquisition module */ + qtm_ptc_init_acquisition_module(&qtlib_acq_set1); + /* Init pointers to DMA sequence memory */ qtm_ptc_qtlib_assign_signal_memory(&touch_acq_signals_raw[0]); @@ -293,21 +215,6 @@ void qtouch_force_calibrate(void) } } -/*============================================================================ -static void init_complete_callback(void) ------------------------------------------------------------------------------- -Purpose: Callback function from binding layer called after the completion of - acquisition module initialization. -Input : none -Output : none -Notes : -============================================================================*/ -static void init_complete_callback(void) -{ - /* Configure touch sensors with Application specific settings */ - touch_sensors_config(); -} - /*============================================================================ static void qtm_measure_complete_callback( void ) ------------------------------------------------------------------------------ @@ -320,88 +227,16 @@ Notes : ============================================================================*/ static void qtm_measure_complete_callback(void) { - qtm_control.binding_layer_flags |= (1 << node_pp_request); -} - -/*============================================================================ -static void qtm_post_process_complete(void) ------------------------------------------------------------------------------- -Purpose: Callback function from binding layer called after the completion of - post processing. This function sets the reburst flag based on the - key sensor group status, calls the datastreamer output function to - display the module data. -Input : none -Output : none -Notes : -============================================================================*/ -static void qtm_post_process_complete(void) -{ - { - // This block is a workaround for a rare touch issue. - // - // After boot, reburst is required until the sensors are calibrated (see reburst_request - // below). Afterwards, they are calibrated and the sensor signal and reference values can be - // used to figure out touch gestures. - // - // Normally, calibration finishes quickly (tests showed in about 12 loop iterations). - // Afterwards, reference and signal values are non-zero. In very rare cases, a sensor can - // have a reference value of 0 until it is physically touched, meaning that touch is - // required to finish calibration. This could be due to a hardware or production quirk. In - // this case, reburst would be requested until that sensor is touched, and gesture detection - // would not start until then. In this csae, a user could not interact with the device at - // all until they first touched the faulty sensor. - // - // As a workaround for this, if we have sensors with a zero reference value of 0 after 30 - // iterations, we assume that all other sensors are calibrated and allow gesture detection - // and user interaction. When the user then touches the weird sensor with a zero reference - // value in normal use of the device, it too would be calibrated and start working normally. - static int counter = 0; - if (counter == 30 && !measurement_done_touch) { - for (uint16_t i = 0; i < DEF_NUM_SENSORS; i++) { - if (qtouch_get_sensor_node_reference(i) == 0) { - measurement_done_touch = true; - break; - } - } - } - counter++; - } - - if ((0U != (qtlib_key_set1.qtm_touch_key_group_data->qtm_keys_status & 0x80U))) { - p_qtm_control->binding_layer_flags |= (1U << reburst_request); - } else { - measurement_done_touch = true; - } - - if (measurement_done_touch) { - qtouch_process_scroller_positions(); // Run the custom filter - } + touch_postprocess_request = 1u; } /*============================================================================ static void qtm_error_callback(uint8_t error) ------------------------------------------------------------------------------ -Purpose: Callback function from binding layer called after the completion of - post processing. This function is called only when there is error. +Purpose: this function is used to report error in the modules. Input : error code Output : decoded module error code Notes : -Error Handling supported by Binding layer module: - Acquisition Module Error codes: 0x8 - 0x81 - Qtm init - 0x82 - start acq - 0x83 - cal sensors - 0x84 - cal hardware - - Post processing Modules error codes: 0x4 - 0x40, 0x41, 0x42, ... - process_id is the sequence of process IDs listed in #define LIB_MODULES_PROC_LIST macro. - Process IDs start from zero and maximum is 15 - - Examples: - 0x40 -> error in post processing module 1 - 0x42 -> error in post processing module 3 - Derived Module_error_codes: Acquisition module error =1 post processing module1 error = 2 @@ -411,12 +246,7 @@ Derived Module_error_codes: ============================================================================*/ static void qtm_error_callback(uint8_t err) { - module_error_code = 0; - if (err & 0x80) { - module_error_code = 1; - } else if (err & 0x40) { - module_error_code = (err & 0x0F) + 2; - } + module_error_code = err + 1u; } /*============================================================================ @@ -432,12 +262,8 @@ void qtouch_init(void) { qtouch_timer_config(); - build_qtm_config(&qtm_control); - - qtm_binding_layer_init(&qtm_control); - - /* get a pointer to the binding layer control */ - p_qtm_control = qmt_get_binding_layer_ptr(); + /* Configure touch sensors with Application specific settings */ + touch_sensors_config(); } /*============================================================================ @@ -454,38 +280,43 @@ void qtouch_process(void) { touch_ret_t touch_ret; - /* check the time_to_measure_touch flag for Touch Acquisition */ - if (p_qtm_control->binding_layer_flags & (1U << time_to_measure_touch)) { + /* check the time_to_measure_touch_flag flag for Touch Acquisition */ + if (time_to_measure_touch_flag == 1u) { /* Do the acquisition */ - touch_ret = qtm_lib_start_acquisition(0); + touch_ret = qtm_ptc_start_measurement_seq(&qtlib_acq_set1, qtm_measure_complete_callback); /* if the Acquistion request was successful then clear the request flag */ if (TOUCH_SUCCESS == touch_ret) { /* Clear the Measure request flag */ - p_qtm_control->binding_layer_flags &= (uint8_t) ~(1U << time_to_measure_touch); + time_to_measure_touch_flag = 0u; } } /* check the flag for node level post processing */ - if (p_qtm_control->binding_layer_flags & (1U << node_pp_request)) { - /* Run Acquisition moudle level post pocessing*/ - touch_ret = qtm_lib_acq_process(); + if (touch_postprocess_request == 1u) { + /* Reset the flags for node_level_post_processing */ + touch_postprocess_request = 0u; + + /* Run Acquisition module level post processing*/ + touch_ret = qtm_acquisition_process(); /* Check the return value */ if (TOUCH_SUCCESS == touch_ret) { /* Returned with success: Start module level post processing */ - qtm_lib_post_process(); + touch_ret = qtm_key_sensors_process(&qtlib_key_set1); + if (TOUCH_SUCCESS != touch_ret) { + qtm_error_callback(1); + } + qtouch_process_scroller_positions(); } else { /* Acq module Eror Detected: Issue an Acq module common error code 0x80 */ - qtm_error_callback(0x80); + qtm_error_callback(0); } - /* Reset the flags for node_level_post_processing */ - p_qtm_control->binding_layer_flags &= (uint8_t) ~(1U << node_pp_request); - - if (p_qtm_control->binding_layer_flags & (1U << reburst_request)) { - p_qtm_control->binding_layer_flags |= (1U << time_to_measure_touch); - p_qtm_control->binding_layer_flags &= ~(1U << reburst_request); + if ((0u != (qtlib_key_set1.qtm_touch_key_group_data->qtm_keys_status & 0x80u))) { + time_to_measure_touch_flag = 1u; + } else { + measurement_done_touch = 1u; } } } @@ -502,7 +333,7 @@ Notes : void qtouch_timer_handler(void) { /* Count complete - Measure touch sensors */ - qtm_control.binding_layer_flags |= (1U << time_to_measure_touch); + time_to_measure_touch_flag = 1u; qtm_update_qtlib_timer(DEF_TOUCH_MEASUREMENT_PERIOD_MS); } @@ -515,11 +346,17 @@ static void qtouch_timer_task_cb(const struct timer_task* const timer_task) void qtouch_timer_config(void) { static struct timer_task Timer_task; + static uint8_t timer_task_added = 0; + + if (timer_task_added) { + timer_remove_task(&TIMER_0, &Timer_task); + } Timer_task.interval = DEF_TOUCH_MEASUREMENT_PERIOD_MS; Timer_task.cb = qtouch_timer_task_cb; Timer_task.mode = TIMER_TASK_REPEAT; timer_add_task(&TIMER_0, &Timer_task); + timer_task_added = 1; } uint16_t qtouch_get_sensor_node_signal(uint16_t sensor_node) @@ -702,10 +539,8 @@ Notes : none ============================================================================*/ void ADC0_1_Handler(void) { - CRITICAL_SECTION_ENTER() ADC0->INTFLAG.reg |= 1U; qtm_samd51_ptc_handler(); - CRITICAL_SECTION_LEAVE() } #endif /* TOUCH_C */ From 0783a549207b6a09ca90441dec1d5a0dd3e44619 Mon Sep 17 00:00:00 2001 From: Niklas Dusenlund Date: Mon, 22 Sep 2025 15:21:48 +0200 Subject: [PATCH 3/6] qtouch: update tuning * Lower the ADC/PTC frequency to 2Mhz * Lower the analog gain as that introduces more noise * Higher analog gain of edge sensors that are less sensitive * Make filter 8x digital gain as per recommendation * Reduce threshold for active to 12 (to be tweaked) * Put sensor groups in AKS groups so that if one sensor is active no other sensor in the same group can become active. * Reduce hysteris to 25% to make "untouch" quicker * Speed up all calibration rates to 1 step per 200ms * Set a maximum touch time of 10s to eventually abort in case someone puts the device on a table * Remove force calibrate. The faster calibration rates should fix the sensors equally quick. * Add all functions from templates that was missing to make future diffs with atmel start smaller. --- .../qtouch/include/touch_api_ptc.h | 10 +- src/bootloader/bootloader.c | 1 - src/qtouch/qtouch.c | 69 +++++----- src/qtouch/qtouch.h | 128 ++++++------------ src/ui/components/orientation_arrows.c | 1 - 5 files changed, 82 insertions(+), 127 deletions(-) diff --git a/external/asf4-drivers/qtouch/include/touch_api_ptc.h b/external/asf4-drivers/qtouch/include/touch_api_ptc.h index 2364b371e7..2ea3b45585 100644 --- a/external/asf4-drivers/qtouch/include/touch_api_ptc.h +++ b/external/asf4-drivers/qtouch/include/touch_api_ptc.h @@ -41,19 +41,23 @@ extern "C" { *----------------------------------------------------------------------------*/ /* Application Helper API's */ uint16_t qtouch_get_sensor_node_signal(uint16_t sensor_node); -uint16_t qtouch_get_sensor_node_reference(uint16_t sensor_node); +void qtouch_update_sensor_node_signal(uint16_t sensor_node, uint16_t new_signal); uint16_t qtouch_get_sensor_node_signal_filtered(uint16_t sensor_node); +uint16_t qtouch_get_sensor_node_reference(uint16_t sensor_node); +void qtouch_update_sensor_node_reference(uint16_t sensor_node, uint16_t new_reference); uint16_t qtouch_get_sensor_cc_val(uint16_t sensor_node); +void qtouch_update_sensor_cc_val(uint16_t sensor_node, uint16_t new_cc_value); uint8_t qtouch_get_sensor_state(uint16_t sensor_node); +void qtouch_update_sensor_state(uint16_t sensor_node, uint8_t new_state); +void qtouch_calibrate_node(uint16_t sensor_node); +uint8_t qtouch_get_scroller_state(uint16_t sensor_node); bool qtouch_is_scroller_active(uint16_t sensor_node); uint16_t qtouch_get_scroller_position(uint16_t sensor_node); void qtouch_timer_handler(void); void qtouch_init(void); void qtouch_process(void); -void qtouch_force_calibrate(void); -void qtimer_task_cb(const struct timer_task *const timer_task); void qtouch_timer_config(void); #ifdef __cplusplus diff --git a/src/bootloader/bootloader.c b/src/bootloader/bootloader.c index 3791fe4e72..4b69f01865 100644 --- a/src/bootloader/bootloader.c +++ b/src/bootloader/bootloader.c @@ -363,7 +363,6 @@ extern uint8_t bootloader_pairing_code_bytes[4]; void bootloader_render_ble_confirm_screen(bool confirmed) { - qtouch_force_calibrate(); bootloader_pairing_request = true; uint32_t pairing_code_int = (*(uint32_t*)&bootloader_pairing_code_bytes[0]) % 1000000; char code_str[10] = {0}; diff --git a/src/qtouch/qtouch.c b/src/qtouch/qtouch.c index fe8fb45f53..047f3582dd 100644 --- a/src/qtouch/qtouch.c +++ b/src/qtouch/qtouch.c @@ -46,11 +46,11 @@ static void qtm_measure_complete_callback(void); /*! \brief Touch Error callback function prototype. */ -static void qtm_error_callback(uint8_t err); +static void qtm_error_callback(uint8_t error); -/*! \brief Calculate scroller positions based on custom filter. +/* Update our scroller implementation */ -static void qtouch_process_scroller_positions(void); +void qtouch_process_scroller_positions(void); /*---------------------------------------------------------------------------- * Global Variables @@ -110,6 +110,9 @@ __extension__ static uint16_t scroller_position[] = {[0 ...(DEF_NUM_SCROLLERS - /* Whether or not scroller reading exceeds threshold for custom filter */ __extension__ static bool scroller_active[DEF_NUM_SCROLLERS] = {[0 ...(DEF_NUM_SCROLLERS - 1)] = 0}; +/* Holds preceding unfiltered scroller positions */ +static uint16_t sensor_previous_filtered_reading[DEF_NUM_SENSORS][DEF_SENSOR_NUM_PREV_POS] = {0}; + /**********************************************************/ /*********************** Keys Module **********************/ /**********************************************************/ @@ -195,26 +198,6 @@ static touch_ret_t touch_sensors_config(void) return (touch_ret); } -/* - * Force calibrate - * - * Call this function when the user "probably" isn't touching the device to reset all the - * calibration values. It will only reset inputs that are not considered to be in "touched" states - */ -void qtouch_force_calibrate(void) -{ - qtm_touch_key_data_t* key; - for (uint16_t i = 0U; i < DEF_NUM_CHANNELS; i++) { - key = &qtlib_key_data_set1[i]; - uint16_t value = key->node_data_struct_ptr->node_acq_signals; - uint16_t reference = key->channel_reference; - int32_t diff = (int32_t)reference - (int32_t)value; - if (!(key->sensor_state & KEY_TOUCHED_MASK) && diff > KEY_FORCE_CALIBRATE_THRESHOLD) { - key->channel_reference = key->node_data_struct_ptr->node_acq_signals; - } - } -} - /*============================================================================ static void qtm_measure_complete_callback( void ) ------------------------------------------------------------------------------ @@ -244,9 +227,9 @@ Derived Module_error_codes: ... and so on ============================================================================*/ -static void qtm_error_callback(uint8_t err) +static void qtm_error_callback(uint8_t error) { - module_error_code = err + 1u; + module_error_code = error + 1u; } /*============================================================================ @@ -364,25 +347,40 @@ uint16_t qtouch_get_sensor_node_signal(uint16_t sensor_node) return (ptc_qtlib_node_stat1[sensor_node].node_acq_signals); } +void qtouch_update_sensor_node_signal(uint16_t sensor_node, uint16_t new_signal) +{ + ptc_qtlib_node_stat1[sensor_node].node_acq_signals = new_signal; +} uint16_t qtouch_get_sensor_node_reference(uint16_t sensor_node) { return (qtlib_key_data_set1[sensor_node].channel_reference); } +void qtouch_update_sensor_node_reference(uint16_t sensor_node, uint16_t new_reference) +{ + qtlib_key_data_set1[sensor_node].channel_reference = new_reference; +} + uint16_t qtouch_get_sensor_cc_val(uint16_t sensor_node) { return (ptc_qtlib_node_stat1[sensor_node].node_comp_caps); } +void qtouch_update_sensor_cc_val(uint16_t sensor_node, uint16_t new_cc_value) +{ + ptc_qtlib_node_stat1[sensor_node].node_comp_caps = new_cc_value; +} + uint8_t qtouch_get_sensor_state(uint16_t sensor_node) { return (qtlib_key_set1.qtm_touch_key_data[sensor_node].sensor_state); } -/* Holds preceding unfiltered scroller positions */ -static uint16_t sensor_previous_filtered_reading[DEF_NUM_SENSORS][DEF_SENSOR_NUM_PREV_POS] = {0}; +void qtouch_update_sensor_state(uint16_t sensor_node, uint8_t new_state) +{ + qtlib_key_set1.qtm_touch_key_data[sensor_node].sensor_state = new_state; +} -/* Custom sensor signal filter. */ uint16_t qtouch_get_sensor_node_signal_filtered(uint16_t sensor_node) { // Filter the sensor signal. @@ -403,11 +401,11 @@ uint16_t qtouch_get_sensor_node_signal_filtered(uint16_t sensor_node) } X = sensor_raw < sensor_reference ? 0 : sensor_raw - sensor_reference; // Add more weight to edge buttons because they are physically smaller (smaller readings). - if ((sensor_node == DEF_SCROLLER_OFFSET_0) || (sensor_node == DEF_SCROLLER_OFFSET_1) || - (sensor_node == DEF_SCROLLER_OFFSET_0 + DEF_SCROLLER_NUM_CHANNELS - 1) || - (sensor_node == DEF_SCROLLER_OFFSET_1 + DEF_SCROLLER_NUM_CHANNELS - 1)) { - X = (uint16_t)((double)X * (1 + DEF_SENSOR_EDGE_WEIGHT)); - } + // if ((sensor_node == DEF_SCROLLER_OFFSET_0) || (sensor_node == DEF_SCROLLER_OFFSET_1) || + // (sensor_node == DEF_SCROLLER_OFFSET_0 + DEF_SCROLLER_NUM_CHANNELS - 1) || + // (sensor_node == DEF_SCROLLER_OFFSET_1 + DEF_SCROLLER_NUM_CHANNELS - 1)) { + // X = (uint16_t)((double)X * (1 + DEF_SENSOR_EDGE_WEIGHT)); + //} // Saturate out-of-range readings. X = (X > DEF_SENSOR_CEILING) ? DEF_SENSOR_CEILING : X; @@ -431,11 +429,10 @@ uint16_t qtouch_get_sensor_node_signal_filtered(uint16_t sensor_node) return X_ave; } -bool qtouch_is_scroller_active(uint16_t scroller) +bool qtouch_is_scroller_active(uint16_t sensor_node) { - return scroller_active[scroller]; + return scroller_active[sensor_node]; } - uint16_t qtouch_get_scroller_position(uint16_t sensor_node) { return scroller_position[sensor_node]; diff --git a/src/qtouch/qtouch.h b/src/qtouch/qtouch.h index f119d06b00..77dd51ed41 100644 --- a/src/qtouch/qtouch.h +++ b/src/qtouch/qtouch.h @@ -17,8 +17,8 @@ Copyright (c) 2017 Microchip. All rights reserved. ------------------------------------------------------------------------------ ============================================================================*/ -#ifndef TOUCH_H -#define TOUCH_H +#ifndef QTOUCH_H +#define QTOUCH_H #ifdef __cplusplus extern "C" { @@ -65,7 +65,7 @@ extern "C" { * Range: FREQ_SEL_0 - FREQ_SEL_15 , FREQ_SEL_SPREAD * Default value: FREQ_SEL_0. */ -#define DEF_SEL_FREQ_INIT FREQ_SEL_8 +#define DEF_SEL_FREQ_INIT FREQ_SEL_0 /*---------------------------------------------------------------------------- * defines @@ -86,63 +86,23 @@ extern "C" { * Gain , Digital Gain), filter level} */ // Slider 1 buttons -#define NODE_0_PARAMS \ - {X_NONE, \ - Y_LINE(26), \ - 0, \ - NODE_RSEL_PRSC(RSEL_VAL_20, PRSC_DIV_SEL_1), \ - NODE_GAIN(GAIN_4, GAIN_4), \ - FILTER_LEVEL_512} -#define NODE_1_PARAMS \ - {X_NONE, \ - Y_LINE(27), \ - 0, \ - NODE_RSEL_PRSC(RSEL_VAL_20, PRSC_DIV_SEL_1), \ - NODE_GAIN(GAIN_4, GAIN_4), \ - FILTER_LEVEL_512} -#define NODE_2_PARAMS \ - {X_NONE, \ - Y_LINE(28), \ - 0, \ - NODE_RSEL_PRSC(RSEL_VAL_20, PRSC_DIV_SEL_1), \ - NODE_GAIN(GAIN_4, GAIN_4), \ - FILTER_LEVEL_512} -#define NODE_3_PARAMS \ - {X_NONE, \ - Y_LINE(29), \ - 0, \ - NODE_RSEL_PRSC(RSEL_VAL_20, PRSC_DIV_SEL_1), \ - NODE_GAIN(GAIN_4, GAIN_4), \ - FILTER_LEVEL_512} +#define NODE_0_PARAMS \ + {X_NONE, Y_LINE(26), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} +#define NODE_1_PARAMS \ + {X_NONE, Y_LINE(27), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_1, GAIN_8), FILTER_LEVEL_64} +#define NODE_2_PARAMS \ + {X_NONE, Y_LINE(28), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_1, GAIN_8), FILTER_LEVEL_64} +#define NODE_3_PARAMS \ + {X_NONE, Y_LINE(29), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} // Slider 0 buttons -#define NODE_4_PARAMS \ - {X_NONE, \ - Y_LINE(30), \ - 0, \ - NODE_RSEL_PRSC(RSEL_VAL_20, PRSC_DIV_SEL_1), \ - NODE_GAIN(GAIN_4, GAIN_4), \ - FILTER_LEVEL_512} -#define NODE_5_PARAMS \ - {X_NONE, \ - Y_LINE(31), \ - 0, \ - NODE_RSEL_PRSC(RSEL_VAL_20, PRSC_DIV_SEL_1), \ - NODE_GAIN(GAIN_4, GAIN_4), \ - FILTER_LEVEL_512} -#define NODE_6_PARAMS \ - {X_NONE, \ - Y_LINE(20), \ - 0, \ - NODE_RSEL_PRSC(RSEL_VAL_20, PRSC_DIV_SEL_1), \ - NODE_GAIN(GAIN_4, GAIN_4), \ - FILTER_LEVEL_512} -#define NODE_7_PARAMS \ - {X_NONE, \ - Y_LINE(21), \ - 0, \ - NODE_RSEL_PRSC(RSEL_VAL_20, PRSC_DIV_SEL_1), \ - NODE_GAIN(GAIN_4, GAIN_4), \ - FILTER_LEVEL_512} +#define NODE_4_PARAMS \ + {X_NONE, Y_LINE(30), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} +#define NODE_5_PARAMS \ + {X_NONE, Y_LINE(31), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_1, GAIN_8), FILTER_LEVEL_64} +#define NODE_6_PARAMS \ + {X_NONE, Y_LINE(20), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_1, GAIN_8), FILTER_LEVEL_64} +#define NODE_7_PARAMS \ + {X_NONE, Y_LINE(21), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} /**********************************************************/ /***************** Key Params ******************/ @@ -157,33 +117,33 @@ extern "C" { * {Sensor Threshold, Sensor Hysterisis, Sensor AKS} */ // 0..3 higher Slider left to right 4..7 lower Slider right to left -#define KEY_0_PARAMS {16, HYST_50, NO_AKS_GROUP} -#define KEY_1_PARAMS {16, HYST_50, NO_AKS_GROUP} -#define KEY_2_PARAMS {16, HYST_50, NO_AKS_GROUP} -#define KEY_3_PARAMS {16, HYST_50, NO_AKS_GROUP} -#define KEY_4_PARAMS {16, HYST_50, NO_AKS_GROUP} -#define KEY_5_PARAMS {16, HYST_50, NO_AKS_GROUP} -#define KEY_6_PARAMS {16, HYST_50, NO_AKS_GROUP} -#define KEY_7_PARAMS {16, HYST_50, NO_AKS_GROUP} +#define KEY_0_PARAMS {12, HYST_25, AKS_GROUP_1} +#define KEY_1_PARAMS {12, HYST_25, AKS_GROUP_1} +#define KEY_2_PARAMS {12, HYST_25, AKS_GROUP_1} +#define KEY_3_PARAMS {12, HYST_25, AKS_GROUP_1} +#define KEY_4_PARAMS {12, HYST_25, AKS_GROUP_2} +#define KEY_5_PARAMS {12, HYST_25, AKS_GROUP_2} +#define KEY_6_PARAMS {12, HYST_25, AKS_GROUP_2} +#define KEY_7_PARAMS {12, HYST_25, AKS_GROUP_2} /* De-bounce counter for additional measurements to confirm touch detection * Range: 0 to 255. * Default value: 4. */ -#define DEF_TOUCH_DET_INT 0 +#define DEF_TOUCH_DET_INT 1 /* De-bounce counter for additional measurements to confirm away from touch signal * to initiate Away from touch re-calibration. * Range: 0 to 255. * Default value: 5. */ -#define DEF_ANTI_TCH_DET_INT 0 +#define DEF_ANTI_TCH_DET_INT 1 /* Threshold beyond with automatic sensor recalibration is initiated. * Range: RECAL_100/ RECAL_50 / RECAL_25 / RECAL_12_5 / RECAL_6_25 / MAX_RECAL * Default value: RECAL_100. */ -#define DEF_ANTI_TCH_RECAL_THRSHLD RECAL_50 +#define DEF_ANTI_TCH_RECAL_THRSHLD RECAL_100 /* Rate at which sensor reference value is adjusted towards sensor signal value * when signal value is greater than reference. @@ -191,7 +151,7 @@ extern "C" { * Range: 0-255 * Default value: 20u = 4 seconds. */ -#define DEF_TCH_DRIFT_RATE 20 +#define DEF_TCH_DRIFT_RATE 1 /* Rate at which sensor reference value is adjusted towards sensor signal value * when signal value is less than reference. @@ -199,33 +159,26 @@ extern "C" { * Range: 0-255 * Default value: 5u = 1 second. */ -#define DEF_ANTI_TCH_DRIFT_RATE 5 +#define DEF_ANTI_TCH_DRIFT_RATE 1 /* Time to restrict drift on all sensor when one or more sensors are activated. * Units: 200ms * Range: 0-255 * Default value: 20u = 4 seconds. */ -#define DEF_DRIFT_HOLD_TIME 20 +#define DEF_DRIFT_HOLD_TIME 1 /* Set mode for additional sensor measurements based on touch activity. * Range: REBURST_NONE / REBURST_UNRESOLVED / REBURST_ALL * Default value: REBURST_UNRESOLVED */ -#define DEF_REBURST_MODE REBURST_ALL +#define DEF_REBURST_MODE REBURST_NONE /* Sensor maximum ON duration upon touch. * Range: 0-255 * Default value: 0 */ -#define DEF_MAX_ON_DURATION 0 - -/* - * The count that the reference value must be above the measured value to - * allow the force calibrate procedure to overwrite the reference to the - * current measured value. - */ -#define KEY_FORCE_CALIBRATE_THRESHOLD 10 +#define DEF_MAX_ON_DURATION 50 /**********************************************************/ /***************** Slider/Wheel Parameters ****************/ @@ -237,21 +190,24 @@ extern "C" { * This allows low noise button readings while keeping * fast responsiveness. */ + #define DEF_NUM_SCROLLERS 2 // Number of scrollers (sliders or wheels) #define DEF_SCROLLER_NUM_CHANNELS 4 // Number of channels per scroller #define DEF_SCROLLER_OFFSET_0 4 // Index of first button in scroller #define DEF_SCROLLER_OFFSET_1 0 // Index of first button in scroller #define DEF_SCROLLER_RESOLUTION 256 // Scroller resolution in bits -#define DEF_SCROLLER_DET_THRESHOLD 25 // Scroller detect threshold -#define DEF_SCROLLER_TOUCH_THRESHOLD 25 // Scroller active threshold -#define DEF_SCROLLER_UNTOUCH_THRESHOLD 20 // Scroller active threshold +#define DEF_SCROLLER_DET_THRESHOLD 12 // Scroller detect threshold +#define DEF_SCROLLER_TOUCH_THRESHOLD 12 // Scroller active threshold +#define DEF_SCROLLER_UNTOUCH_THRESHOLD 9 // Scroller active threshold #define DEF_SCROLLER_DEADBAND 13 // 13 bits = 5% of 256-bit range #define DEF_SCROLLER_NUM_PREV_POS \ 4 // Number of previous scroller positions to remember; used in a simple filter #define DEF_SCROLLER_OFF \ 0xFFFF // Marker for indicating scroller reading does not exceed detection threshold +/* #define DEF_SENSOR_EDGE_WEIGHT \ 0.15 // Percent added weight to edge sensors, which are physically smaller +*/ #define DEF_SENSOR_NUM_PREV_POS \ 4 // Number of previous sensor positions to remember; used in a simple filter #define DEF_SENSOR_CEILING \ @@ -261,4 +217,4 @@ extern "C" { #ifdef __cplusplus } #endif // __cplusplus -#endif // TOUCH_C +#endif // QTOUCH_H diff --git a/src/ui/components/orientation_arrows.c b/src/ui/components/orientation_arrows.c index 5689f32f4d..d6843c563b 100644 --- a/src/ui/components/orientation_arrows.c +++ b/src/ui/components/orientation_arrows.c @@ -130,7 +130,6 @@ static void _render(component_t* component) } data->enable_touch = true; } - qtouch_force_calibrate(); data->screen_count++; } From 71b237cf8fe4e77719b1687367123d21ff05fb33 Mon Sep 17 00:00:00 2001 From: Niklas Dusenlund Date: Wed, 24 Sep 2025 14:31:38 +0200 Subject: [PATCH 4/6] qtouch: Update prescaler enum according to latest qtouch template --- .../asf4-drivers/qtouch/include/qtm_acq_same54_0x000f_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/external/asf4-drivers/qtouch/include/qtm_acq_same54_0x000f_api.h b/external/asf4-drivers/qtouch/include/qtm_acq_same54_0x000f_api.h index a75fbcce22..9e03ecb380 100644 --- a/external/asf4-drivers/qtouch/include/qtm_acq_same54_0x000f_api.h +++ b/external/asf4-drivers/qtouch/include/qtm_acq_same54_0x000f_api.h @@ -80,14 +80,14 @@ typedef enum tag_gain_t { GAIN_1, GAIN_2, GAIN_4, GAIN_8, GAIN_16 } gain_t; * */ typedef enum tag_prsc_div_sel_t { - PRSC_DIV_SEL_1, PRSC_DIV_SEL_2, PRSC_DIV_SEL_4, PRSC_DIV_SEL_8, PRSC_DIV_SEL_16, PRSC_DIV_SEL_32, PRSC_DIV_SEL_64, - PRSC_DIV_SEL_128 + PRSC_DIV_SEL_128, + PRSC_DIV_SEL_256 } prsc_div_sel_t; /** From f4d71315b937ca994396e33f70cc1f08074524ff Mon Sep 17 00:00:00 2001 From: Niklas Dusenlund Date: Thu, 2 Oct 2025 16:06:56 +0200 Subject: [PATCH 5/6] rewrite scroller --- src/qtouch/qtouch.c | 374 ++++++++++++++++++++++++------------------- src/qtouch/qtouch.h | 112 +++++++------ src/touch/gestures.h | 2 +- 3 files changed, 275 insertions(+), 213 deletions(-) diff --git a/src/qtouch/qtouch.c b/src/qtouch/qtouch.c index 047f3582dd..8d0b97de4f 100644 --- a/src/qtouch/qtouch.c +++ b/src/qtouch/qtouch.c @@ -18,19 +18,18 @@ Support: Visit http://www.microchip.com/support/hottopics.aspx Copyright (c) 2017 Microchip. All rights reserved. ------------------------------------------------------------------------------ ============================================================================*/ - #ifndef TOUCH_C #define TOUCH_C /*---------------------------------------------------------------------------- * include files *----------------------------------------------------------------------------*/ -#include "qtouch.h" +#include + #include "license.h" -#include "touch_api_ptc.h" -#include "util.h" -#include -#include +#include "qtouch.h" + +// #include "datastreamer.h" /*---------------------------------------------------------------------------- * prototypes @@ -50,7 +49,7 @@ static void qtm_error_callback(uint8_t error); /* Update our scroller implementation */ -void qtouch_process_scroller_positions(void); +void qtouch_process_scroller_positions(scroller_control_t* scrollers); /*---------------------------------------------------------------------------- * Global Variables @@ -99,20 +98,6 @@ qtm_acquisition_control_t qtlib_acq_set1 = { &ptc_seq_node_cfg1[0], &ptc_qtlib_node_stat1[0]}; -/* Stores recent unfiltered scroller positions for custom filter */ -__extension__ static uint16_t scroller_previous_position[][DEF_SCROLLER_NUM_PREV_POS] = { - [0 ...(DEF_NUM_SCROLLERS - 1)][0 ...(DEF_SCROLLER_NUM_PREV_POS - 1)] = 0}; - -/* Current scroller position consisting of a moving-average of preceding positions for custom filter - */ -__extension__ static uint16_t scroller_position[] = {[0 ...(DEF_NUM_SCROLLERS - 1)] = 0}; - -/* Whether or not scroller reading exceeds threshold for custom filter */ -__extension__ static bool scroller_active[DEF_NUM_SCROLLERS] = {[0 ...(DEF_NUM_SCROLLERS - 1)] = 0}; - -/* Holds preceding unfiltered scroller positions */ -static uint16_t sensor_previous_filtered_reading[DEF_NUM_SENSORS][DEF_SENSOR_NUM_PREV_POS] = {0}; - /**********************************************************/ /*********************** Keys Module **********************/ /**********************************************************/ @@ -144,6 +129,7 @@ qtm_touch_key_config_t qtlib_key_configs_set1[DEF_NUM_SENSORS] = { KEY_5_PARAMS, KEY_6_PARAMS, KEY_7_PARAMS}; + /* Container */ qtm_touch_key_control_t qtlib_key_set1 = { &qtlib_key_grp_data_set1, @@ -163,6 +149,34 @@ qtm_touch_key_control_t qtlib_key_set1 = { * fast responsiveness. */ +/* Holds preceding touch key deltas (signal - reference) */ +__extension__ int16_t scroller_deltas[DEF_NUM_SENSORS] = {0}; + +scroller_config_t scroller_config[2] = { + [0] = + {DEF_SCROLLER_OFFSET_0, + DEF_SCROLLER_NUM_CHANNELS, + DEF_SCROLLER_RESOLUTION, + DEF_SCROLLER_TOUCH_THRESHOLD, + DEF_SCROLLER_UNTOUCH_THRESHOLD, + DEF_SCROLLER_DEADBAND, + DEF_SCROLLER_HYSTERESIS}, + [1] = + {DEF_SCROLLER_OFFSET_1, + DEF_SCROLLER_NUM_CHANNELS, + DEF_SCROLLER_RESOLUTION, + DEF_SCROLLER_TOUCH_THRESHOLD, + DEF_SCROLLER_UNTOUCH_THRESHOLD, + DEF_SCROLLER_DEADBAND, + DEF_SCROLLER_HYSTERESIS}, +}; +scroller_data_t scroller_data[2] = {0}; + +scroller_control_t scroller_control[2] = { + [0] = {&scroller_config[0], &scroller_data[0]}, + [1] = {&scroller_config[1], &scroller_data[1]}, +}; + /*============================================================================ static touch_ret_t touch_sensors_config(void) ------------------------------------------------------------------------------ @@ -171,8 +185,8 @@ Input : none Output : none Notes : ============================================================================*/ -/* Touch sensors config - assign nodes to buttons / wheels / sliders / surfaces / water level / etc - */ +/* Touch sensors config - assign nodes to buttons / wheels / sliders / surfaces + * / water level / etc */ static touch_ret_t touch_sensors_config(void) { uint16_t sensor_nodes; @@ -185,14 +199,14 @@ static touch_ret_t touch_sensors_config(void) qtm_ptc_qtlib_assign_signal_memory(&touch_acq_signals_raw[0]); /* Initialize sensor nodes */ - for (sensor_nodes = 0U; sensor_nodes < DEF_NUM_CHANNELS; sensor_nodes++) { + for (sensor_nodes = 0u; sensor_nodes < DEF_NUM_CHANNELS; sensor_nodes++) { /* Enable each node for measurement and mark for calibration */ qtm_enable_sensor_node(&qtlib_acq_set1, sensor_nodes); qtm_calibrate_sensor_node(&qtlib_acq_set1, sensor_nodes); } /* Enable sensor keys and assign nodes */ - for (sensor_nodes = 0U; sensor_nodes < DEF_NUM_CHANNELS; sensor_nodes++) { + for (sensor_nodes = 0u; sensor_nodes < DEF_NUM_CHANNELS; sensor_nodes++) { qtm_init_sensor_key(&qtlib_key_set1, sensor_nodes, &ptc_qtlib_node_stat1[sensor_nodes]); } return (touch_ret); @@ -201,7 +215,7 @@ static touch_ret_t touch_sensors_config(void) /*============================================================================ static void qtm_measure_complete_callback( void ) ------------------------------------------------------------------------------ -Purpose: Callback function from binding layer called after the completion of +Purpose: this function is called after the completion of measurement cycle. This function sets the post processing request flag to trigger the post processing. Input : none @@ -221,21 +235,39 @@ Input : error code Output : decoded module error code Notes : Derived Module_error_codes: - Acquisition module error =1 - post processing module1 error = 2 - post processing module2 error = 3 - ... and so on + Acquisition module error =1 + post processing module1 error = 2 + post processing module2 error = 3 + ... and so on ============================================================================*/ static void qtm_error_callback(uint8_t error) { module_error_code = error + 1u; + +#if DEF_TOUCH_DATA_STREAMER_ENABLE == 1 + datastreamer_output(); +#endif +} + +static void scroller_init(void) +{ + for (int i = 0; i < DEF_NUM_SCROLLERS; i++) { + scroller_config_t* config = scroller_control[i].config; + scroller_data_t* data = scroller_control[i].data; + data->deltas = &scroller_deltas[config->start_key]; + data->hyst_left = config->hysteresis / 2; + data->hyst_right = config->hysteresis / 2; + data->position = 0; + data->raw_position = 0; + data->touch_area = 0; + } } /*============================================================================ -void qtouch_init(void) +void touch_init(void) ------------------------------------------------------------------------------ -Purpose: Initialization of touch library. PTC, timer, binding layer and +Purpose: Initialization of touch library. PTC, timer, and datastreamer modules are initialized in this function. Input : none Output : none @@ -247,10 +279,17 @@ void qtouch_init(void) /* Configure touch sensors with Application specific settings */ touch_sensors_config(); + + /* Configure scrollers */ + scroller_init(); + +#if DEF_TOUCH_DATA_STREAMER_ENABLE == 1 + datastreamer_init(); +#endif } /*============================================================================ -void qtouch_process(void) +void touch_process(void) ------------------------------------------------------------------------------ Purpose: Main processing function of touch library. This function initiates the acquisition, calls post processing after the acquistion complete and @@ -290,7 +329,7 @@ void qtouch_process(void) if (TOUCH_SUCCESS != touch_ret) { qtm_error_callback(1); } - qtouch_process_scroller_positions(); + qtouch_process_scroller_positions(scroller_control); } else { /* Acq module Eror Detected: Issue an Acq module common error code 0x80 */ qtm_error_callback(0); @@ -301,11 +340,15 @@ void qtouch_process(void) } else { measurement_done_touch = 1u; } + +#if DEF_TOUCH_DATA_STREAMER_ENABLE == 1 + datastreamer_output(); +#endif } } /*============================================================================ -void qtouch_timer_handler(void) +void touch_timer_handler(void) ------------------------------------------------------------------------------ Purpose: This function updates the time elapsed to the touch key module to synchronize the internal time counts used by the module. @@ -320,7 +363,7 @@ void qtouch_timer_handler(void) qtm_update_qtlib_timer(DEF_TOUCH_MEASUREMENT_PERIOD_MS); } -static void qtouch_timer_task_cb(const struct timer_task* const timer_task) +static void Timer_task_cb(const struct timer_task* const timer_task) { (void)timer_task; qtouch_timer_handler(); @@ -334,12 +377,17 @@ void qtouch_timer_config(void) if (timer_task_added) { timer_remove_task(&TIMER_0, &Timer_task); } +#if (KRONO_GESTURE_ENABLE == 1u) + Timer_task.interval = 1; +#else Timer_task.interval = DEF_TOUCH_MEASUREMENT_PERIOD_MS; - Timer_task.cb = qtouch_timer_task_cb; +#endif + Timer_task.cb = Timer_task_cb; Timer_task.mode = TIMER_TASK_REPEAT; timer_add_task(&TIMER_0, &Timer_task); timer_task_added = 1; + timer_start(&TIMER_0); } uint16_t qtouch_get_sensor_node_signal(uint16_t sensor_node) @@ -351,6 +399,7 @@ void qtouch_update_sensor_node_signal(uint16_t sensor_node, uint16_t new_signal) { ptc_qtlib_node_stat1[sensor_node].node_acq_signals = new_signal; } + uint16_t qtouch_get_sensor_node_reference(uint16_t sensor_node) { return (qtlib_key_data_set1[sensor_node].channel_reference); @@ -381,151 +430,146 @@ void qtouch_update_sensor_state(uint16_t sensor_node, uint8_t new_state) qtlib_key_set1.qtm_touch_key_data[sensor_node].sensor_state = new_state; } -uint16_t qtouch_get_sensor_node_signal_filtered(uint16_t sensor_node) +bool qtouch_is_scroller_active(uint16_t scroller) { - // Filter the sensor signal. - // - // Smooth it out and saturate it so that values never go beyond DEF_SENSOR_CEILING. - // This helps to mitigate 'jumpy' channels that exist at higher sensor readings when - // in noisy environments. - // - uint16_t X; - uint16_t sensor_raw = qtouch_get_sensor_node_signal(sensor_node); - uint16_t sensor_reference = qtouch_get_sensor_node_reference(sensor_node); - - if (sensor_reference == 0) { - // If a sensor reference is 0, it means that the sensor is not yet calibrated (or dead). - // The signal can be high anyway, which makes it look like the sensor is being touched when - // it isn't. - return 0; - } - X = sensor_raw < sensor_reference ? 0 : sensor_raw - sensor_reference; - // Add more weight to edge buttons because they are physically smaller (smaller readings). - // if ((sensor_node == DEF_SCROLLER_OFFSET_0) || (sensor_node == DEF_SCROLLER_OFFSET_1) || - // (sensor_node == DEF_SCROLLER_OFFSET_0 + DEF_SCROLLER_NUM_CHANNELS - 1) || - // (sensor_node == DEF_SCROLLER_OFFSET_1 + DEF_SCROLLER_NUM_CHANNELS - 1)) { - // X = (uint16_t)((double)X * (1 + DEF_SENSOR_EDGE_WEIGHT)); - //} - // Saturate out-of-range readings. - X = (X > DEF_SENSOR_CEILING) ? DEF_SENSOR_CEILING : X; - - // Calculate sensor readout using a moving average - // The moving average wieghts previous N readings twice current reading - uint16_t moving_average_cummulative_weight = 1; // Add one for current reading calculated above - uint16_t X_ave = X; - for (size_t j = 0; j < DEF_SENSOR_NUM_PREV_POS; j++) { - moving_average_cummulative_weight += 2; - X_ave += sensor_previous_filtered_reading[sensor_node][j] * 2; - } - X_ave = X_ave / moving_average_cummulative_weight; - - // Update recorded previous positions - for (size_t j = 0; j < DEF_SENSOR_NUM_PREV_POS - 1; j++) { - sensor_previous_filtered_reading[sensor_node][j] = - sensor_previous_filtered_reading[sensor_node][j + 1]; - } - sensor_previous_filtered_reading[sensor_node][DEF_SENSOR_NUM_PREV_POS - 1] = X; - - return X_ave; -} - -bool qtouch_is_scroller_active(uint16_t sensor_node) -{ - return scroller_active[sensor_node]; + return scroller_control[scroller].data->active; } -uint16_t qtouch_get_scroller_position(uint16_t sensor_node) +uint16_t qtouch_get_scroller_position(uint16_t scroller) { - return scroller_position[sensor_node]; + return scroller_control[scroller].data->position; } -void qtouch_process_scroller_positions(void) +void qtouch_process_scroller_positions(scroller_control_t* scrollers) { - for (uint8_t scroller = 0; scroller < DEF_NUM_SCROLLERS; scroller++) { - uint8_t i, j; - uint16_t sum = 0; - uint16_t max_sensor_reading = 0; - uint16_t min_sensor_reading = DEF_SENSOR_CEILING; - uint16_t weighted_sum = 0; - uint16_t filtered_readings[DEF_SCROLLER_NUM_CHANNELS] = {0}; - uint16_t sensor_location[DEF_SCROLLER_NUM_CHANNELS] = { - 1, // Offset by `1` because a `0` location cannot be weight-averaged - DEF_SCROLLER_RESOLUTION / 3, - DEF_SCROLLER_RESOLUTION / 3 * 2, - DEF_SCROLLER_RESOLUTION}; - - for (i = 0; i < DEF_SCROLLER_NUM_CHANNELS; i++) { - filtered_readings[i] = qtouch_get_sensor_node_signal_filtered( - i + (scroller ? DEF_SCROLLER_OFFSET_1 : DEF_SCROLLER_OFFSET_0)); - min_sensor_reading = (filtered_readings[i] < min_sensor_reading) ? filtered_readings[i] - : min_sensor_reading; - max_sensor_reading = (filtered_readings[i] > max_sensor_reading) ? filtered_readings[i] - : max_sensor_reading; + scroller_control_t* scroller; + scroller_control_t* scrollers_end = scrollers + DEF_NUM_SCROLLERS; + for (scroller = scrollers; scroller < scrollers_end; scroller++) { + scroller_config_t* config = scroller->config; + scroller_data_t* data = scroller->data; + int node_max = -1; + int16_t node_max_value = INT16_MIN; + data->touch_area = 0; + + for (int i = 0; i < config->number_of_keys; i++) { + uint8_t node = config->start_key + i; + int16_t delta = max( + 0, qtouch_get_sensor_node_signal(node) - qtouch_get_sensor_node_reference(node)); + // Apply weighted moving average + data->deltas[i] = (2 * delta + data->deltas[i]) / 3; + // multiply inner sensors with 1.75 (The ones at the edges have higher PTC gain) + if (i > 0 && i < config->number_of_keys - 1) { + data->deltas[i] += (data->deltas[i] >> 1) + (data->deltas[i] >> 2); + } + // If any key is in touch, the scroller is considered in touch + if ((qtouch_get_sensor_state(node) & QTM_KEY_DETECT) == QTM_KEY_DETECT) { + data->active = 1; + } + // Find the node with the highest signal to determine how to calculate touch area. + if (data->deltas[i] > node_max_value) { + node_max = i; + node_max_value = data->deltas[i]; + } + } + + switch (node_max) { + case 0: + data->touch_area = data->deltas[0] + (data->deltas[1] >> 1); + break; + case 1: + data->touch_area = (data->deltas[0] >> 1) + data->deltas[1] + (data->deltas[2] >> 1); + break; + case 2: + data->touch_area = (data->deltas[1] >> 1) + data->deltas[2] + (data->deltas[3] >> 1); + break; + case 3: + data->touch_area = (data->deltas[2] >> 1) + data->deltas[3]; + break; + default: + break; } - // Read filterd data and weight by sensor physical location - // Reduce the value by the min_sensor_reading to improve positional accuracy. - // Touch position is calculated with a weighted average of the sensor readings. - // If properly calibrated, sensors on the opposite end of a finger touch would - // be zero and thus make no contribution to the weighted average. If the baseline - // sensor readings are elevated, the sensors on the opposite edge DO contribute - // to the weighted average making a positional artifact (i.e. the position is more - // central than it should be in reality). This artifact is higher when the finger - // is a bit distant while approaching and lower/negligible when the finger is - // fully touching the device. This can cause the position to move enough to enter - // "slide" mode and disable "tap" events being emitted. - for (i = 0; i < DEF_SCROLLER_NUM_CHANNELS; i++) { - sum += filtered_readings[i] - min_sensor_reading; - weighted_sum += (filtered_readings[i] - min_sensor_reading) * sensor_location[i]; + // In case no single node is in touch, but multiple nodes together are, treat that as in + // touch + if (data->touch_area > config->contact_threshold) { + data->active = 1; + } else if (data->touch_area < config->untouch_threshold) { + data->active = 0; } - // Compensate for deadband (i.e. when only a single edge button gives a reading and - // neighbors do not) - uint16_t scaled_value = weighted_sum / sum; - scaled_value = - (scaled_value < DEF_SCROLLER_DEADBAND) ? DEF_SCROLLER_DEADBAND : (weighted_sum / sum); - scaled_value = (scaled_value > (DEF_SCROLLER_RESOLUTION - DEF_SCROLLER_DEADBAND)) - ? (DEF_SCROLLER_RESOLUTION - DEF_SCROLLER_DEADBAND) - : scaled_value; - scaled_value = ((scaled_value - DEF_SCROLLER_DEADBAND) * (DEF_SCROLLER_RESOLUTION - 1)) / - (DEF_SCROLLER_RESOLUTION - 2 * DEF_SCROLLER_DEADBAND); - - // Calculate scroller position using a moving average - // The moving average wieghts previous N readings twice current reading - if (sum >= DEF_SCROLLER_DET_THRESHOLD) { - uint16_t moving_average_cummulative_weight = 0; - scroller_position[scroller] = 0; - for (j = 0; j < DEF_SCROLLER_NUM_PREV_POS; j++) { - if (scroller_previous_position[scroller][j] != DEF_SCROLLER_OFF) { - moving_average_cummulative_weight += 2; - scroller_position[scroller] += scroller_previous_position[scroller][j] * 2; + uint32_t fixed_precision_offset = 16; + if (data->active) { + int32_t raw_pos = 0; + int32_t weight_sum = 0; + uint32_t sum = 0; + for (int i = 0; i < config->number_of_keys; ++i) { + // Ignore all sensor values below 5 + // int32_t delta = data->deltas[i] > 5 ? data->deltas[i] : 0; + int32_t delta = data->deltas[i]; + sum += delta; + int32_t weight = (i << fixed_precision_offset); + // int32_t weight = i; + // float weight = (float)i / (config->number_of_keys - 1); + raw_pos += max(0, delta * weight) * 2; + weight_sum += i; + } + // Make weighted average + raw_pos /= weight_sum; + // Normalize position + raw_pos /= sum; + raw_pos <<= config->resolution; + // Bring back down + raw_pos >>= fixed_precision_offset; + + // use weighted moving average on raw position + raw_pos = (data->raw_position + 2 * raw_pos) / 3; + + int32_t pos = data->position; + + int32_t raw_pos_delta = raw_pos - data->position; + if (raw_pos_delta < -data->hyst_left || raw_pos_delta > data->hyst_right) { + pos = raw_pos; + + /* handle hysterisis, when finger changes direction */ + if (pos < data->position) { + data->hyst_left = 0; + data->hyst_right = config->hysteresis; + } + if (pos > data->position) { + data->hyst_left = config->hysteresis; + data->hyst_right = 0; } } - scroller_position[scroller] += - scaled_value; // Most recent signal is half weight of others to help avoid bounce - // when finger is released - scroller_position[scroller] = - scroller_position[scroller] / (moving_average_cummulative_weight + 1); - } - // Update recorded previous positions and scroller active state - for (j = 0; j < DEF_SCROLLER_NUM_PREV_POS - 1; j++) { - scroller_previous_position[scroller][j] = scroller_previous_position[scroller][j + 1]; - } - if (sum >= DEF_SCROLLER_DET_THRESHOLD) { - scroller_previous_position[scroller][DEF_SCROLLER_NUM_PREV_POS - 1] = scaled_value; + /* Handle deadband (close to 0 and close to max resolution) */ + if (raw_pos < config->deadband) { + pos = 0; + data->hyst_left = 0; + data->hyst_right = config->hysteresis; + } + if (raw_pos >= ((1 << config->resolution) - 1) - config->deadband) { + pos = (1 << config->resolution) - 1; + data->hyst_left = config->hysteresis; + data->hyst_right = 0; + } + + data->position = pos; + data->raw_position = raw_pos; + // data->position = raw_pos; } else { - scroller_previous_position[scroller][DEF_SCROLLER_NUM_PREV_POS - 1] = DEF_SCROLLER_OFF; - } - // Use the maximum value of all sensor readings as an estimate of pressure. - // Put a threshold on this to detect whether we're touching or not. - if (max_sensor_reading >= DEF_SCROLLER_TOUCH_THRESHOLD) { - scroller_active[scroller] = true; - } else if (max_sensor_reading <= DEF_SCROLLER_UNTOUCH_THRESHOLD) { - scroller_active[scroller] = false; + data->hyst_left = config->hysteresis / 2; + data->hyst_right = config->hysteresis / 2; } } } +void qtouch_calibrate_node(uint16_t sensor_node) +{ + /* Calibrate Node */ + qtm_calibrate_sensor_node(&qtlib_acq_set1, sensor_node); + /* Initialize key */ + qtm_init_sensor_key(&qtlib_key_set1, sensor_node, &ptc_qtlib_node_stat1[sensor_node]); +} + /*============================================================================ ISR(ADC0_RESRDY_vect) ------------------------------------------------------------------------------ @@ -536,7 +580,7 @@ Notes : none ============================================================================*/ void ADC0_1_Handler(void) { - ADC0->INTFLAG.reg |= 1U; + ADC0->INTFLAG.reg |= 1u; qtm_samd51_ptc_handler(); } diff --git a/src/qtouch/qtouch.h b/src/qtouch/qtouch.h index 77dd51ed41..180e246cc8 100644 --- a/src/qtouch/qtouch.h +++ b/src/qtouch/qtouch.h @@ -17,8 +17,8 @@ Copyright (c) 2017 Microchip. All rights reserved. ------------------------------------------------------------------------------ ============================================================================*/ -#ifndef QTOUCH_H -#define QTOUCH_H +#ifndef TOUCH_H +#define TOUCH_H #ifdef __cplusplus extern "C" { @@ -30,6 +30,31 @@ extern "C" { #include "touch_api_ptc.h" +typedef struct { + uint16_t start_key; + uint8_t number_of_keys; + uint8_t resolution; + uint16_t contact_threshold; + uint16_t untouch_threshold; + uint8_t deadband; + uint8_t hysteresis; +} scroller_config_t; + +typedef struct { + int16_t* deltas; + uint16_t touch_area; + uint16_t raw_position; + uint16_t position; + uint8_t active; + uint8_t hyst_left; + uint8_t hyst_right; +} scroller_data_t; + +typedef struct { + scroller_config_t* config; + scroller_data_t* data; +} scroller_control_t; + /**********************************************************/ /******************* Acquisition controls *****************/ /**********************************************************/ @@ -37,21 +62,22 @@ extern "C" { * Range: 1 to 255. * Default value: 20. */ -#define DEF_TOUCH_MEASUREMENT_PERIOD_MS 20 +#define DEF_TOUCH_MEASUREMENT_PERIOD_MS 10 /* Defines the Type of sensor * Default value: NODE_MUTUAL. */ #define DEF_SENSOR_TYPE NODE_SELFCAP -/* Set sensor calibration mode for charge share delay ,Prescaler or series resistor. - * Range: CAL_AUTO_TUNE_NONE / CAL_AUTO_TUNE_RSEL / CAL_AUTO_TUNE_PRSC / CAL_AUTO_TUNE_CSD - * Default value: CAL_AUTO_TUNE_NONE. +/* Set sensor calibration mode for charge share delay ,Prescaler or series + * resistor. Range: CAL_AUTO_TUNE_NONE / CAL_AUTO_TUNE_RSEL / CAL_AUTO_TUNE_PRSC + * / CAL_AUTO_TUNE_CSD Default value: CAL_AUTO_TUNE_NONE. */ #define DEF_PTC_CAL_OPTION CAL_AUTO_TUNE_NONE -/* Defines the interrupt priority for the PTC. Set low priority to PTC interrupt for applications - * having interrupt time constraints. Range: 0 to 2 Default: 2 (Lowest Priority) +/* Defines the interrupt priority for the PTC. Set low priority to PTC interrupt + * for applications having interrupt time constraints. Range: 0 to 2 Default: 2 + * (Lowest Priority) */ #define DEF_PTC_INTERRUPT_PRIORITY 2 @@ -81,11 +107,10 @@ extern "C" { */ #define DEF_NUM_CHANNELS (8) -/* Defines node parameter setting - * {X-line, Y-line, Charge Share Delay, NODE_RSEL_PRSC(series resistor, prescaler), NODE_G(Analog - * Gain , Digital Gain), filter level} +/* Defines self-cap node parameter setting + * {X-line, Y-line, Charge Share Delay, Prescaler, NODE_G(Analog Gain , Digital + * Gain), filter level} */ -// Slider 1 buttons #define NODE_0_PARAMS \ {X_NONE, Y_LINE(26), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} #define NODE_1_PARAMS \ @@ -94,7 +119,6 @@ extern "C" { {X_NONE, Y_LINE(28), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_1, GAIN_8), FILTER_LEVEL_64} #define NODE_3_PARAMS \ {X_NONE, Y_LINE(29), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} -// Slider 0 buttons #define NODE_4_PARAMS \ {X_NONE, Y_LINE(30), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} #define NODE_5_PARAMS \ @@ -111,20 +135,19 @@ extern "C" { * Range: 1 to 65535. * Default value: 1 */ -#define DEF_NUM_SENSORS (DEF_NUM_CHANNELS) +#define DEF_NUM_SENSORS (8) /* Defines Key Sensor setting * {Sensor Threshold, Sensor Hysterisis, Sensor AKS} */ -// 0..3 higher Slider left to right 4..7 lower Slider right to left -#define KEY_0_PARAMS {12, HYST_25, AKS_GROUP_1} +#define KEY_0_PARAMS {24, HYST_25, AKS_GROUP_1} #define KEY_1_PARAMS {12, HYST_25, AKS_GROUP_1} -#define KEY_2_PARAMS {12, HYST_25, AKS_GROUP_1} -#define KEY_3_PARAMS {12, HYST_25, AKS_GROUP_1} -#define KEY_4_PARAMS {12, HYST_25, AKS_GROUP_2} -#define KEY_5_PARAMS {12, HYST_25, AKS_GROUP_2} -#define KEY_6_PARAMS {12, HYST_25, AKS_GROUP_2} -#define KEY_7_PARAMS {12, HYST_25, AKS_GROUP_2} +#define KEY_2_PARAMS {15, HYST_25, AKS_GROUP_1} +#define KEY_3_PARAMS {26, HYST_25, AKS_GROUP_1} +#define KEY_4_PARAMS {24, HYST_25, AKS_GROUP_2} +#define KEY_5_PARAMS {13, HYST_25, AKS_GROUP_2} +#define KEY_6_PARAMS {15, HYST_25, AKS_GROUP_2} +#define KEY_7_PARAMS {23, HYST_25, AKS_GROUP_2} /* De-bounce counter for additional measurements to confirm touch detection * Range: 0 to 255. @@ -132,10 +155,9 @@ extern "C" { */ #define DEF_TOUCH_DET_INT 1 -/* De-bounce counter for additional measurements to confirm away from touch signal - * to initiate Away from touch re-calibration. - * Range: 0 to 255. - * Default value: 5. +/* De-bounce counter for additional measurements to confirm away from touch + * signal to initiate Away from touch re-calibration. Range: 0 to 255. Default + * value: 5. */ #define DEF_ANTI_TCH_DET_INT 1 @@ -172,13 +194,13 @@ extern "C" { * Range: REBURST_NONE / REBURST_UNRESOLVED / REBURST_ALL * Default value: REBURST_UNRESOLVED */ -#define DEF_REBURST_MODE REBURST_NONE +#define DEF_REBURST_MODE REBURST_UNRESOLVED /* Sensor maximum ON duration upon touch. * Range: 0-255 * Default value: 0 */ -#define DEF_MAX_ON_DURATION 50 +#define DEF_MAX_ON_DURATION 0 /**********************************************************/ /***************** Slider/Wheel Parameters ****************/ @@ -195,26 +217,22 @@ extern "C" { #define DEF_SCROLLER_NUM_CHANNELS 4 // Number of channels per scroller #define DEF_SCROLLER_OFFSET_0 4 // Index of first button in scroller #define DEF_SCROLLER_OFFSET_1 0 // Index of first button in scroller -#define DEF_SCROLLER_RESOLUTION 256 // Scroller resolution in bits -#define DEF_SCROLLER_DET_THRESHOLD 12 // Scroller detect threshold -#define DEF_SCROLLER_TOUCH_THRESHOLD 12 // Scroller active threshold -#define DEF_SCROLLER_UNTOUCH_THRESHOLD 9 // Scroller active threshold -#define DEF_SCROLLER_DEADBAND 13 // 13 bits = 5% of 256-bit range -#define DEF_SCROLLER_NUM_PREV_POS \ - 4 // Number of previous scroller positions to remember; used in a simple filter -#define DEF_SCROLLER_OFF \ - 0xFFFF // Marker for indicating scroller reading does not exceed detection threshold -/* -#define DEF_SENSOR_EDGE_WEIGHT \ - 0.15 // Percent added weight to edge sensors, which are physically smaller -*/ -#define DEF_SENSOR_NUM_PREV_POS \ - 4 // Number of previous sensor positions to remember; used in a simple filter -#define DEF_SENSOR_CEILING \ - 50 // Maximum sensor reading. Mitigates 'jumpy' channels that exist at higher - // sensor readings when in noisy environments. +#define DEF_SCROLLER_RESOLUTION 8 // Scroller resolution in bits +#define DEF_SCROLLER_TOUCH_THRESHOLD 25 // Scroller active threshold +#define DEF_SCROLLER_UNTOUCH_THRESHOLD 15 // Scroller active threshold +#define DEF_SCROLLER_DEADBAND \ + 12 // everything below deadband is locked to 0 and above max-deadband is locked to max +#define DEF_SCROLLER_HYSTERESIS 10 // Position needs to move at least this much + +/**********************************************************/ +/***************** Communication - Data Streamer ******************/ +/**********************************************************/ + +#define DEF_TOUCH_DATA_STREAMER_ENABLE 0u +#define DATA_STREAMER_BOARD_TYPE USER_BOARD +#define KRONO_GESTURE_ENABLE 0 #ifdef __cplusplus } #endif // __cplusplus -#endif // QTOUCH_H +#endif // TOUCH_C diff --git a/src/touch/gestures.h b/src/touch/gestures.h index 47198104bc..93fdbbe758 100644 --- a/src/touch/gestures.h +++ b/src/touch/gestures.h @@ -24,7 +24,7 @@ #include "qtouch.h" #define TOUCH_NUM_BUTTONS DEF_NUM_CHANNELS #define TOUCH_NUM_SLIDERS DEF_NUM_SCROLLERS -#define MAX_SLIDER_POS (DEF_SCROLLER_RESOLUTION - 1) +#define MAX_SLIDER_POS ((1 << DEF_SCROLLER_RESOLUTION) - 1) #else #define TOUCH_NUM_BUTTONS (8) #define TOUCH_NUM_SLIDERS (2) From c16065935abd06098b352badadc5631340748672 Mon Sep 17 00:00:00 2001 From: Niklas Dusenlund Date: Fri, 3 Oct 2025 12:17:01 +0200 Subject: [PATCH 6/6] wip --- src/qtouch/qtouch.c | 120 +++++++++++++++++++++++++------------------- src/qtouch/qtouch.h | 31 ++++++------ 2 files changed, 84 insertions(+), 67 deletions(-) diff --git a/src/qtouch/qtouch.c b/src/qtouch/qtouch.c index 8d0b97de4f..46c8e338cf 100644 --- a/src/qtouch/qtouch.c +++ b/src/qtouch/qtouch.c @@ -160,7 +160,8 @@ scroller_config_t scroller_config[2] = { DEF_SCROLLER_TOUCH_THRESHOLD, DEF_SCROLLER_UNTOUCH_THRESHOLD, DEF_SCROLLER_DEADBAND, - DEF_SCROLLER_HYSTERESIS}, + DEF_SCROLLER_HYSTERESIS, + DEF_SCROLLER_TOUCH_DRIFT_IN}, [1] = {DEF_SCROLLER_OFFSET_1, DEF_SCROLLER_NUM_CHANNELS, @@ -168,7 +169,8 @@ scroller_config_t scroller_config[2] = { DEF_SCROLLER_TOUCH_THRESHOLD, DEF_SCROLLER_UNTOUCH_THRESHOLD, DEF_SCROLLER_DEADBAND, - DEF_SCROLLER_HYSTERESIS}, + DEF_SCROLLER_HYSTERESIS, + DEF_SCROLLER_TOUCH_DRIFT_IN}, }; scroller_data_t scroller_data[2] = {0}; @@ -449,20 +451,27 @@ void qtouch_process_scroller_positions(scroller_control_t* scrollers) int node_max = -1; int16_t node_max_value = INT16_MIN; data->touch_area = 0; + bool key_active = 0; + bool scroller_active = data->active; for (int i = 0; i < config->number_of_keys; i++) { uint8_t node = config->start_key + i; int16_t delta = max( 0, qtouch_get_sensor_node_signal(node) - qtouch_get_sensor_node_reference(node)); - // Apply weighted moving average - data->deltas[i] = (2 * delta + data->deltas[i]) / 3; - // multiply inner sensors with 1.75 (The ones at the edges have higher PTC gain) + // delta = max(0, delta - qtlib_key_configs_set1[node].channel_threshold); + // multiply inner sensors with 1.50 (The ones at the edges have higher PTC gain) if (i > 0 && i < config->number_of_keys - 1) { - data->deltas[i] += (data->deltas[i] >> 1) + (data->deltas[i] >> 2); + // data->deltas[i] += + // (data->deltas[i] >> 1) + (data->deltas[i] >> 2) + (data->deltas[i] >> 3); + // data->deltas[i] += (data->deltas[i] >> 1) + (data->deltas[i] >> 3); + data->deltas[i] += data->deltas[i] >> 1; } + + // Apply weighted moving average if it was active + data->deltas[i] = (2 * delta + data->deltas[i]) / 3; // If any key is in touch, the scroller is considered in touch - if ((qtouch_get_sensor_state(node) & QTM_KEY_DETECT) == QTM_KEY_DETECT) { - data->active = 1; + if (qtouch_get_sensor_state(node) == QTM_KEY_STATE_DETECT) { + key_active = 1; } // Find the node with the highest signal to determine how to calculate touch area. if (data->deltas[i] > node_max_value) { @@ -490,75 +499,80 @@ void qtouch_process_scroller_positions(scroller_control_t* scrollers) // In case no single node is in touch, but multiple nodes together are, treat that as in // touch - if (data->touch_area > config->contact_threshold) { - data->active = 1; - } else if (data->touch_area < config->untouch_threshold) { - data->active = 0; + if (data->touch_area > config->touch_threshold) { + data->touch_count_in = min(255, data->touch_count_in + 1); + if (data->touch_count_in > config->touch_count_in) { + scroller_active = 1; + } + } + if (data->touch_area < config->untouch_threshold) { + scroller_active = 0; + data->touch_count_in = 0; } - uint32_t fixed_precision_offset = 16; - if (data->active) { - int32_t raw_pos = 0; - int32_t weight_sum = 0; - uint32_t sum = 0; - for (int i = 0; i < config->number_of_keys; ++i) { - // Ignore all sensor values below 5 - // int32_t delta = data->deltas[i] > 5 ? data->deltas[i] : 0; - int32_t delta = data->deltas[i]; - sum += delta; - int32_t weight = (i << fixed_precision_offset); - // int32_t weight = i; - // float weight = (float)i / (config->number_of_keys - 1); - raw_pos += max(0, delta * weight) * 2; - weight_sum += i; - } - // Make weighted average - raw_pos /= weight_sum; - // Normalize position - raw_pos /= sum; - raw_pos <<= config->resolution; - // Bring back down - raw_pos >>= fixed_precision_offset; + bool active = key_active | scroller_active; + + // offset all calculations to increase precision + uint32_t fp_offset = 2; + uint32_t raw_pos = 0; + uint32_t weight_sum = 0; + uint32_t sum = 0; + for (int i = 0; i < config->number_of_keys; ++i) { + int32_t delta = data->deltas[i]; + sum += delta; + int32_t weight = (i << (config->resolution + fp_offset)) / (config->number_of_keys - 1); + raw_pos += delta * weight; + weight_sum += weight; + } + raw_pos /= sum; + raw_pos >>= fp_offset; - // use weighted moving average on raw position - raw_pos = (data->raw_position + 2 * raw_pos) / 3; + raw_pos = (data->raw_position + 4 * raw_pos) / 5; + if (active) { int32_t pos = data->position; - int32_t raw_pos_delta = raw_pos - data->position; - if (raw_pos_delta < -data->hyst_left || raw_pos_delta > data->hyst_right) { - pos = raw_pos; - - /* handle hysterisis, when finger changes direction */ - if (pos < data->position) { - data->hyst_left = 0; - data->hyst_right = config->hysteresis; - } - if (pos > data->position) { - data->hyst_left = config->hysteresis; - data->hyst_right = 0; + // use weighted moving average on raw position if it was active + if (data->active) { + int32_t raw_pos_delta = raw_pos - pos; + if (raw_pos_delta < -data->hyst_left || raw_pos_delta > data->hyst_right) { + pos = raw_pos; + + /* handle hysterisis, when finger changes direction */ + if (pos < data->position) { + data->hyst_left = 0; + data->hyst_right = config->hysteresis; + } + if (pos > data->position) { + data->hyst_left = config->hysteresis; + data->hyst_right = 0; + } } + } else { + pos = raw_pos; } /* Handle deadband (close to 0 and close to max resolution) */ if (raw_pos < config->deadband) { pos = 0; data->hyst_left = 0; - data->hyst_right = config->hysteresis; + data->hyst_right = config->hysteresis / 2; } - if (raw_pos >= ((1 << config->resolution) - 1) - config->deadband) { + if (raw_pos >= (uint32_t)((1 << config->resolution) - 1) - config->deadband) { pos = (1 << config->resolution) - 1; - data->hyst_left = config->hysteresis; + data->hyst_left = config->hysteresis / 2; data->hyst_right = 0; } data->position = pos; data->raw_position = raw_pos; - // data->position = raw_pos; } else { + // data->position = data->raw_position; + data->raw_position = raw_pos; data->hyst_left = config->hysteresis / 2; data->hyst_right = config->hysteresis / 2; } + data->active = active; } } diff --git a/src/qtouch/qtouch.h b/src/qtouch/qtouch.h index 180e246cc8..26a9ecda72 100644 --- a/src/qtouch/qtouch.h +++ b/src/qtouch/qtouch.h @@ -34,10 +34,11 @@ typedef struct { uint16_t start_key; uint8_t number_of_keys; uint8_t resolution; - uint16_t contact_threshold; + uint16_t touch_threshold; uint16_t untouch_threshold; uint8_t deadband; uint8_t hysteresis; + uint8_t touch_count_in; } scroller_config_t; typedef struct { @@ -48,6 +49,7 @@ typedef struct { uint8_t active; uint8_t hyst_left; uint8_t hyst_right; + uint8_t touch_count_in; } scroller_data_t; typedef struct { @@ -120,7 +122,7 @@ typedef struct { #define NODE_3_PARAMS \ {X_NONE, Y_LINE(29), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} #define NODE_4_PARAMS \ - {X_NONE, Y_LINE(30), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_2, GAIN_8), FILTER_LEVEL_64} + {X_NONE, Y_LINE(30), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_1, GAIN_8), FILTER_LEVEL_64} #define NODE_5_PARAMS \ {X_NONE, Y_LINE(31), 0, PRSC_DIV_SEL_4, NODE_GAIN(GAIN_1, GAIN_8), FILTER_LEVEL_64} #define NODE_6_PARAMS \ @@ -140,14 +142,14 @@ typedef struct { /* Defines Key Sensor setting * {Sensor Threshold, Sensor Hysterisis, Sensor AKS} */ -#define KEY_0_PARAMS {24, HYST_25, AKS_GROUP_1} -#define KEY_1_PARAMS {12, HYST_25, AKS_GROUP_1} +#define KEY_0_PARAMS {15, HYST_25, AKS_GROUP_1} +#define KEY_1_PARAMS {15, HYST_25, AKS_GROUP_1} #define KEY_2_PARAMS {15, HYST_25, AKS_GROUP_1} -#define KEY_3_PARAMS {26, HYST_25, AKS_GROUP_1} -#define KEY_4_PARAMS {24, HYST_25, AKS_GROUP_2} -#define KEY_5_PARAMS {13, HYST_25, AKS_GROUP_2} -#define KEY_6_PARAMS {15, HYST_25, AKS_GROUP_2} -#define KEY_7_PARAMS {23, HYST_25, AKS_GROUP_2} +#define KEY_3_PARAMS {21, HYST_25, AKS_GROUP_1} +#define KEY_4_PARAMS {12, HYST_25, AKS_GROUP_2} +#define KEY_5_PARAMS {15, HYST_25, AKS_GROUP_2} +#define KEY_6_PARAMS {16, HYST_25, AKS_GROUP_2} +#define KEY_7_PARAMS {21, HYST_25, AKS_GROUP_2} /* De-bounce counter for additional measurements to confirm touch detection * Range: 0 to 255. @@ -194,7 +196,7 @@ typedef struct { * Range: REBURST_NONE / REBURST_UNRESOLVED / REBURST_ALL * Default value: REBURST_UNRESOLVED */ -#define DEF_REBURST_MODE REBURST_UNRESOLVED +#define DEF_REBURST_MODE REBURST_ALL /* Sensor maximum ON duration upon touch. * Range: 0-255 @@ -218,11 +220,12 @@ typedef struct { #define DEF_SCROLLER_OFFSET_0 4 // Index of first button in scroller #define DEF_SCROLLER_OFFSET_1 0 // Index of first button in scroller #define DEF_SCROLLER_RESOLUTION 8 // Scroller resolution in bits -#define DEF_SCROLLER_TOUCH_THRESHOLD 25 // Scroller active threshold -#define DEF_SCROLLER_UNTOUCH_THRESHOLD 15 // Scroller active threshold +#define DEF_SCROLLER_TOUCH_THRESHOLD 32 // Scroller active threshold +#define DEF_SCROLLER_UNTOUCH_THRESHOLD 16 // Scroller active threshold #define DEF_SCROLLER_DEADBAND \ - 12 // everything below deadband is locked to 0 and above max-deadband is locked to max -#define DEF_SCROLLER_HYSTERESIS 10 // Position needs to move at least this much + 5 // everything below deadband is locked to 0 and above max-deadband is locked to max +#define DEF_SCROLLER_HYSTERESIS 20 // Position needs to move at least this much +#define DEF_SCROLLER_TOUCH_DRIFT_IN 2 // number of counts in touch before being active /**********************************************************/ /***************** Communication - Data Streamer ******************/