Pada contoh ini, kita aktifkan interupt pada dua channel sensor sentuh untuk menghitung sentuhan pada pin dan menampilkan statistik dalam periodic FreeRTOS task.
Digunakan dua hook-up kabel dengan pin jantan untuk tujuan ini. Terhubung ke GPIO32 (Touch 9) dan GPIO33 (Touch 8) dari devkit ESP32.
//bagian import library
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/touch_pad.h"
#include <string.h>
static portMUX_TYPE mut = portMUX_INITIALIZER_UNLOCKED;
typedef struct
{
int pin_num;
TickType_t when;
} touch_info_t;
#define TI_LIST_SIZE 10
static volatile touch_info_t ti_list[TI_LIST_SIZE];
static volatile size_t ti_cnt = 0;
static const TickType_t check_period = 500 / portTICK_PERIOD_MS;
//bagian touch handler
static void IRAM_ATTR tp_handler(void *arg)
{
uint32_t pad_intr = touch_pad_get_status();
touch_pad_clear_status();
touch_info_t touch = {
.pin_num = (pad_intr >> TOUCH_PAD_NUM8) & 0x01 ? TOUCH_PAD_NUM8 : TOUCH_PAD_NUM9,
.when = xTaskGetTickCountFromISR()};
portENTER_CRITICAL_SAFE(&mut);
if (ti_cnt < TI_LIST_SIZE)
{
bool skip = (ti_cnt > 0) && ((touch.when - ti_list[ti_cnt - 1].when) < check_period) && (touch.pin_num == ti_list[ti_cnt - 1].pin_num);
if (!skip)
{
ti_list[ti_cnt++] = touch;
}
}
portEXIT_CRITICAL_SAFE(&mut);
}
//bagian fungsi monitor
static void monitor(void *arg)
{
touch_info_t ti_list_local[TI_LIST_SIZE];
size_t ti_cnt_local;
while (1)
{
vTaskDelay(10000 / portTICK_PERIOD_MS);
ti_cnt_local = 0;
portENTER_CRITICAL_SAFE(&mut);
if (ti_cnt > 0)
{
memcpy((void *)ti_list_local, (const void *)ti_list, ti_cnt * sizeof(touch_info_t));
ti_cnt_local = ti_cnt;
ti_cnt = 0;
}
portEXIT_CRITICAL_SAFE(&mut);
if (ti_cnt_local > 0)
{
int t8_cnt = 0;
for (int i = 0; i < ti_cnt_local; ++i)
{
if (ti_list_local[i].pin_num == TOUCH_PAD_NUM8)
{
++t8_cnt;
}
}
printf("First touch tick: %u\n", ti_list_local[0].when);
printf("Last touch tick: %u\n", ti_list_local[ti_cnt_local - 1].when);
printf("Touch8 count: %d\n", t8_cnt);
printf("Touch9 count: %d\n", ti_cnt_local - t8_cnt);
}
else
{
printf("No touch detected\n");
}
}
}
//bagian init hardware
static void init_hw(void)
{
touch_pad_init();
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5,
TOUCH_HVOLT_ATTEN_1V);
touch_pad_config(TOUCH_PAD_NUM8, 0);
touch_pad_config(TOUCH_PAD_NUM9, 0);
touch_pad_filter_start(10);
uint16_t val;
touch_pad_read_filtered(TOUCH_PAD_NUM8, &val);
touch_pad_set_thresh(TOUCH_PAD_NUM8, val * 0.2);
touch_pad_read_filtered(TOUCH_PAD_NUM9, &val);
touch_pad_set_thresh(TOUCH_PAD_NUM9, val * 0.2);
touch_pad_isr_register(tp_handler, NULL);
}
//bagian main function
void app_main(void)
{
init_hw();
TaskHandle_t taskh;
if (xTaskCreatePinnedToCore(monitor, "monitor", 1024, NULL, 2, &taskh, APP_CPU_NUM) == pdPASS)
{
printf("info: monitor started\n");
}
else
{
printf("err: monitor task couldn't start\n");
}
char buffer[128];
vTaskList(buffer);
printf("%s\n", buffer);
touch_pad_intr_enable();
}
Penjelasan Code
Bagian Import Library
Untuk touchpad driver digunakan file header driver/touch_pad.h yang berisi fungsi dan type definitions. Kita gunakan mutex type portMUX_TYPE untuk menjaga shared resources dari akses secara berasamaan. Mutex type definition adalah spesifik ESP-IDF. Shared
resources yang kita gunakan adalah ti_list dan ti_cnt,
Bagian Touch Handler
Fungsi tp_handler adalah ISR untuk device touch. Jika terdeteksi sentuhan pada salah satu dari dua channels, ISR akan dijalankan. touch peripheral dibaca dengan menggunakan perintah touch_pad_get_status untuk mengetahui pin mana yang disentuh dan menyimpan informasi dalam variable touch, bersamaan dengan informasi waktu dalam ticks, dengan menggunakan fungsi xTaskGetTickCountFromISR.
Perhatian, Untuk beberapa fungsi, FreeRTOS menyediakan 2 versi. Jika fungsi berakhiran FromISR, berarti ISR version untuk fungsi bersangkutan. Jika tanpa suffix, berarti dipanggil dari task.
Kemudian, kita masuk ke bagian critical dengan memamnggil macro portENTER_CRITICAL_SAFE dengan alamat mutex. Bagian ini critical karena nilai ti_list dan ti_cnt akan dimodifikasi dan nilainya harus konsisten.
Untuk tetap konsisten, kita harus mencegah setiap akses pada saat melakukan modifikasi. Setelah selesai proses modifikasi, jalankan perintah portEXIT_CRITICAL_SAFE untuk free mutex, supaya shared resources dapat diakses dari task lainnya.
Bagian Fungsi Monitor
monitor adalah task function dimana kita akan print informasi touch yang setiap 10 seconds.
Dalam while loop, kembali kita gunakan portENTER_CRITICAL_SAFE dan portEXIT_CRITICAL_SAFE untuk mengakses nilai ti_list dan ti_cnt.
Hal crucial disini adalah dilakukan proses copy values dari shared resources ke local variables, ti_list_local and ti_cnt_local, dengan tujuan proses critical section secepat mungkin, supaya shared resources segera tersedia untuk interrupt handler.
Sisa dari fungsi ini adalah melakukan proses print statistik yang telah dicopy ke local variable.
Bagian Init Hardware
Pada fungsi the init_hw, kita inisialisasi device touch. Pertama inisialisasi driver, kemudian batasi state machine mode dari device dan voltage reference values.
Berikutnya adalah melakukan kalibrasi touch pins 8 dan 9 dengan nilai threshold sebagai interrupt trigger. Saat melakukan kalibrasi, pastikan tidak ada kontak terhadap pins.
Terakhir kita set tp_handler sebagai ISR touch interrupt.
Bagian Main Function
PErtama kita panggil fungsi init_hw , lalu buat monitor task dengan perintah xTaskCreatePinnedToCore, parameter yang digunakan adalah:
- Fungsi untuk dijalanakan sebagai task, dalam hal ini fungsi monitor.
- Nama dari task untuk keperluan diagnostic.
- Ukuran stack untuk digunakan oleh task dalam bytes. (Pada vanilla FreeRTOS dalam words). Jika tidak diset lebih besar dari jumlah yang dibutuhkan oleh task, aplikasi akan crash.
- void* parameter untuk task function, dalam hal ini fungsi monitor tidak memerlukan, jadi digunakan NULL.
- Prioritas dari task, low value berarti prioritas rendah.
- Address dari task handle. Jika disediakan, fungsi xTaskCreate* akan mengatur valuenya dan kita dapat menggunakan task handle untuk memanage task (seperti suspending, resuming atau deleting).
- Core yang digunakan untuk menjalankan task. Parameter ini spesifik untuk perintah xTaskCreatePinnedToCore, yang hanya tersedia pada ESP-IDF FreeRTOS.
Kita dapat lihat task saat ini dengan perintah vTaskList dengan parameter buffer. Fungsi monitor akan ditampilkan dalam output.
Terakhir adalah enable interupts.
Sebelum mengcompile code, kita ubah platformio.ini, tambahkan konfigurasi berikut:
monitor_speed = 115200 build_flags = -DCONFIG_FREERTOS_USE_TRACE_FACILITY=1 -DCONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=1
Sekarang kita kompile dan upload ke ESP32 devkit. Untuk test aplikasi, kita cukup sentuh hookup wires. Dapat kita lihat pada serial monitors, task monitor akan menampilkan touch
statistics setiap 10 seconds.