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. - * - * @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 intr_alloc_flags, touch_isr_handle_t *handle); - +esp_err_t touch_pad_isr_handler_register(void(*fn)(void *), void *arg, int unused, intr_handle_t *handle_unused) __attribute__ ((deprecated)); /** - * *************** 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. + * @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_register(intr_handler_t fn, void* arg); + /** - *----------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 + * @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); + /** - *----------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 - **/ + * @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) { - xSemaphoreTake(rtc_touch_sem, portMAX_DELAY); + 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_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); -} - -esp_err_t touch_pad_deinit() -{ - - if(rtc_touch_sem == NULL) { - return ESP_FAIL; - } - vSemaphoreDelete(rtc_touch_sem); - rtc_touch_sem=NULL; + portEXIT_CRITICAL(&rtc_spinlock); return ESP_OK; } -static void touch_pad_counter_init(touch_pad_t touch_num) +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); + 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 > TOUCH_HVOLT_KEEP) { + RTCIO.touch_cfg.drefh = refh; + } + if (refl > TOUCH_LVOLT_KEEP) { + RTCIO.touch_cfg.drefl = refl; + } + if (atten > TOUCH_HVOLT_ATTEN_KEEP) { + RTCIO.touch_cfg.drange = atten; + } portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; } -static void touch_pad_power_on(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 Touch Pad Power on - SET_PERI_REG_MASK(RTC_IO_TOUCH_PAD0_REG + touch_num * 4, RTC_IO_TOUCH_PAD0_XPD_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; } -static void toch_pad_io_init(touch_pad_t touch_num) +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; +} + +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); + 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; +} + +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(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((mode < TOUCH_FSM_MODE_MAX), "touch fsm mode error", ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); - - //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))); + 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() +{ + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_touch_ctrl2.touch_meas_en_clr = 1; + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +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