-
Notifications
You must be signed in to change notification settings - Fork 7k
/
tp_interrupt_main.c
171 lines (155 loc) · 6.14 KB
/
tp_interrupt_main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/* Touch Pad Interrupt Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "driver/touch_pad.h"
#include "soc/rtc_periph.h"
#include "soc/sens_periph.h"
static const char *TAG = "Touch pad";
#define TOUCH_THRESH_NO_USE (0)
#define TOUCH_THRESH_PERCENT (80)
#define TOUCHPAD_FILTER_TOUCH_PERIOD (10)
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 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.
Do not touch any pads when this routine
is running (on application start).
*/
static void tp_example_set_thresholds(void)
{
uint16_t touch_value;
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
//read filtered value
touch_pad_read_filtered(i, &touch_value);
s_pad_init_val[i] = touch_value;
ESP_LOGI(TAG, "test init: touch pad [%d] val is %d", i, touch_value);
//set interrupt threshold.
ESP_ERROR_CHECK(touch_pad_set_thresh(i, touch_value * 2 / 3));
}
}
/*
Check if any of touch pads has been activated
by reading a table updated by rtc_intr()
If so, then print it out on a serial monitor.
Clear related entry in the table afterwards
In interrupt mode, the table is updated in touch ISR.
In filter mode, we will compare the current filtered value with the initial one.
If the current filtered value is less than 80% of the initial value, we can
regard it as a 'touched' event.
When calling touch_pad_init, a timer will be started to run the filter.
This mode is designed for the situation that the pad is covered
by a 2-or-3-mm-thick medium, usually glass or plastic.
The difference caused by a 'touch' action could be very small, but we can still use
filter mode to detect a 'touch' event.
*/
static void tp_example_read_task(void *pvParameter)
{
static int show_message;
int change_mode = 0;
int filter_mode = 0;
while (1) {
if (filter_mode == 0) {
//interrupt mode, enable touch interrupt
touch_pad_intr_enable();
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
if (s_pad_activated[i] == true) {
ESP_LOGI(TAG, "T%d activated!", i);
// Wait a while for the pad being released
vTaskDelay(200 / portTICK_PERIOD_MS);
// Clear information on pad activation
s_pad_activated[i] = false;
// Reset the counter triggering a message
// that application is running
show_message = 1;
}
}
} else {
//filter mode, disable touch interrupt
touch_pad_intr_disable();
touch_pad_clear_status();
for (int i = 0; i < TOUCH_PAD_MAX; i++) {
uint16_t value = 0;
touch_pad_read_filtered(i, &value);
if (value < s_pad_init_val[i] * TOUCH_THRESH_PERCENT / 100) {
ESP_LOGI(TAG, "T%d activated!", i);
ESP_LOGI(TAG, "value: %d; init val: %d", value, s_pad_init_val[i]);
vTaskDelay(200 / portTICK_PERIOD_MS);
// Reset the counter to stop changing mode.
change_mode = 1;
show_message = 1;
}
}
}
vTaskDelay(10 / portTICK_PERIOD_MS);
// If no pad is touched, every couple of seconds, show a message
// that application is running
if (show_message++ % 500 == 0) {
ESP_LOGI(TAG, "Waiting for any pad being touched...");
}
// Change mode if no pad is touched for a long time.
// We can compare the two different mode.
if (change_mode++ % 2000 == 0) {
filter_mode = !filter_mode;
ESP_LOGW(TAG, "Change mode...%s", filter_mode == 0 ? "interrupt mode" : "filter mode");
}
}
}
/*
Handle an interrupt triggered when a pad is touched.
Recognize what pad has been touched and save it in a table.
*/
static void tp_example_rtc_intr(void *arg)
{
uint32_t pad_intr = touch_pad_get_status();
//clear interrupt
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(void)
{
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(void)
{
// Initialize touch pad peripheral, it will start a timer to run a filter
ESP_LOGI(TAG, "Initializing touch pad");
ESP_ERROR_CHECK(touch_pad_init());
// If use interrupt trigger mode, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'.
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
// Set reference voltage for charging/discharging
// For most usage scenarios, we recommend using the following combination:
// the high reference valtage will be 2.7V - 1V = 1.7V, The low reference voltage will be 0.5V.
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
// Init touch pad IO
tp_example_touch_pad_init();
// Initialize and start a software filter to detect slight change of capacitance.
touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD);
// Set thresh hold
tp_example_set_thresholds();
// 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);
}