From 842caaab21f8d58d50c6719127f3b976373f6ac5 Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Tue, 18 Jul 2017 19:57:28 +0800 Subject: [PATCH] driver(touch): fix bug and add more features 1. add sens_struct.h 2. add definition of RTCCNTL and RTCIO 3. modify touch pad examples 4. update example code. 5. add comments add option in menuconfig 6. fix issue that pad index 8 and 9 are mismatched 7. add touch_pad_read_filtered() api to get value filtered by iir filter 8. modify touch pad isr func 9. Make the items in perihperal.ld in the sequence of address 10. delete Kconfig for touch pad 11. add touchpad filter APIs to adjust the filter 12. add touch_pad into index.rst 13. add touch_pad in Doxyfile 14. add touch_pad.rst --- components/driver/include/driver/touch_pad.h | 538 ++++++++++++++---- components/driver/rtc_module.c | 534 +++++++++++++---- components/esp32/ld/esp32.peripherals.ld | 3 + .../soc/esp32/include/soc/rtc_cntl_struct.h | 1 + .../soc/esp32/include/soc/rtc_io_struct.h | 1 + .../soc/esp32/include/soc/sens_struct.h | 316 ++++++++++ docs/Doxyfile | 1 + docs/api-reference/peripherals/index.rst | 1 + docs/api-reference/peripherals/touch_pad.rst | 23 + .../main/tp_interrupt_main.c | 127 ++++- .../touch_pad_read/main/tp_read_main.c | 71 ++- 11 files changed, 1377 insertions(+), 239 deletions(-) create mode 100644 components/soc/esp32/include/soc/sens_struct.h create mode 100644 docs/api-reference/peripherals/touch_pad.rst diff --git a/components/driver/include/driver/touch_pad.h b/components/driver/include/driver/touch_pad.h index e880ff611f..548edbcf52 100644 --- a/components/driver/include/driver/touch_pad.h +++ b/components/driver/include/driver/touch_pad.h @@ -20,150 +20,476 @@ extern "C" { #include "esp_intr.h" #include "esp_err.h" #include "esp_intr_alloc.h" -#define TOUCH_PAD_SLEEP_CYCLE_CONFIG (0x1000)//The Time is 150Khz,the Max value is 0xffff -#define TOUCH_PAD_MEASURE_CYCLE_CONFIG (0xffff)//The Time is 8Mhz,the Max value is 0xffff + typedef enum { TOUCH_PAD_NUM0 = 0, /*!< Touch pad channel 0 is GPIO4 */ - TOUCH_PAD_NUM1, /*!< Touch pad channel 0 is GPIO0 */ - TOUCH_PAD_NUM2, /*!< Touch pad channel 0 is GPIO2 */ - TOUCH_PAD_NUM3, /*!< Touch pad channel 0 is GPIO15 */ - TOUCH_PAD_NUM4, /*!< Touch pad channel 0 is GPIO13 */ - TOUCH_PAD_NUM5, /*!< Touch pad channel 0 is GPIO12 */ - TOUCH_PAD_NUM6, /*!< Touch pad channel 0 is GPIO14 */ - TOUCH_PAD_NUM7, /*!< Touch pad channel 0 is GPIO27*/ - TOUCH_PAD_NUM8, /*!< Touch pad channel 0 is GPIO33*/ - TOUCH_PAD_NUM9, /*!< Touch pad channel 0 is GPIO32*/ + TOUCH_PAD_NUM1, /*!< Touch pad channel 1 is GPIO0 */ + TOUCH_PAD_NUM2, /*!< Touch pad channel 2 is GPIO2 */ + TOUCH_PAD_NUM3, /*!< Touch pad channel 3 is GPIO15*/ + TOUCH_PAD_NUM4, /*!< Touch pad channel 4 is GPIO13*/ + TOUCH_PAD_NUM5, /*!< Touch pad channel 5 is GPIO12*/ + TOUCH_PAD_NUM6, /*!< Touch pad channel 6 is GPIO14*/ + TOUCH_PAD_NUM7, /*!< Touch pad channel 7 is GPIO27*/ + TOUCH_PAD_NUM8, /*!< Touch pad channel 8 is GPIO32*/ + TOUCH_PAD_NUM9, /*!< Touch pad channel 9 is GPIO33*/ TOUCH_PAD_MAX, } touch_pad_t; +typedef enum { + TOUCH_HVOLT_KEEP = -1, /*!NumTouch,so you can select a interrupt threshold. + * @brief get touch sensor counter value. + * Each touch sensor has a counter to count the number of charge/discharge cycles. + * When the pad is not 'touched', we can get a number of the counter. + * When the pad is 'touched', the value in counter will get smaller because of the larger equivalent capacitance. + * User can use this function to determine the interrupt trigger threshold. * - * @param[in] touch_num : touch num - * @param[out] touch_value : touch output value - * - * @return - ESP_OK Success + * @param touch_num touch pad index + * @param touch_value pointer to accept touch sensor value + * @return - ESP_OK Success * - ESP_ERR_INVALID_ARG Touch pad error * - ESP_FAIL Touch pad not initialized - * */ esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t * touch_value); /** - * @brief register TouchPad interrupt handler, the handler is an ISR. - * The handler will be attached to the same CPU core that this function is running on. - * - * @param fn Interrupt handler function. - * @param arg Parameter for handler function - * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) - * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. - * @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will - * be returned here. + * @brief get filtered touch sensor counter value by IIR filter. + * @note touch_pad_filter_start has to be called before calling touch_pad_read_filtered. + * This function can be called from ISR * + * @param touch_num touch pad index + * @param touch_value pointer to accept touch sensor value + * @return - ESP_OK Success + * - ESP_ERR_INVALID_ARG Touch pad error + * - ESP_FAIL Touch pad not initialized + */ +esp_err_t touch_pad_read_filtered(touch_pad_t touch_num, uint16_t *touch_value); + +/** + * @brief Register touch-pad ISR, + * @note Deprecated function, users should replace this with touch_pad_isr_register, + * because RTC modules share a same interrupt index. + * @param fn Pointer to ISR handler + * @param arg Parameter for ISR + * @param unused Reserved, not used + * @param handle_unused Reserved, not used + * @return + * - ESP_OK Success ; + * - ESP_ERR_INVALID_ARG GPIO error + */ +esp_err_t touch_pad_isr_handler_register(void(*fn)(void *), void *arg, int unused, intr_handle_t *handle_unused) __attribute__ ((deprecated)); + +/** + * @brief Register touch-pad ISR. + * The handler will be attached to the same CPU core that this function is running on. + * @param fn Pointer to ISR handler + * @param arg Parameter for ISR * @return * - ESP_OK Success ; * - ESP_ERR_INVALID_ARG GPIO error */ -esp_err_t touch_pad_isr_handler_register(void(*fn)(void *), void *arg, int intr_alloc_flags, touch_isr_handle_t *handle); - - -/** - * *************** ATTENTION ********************/ -/** - *@attention - *Touch button is through the body's capacitive characteristics, - *there is a charge discharge circuit inside the. When the hands touch, - *the charge and discharge time will be slow. - *Because of the different hardware, each pad needs to be calibrated at the factory. - *We use touch_pad_read to determine factory parameters. - */ -/** - *----------EXAMPLE TO CONFIGURE GPIO AS OUTPUT ------------ * - * @code{c} - * touch_pad_init(); - * void taskA(void* arg) - * { - * for(;;){ - * vtaskDelay(20/portTICK_PERIOD_MS); - * ets_printf("touch pad value %u\n",touch_pad_read(0));//Take the touched status and untouched status value - * } - * } - * @endcode - **/ -/** - *----------EXAMPLE TO SET ISR HANDLER ---------------------- - * @code{c} - * touch_pad_isr_handler_register(rtc_intr,NULL, 0, NULL) //hook the isr handler for TouchPad interrupt - * @endcode - */ -/** - *----------EXAMPLE TO USE TOUCH_PAD------------ * - * @code{c} - * touch_pad_init();//only init one time - * touch_pad_config(0,300);//set the intr threshold,use touch_pad_read to determine this threshold - * touch_pad_isr_handler_register(rtc_intr,NULL, 0, NULL) - * #include "esp_attr.h" - * void rtc_intr(void * arg) - * { - * uint32_t pad_intr = READ_PERI_REG(SARADC_SAR_TOUCH_CTRL2_REG) & 0x3ff; - * uint8_t i = 0; - * uint32_t rtc_intr = READ_PERI_REG(RTC_CNTL_INT_ST_REG); - * WRITE_PERI_REG(RTC_CNTL_INT_CLR_REG, rtc_intr); - * SET_PERI_REG_MASK(SARADC_SAR_TOUCH_CTRL2_REG, SARADC_TOUCH_MEAS_EN_CLR); - * if (rtc_intr & RTC_CNTL_TOUCH_INT_ST) { - * for (i = 0; i < TOUCH_PAD_MAX; ++i) { - * if ((pad_intr >> i) & 0x01) { - * ets_printf("touch pad intr %u\n",i); - * } - * } - * } - * } - * @endcode - **/ +esp_err_t touch_pad_isr_register(intr_handler_t fn, void* arg); + +/** + * @brief Deregister the handler previously registered using touch_pad_isr_handler_register + * @param fn handler function to call (as passed to touch_pad_isr_handler_register) + * @param arg argument of the handler (as passed to touch_pad_isr_handler_register) + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if a handler matching both fn and + * arg isn't registered + */ +esp_err_t touch_pad_isr_deregister(void(*fn)(void *), void *arg); + +/** + * @brief Set touch sensor measurement and sleep time + * @param sleep_cycle The touch sensor will sleep after each measurement. + * sleep_cycle decide the interval between each measurement. + * t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency). + * The approximate frequency value of RTC_SLOW_CLK can be obtained using rtc_clk_slow_freq_get_hz function. + * @param meas_cycle The duration of the touch sensor measurement. + * t_meas = meas_cycle / 8M, the maximum measure time is 0xffff / 8M = 8.19 ms + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_set_meas_time(uint16_t sleep_cycle, uint16_t meas_cycle); + +/** + * @brief Get touch sensor measurement and sleep time + * @param sleep_cycle Pointer to accept sleep cycle number + * @param meas_cycle Pointer to accept measurement cycle count. + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_get_meas_time(uint16_t *sleep_cycle, uint16_t *meas_cycle); + +/** + * @brief Set touch sensor reference voltage, if the voltage gap between high and low reference voltage get less, + * the charging and discharging time would be faster, accordingly, the counter value would be larger. + * In the case of detecting very slight change of capacitance, we can narrow down the gap so as to increase + * the sensitivity. On the other hand, narrow voltage gap would also introduce more noise, but we can use a + * software filter to pre-process the counter value. + * @param refh the value of DREFH + * @param refl the value of DREFL + * @param atten the attenuation on DREFH + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_set_voltage(touch_high_volt_t refh, touch_low_volt_t refl, touch_volt_atten_t atten); + +/** + * @brief Get touch sensor reference voltage, + * @param refh pointer to accept DREFH value + * @param refl pointer to accept DREFL value + * @param atten pointer to accept the attenuation on DREFH + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_get_voltage(touch_high_volt_t *refh, touch_low_volt_t *refl, touch_volt_atten_t *atten); + +/** + * @brief Set touch sensor charge/discharge speed for each pad. + * If the slope is 0, the counter would always be zero. + * If the slope is 1, the charging and discharging would be slow, accordingly, the counter value would be small. + * If the slope is set 7, which is the maximum value, the charging and discharging would be fast, accordingly, the + * counter value would be larger. + * @param touch_num touch pad index + * @param slope touch pad charge/discharge speed + * @param opt the initial voltage + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_set_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t slope, touch_tie_opt_t opt); + +/** + * @brief Get touch sensor charge/discharge speed for each pad + * @param touch_num touch pad index + * @param slope pointer to accept touch pad charge/discharge slope + * @param opt pointer to accept the initial voltage + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_get_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t *slope, touch_tie_opt_t *opt); + +/** + * @brief Initialize touch pad GPIO + * @param touch_num touch pad index + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_io_init(touch_pad_t touch_num); + +/** + * @brief Set touch sensor FSM mode, the test action can be triggered by the timer, + * as well as by the software. + * @param mode FSM mode + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_set_fsm_mode(touch_fsm_mode_t mode); + +/** + * @brief Get touch sensor FSM mode + * @param mode pointer to accept FSM mode + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_get_fsm_mode(touch_fsm_mode_t *mode); + +/** + * @brief Trigger a touch sensor measurement, only support in SW mode of FSM + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_sw_start(); + +/** + * @brief Set touch sensor interrupt threshold + * @param touch_num touch pad index + * @param threshold threshold of touchpad count, refer to touch_pad_set_trigger_mode to see how to set trigger mode. + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_set_thresh(touch_pad_t touch_num, uint16_t threshold); + +/** + * @brief Get touch sensor interrupt threshold + * @param touch_num touch pad index + * @param threshold pointer to accept threshold + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_get_thresh(touch_pad_t touch_num, uint16_t *threshold); + +/** + * @brief Set touch sensor interrupt trigger mode. + * Interrupt can be triggered either when counter result is less than + * threshold or when counter result is more than threshold. + * @param mode touch sensor interrupt trigger mode + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_set_trigger_mode(touch_trigger_mode_t mode); + +/** + * @brief Get touch sensor interrupt trigger mode + * @param mode pointer to accept touch sensor interrupt trigger mode + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_get_trigger_mode(touch_trigger_mode_t *mode); + +/** + * @brief Set touch sensor interrupt trigger source. There are two sets of touch signals. + * Set1 and set2 can be mapped to several touch signals. Either set will be triggered + * if at least one of its touch signal is 'touched'. The interrupt can be configured to be generated + * if set1 is triggered, or only if both sets are triggered. + * @param src touch sensor interrupt trigger source + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_set_trigger_source(touch_trigger_src_t src); + +/** + * @brief Get touch sensor interrupt trigger source + * @param src pointer to accept touch sensor interrupt trigger source + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_get_trigger_source(touch_trigger_src_t *src); + +/** + * @brief Set touch sensor group mask. + * Touch pad module has two sets of signals, 'Touched' signal is triggered only if + * at least one of touch pad in this group is "touched". + * This function will set the register bits according to the given bitmask. + * @param set1_mask bitmask of touch sensor signal group1, it's a 10-bit value + * @param set2_mask bitmask of touch sensor signal group2, it's a 10-bit value + * @param en_mask bitmask of touch sensor work enable, it's a 10-bit value + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_set_group_mask(uint16_t set1_mask, uint16_t set2_mask, uint16_t en_mask); + +/** + * @brief Get touch sensor group mask. + * @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value + * @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value + * @param en_mask pointer to accept bitmask of touch sensor work enable, it's a 10-bit value + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_get_group_mask(uint16_t *set1_mask, uint16_t *set2_mask, uint16_t *en_mask); + +/** + * @brief Clear touch sensor group mask. + * Touch pad module has two sets of signals, Interrupt is triggered only if + * at least one of touch pad in this group is "touched". + * This function will clear the register bits according to the given bitmask. + * @param set1_mask bitmask touch sensor signal group1, it's a 10-bit value + * @param set2_mask bitmask touch sensor signal group2, it's a 10-bit value + * @param en_mask bitmask of touch sensor work enable, it's a 10-bit value + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if argument is wrong + */ +esp_err_t touch_pad_clear_group_mask(uint16_t set1_mask, uint16_t set2_mask, uint16_t en_mask); + +/** + * @brief To clear the touch status register, usually use this function in touch ISR to clear status. + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_clear_status(); + +/** + * @brief Get the touch sensor status, usually used in ISR to decide which pads are 'touched'. + * @return + * - touch status + */ +uint32_t touch_pad_get_status(); + +/** + * @brief To enable touch pad interrupt + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_intr_enable(); + +/** + * @brief To disable touch pad interrupt + * @return + * - ESP_OK on success + */ +esp_err_t touch_pad_intr_disable(); + +/** + * @brief set touch pad filter calibration period, in ms. + * Need to call touch_pad_filter_start before all touch filter APIs + * @param new_period_ms filter period, in ms + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_STATE driver state error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t touch_pad_set_filter_period(uint32_t new_period_ms); + +/** + * @brief get touch pad filter calibration period, in ms + * Need to call touch_pad_filter_start before all touch filter APIs + * @param p_period_ms pointer to accept period + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_STATE driver state error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t touch_pad_get_filter_period(uint32_t* p_period_ms); + +/** + * @brief start touch pad filter function + * This API will start a filter to process the noise in order to prevent false triggering + * when detecting slight change of capacitance. + * Need to call touch_pad_filter_start before all touch filter APIs + * + * If filter is not initialized, this API will initialize the filter with given period. + * If filter is already initialized, this API will update the filter period. + * @note This filter uses FreeRTOS timer, which is dipatched from a task with + * priority 1 by default on CPU 0. So if some application task with higher priority + * takes a lot of CPU0 time, then the quality of data obtained from this filter will be affected. + * You can adjust FreeRTOS timer task priority in menuconfig. + * @param filter_period_ms filter calibration period, in ms + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG parameter error + * - ESP_ERR_NO_MEM No memory for driver + * - ESP_ERR_INVALID_STATE driver state error + */ +esp_err_t touch_pad_filter_start(uint32_t filter_period_ms); + +/** + * @brief stop touch pad filter function + * Need to call touch_pad_filter_start before all touch filter APIs + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_STATE driver state error + */ +esp_err_t touch_pad_filter_stop(); + +/** + * @brief delete touch pad filter driver and release the memory + * Need to call touch_pad_filter_start before all touch filter APIs + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_STATE driver state error + */ +esp_err_t touch_pad_filter_delete(); #ifdef __cplusplus } diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index 39e5de72dd..eb89da60cb 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -15,8 +15,11 @@ #include "rom/ets_sys.h" #include "esp_log.h" #include "soc/rtc_io_reg.h" +#include "soc/rtc_io_struct.h" #include "soc/sens_reg.h" +#include "soc/sens_struct.h" #include "soc/rtc_cntl_reg.h" +#include "soc/rtc_cntl_struct.h" #include "rtc_io.h" #include "touch_pad.h" #include "adc.h" @@ -24,6 +27,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/xtensa_api.h" #include "freertos/semphr.h" +#include "freertos/timers.h" #include "esp_intr_alloc.h" #include "sys/lock.h" #include "driver/rtc_cntl.h" @@ -43,6 +47,11 @@ static const char *RTC_MODULE_TAG = "RTC_MODULE"; return (ret_val); \ } +#define RTC_RES_CHECK(res, ret_val) if ( (a) != ESP_OK) { \ + ESP_LOGE(RTC_MODULE_TAG,"%s:%d (%s)", __FILE__, __LINE__, __FUNCTION__); \ + return (ret_val); \ +} + #define ADC1_CHECK_FUNCTION_RET(fun_ret) if(fun_ret!=ESP_OK){\ ESP_LOGE(RTC_MODULE_TAG,"%s:%d\n",__FUNCTION__,__LINE__);\ return ESP_FAIL;\ @@ -51,7 +60,17 @@ static const char *RTC_MODULE_TAG = "RTC_MODULE"; #define DAC_ERR_STR_CHANNEL_ERROR "DAC channel error" portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED; -static xSemaphoreHandle rtc_touch_sem = NULL; +static SemaphoreHandle_t rtc_touch_mux = NULL; + + +typedef struct { + TimerHandle_t timer; + uint32_t filtered_val[TOUCH_PAD_MAX]; + uint32_t filter_period; + uint32_t period; + bool enable; +} touch_pad_filter_t; +static touch_pad_filter_t *s_touch_pad_filter = NULL; //Reg,Mux,Fun,IE,Up,Down,Rtc_number const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = { @@ -337,10 +356,21 @@ void rtc_gpio_force_hold_dis_all() /*--------------------------------------------------------------- Touch Pad ---------------------------------------------------------------*/ -esp_err_t touch_pad_isr_handler_register(void(*fn)(void *), void *arg, int intr_alloc_flags, touch_isr_handle_t *handle) +esp_err_t touch_pad_isr_handler_register(void (*fn)(void *), void *arg, int no_use, intr_handle_t *handle_no_use) { RTC_MODULE_CHECK(fn, "Touch_Pad ISR null", ESP_ERR_INVALID_ARG); - return esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); + return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M); +} + +esp_err_t touch_pad_isr_register(intr_handler_t fn, void* arg) +{ + RTC_MODULE_CHECK(fn, "Touch_Pad ISR null", ESP_ERR_INVALID_ARG); + return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M); +} + +esp_err_t touch_pad_isr_deregister(intr_handler_t fn, void *arg) +{ + return rtc_isr_deregister(fn, arg); } static esp_err_t touch_pad_get_io_num(touch_pad_t touch_num, gpio_num_t *gpio_num) @@ -371,129 +401,346 @@ static esp_err_t touch_pad_get_io_num(touch_pad_t touch_num, gpio_num_t *gpio_nu *gpio_num = 27; break; case TOUCH_PAD_NUM8: - *gpio_num = 33; + *gpio_num = 32; break; case TOUCH_PAD_NUM9: - *gpio_num = 32; + *gpio_num = 33; break; default: return ESP_ERR_INVALID_ARG; } - return ESP_OK; } -static esp_err_t touch_pad_init_config(uint16_t sleep_cycle, uint16_t sample_cycle_num) +#define TOUCH_PAD_FILTER_FACTOR_DEFAULT (16) +#define TOUCH_PAD_SHIFT_DEFAULT (4) +static uint32_t _touch_filter_iir(uint32_t in_now, uint32_t out_last, uint32_t k) +{ + if (k == 0) { + return in_now; + } else { + uint32_t out_now = (in_now + (k - 1) * out_last) / k; + return out_now; + } +} + +static void touch_pad_filter_cb(void *arg) +{ + if (s_touch_pad_filter == NULL) { + return; + } + uint16_t val; + for (int i = 0; i < TOUCH_PAD_MAX; i++) { + touch_pad_read(i, &val); + s_touch_pad_filter->filtered_val[i] = s_touch_pad_filter->filtered_val[i] == 0 ? (val << TOUCH_PAD_SHIFT_DEFAULT) : s_touch_pad_filter->filtered_val[i]; + s_touch_pad_filter->filtered_val[i] = _touch_filter_iir((val << TOUCH_PAD_SHIFT_DEFAULT), + s_touch_pad_filter->filtered_val[i], TOUCH_PAD_FILTER_FACTOR_DEFAULT); + } +} + +esp_err_t touch_pad_set_meas_time(uint16_t sleep_cycle, uint16_t meas_cycle) { - xSemaphoreTake(rtc_touch_sem, portMAX_DELAY); + xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); portENTER_CRITICAL(&rtc_spinlock); - SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS, 1, RTC_IO_TOUCH_XPD_BIAS_S); - SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR); - //clear touch enable - WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, 0x0); - //enable Rtc Touch pad Timer - SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_TOUCH_SLP_TIMER_EN); - //config pad module sleep time and sample num - //Touch pad SleepCycle Time = 150Khz - SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_SLEEP_CYCLES, sleep_cycle, SENS_TOUCH_SLEEP_CYCLES_S);//150kHZ - //Touch Pad Measure Time= 8Mhz - SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_MEAS_DELAY, sample_cycle_num, SENS_TOUCH_MEAS_DELAY_S); //8Mhz + //touch sensor sleep cycle Time = sleep_cycle / RTC_SLOW_CLK( can be 150k or 32k depending on the options) + SENS.sar_touch_ctrl2.touch_sleep_cycles = sleep_cycle; + //touch sensor measure time= meas_cycle / 8Mhz + SENS.sar_touch_ctrl1.touch_meas_delay = meas_cycle; portEXIT_CRITICAL(&rtc_spinlock); - xSemaphoreGive(rtc_touch_sem); + xSemaphoreGive(rtc_touch_mux); return ESP_OK; } -esp_err_t touch_pad_init() +esp_err_t touch_pad_get_meas_time(uint16_t *sleep_cycle, uint16_t *meas_cycle) { - if(rtc_touch_sem == NULL) { - rtc_touch_sem = xSemaphoreCreateMutex(); + portENTER_CRITICAL(&rtc_spinlock); + if (sleep_cycle) { + *sleep_cycle = SENS.sar_touch_ctrl2.touch_sleep_cycles; } - if(rtc_touch_sem == NULL) { - return ESP_FAIL; + if (meas_cycle) { + *meas_cycle = SENS.sar_touch_ctrl1.touch_meas_delay; } - return touch_pad_init_config(TOUCH_PAD_SLEEP_CYCLE_CONFIG, TOUCH_PAD_MEASURE_CYCLE_CONFIG); + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; } -esp_err_t touch_pad_deinit() +esp_err_t touch_pad_set_voltage(touch_high_volt_t refh, touch_low_volt_t refl, touch_volt_atten_t atten) { + RTC_MODULE_CHECK(((refh < TOUCH_HVOLT_MAX) && (refh >= (int )TOUCH_HVOLT_KEEP)), "touch refh error", + ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(((refl < TOUCH_LVOLT_MAX) && (refh >= (int )TOUCH_LVOLT_KEEP)), "touch refl error", + ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(((atten < TOUCH_HVOLT_ATTEN_MAX) && (refh >= (int )TOUCH_HVOLT_ATTEN_KEEP)), "touch atten error", + ESP_ERR_INVALID_ARG); - if(rtc_touch_sem == NULL) { - return ESP_FAIL; + portENTER_CRITICAL(&rtc_spinlock); + if (refh > TOUCH_HVOLT_KEEP) { + RTCIO.touch_cfg.drefh = refh; + } + if (refl > TOUCH_LVOLT_KEEP) { + RTCIO.touch_cfg.drefl = refl; } - vSemaphoreDelete(rtc_touch_sem); - rtc_touch_sem=NULL; + if (atten > TOUCH_HVOLT_ATTEN_KEEP) { + RTCIO.touch_cfg.drange = atten; + } + portEXIT_CRITICAL(&rtc_spinlock); return ESP_OK; } -static void touch_pad_counter_init(touch_pad_t touch_num) +esp_err_t touch_pad_get_voltage(touch_high_volt_t *refh, touch_low_volt_t *refl, touch_volt_atten_t *atten) { portENTER_CRITICAL(&rtc_spinlock); - //Enable Tie,Init Level(Counter) - SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + touch_num * 4, RTC_IO_TOUCH_PAD0_TIE_OPT_M); - //Touch Set Slop(Counter) - SET_PERI_REG_BITS(RTC_IO_TOUCH_PAD0_REG + touch_num * 4, RTC_IO_TOUCH_PAD0_DAC_V, 7, RTC_IO_TOUCH_PAD0_DAC_S); - //Enable Touch Pad IO - SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + touch_num * 4, RTC_IO_TOUCH_PAD0_START_M); + if (refh) { + *refh = RTCIO.touch_cfg.drefh; + } + if (refl) { + *refl = RTCIO.touch_cfg.drefl; + } + if (atten) { + *atten = RTCIO.touch_cfg.drange; + } + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t touch_pad_set_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t slope, touch_tie_opt_t opt) +{ + RTC_MODULE_CHECK((slope < TOUCH_PAD_SLOPE_MAX), "touch slope error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((opt < TOUCH_PAD_TIE_OPT_MAX), "touch opt error", ESP_ERR_INVALID_ARG); + portENTER_CRITICAL(&rtc_spinlock); + //set tie opt value, high or low level seem no difference for counter + RTCIO.touch_pad[touch_num].tie_opt = opt; + //touch sensor set slope for charging and discharging. + RTCIO.touch_pad[touch_num].dac = slope; portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; } -static void touch_pad_power_on(touch_pad_t touch_num) +esp_err_t touch_pad_get_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t *slope, touch_tie_opt_t *opt) { + RTC_MODULE_CHECK((touch_num < TOUCH_PAD_MAX), "touch IO error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); - //Enable Touch Pad Power on - SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + touch_num * 4, RTC_IO_TOUCH_PAD0_XPD_M); + if (slope) { + *slope = RTCIO.touch_pad[touch_num].dac; + } + if (opt) { + *opt = RTCIO.touch_pad[touch_num].tie_opt; + } portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; } -static void toch_pad_io_init(touch_pad_t touch_num) +esp_err_t touch_pad_io_init(touch_pad_t touch_num) { + RTC_MODULE_CHECK((touch_num < TOUCH_PAD_MAX), "touch IO error", ESP_ERR_INVALID_ARG); gpio_num_t gpio_num = GPIO_NUM_0; touch_pad_get_io_num(touch_num, &gpio_num); rtc_gpio_init(gpio_num); rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED); rtc_gpio_pulldown_dis(gpio_num); rtc_gpio_pullup_dis(gpio_num); + return ESP_OK; } -static esp_err_t touch_start(touch_pad_t touch_num) +esp_err_t touch_pad_set_fsm_mode(touch_fsm_mode_t mode) +{ + RTC_MODULE_CHECK((mode < TOUCH_FSM_MODE_MAX), "touch fsm mode error", ESP_ERR_INVALID_ARG); + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_touch_ctrl2.touch_start_en = 0; + SENS.sar_touch_ctrl2.touch_start_force = mode; + RTCCNTL.state0.touch_slp_timer_en = (mode == TOUCH_FSM_MODE_TIMER ? 1 : 0); + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t touch_pad_get_fsm_mode(touch_fsm_mode_t *mode) +{ + if (mode) { + *mode = SENS.sar_touch_ctrl2.touch_start_force; + } + return ESP_OK; +} + +esp_err_t touch_pad_sw_start() +{ + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_touch_ctrl2.touch_start_en = 0; + SENS.sar_touch_ctrl2.touch_start_en = 1; + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t touch_pad_set_thresh(touch_pad_t touch_num, uint16_t threshold) +{ + RTC_MODULE_CHECK((touch_num < TOUCH_PAD_MAX), "touch IO error", ESP_ERR_INVALID_ARG); + portENTER_CRITICAL(&rtc_spinlock); + if (touch_num & 0x1) { + SENS.touch_thresh[touch_num / 2].l_thresh = threshold; + } else { + SENS.touch_thresh[touch_num / 2].h_thresh = threshold; + + } + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t touch_pad_get_thresh(touch_pad_t touch_num, uint16_t *threshold) +{ + RTC_MODULE_CHECK((touch_num < TOUCH_PAD_MAX), "touch IO error", ESP_ERR_INVALID_ARG); + if (threshold) { + *threshold = (touch_num & 0x1 )? \ + SENS.touch_thresh[touch_num / 2].l_thresh : \ + SENS.touch_thresh[touch_num / 2].h_thresh; + } + return ESP_OK; +} + +esp_err_t touch_pad_set_trigger_mode(touch_trigger_mode_t mode) +{ + RTC_MODULE_CHECK((mode < TOUCH_TRIGGER_MAX), "touch trigger mode error", ESP_ERR_INVALID_ARG); + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_touch_ctrl1.touch_out_sel = mode; + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t touch_pad_get_trigger_mode(touch_trigger_mode_t *mode) +{ + if (mode) { + *mode = SENS.sar_touch_ctrl1.touch_out_sel; + } + return ESP_OK; +} + +esp_err_t touch_pad_set_trigger_source(touch_trigger_src_t src) +{ + RTC_MODULE_CHECK((src < TOUCH_TRIGGER_SOURCE_MAX), "touch trigger source error", ESP_ERR_INVALID_ARG); + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_touch_ctrl1.touch_out_1en = src; + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t touch_pad_get_trigger_source(touch_trigger_src_t *src) +{ + if (src) { + *src = SENS.sar_touch_ctrl1.touch_out_1en; + } + return ESP_OK; +} + +esp_err_t touch_pad_set_group_mask(uint16_t set1_mask, uint16_t set2_mask, uint16_t en_mask) +{ + RTC_MODULE_CHECK((set1_mask <= TOUCH_PAD_BIT_MASK_MAX), "touch set1 bitmask error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((set2_mask <= TOUCH_PAD_BIT_MASK_MAX), "touch set2 bitmask error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((en_mask <= TOUCH_PAD_BIT_MASK_MAX), "touch work_en bitmask error", ESP_ERR_INVALID_ARG); + + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_touch_enable.touch_pad_outen1 |= set1_mask; + SENS.sar_touch_enable.touch_pad_outen2 |= set2_mask; + SENS.sar_touch_enable.touch_pad_worken |= en_mask; + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t touch_pad_get_group_mask(uint16_t *set1_mask, uint16_t *set2_mask, uint16_t *en_mask) +{ + portENTER_CRITICAL(&rtc_spinlock); + if (set1_mask) { + *set1_mask = SENS.sar_touch_enable.touch_pad_outen1; + } + if (set2_mask) { + *set2_mask = SENS.sar_touch_enable.touch_pad_outen2; + } + if (en_mask) { + *en_mask = SENS.sar_touch_enable.touch_pad_worken; + } + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t touch_pad_clear_group_mask(uint16_t set1_mask, uint16_t set2_mask, uint16_t en_mask) +{ + RTC_MODULE_CHECK((set1_mask <= TOUCH_PAD_BIT_MASK_MAX), "touch set1 bitmask error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((set2_mask <= TOUCH_PAD_BIT_MASK_MAX), "touch set2 bitmask error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((en_mask <= TOUCH_PAD_BIT_MASK_MAX), "touch work_en bitmask error", ESP_ERR_INVALID_ARG); + + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_touch_enable.touch_pad_outen1 &= (~set1_mask); + SENS.sar_touch_enable.touch_pad_outen2 &= (~set2_mask); + SENS.sar_touch_enable.touch_pad_worken &= (~en_mask); + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +uint32_t IRAM_ATTR touch_pad_get_status() +{ + return SENS.sar_touch_ctrl2.touch_meas_en; +} + +esp_err_t IRAM_ATTR touch_pad_clear_status() { - RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_touch_ctrl2.touch_meas_en_clr = 1; + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} - //Enable Digital rtc control :work mode and out mode - SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, (1 << (touch_num + SENS_TOUCH_PAD_WORKEN_S)) | \ - (1 << (touch_num + SENS_TOUCH_PAD_OUTEN2_S)) | \ - (1 << (touch_num + SENS_TOUCH_PAD_OUTEN1_S))); +esp_err_t touch_pad_intr_enable() +{ + portENTER_CRITICAL(&rtc_spinlock); + RTCCNTL.int_ena.rtc_touch = 1; portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} +esp_err_t touch_pad_intr_disable() +{ + portENTER_CRITICAL(&rtc_spinlock); + RTCCNTL.int_ena.rtc_touch = 0; + portEXIT_CRITICAL(&rtc_spinlock); return ESP_OK; } esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold) { - RTC_MODULE_CHECK(rtc_touch_sem != NULL, "Touch pad not initialized", ESP_FAIL); + RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL); RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG); - xSemaphoreTake(rtc_touch_sem, portMAX_DELAY); - portENTER_CRITICAL(&rtc_spinlock); - //clear touch force ,select the Touch mode is Timer - CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M); - CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FORCE_M); - //set threshold - uint8_t shift; - shift = (touch_num & 1) ? SENS_TOUCH_OUT_TH1_S : SENS_TOUCH_OUT_TH0_S; - SET_PERI_REG_BITS((SENS_SAR_TOUCH_THRES1_REG + (touch_num / 2) * 4), SENS_TOUCH_OUT_TH0, threshold, shift); - //When touch value < threshold ,the Intr will give - CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_SEL); - //Intr will give ,when SET0 < threshold - SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_1EN); - //Enable Rtc Touch Module Intr,the Interrupt need Rtc out Enable - SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_TOUCH_INT_ENA); - portEXIT_CRITICAL(&rtc_spinlock); - xSemaphoreGive(rtc_touch_sem); - touch_pad_power_on(touch_num); - toch_pad_io_init(touch_num); - touch_pad_counter_init(touch_num); - touch_start(touch_num); + touch_pad_set_thresh(touch_num, threshold); + touch_pad_io_init(touch_num); + touch_pad_set_cnt_mode(touch_num, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_HIGH); + touch_pad_set_group_mask((1 << touch_num), (1 << touch_num), (1 << touch_num)); + return ESP_OK; +} + +esp_err_t touch_pad_init() +{ + if (rtc_touch_mux == NULL) { + rtc_touch_mux = xSemaphoreCreateMutex(); + } + if (rtc_touch_mux == NULL) { + return ESP_FAIL; + } + touch_pad_intr_disable(); + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_DEFAULT); + touch_pad_set_trigger_mode(TOUCH_TRIGGER_MODE_DEFAULT); + touch_pad_set_trigger_source(TOUCH_TRIGGER_SOURCE_DEFAULT); + touch_pad_clear_status(); + touch_pad_set_meas_time(TOUCH_PAD_SLEEP_CYCLE_DEFAULT, TOUCH_PAD_MEASURE_CYCLE_DEFAULT); + return ESP_OK; +} + +esp_err_t touch_pad_deinit() +{ + if (rtc_touch_mux == NULL) { + return ESP_FAIL; + } + touch_pad_filter_delete(); + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_SW); + touch_pad_clear_status(); + touch_pad_intr_disable(); + vSemaphoreDelete(rtc_touch_mux); + rtc_touch_mux = NULL; return ESP_OK; } @@ -501,33 +748,125 @@ esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t *touch_value) { RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG); RTC_MODULE_CHECK(touch_value != NULL, "touch_value", ESP_ERR_INVALID_ARG); - RTC_MODULE_CHECK(rtc_touch_sem != NULL, "Touch pad not initialized", ESP_FAIL); - xSemaphoreTake(rtc_touch_sem, portMAX_DELAY); - uint32_t v0 = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG); - portENTER_CRITICAL(&rtc_spinlock); - SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, (1 << (touch_num))); - //Disable Intr - CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, (1 << (touch_num + SENS_TOUCH_PAD_OUTEN2_S)) | \ - ((1 << (touch_num + SENS_TOUCH_PAD_OUTEN1_S)))); - toch_pad_io_init(touch_num); - touch_pad_counter_init(touch_num); - touch_pad_power_on(touch_num); - //force oneTime test start - SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M); - SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FORCE_M); - SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_XPD_WAIT, 10, SENS_TOUCH_XPD_WAIT_S); - portEXIT_CRITICAL(&rtc_spinlock); - while (GET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_DONE) == 0) {}; - uint8_t shift = (touch_num & 1) ? SENS_TOUCH_MEAS_OUT1_S : SENS_TOUCH_MEAS_OUT0_S; - *touch_value = READ_PERI_REG(SENS_SAR_TOUCH_OUT1_REG + (touch_num / 2) * 4) >> shift; - WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, v0); - //force oneTime test end - //clear touch force ,select the Touch mode is Timer - portENTER_CRITICAL(&rtc_spinlock); - CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M); - CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FORCE_M); - portEXIT_CRITICAL(&rtc_spinlock); - xSemaphoreGive(rtc_touch_sem); + RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL); + xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); + while (SENS.sar_touch_ctrl2.touch_meas_done == 0) {}; + *touch_value = (touch_num & 0x1) ? \ + SENS.touch_meas[touch_num / 2].l_val: \ + SENS.touch_meas[touch_num / 2].h_val; + xSemaphoreGive(rtc_touch_mux); + return ESP_OK; +} + +IRAM_ATTR esp_err_t touch_pad_read_filtered(touch_pad_t touch_num, uint16_t *touch_value) +{ + RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_FAIL); + RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(touch_value != NULL, "touch_value", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE); + + *touch_value = (s_touch_pad_filter->filtered_val[touch_num] >> TOUCH_PAD_SHIFT_DEFAULT); + return ESP_OK; +} + +esp_err_t touch_pad_set_filter_period(uint32_t new_period_ms) +{ + RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE); + RTC_MODULE_CHECK(new_period_ms > 0, "Touch pad filter period error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); + if (s_touch_pad_filter != NULL) { + xTimerChangePeriod(s_touch_pad_filter->timer, new_period_ms / portTICK_PERIOD_MS, portMAX_DELAY); + s_touch_pad_filter->period = new_period_ms; + } else { + ESP_LOGE(RTC_MODULE_TAG, "Touch pad filter deleted"); + ret = ESP_ERR_INVALID_STATE; + } + xSemaphoreGive(rtc_touch_mux); + return ret; +} + +esp_err_t touch_pad_get_filter_period(uint32_t* p_period_ms) +{ + RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE); + RTC_MODULE_CHECK(p_period_ms != NULL, "Touch pad period pointer error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); + if (s_touch_pad_filter != NULL) { + *p_period_ms = s_touch_pad_filter->period; + } else { + ESP_LOGE(RTC_MODULE_TAG, "Touch pad filter deleted"); + ret = ESP_ERR_INVALID_STATE; + } + xSemaphoreGive(rtc_touch_mux); + return ret; +} + +esp_err_t touch_pad_filter_start(uint32_t filter_period_ms) +{ + RTC_MODULE_CHECK(filter_period_ms >= portTICK_PERIOD_MS, "Touch pad filter period error", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); + if (s_touch_pad_filter == NULL) { + s_touch_pad_filter = (touch_pad_filter_t *) calloc(1, sizeof(touch_pad_filter_t)); + if (s_touch_pad_filter == NULL) { + ret = ESP_ERR_NO_MEM; + } + } + if (s_touch_pad_filter->timer == NULL) { + s_touch_pad_filter->timer = xTimerCreate("filter_tmr", filter_period_ms / portTICK_PERIOD_MS, pdTRUE, + NULL, touch_pad_filter_cb); + if (s_touch_pad_filter->timer == NULL) { + ret = ESP_ERR_NO_MEM; + } + xTimerStart(s_touch_pad_filter->timer, portMAX_DELAY); + s_touch_pad_filter->enable = true; + } else { + xTimerChangePeriod(s_touch_pad_filter->timer, filter_period_ms / portTICK_PERIOD_MS, portMAX_DELAY); + s_touch_pad_filter->period = filter_period_ms; + xTimerStart(s_touch_pad_filter->timer, portMAX_DELAY); + } + xSemaphoreGive(rtc_touch_mux); + return ret; +} + +esp_err_t touch_pad_filter_stop() +{ + RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); + if (s_touch_pad_filter != NULL) { + xTimerStop(s_touch_pad_filter->timer, portMAX_DELAY); + s_touch_pad_filter->enable = false; + } else { + ESP_LOGE(RTC_MODULE_TAG, "Touch pad filter deleted"); + ret = ESP_ERR_INVALID_STATE; + } + xSemaphoreGive(rtc_touch_mux); + return ret; +} + +esp_err_t touch_pad_filter_delete() +{ + RTC_MODULE_CHECK(s_touch_pad_filter != NULL, "Touch pad filter not initialized", ESP_ERR_INVALID_STATE); + xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); + if (s_touch_pad_filter != NULL) { + if (s_touch_pad_filter->timer != NULL) { + xTimerStop(s_touch_pad_filter->timer, portMAX_DELAY); + xTimerDelete(s_touch_pad_filter->timer, portMAX_DELAY); + s_touch_pad_filter->timer = NULL; + } + free(s_touch_pad_filter); + s_touch_pad_filter = NULL; + } + xSemaphoreGive(rtc_touch_mux); return ESP_OK; } @@ -578,7 +917,6 @@ static esp_err_t adc1_pad_init(adc1_channel_t channel) ADC1_CHECK_FUNCTION_RET(rtc_gpio_output_disable(gpio_num)); ADC1_CHECK_FUNCTION_RET(rtc_gpio_input_disable(gpio_num)); ADC1_CHECK_FUNCTION_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING)); - return ESP_OK; } diff --git a/components/esp32/ld/esp32.peripherals.ld b/components/esp32/ld/esp32.peripherals.ld index 79becfc928..2ff635f20f 100644 --- a/components/esp32/ld/esp32.peripherals.ld +++ b/components/esp32/ld/esp32.peripherals.ld @@ -3,6 +3,9 @@ PROVIDE ( SPI1 = 0x3ff42000 ); PROVIDE ( SPI0 = 0x3ff43000 ); PROVIDE ( GPIO = 0x3ff44000 ); PROVIDE ( SIGMADELTA = 0x3ff44f00 ); +PROVIDE ( RTCCNTL = 0x3ff48000 ); +PROVIDE ( RTCIO = 0x3ff48400 ); +PROVIDE ( SENS = 0x3ff48800 ); PROVIDE ( UHCI1 = 0x3ff4C000 ); PROVIDE ( I2S0 = 0x3ff4F000 ); PROVIDE ( UART1 = 0x3ff50000 ); diff --git a/components/soc/esp32/include/soc/rtc_cntl_struct.h b/components/soc/esp32/include/soc/rtc_cntl_struct.h index acb12432b0..c2a7f63c43 100644 --- a/components/soc/esp32/include/soc/rtc_cntl_struct.h +++ b/components/soc/esp32/include/soc/rtc_cntl_struct.h @@ -550,4 +550,5 @@ typedef volatile struct { uint32_t val; } date; } rtc_cntl_dev_t; +extern rtc_cntl_dev_t RTCCNTL; #endif /* _SOC_RTC_CNTL_STRUCT_H_ */ diff --git a/components/soc/esp32/include/soc/rtc_io_struct.h b/components/soc/esp32/include/soc/rtc_io_struct.h index da27078c8e..f9964e376e 100644 --- a/components/soc/esp32/include/soc/rtc_io_struct.h +++ b/components/soc/esp32/include/soc/rtc_io_struct.h @@ -277,4 +277,5 @@ typedef volatile struct { uint32_t val; } date; } rtc_io_dev_t; +extern rtc_io_dev_t RTCIO; #endif /* _SOC_RTC_IO_STRUCT_H_ */ diff --git a/components/soc/esp32/include/soc/sens_struct.h b/components/soc/esp32/include/soc/sens_struct.h new file mode 100644 index 0000000000..b0fce389df --- /dev/null +++ b/components/soc/esp32/include/soc/sens_struct.h @@ -0,0 +1,316 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _SOC_SENS_STRUCT_H_ +#define _SOC_SENS_STRUCT_H_ +typedef volatile struct { + union { + struct { + uint32_t sar1_clk_div: 8; + uint32_t sar1_sample_cycle: 8; + uint32_t sar1_sample_bit: 2; + uint32_t sar1_clk_gated: 1; + uint32_t sar1_sample_num: 8; + uint32_t sar1_dig_force: 1; + uint32_t sar1_data_inv: 1; + uint32_t reserved29: 3; + }; + uint32_t val; + } sar_read_ctrl; + uint32_t sar_read_status1; /**/ + union { + struct { + uint32_t sar_amp_wait1:16; + uint32_t sar_amp_wait2:16; + }; + uint32_t val; + } sar_meas_wait1; + union { + struct { + uint32_t sar_amp_wait3: 16; + uint32_t force_xpd_amp: 2; + uint32_t force_xpd_sar: 2; + uint32_t sar2_rstb_wait: 8; + uint32_t reserved28: 4; + }; + uint32_t val; + } sar_meas_wait2; + union { + struct { + uint32_t xpd_sar_amp_fsm: 4; + uint32_t amp_rst_fb_fsm: 4; + uint32_t amp_short_ref_fsm: 4; + uint32_t amp_short_ref_gnd_fsm: 4; + uint32_t xpd_sar_fsm: 4; + uint32_t sar_rstb_fsm: 4; + uint32_t sar2_xpd_wait: 8; + }; + uint32_t val; + } sar_meas_ctrl; + uint32_t sar_read_status2; /**/ + uint32_t ulp_cp_sleep_cyc0; /**/ + uint32_t ulp_cp_sleep_cyc1; /**/ + uint32_t ulp_cp_sleep_cyc2; /**/ + uint32_t ulp_cp_sleep_cyc3; /**/ + uint32_t ulp_cp_sleep_cyc4; /**/ + union { + struct { + uint32_t sar1_bit_width: 2; + uint32_t sar2_bit_width: 2; + uint32_t sar2_en_test: 1; + uint32_t sar2_pwdet_cct: 3; + uint32_t ulp_cp_force_start_top: 1; + uint32_t ulp_cp_start_top: 1; + uint32_t sarclk_en: 1; + uint32_t pc_init: 11; + uint32_t sar2_stop: 1; + uint32_t sar1_stop: 1; + uint32_t sar2_pwdet_en: 1; + uint32_t reserved25: 7; + }; + uint32_t val; + } sar_start_force; + union { + struct { + uint32_t mem_wr_addr_init: 11; + uint32_t mem_wr_addr_size: 11; + uint32_t rtc_mem_wr_offst_clr: 1; + uint32_t reserved23: 9; + }; + uint32_t val; + } sar_mem_wr_ctrl; + uint32_t sar_atten1; /**/ + uint32_t sar_atten2; /**/ + union { + struct { + uint32_t i2c_slave_addr1: 11; + uint32_t i2c_slave_addr0: 11; + uint32_t meas_status: 8; + uint32_t reserved30: 2; + }; + uint32_t val; + } sar_slave_addr1; + union { + struct { + uint32_t i2c_slave_addr3:11; + uint32_t i2c_slave_addr2:11; + uint32_t reserved22: 10; + }; + uint32_t val; + } sar_slave_addr2; + union { + struct { + uint32_t i2c_slave_addr5:11; + uint32_t i2c_slave_addr4:11; + uint32_t tsens_out: 8; + uint32_t tsens_rdy_out: 1; + uint32_t reserved31: 1; + }; + uint32_t val; + } sar_slave_addr3; + union { + struct { + uint32_t i2c_slave_addr7:11; + uint32_t i2c_slave_addr6:11; + uint32_t i2c_rdata: 8; + uint32_t i2c_done: 1; + uint32_t reserved31: 1; + }; + uint32_t val; + } sar_slave_addr4; + union { + struct { + uint32_t tsens_xpd_wait: 12; + uint32_t tsens_xpd_force: 1; + uint32_t tsens_clk_inv: 1; + uint32_t tsens_clk_gated: 1; + uint32_t tsens_in_inv: 1; + uint32_t tsens_clk_div: 8; + uint32_t tsens_power_up: 1; + uint32_t tsens_power_up_force: 1; + uint32_t tsens_dump_out: 1; + uint32_t reserved27: 5; + }; + uint32_t val; + } sar_tctrl; + union { + struct { + uint32_t sar_i2c_ctrl: 28; + uint32_t sar_i2c_start: 1; + uint32_t sar_i2c_start_force: 1; + uint32_t reserved30: 2; + }; + uint32_t val; + } sar_i2c_ctrl; + union { + struct { + uint32_t meas1_data_sar: 16; + uint32_t meas1_done_sar: 1; + uint32_t meas1_start_sar: 1; + uint32_t meas1_start_force: 1; + uint32_t sar1_en_pad: 12; + uint32_t sar1_en_pad_force: 1; + }; + uint32_t val; + } sar_meas_start1; + union { + struct { + uint32_t touch_meas_delay:16; + uint32_t touch_xpd_wait: 8; + uint32_t touch_out_sel: 1; + uint32_t touch_out_1en: 1; + uint32_t xpd_hall_force: 1; + uint32_t hall_phase_force: 1; + uint32_t reserved28: 4; + }; + uint32_t val; + } sar_touch_ctrl1; + union { + struct { + uint32_t l_thresh: 16; + uint32_t h_thresh: 16; + }; + uint32_t val; + } touch_thresh[5]; + union { + struct { + uint32_t l_val: 16; + uint32_t h_val: 16; + }; + uint32_t val; + } touch_meas[5]; + union { + struct { + uint32_t touch_meas_en: 10; + uint32_t touch_meas_done: 1; + uint32_t touch_start_fsm_en: 1; + uint32_t touch_start_en: 1; + uint32_t touch_start_force: 1; + uint32_t touch_sleep_cycles:16; + uint32_t touch_meas_en_clr: 1; + uint32_t reserved31: 1; + }; + uint32_t val; + } sar_touch_ctrl2; + uint32_t reserved_88; + union { + struct { + uint32_t touch_pad_worken:10; + uint32_t touch_pad_outen2:10; + uint32_t touch_pad_outen1:10; + uint32_t reserved30: 2; + }; + uint32_t val; + } sar_touch_enable; + union { + struct { + uint32_t sar2_clk_div: 8; + uint32_t sar2_sample_cycle: 8; + uint32_t sar2_sample_bit: 2; + uint32_t sar2_clk_gated: 1; + uint32_t sar2_sample_num: 8; + uint32_t sar2_pwdet_force: 1; + uint32_t sar2_dig_force: 1; + uint32_t sar2_data_inv: 1; + uint32_t reserved30: 2; + }; + uint32_t val; + } sar_read_ctrl2; + union { + struct { + uint32_t meas2_data_sar: 16; + uint32_t meas2_done_sar: 1; + uint32_t meas2_start_sar: 1; + uint32_t meas2_start_force: 1; + uint32_t sar2_en_pad: 12; + uint32_t sar2_en_pad_force: 1; + }; + uint32_t val; + } sar_meas_start2; + union { + struct { + uint32_t sw_fstep: 16; + uint32_t sw_tone_en: 1; + uint32_t debug_bit_sel: 5; + uint32_t dac_dig_force: 1; + uint32_t dac_clk_force_low: 1; + uint32_t dac_clk_force_high: 1; + uint32_t dac_clk_inv: 1; + uint32_t reserved26: 6; + }; + uint32_t val; + } sar_dac_ctrl1; + union { + struct { + uint32_t dac_dc1: 8; + uint32_t dac_dc2: 8; + uint32_t dac_scale1: 2; + uint32_t dac_scale2: 2; + uint32_t dac_inv1: 2; + uint32_t dac_inv2: 2; + uint32_t dac_cw_en1: 1; + uint32_t dac_cw_en2: 1; + uint32_t reserved26: 6; + }; + uint32_t val; + } sar_dac_ctrl2; + union { + struct { + uint32_t sar1_dac_xpd_fsm: 4; + uint32_t sar1_dac_xpd_fsm_idle: 1; + uint32_t xpd_sar_amp_fsm_idle: 1; + uint32_t amp_rst_fb_fsm_idle: 1; + uint32_t amp_short_ref_fsm_idle: 1; + uint32_t amp_short_ref_gnd_fsm_idle: 1; + uint32_t xpd_sar_fsm_idle: 1; + uint32_t sar_rstb_fsm_idle: 1; + uint32_t sar2_rstb_force: 2; + uint32_t amp_rst_fb_force: 2; + uint32_t amp_short_ref_force: 2; + uint32_t amp_short_ref_gnd_force: 2; + uint32_t reserved19: 13; + }; + uint32_t val; + } sar_meas_ctrl2; + uint32_t reserved_a4; + uint32_t reserved_a8; + uint32_t reserved_ac; + uint32_t reserved_b0; + uint32_t reserved_b4; + uint32_t reserved_b8; + uint32_t reserved_bc; + uint32_t reserved_c0; + uint32_t reserved_c4; + uint32_t reserved_c8; + uint32_t reserved_cc; + uint32_t reserved_d0; + uint32_t reserved_d4; + uint32_t reserved_d8; + uint32_t reserved_dc; + uint32_t reserved_e0; + uint32_t reserved_e4; + uint32_t reserved_e8; + uint32_t reserved_ec; + uint32_t reserved_f0; + uint32_t reserved_f4; + uint32_t sar_nouse; /**/ + union { + struct { + uint32_t sar_date: 28; + uint32_t reserved28: 4; + }; + uint32_t val; + } sardate; +} sens_dev_t; +extern sens_dev_t SENS; +#endif /* _SOC_SENS_STRUCT_H_ */ diff --git a/docs/Doxyfile b/docs/Doxyfile index 1873be46d3..c8e2364c48 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -72,6 +72,7 @@ INPUT = \ ../components/driver/include/driver/spi_master.h \ ../components/driver/include/driver/spi_slave.h \ ../components/driver/include/driver/timer.h \ + ../components/driver/include/driver/touch_pad.h \ ../components/driver/include/driver/uart.h \ ## ## Protocols - API Reference diff --git a/docs/api-reference/peripherals/index.rst b/docs/api-reference/peripherals/index.rst index 491d98033f..51a46febd4 100644 --- a/docs/api-reference/peripherals/index.rst +++ b/docs/api-reference/peripherals/index.rst @@ -18,6 +18,7 @@ Peripherals API SPI Master SPI Slave Timer + Touch pad UART Example code for this API section is provided in :example:`peripherals` directory of ESP-IDF examples. diff --git a/docs/api-reference/peripherals/touch_pad.rst b/docs/api-reference/peripherals/touch_pad.rst new file mode 100644 index 0000000000..274d694db3 --- /dev/null +++ b/docs/api-reference/peripherals/touch_pad.rst @@ -0,0 +1,23 @@ +Touch sensor +=========== + +Overview +-------- + +A touch-sensor system is built on a substrate which carries electrodes and relevant connections under a protective flat surface. +When a user touches the surface, the capacitance variation is triggered and a binary signal is generated to indicate whether the touch is valid. + +ESP32 can provide up to 10 capacitive touch pads / GPIOs. The sensing pads can be arranged in different combinations, +so that a larger area or more points can be detected. The touch pad sensing process is under the control of a hardware-implemented finite-state machine (FSM) which is initiated by software or a dedicated hardware timer. + +Application Example +------------------- + +Touch sensor read example: :example:`peripherals/touch_pad_read`. +Touch sensor interrupt example: :example:`peripherals/touch_pad_interrupt`. + +API Reference +------------- + +.. include:: /_build/inc/touch_pad.inc + diff --git a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c index 490d8683ec..a1c58762a7 100644 --- a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c +++ b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c @@ -16,13 +16,16 @@ #include "soc/sens_reg.h" static const char* TAG = "Touch pad"; +#define TOUCH_THRESH_NO_USE (0) +#define TOUCH_THRESH_PERCENT (99) static bool s_pad_activated[TOUCH_PAD_MAX]; +static uint32_t s_pad_init_val[TOUCH_PAD_MAX]; /* Read values sensed at all available touch pads. - Use half of read value as the threshold + Use 2 / 3 of read value as the threshold to trigger interrupt when the pad is touched. Note: this routine demonstrates a simple way to configure activation threshold for the touch pads. @@ -32,9 +35,17 @@ static bool s_pad_activated[TOUCH_PAD_MAX]; static void tp_example_set_thresholds(void) { uint16_t touch_value; - for (int i=0; i> i) & 0x01) { - s_pad_activated[i] = true; - } + touch_pad_clear_status(); + for (int i = 0; i < TOUCH_PAD_MAX; i++) { + if ((pad_intr >> i) & 0x01) { + s_pad_activated[i] = true; } } } +/* + * Before reading touch pad, we need to initialize the RTC IO. + */ +static void tp_example_touch_pad_init() +{ + for (int i = 0;i< TOUCH_PAD_MAX;i++) { + //init RTC IO and mode for touch pad. + touch_pad_config(i, TOUCH_THRESH_NO_USE); + } +} void app_main() { - // Initialize touch pad peripheral + // Initialize touch pad peripheral, it will start a timer to run a filter ESP_LOGI(TAG, "Initializing touch pad"); touch_pad_init(); + + // Initialize and start a software filter to detect slight change of capacitance. + touch_pad_filter_start(10); + // Set measuring time and sleep time + // In this case, measurement will sustain 0xffff / 8Mhz = 8.19ms + // Meanwhile, sleep time between two measurement will be 0x1000 / 150Khz = 27.3 ms + touch_pad_set_meas_time(0x1000, 0xffff); + + //set reference voltage for charging/discharging + // In this case, the high reference valtage will be 2.4V - 1.5V = 0.9V + // The low reference voltage will be 0.8V, so that the procedure of charging + // and discharging would be very fast. + touch_pad_set_voltage(TOUCH_HVOLT_2V4, TOUCH_LVOLT_0V8, TOUCH_HVOLT_ATTEN_1V5); + // Init touch pad IO + tp_example_touch_pad_init(); + // Set thresh hold tp_example_set_thresholds(); - touch_pad_isr_handler_register(tp_example_rtc_intr, NULL, 0, NULL); + // Register touch interrupt ISR + touch_pad_isr_register(tp_example_rtc_intr, NULL); // Start a task to show what pads have been touched xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL); diff --git a/examples/peripherals/touch_pad_read/main/tp_read_main.c b/examples/peripherals/touch_pad_read/main/tp_read_main.c index da7baa6baf..def1dacf07 100644 --- a/examples/peripherals/touch_pad_read/main/tp_read_main.c +++ b/examples/peripherals/touch_pad_read/main/tp_read_main.c @@ -9,24 +9,78 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" - #include "driver/touch_pad.h" - +#define TOUCH_TEST_LOOP_NUM (10) +#define TOUCH_PAD_NO_CHANGE (-1) +#define TOUCH_THRESH_NO_USE (0) /* Read values sensed at all available touch pads. - Print out values in a loop on a serial monitor. + Print out values in a loop on a serial monitor. */ static void tp_example_read_task(void *pvParameter) { while (1) { uint16_t touch_value; - for (int i=0; i