feat!: main structure of handle changed to double pointer
This commit is contained in:
1 parent
73a2b00c2a
commit
be6f843c9a
5 files changed
+319
-160
No files matched your search
@@ -1,26 +1,27 @@
|
|||||||
# ESP32 ESP-IDF component for TTP229 touch pad (via RMT driver)
|
# ESP32 ESP-IDF component for TTP229 touch pad (via RMT driver)
|
||||||
|
|
||||||
## Tested on
|
|
||||||
|
|
||||||
1. [ESP32 ESP-IDF v6.0.0](https://docs.espressif.com/projects/esp-idf/en/v6.0/esp32/index.html)
|
|
||||||
|
|
||||||
## SAST Tools
|
## SAST Tools
|
||||||
|
|
||||||
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
|
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
1. Support up to 4 touch pads on one device (depends on the used ESP32 chip).
|
1. Support for 8-pad and 16-pad TTP229 configurations.
|
||||||
2. Support 8 or 16 pad work mode.
|
2. RMT-based SPI-like communication without GPIO bit-banging.
|
||||||
|
3. Multi-device support with unique device numbering.
|
||||||
|
4. FreeRTOS task for debouncing and event dispatching.
|
||||||
|
5. Error statistics tracking (RMT driver, event post, queue overflow, stack).
|
||||||
|
6. Event-based API via esp_event framework.
|
||||||
|
7. IRAM-safe ISR handler and RMT callback.
|
||||||
|
|
||||||
## Note
|
## Attention
|
||||||
|
|
||||||
1. After start/reset first touch not work.
|
1. After start/reset first touch not work.
|
||||||
2. Multi touch not supported.
|
2. Multi touch not supported.
|
||||||
|
|
||||||
## Attention
|
## Note
|
||||||
|
|
||||||
1. For correct operation, please enable the following settings in the menuconfig:
|
Enable the following settings in menuconfig:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
CONFIG_GPIO_CTRL_FUNC_IN_IRAM
|
CONFIG_GPIO_CTRL_FUNC_IN_IRAM
|
||||||
@@ -36,7 +37,7 @@ CONFIG_RMT_RX_ISR_CACHE_SAFE
|
|||||||
|
|
||||||
In an existing project, run the following command to install the components:
|
In an existing project, run the following command to install the components:
|
||||||
|
|
||||||
```text
|
```bash
|
||||||
cd ../your_project/components
|
cd ../your_project/components
|
||||||
git clone https://github.com/aZholtikov/zh_ttp229
|
git clone https://github.com/aZholtikov/zh_ttp229
|
||||||
```
|
```
|
||||||
@@ -47,16 +48,14 @@ In the application, add the component:
|
|||||||
#include "zh_ttp229.h"
|
#include "zh_ttp229.h"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Examples
|
## Example
|
||||||
|
|
||||||
One touch pad on device:
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include "zh_ttp229.h"
|
#include "zh_ttp229.h"
|
||||||
|
|
||||||
#define TTP229_NUMBER 0x01
|
#define TTP229_NUMBER 0x01
|
||||||
|
|
||||||
zh_ttp229_handle_t ttp229_handle = {0};
|
zh_ttp229_handle_t *ttp229_handle = NULL;
|
||||||
|
|
||||||
void zh_ttp229_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
void zh_ttp229_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
description: ESP32 ESP-IDF component for TTP229 touch pad (via RMT driver)
|
||||||
|
url: https://github.com/aZholtikov/zh_ttp229
|
||||||
|
version: "2.0.0"
|
||||||
|
license: "Apache-2.0"
|
||||||
|
maintainers:
|
||||||
|
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
|
||||||
|
dependencies:
|
||||||
|
idf: ">=5.0"
|
||||||
|
zh_vector:
|
||||||
|
git: "https://github.com/aZholtikov/zh_vector.git"
|
||||||
|
version: "dev"
|
||||||
+89
-60
@@ -1,5 +1,22 @@
|
|||||||
/**
|
/**
|
||||||
* @file zh_ttp229.h
|
* @file zh_ttp229.h
|
||||||
|
*
|
||||||
|
* @brief Driver for TTP229 capacitive touch pad controller via SPI-like
|
||||||
|
* interface (SCL/SDO) using ESP-IDF RMT peripheral.
|
||||||
|
*
|
||||||
|
* This module provides a FreeRTOS-based driver for the TTP229 touch
|
||||||
|
* controller. It uses the RMT transmitter to generate SCL clock pulses
|
||||||
|
* and the RMT receiver to capture SDO data, enabling reading of touch
|
||||||
|
* status from 8 or 16 pad configurations. Each touch event triggers an
|
||||||
|
* ISR that initiates RMT transfer and posts an event with the touched
|
||||||
|
* pad number.
|
||||||
|
*
|
||||||
|
* Key features:
|
||||||
|
* - Supports 8-pad and 16-pad TTP229 configurations
|
||||||
|
* - RMT-based SPI-like communication (no GPIO bit-banging)
|
||||||
|
* - FreeRTOS task for debouncing and event dispatching
|
||||||
|
* - Per-device unique numbering for multi-device support
|
||||||
|
* - Error statistics tracking (RMT, queue, stack)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -11,10 +28,8 @@
|
|||||||
#include "driver/rmt_rx.h"
|
#include "driver/rmt_rx.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
|
#include "zh_vector.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief TTP229 touch pad initial default values.
|
|
||||||
*/
|
|
||||||
#define ZH_TTP229_INIT_CONFIG_DEFAULT() \
|
#define ZH_TTP229_INIT_CONFIG_DEFAULT() \
|
||||||
{ \
|
{ \
|
||||||
.task_priority = 1, \
|
.task_priority = 1, \
|
||||||
@@ -32,108 +47,122 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern TaskHandle_t zh_ttp229; /*!< Unique task handle. */
|
/**
|
||||||
|
* @brief External task handle for the TTP229 ISR processing task.
|
||||||
|
*/
|
||||||
|
extern TaskHandle_t zh_ttp229;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enumeration of TTP229 touch pad work mode.
|
* @brief Opaque handle returned by zh_ttp229_init().
|
||||||
|
*
|
||||||
|
* Internal fields are defined in zh_ttp229.c. Users must not access
|
||||||
|
* the handle's members directly.
|
||||||
|
*/
|
||||||
|
typedef struct _zh_ttp229_handle_t zh_ttp229_handle_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TTP229 touch pad work mode (number of pads).
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
ZH_TTP229_8_PAD = 8,
|
ZH_TTP229_8_PAD = 8, /*!< 8-pad TTP229 configuration */
|
||||||
ZH_TTP229_16_PAD = 16,
|
ZH_TTP229_16_PAD = 16, /*!< 16-pad TTP229 configuration */
|
||||||
} zh_ttp229_work_mode_t;
|
} zh_ttp229_work_mode_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Structure for initial initialization of TTP229 touch pad.
|
* @brief Configuration structure for TTP229 initialization.
|
||||||
|
*
|
||||||
|
* Use ZH_TTP229_INIT_CONFIG_DEFAULT() to obtain sensible defaults
|
||||||
|
* and override only the fields that differ from defaults.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint16_t stack_size; /*!< Stack size for task for the TTP229 touch pad isr processing processing. @note The minimum size is configMINIMAL_STACK_SIZE. */
|
uint16_t stack_size; /*!< Task stack size in bytes. @note Minimum: configMINIMAL_STACK_SIZE */
|
||||||
uint16_t debounce_time; /*!< Touch pad button debounce time. @note Minimum value is 10 (in milliseconds). */
|
uint16_t debounce_time; /*!< Button debounce time in milliseconds. @note Minimum: 10 ms */
|
||||||
uint8_t task_priority; /*!< Task priority for the TTP229 touch pad isr processing. @note Minimum value is 1. */
|
uint8_t task_priority; /*!< FreeRTOS task priority. @note Minimum: 1 */
|
||||||
uint8_t queue_size; /*!< Queue size for task for the touch pad processing. @note Minimum value is 1. */
|
uint8_t queue_size; /*!< Event queue depth. @note Minimum: 1 */
|
||||||
uint8_t device_number; /*!< Touch pad unique number. @note Must be greater than 0. */
|
uint8_t device_number; /*!< Unique device identifier. @note Must be > 0 */
|
||||||
uint8_t rmt_tx_start_delay; /*!< The time between the low-level pulse in the interrupt and the actual start time of the RMT signal generator (in microseconds). @note Minimum value is 15. */
|
uint8_t rmt_tx_start_delay; /*!< RMT TX delay in microseconds after SDO interrupt. @note Minimum: 15 us */
|
||||||
gpio_num_t sdo_gpio; /*!< SDO GPIO. */
|
gpio_num_t sdo_gpio; /*!< SDO (Serial Data Out) GPIO pin */
|
||||||
gpio_num_t scl_gpio; /*!< SCL GPIO. */
|
gpio_num_t scl_gpio; /*!< SCL (Serial Clock) GPIO pin */
|
||||||
zh_ttp229_work_mode_t work_mode; /*!< Touch pad work mode. */
|
zh_ttp229_work_mode_t work_mode; /*!< Touch pad configuration (8 or 16 pads) */
|
||||||
} zh_ttp229_init_config_t;
|
} zh_ttp229_init_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief TTP229 touch pad handle.
|
* @brief Error and runtime statistics for the TTP229 driver.
|
||||||
|
*
|
||||||
|
* Retrieved via zh_ttp229_get_stats(). Reset with zh_ttp229_reset_stats().
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool is_initialized; /*!< Touch pad initialization flag. */
|
uint32_t rmt_driver_error; /*!< Count of RMT driver errors */
|
||||||
gpio_num_t sdo_gpio; /*!< SDO GPIO. */
|
uint32_t event_post_error; /*!< Count of esp_event_post failures */
|
||||||
uint8_t device_number; /*!< Touch pad unique number. */
|
uint32_t queue_overflow_error; /*!< Count of event queue overflows */
|
||||||
uint8_t rmt_tx_start_delay; /*!< The time between the low-level pulse in the interrupt and the actual start time of the RMT signal generator (in microseconds). */
|
uint32_t min_stack_size; /*!< Minimum free stack (bytes) observed */
|
||||||
uint16_t debounce_time; /*!< Touch pad button debounce_time. */
|
|
||||||
zh_ttp229_work_mode_t work_mode; /*!< Touch pad work mode. */
|
|
||||||
rmt_symbol_word_t rx_symbols; /*!< Received symbols. */
|
|
||||||
rmt_channel_handle_t tx_channel; /*!< Unique RMT TX device handle. */
|
|
||||||
rmt_channel_handle_t rx_channel; /*!< Unique RMT RX device handle. */
|
|
||||||
rmt_encoder_handle_t copy_encoder; /*!< Unique copy encoder handle. */
|
|
||||||
} zh_ttp229_handle_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Structure for error statistics storage.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t rmt_driver_error; /*!< Number of RMT driver error. */
|
|
||||||
uint32_t event_post_error; /*!< Number of event post error. */
|
|
||||||
uint32_t queue_overflow_error; /*!< Number of queue overflow error. */
|
|
||||||
uint32_t min_stack_size; /*!< Minimum free stack size. */
|
|
||||||
} zh_ttp229_stats_t;
|
} zh_ttp229_stats_t;
|
||||||
|
|
||||||
ESP_EVENT_DECLARE_BASE(ZH_TTP229);
|
ESP_EVENT_DECLARE_BASE(ZH_TTP229);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Structure for sending data to the event handler when cause an interrupt.
|
* @brief Event payload delivered on touch detection.
|
||||||
*
|
*
|
||||||
* @note Should be used with ZH_TTP229 event base.
|
* Should be used with the ZH_TTP229 event base.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t pad_number; /*!< The pad that caused the interrupt. */
|
uint8_t pad_number; /*!< Number of the pad that triggered the interrupt (1-based) */
|
||||||
uint8_t device_number; /*!< Touch pad unique number. */
|
uint8_t device_number; /*!< Unique device identifier matching the init config */
|
||||||
} zh_ttp229_event_on_isr_t;
|
} zh_ttp229_event_on_isr_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize TTP229 touch pad.
|
* @brief Initialize the TTP229 touch pad driver.
|
||||||
*
|
*
|
||||||
* @param[in] config Pointer to TTP229 initialized configuration structure. Can point to a temporary variable.
|
* Allocates a handle, validates the configuration, initializes RMT
|
||||||
* @param[out] handle Pointer to unique TTP229 handle.
|
* TX/RMT channels, installs the GPIO ISR handler, and creates the
|
||||||
|
* processing task. Supports multiple devices via unique device
|
||||||
|
* numbers.
|
||||||
*
|
*
|
||||||
* @attention I2C driver must be initialized first.
|
* @param[in] config Pointer to initialization configuration (must not be NULL)
|
||||||
|
* @param[out] handle Pointer to unique touch pad handle (must not be NULL)
|
||||||
*
|
*
|
||||||
* @note Before initialize the expander recommend initialize zh_ttp229_init_config_t structure with default values.
|
* @return ESP_OK on success
|
||||||
*
|
* @return ESP_ERR_INVALID_ARG if config or handle is NULL, or if any configuration value is out of range
|
||||||
* @code zh_ttp229_init_config_t config = ZH_TTP229_INIT_CONFIG_DEFAULT() @endcode
|
* @return ESP_ERR_INVALID_STATE if the device is already initialized
|
||||||
*
|
* @return ESP_FAIL on resource allocation or peripheral failure
|
||||||
* @return ESP_OK if success or an error code otherwise.
|
|
||||||
*/
|
*/
|
||||||
esp_err_t zh_ttp229_init(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t *handle);
|
esp_err_t zh_ttp229_init(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t **handle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deinitialize TTP229 touch pad.
|
* @brief Deinitialize a TTP229 touch pad instance.
|
||||||
*
|
*
|
||||||
* @param[in] handle Pointer to unique TTP229 handle.
|
* Disables RMT channels, removes the GPIO ISR handler, frees the
|
||||||
|
* handle, and removes the device from the internal device list.
|
||||||
|
* The processing task and shared resources are deleted only when
|
||||||
|
* the last device is deinitialized.
|
||||||
*
|
*
|
||||||
* @return ESP_OK if success or an error code otherwise.
|
* @param[in,out] handle Pointer to unique touch pad handle (must not be NULL)
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
* @return ESP_ERR_INVALID_ARG if handle is NULL or points to a device not found in the internal list
|
||||||
*/
|
*/
|
||||||
esp_err_t zh_ttp229_deinit(zh_ttp229_handle_t *handle);
|
esp_err_t zh_ttp229_deinit(zh_ttp229_handle_t **handle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get error statistics.
|
* @brief Retrieve a pointer to the current error statistics.
|
||||||
*
|
*
|
||||||
* @return Pointer to the statistics structure.
|
* The returned pointer remains valid until zh_ttp229_reset_stats()
|
||||||
|
* is called or the module is deinitialized.
|
||||||
|
*
|
||||||
|
* @return Pointer to the static zh_ttp229_stats_t structure
|
||||||
*/
|
*/
|
||||||
const zh_ttp229_stats_t *zh_ttp229_get_stats(void);
|
const zh_ttp229_stats_t *zh_ttp229_get_stats(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset error statistics.
|
* @brief Reset all error and runtime statistics to zero.
|
||||||
|
*
|
||||||
|
* Call this function to clear accumulated counters. The
|
||||||
|
* min_stack_size field is also cleared and will be updated on the
|
||||||
|
* next processing cycle.
|
||||||
*/
|
*/
|
||||||
void zh_ttp229_reset_stats(void);
|
void zh_ttp229_reset_stats(void);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
1.0.1
|
2.0.0
|
||||||
+205
-85
@@ -13,96 +13,208 @@ static const char *TAG = "zh_ttp229";
|
|||||||
return err; \
|
return err; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ZH_ERROR_CHECK_CONT(cond, cleanup, msg, ...) \
|
||||||
|
if (!(cond)) \
|
||||||
|
{ \
|
||||||
|
ZH_LOGE(msg, ESP_FAIL, ##__VA_ARGS__); \
|
||||||
|
cleanup; \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Internal handle for a single TTP229 device instance.
|
||||||
|
*
|
||||||
|
* Fields are initialized by zh_ttp229_init() and used by the
|
||||||
|
* ISR handler, processing task, and deinitialization.
|
||||||
|
*/
|
||||||
|
struct _zh_ttp229_handle_t
|
||||||
|
{
|
||||||
|
gpio_num_t sdo_gpio; /*!< SDO (Serial Data Out) GPIO pin for touch data */
|
||||||
|
uint8_t device_number; /*!< Unique device number assigned at initialization */
|
||||||
|
uint8_t rmt_tx_start_delay; /*!< Time between SDO low-level pulse and RMT TX start (in microseconds) */
|
||||||
|
uint16_t debounce_time; /*!< Button debounce time in milliseconds */
|
||||||
|
zh_ttp229_work_mode_t work_mode; /*!< Touch pad configuration (8 or 16 pads) */
|
||||||
|
rmt_symbol_word_t rx_symbols; /*!< Received RMT symbol containing duration1 (pad data) */
|
||||||
|
rmt_channel_handle_t tx_channel; /*!< RMT TX channel handle (SCL clock generation) */
|
||||||
|
rmt_channel_handle_t rx_channel; /*!< RMT RX channel handle (SDO data capture) */
|
||||||
|
rmt_encoder_handle_t copy_encoder; /*!< Copy encoder handle for RMT TX */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Queue entry passed from RMT RX callback to the ISR processing task.
|
||||||
|
*
|
||||||
|
* Contains a pointer to the TTP229 device handle for the device
|
||||||
|
* that triggered the interrupt.
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
zh_ttp229_handle_t *handle;
|
zh_ttp229_handle_t *handle; /*!< Pointer to the TTP229 device handle */
|
||||||
} zh_ttp229_queue_t;
|
} zh_ttp229_queue_t;
|
||||||
|
|
||||||
TaskHandle_t zh_ttp229 = NULL;
|
TaskHandle_t zh_ttp229 = NULL; /*!< FreeRTOS task handle for the ISR processing task */
|
||||||
static QueueHandle_t _queue_handle = NULL;
|
static QueueHandle_t _queue_handle = NULL; /*!< Internal event queue */
|
||||||
|
static zh_ttp229_stats_t _stats = {0}; /*!< Accumulated error and runtime statistics */
|
||||||
volatile static uint8_t _pad_counter = {0};
|
static zh_vector_t *_vector = NULL; /*!< Vector of device_number values for all initialized TTP229 devices */
|
||||||
volatile static uint8_t _pad_number_matrix[4] = {0};
|
|
||||||
static zh_ttp229_stats_t _stats = {0};
|
|
||||||
|
|
||||||
|
/** @brief Validate the user-provided initialization configuration.
|
||||||
|
*
|
||||||
|
* Checks all parameter ranges, ensures work_mode is valid, and
|
||||||
|
* verifies device_number uniqueness across initialized devices.
|
||||||
|
*
|
||||||
|
* @param config Pointer to the user configuration
|
||||||
|
* @param handle Pointer to the allocated handle (partially filled)
|
||||||
|
*
|
||||||
|
* @return ESP_OK if all checks pass
|
||||||
|
* @return ESP_ERR_INVALID_ARG on invalid parameter values
|
||||||
|
*/
|
||||||
static esp_err_t _zh_ttp229_validate_config(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t *handle);
|
static esp_err_t _zh_ttp229_validate_config(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t *handle);
|
||||||
|
|
||||||
|
/** @brief Configure GPIO for SDO input with positive-edge interrupt.
|
||||||
|
*
|
||||||
|
* Installs the ISR service if not yet installed, configures SDO as
|
||||||
|
* input with GPIO_INTR_POSEDGE, and registers the ISR handler.
|
||||||
|
*
|
||||||
|
* @param config Pointer to the user configuration
|
||||||
|
* @param handle Pointer to the handle (stores sdo_gpio)
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
* @return ESP_ERR_INVALID_ARG if GPIO pins are invalid or identical
|
||||||
|
* @return ESP_FAIL on ISR service or handler installation failure
|
||||||
|
*/
|
||||||
static esp_err_t _zh_ttp229_gpio_init(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t *handle);
|
static esp_err_t _zh_ttp229_gpio_init(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t *handle);
|
||||||
|
|
||||||
|
/** @brief Initialize RMT TX and RX channels with callbacks.
|
||||||
|
*
|
||||||
|
* Creates TX channel on SCL GPIO, RX channel on SDO GPIO, allocates
|
||||||
|
* the copy encoder, enables both channels, and registers the RX done
|
||||||
|
* callback.
|
||||||
|
*
|
||||||
|
* @param config Pointer to the user configuration
|
||||||
|
* @param handle Pointer to the handle (stores RMT handles)
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
* @return ESP_FAIL on RMT channel, encoder, or callback registration failure
|
||||||
|
*/
|
||||||
static esp_err_t _zh_ttp229_rmt_init(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t *handle);
|
static esp_err_t _zh_ttp229_rmt_init(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t *handle);
|
||||||
|
|
||||||
|
/** @brief Create the shared event queue on first device initialization.
|
||||||
|
*
|
||||||
|
* The queue is created only when vector_size equals 1 (first device).
|
||||||
|
*
|
||||||
|
* @param config Pointer to the user configuration
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
* @return ESP_FAIL if queue allocation fails
|
||||||
|
*/
|
||||||
static esp_err_t _zh_ttp229_resources_init(const zh_ttp229_init_config_t *config);
|
static esp_err_t _zh_ttp229_resources_init(const zh_ttp229_init_config_t *config);
|
||||||
|
|
||||||
|
/** @brief Create the ISR processing task on first device initialization.
|
||||||
|
*
|
||||||
|
* The task is created only when vector_size equals 1 (first device).
|
||||||
|
*
|
||||||
|
* @param config Pointer to the user configuration
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success
|
||||||
|
* @return ESP_FAIL if task creation fails
|
||||||
|
*/
|
||||||
static esp_err_t _zh_ttp229_task_init(const zh_ttp229_init_config_t *config);
|
static esp_err_t _zh_ttp229_task_init(const zh_ttp229_init_config_t *config);
|
||||||
|
|
||||||
|
/** @brief GPIO ISR handler triggered on SDO positive edge.
|
||||||
|
*
|
||||||
|
* Disables further interrupts, starts RMT receive on SDO, generates
|
||||||
|
* SCL clock pulses via RMT transmit on SCL, and yields to higher
|
||||||
|
* priority tasks.
|
||||||
|
*
|
||||||
|
* @param arg Pointer to the zh_ttp229_handle_t for this device
|
||||||
|
*/
|
||||||
static void _zh_ttp229_isr_handler(void *arg);
|
static void _zh_ttp229_isr_handler(void *arg);
|
||||||
|
|
||||||
|
/** @brief FreeRTOS task that processes RMT RX data and posts events.
|
||||||
|
*
|
||||||
|
* Receives queue entries from the RMT RX callback, decodes the pad
|
||||||
|
* number from rx_symbols.duration1, posts a ZH_TTP229 event for
|
||||||
|
* detected touches, debounces by delaying, then re-enables GPIO
|
||||||
|
* interrupts. Runs until the queue is deleted.
|
||||||
|
*
|
||||||
|
* @param pvParameter Unused
|
||||||
|
*/
|
||||||
static void _zh_ttp229_isr_processing_task(void *pvParameter);
|
static void _zh_ttp229_isr_processing_task(void *pvParameter);
|
||||||
|
|
||||||
|
/** @brief RMT RX done callback that enqueues data to the processing task.
|
||||||
|
*
|
||||||
|
* Sends a zh_ttp229_queue_t entry to _queue_handle. Increments
|
||||||
|
* queue overflow error counter if the send fails.
|
||||||
|
*
|
||||||
|
* @param channel RMT channel handle (unused)
|
||||||
|
* @param edata RX done event data (unused)
|
||||||
|
* @param user_data Pointer to the zh_ttp229_handle_t
|
||||||
|
*
|
||||||
|
* @return true if a context switch was requested
|
||||||
|
* @return false otherwise
|
||||||
|
*/
|
||||||
static bool _zh_ttp229_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data);
|
static bool _zh_ttp229_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data);
|
||||||
|
|
||||||
ESP_EVENT_DEFINE_BASE(ZH_TTP229);
|
ESP_EVENT_DEFINE_BASE(ZH_TTP229);
|
||||||
|
|
||||||
esp_err_t zh_ttp229_init(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t *handle) // -V2008
|
esp_err_t zh_ttp229_init(const zh_ttp229_init_config_t *config, zh_ttp229_handle_t **handle) // -V2008
|
||||||
{
|
{
|
||||||
ZH_LOGI("Touch pad initialization started.");
|
ZH_LOGI("Touch pad initialization started.");
|
||||||
ZH_ERROR_CHECK(config != NULL && handle != NULL, ESP_ERR_INVALID_ARG, NULL, "Touch pad initialization failed. Invalid argument.");
|
ZH_ERROR_CHECK(config != NULL && handle != NULL, ESP_ERR_INVALID_ARG, NULL, "Touch pad initialization failed. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(handle->is_initialized == false, ESP_ERR_INVALID_STATE, NULL, "Touch pad initialization failed. Touch pad is already initialized.");
|
ZH_ERROR_CHECK(*handle == NULL, ESP_ERR_INVALID_STATE, NULL, "Touch pad initialization failed. Touch pad is already initialized.");
|
||||||
ZH_ERROR_CHECK(_pad_counter < sizeof(_pad_number_matrix), ESP_ERR_INVALID_ARG, NULL, "Touch pad initialization failed. Maximum quantity reached.");
|
*handle = heap_caps_calloc(1, sizeof(zh_ttp229_handle_t), MALLOC_CAP_8BIT);
|
||||||
ZH_ERROR_CHECK(_zh_ttp229_validate_config(config, handle) == ESP_OK, ESP_FAIL, NULL, "Touch pad initialization failed. Initial configuration check failed.");
|
ZH_ERROR_CHECK(_zh_ttp229_validate_config(config, *handle) == ESP_OK, ESP_FAIL, heap_caps_free(*handle); *handle = NULL, "Touch pad initialization failed. Initial configuration check failed.");
|
||||||
ZH_ERROR_CHECK(_zh_ttp229_resources_init(config) == ESP_OK, ESP_FAIL, NULL, "Touch pad initialization failed. Resources initialization failed.");
|
if (_vector == NULL)
|
||||||
|
{
|
||||||
|
ZH_ERROR_CHECK(zh_vector_init(&_vector, sizeof(uint8_t)) == ESP_OK, ESP_FAIL, heap_caps_free(*handle); *handle = NULL, "Touch pad initialization failed. Failed to create vector.");
|
||||||
|
}
|
||||||
|
ZH_ERROR_CHECK(zh_vector_push_back(&_vector, &config->device_number) == ESP_OK, ESP_FAIL, heap_caps_free(*handle); *handle = NULL, "Touch pad initialization failed. Failed to add vector data.");
|
||||||
|
ZH_ERROR_CHECK(_zh_ttp229_resources_init(config) == ESP_OK, ESP_FAIL, zh_vector_delete_back(&_vector); heap_caps_free(*handle); *handle = NULL, "Touch pad initialization failed. Resources initialization failed.");
|
||||||
|
// clang-format off
|
||||||
ZH_ERROR_CHECK(_zh_ttp229_task_init(config) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(_zh_ttp229_task_init(config) == ESP_OK, ESP_FAIL,
|
||||||
vQueueDelete(_queue_handle), "Touch pad initialization failed. Processing task initialization failed.");
|
zh_vector_delete_back(&_vector); heap_caps_free(*handle); *handle = NULL, "Touch pad initialization failed. Processing task initialization failed.");
|
||||||
ZH_ERROR_CHECK(_zh_ttp229_rmt_init(config, handle) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(_zh_ttp229_rmt_init(config, *handle) == ESP_OK, ESP_FAIL,
|
||||||
vQueueDelete(_queue_handle);
|
zh_vector_delete_back(&_vector); heap_caps_free(*handle); *handle = NULL, "Touch pad initialization failed. RMT initialization failed.");
|
||||||
vTaskDelete(zh_ttp229), "Touch pad initialization failed. RMT initialization failed.");
|
// clang-format on
|
||||||
ZH_ERROR_CHECK(_zh_ttp229_gpio_init(config, handle) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(_zh_ttp229_gpio_init(config, *handle) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(rmt_disable(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel disable failed.");
|
{ZH_ERROR_CHECK(rmt_disable((*handle)->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel disable failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_disable(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "RX channel disable failed.");
|
{ZH_ERROR_CHECK(rmt_disable((*handle)->rx_channel) == ESP_OK, ESP_FAIL, NULL, "RX channel disable failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.");
|
{ZH_ERROR_CHECK(rmt_del_encoder((*handle)->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete TX channel failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel((*handle)->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete TX channel failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete RX channel failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel((*handle)->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete RX channel failed.")};
|
||||||
vQueueDelete(_queue_handle);
|
zh_vector_delete_back(&_vector); heap_caps_free(*handle); *handle = NULL, "Touch pad initialization failed. GPIO initialization failed.");
|
||||||
vTaskDelete(zh_ttp229), "Encoder initialization failed. GPIO initialization failed.");
|
|
||||||
if (_stats.min_stack_size == 0)
|
if (_stats.min_stack_size == 0)
|
||||||
{
|
{
|
||||||
_stats.min_stack_size = config->stack_size;
|
_stats.min_stack_size = config->stack_size;
|
||||||
}
|
}
|
||||||
handle->debounce_time = config->debounce_time;
|
(*handle)->debounce_time = config->debounce_time;
|
||||||
handle->is_initialized = true;
|
|
||||||
++_pad_counter;
|
|
||||||
for (uint8_t i = 0; i < sizeof(_pad_number_matrix); ++i)
|
|
||||||
{
|
|
||||||
if (_pad_number_matrix[i] == 0)
|
|
||||||
{
|
|
||||||
_pad_number_matrix[i] = handle->device_number;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ZH_LOGI("Touch pad initialization completed successfully.");
|
ZH_LOGI("Touch pad initialization completed successfully.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t zh_ttp229_deinit(zh_ttp229_handle_t *handle) // -V2008
|
esp_err_t zh_ttp229_deinit(zh_ttp229_handle_t **handle) // -V2008
|
||||||
{
|
{
|
||||||
ZH_LOGI("Touch pad deinitialization started.");
|
ZH_LOGI("Touch pad deinitialization started.");
|
||||||
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "Touch pad deinitialization failed. Invalid argument.");
|
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "Touch pad deinitialization failed. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_FAIL, NULL, "Touch pad deinitialization failed. Touch pad not initialized.");
|
ZH_ERROR_CHECK(rmt_disable((*handle)->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. TX channel disable failed.");
|
||||||
ZH_ERROR_CHECK(rmt_disable(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. TX channel disable failed.");
|
ZH_ERROR_CHECK(rmt_disable((*handle)->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. RX channel disable failed.");
|
||||||
ZH_ERROR_CHECK(rmt_disable(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. RX channel disable failed.");
|
ZH_ERROR_CHECK(rmt_del_encoder((*handle)->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Delete encoder failed.");
|
||||||
ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Delete encoder failed.");
|
ZH_ERROR_CHECK(rmt_del_channel((*handle)->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Delete TX channel failed.");
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Delete TX channel failed.");
|
ZH_ERROR_CHECK(rmt_del_channel((*handle)->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Delete RX channel failed.");
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Delete RX channel failed.");
|
ZH_ERROR_CHECK(gpio_isr_handler_remove((*handle)->sdo_gpio) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Remove GPIO isr handler failed.");
|
||||||
ZH_ERROR_CHECK(gpio_isr_handler_remove((gpio_num_t)handle->sdo_gpio) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Remove GPIO isr handler failed.");
|
ZH_ERROR_CHECK(gpio_reset_pin((*handle)->sdo_gpio) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Reset GPIO failed.");
|
||||||
ZH_ERROR_CHECK(gpio_reset_pin((gpio_num_t)handle->sdo_gpio) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Reset GPIO failed.");
|
int32_t index = 0;
|
||||||
if (_pad_counter == 1)
|
ZH_ERROR_CHECK(zh_vector_find_item(&_vector, &(*handle)->device_number, &index) == ESP_ERR_NOT_FOUND, ESP_ERR_INVALID_ARG, NULL, "Touch pad deinitialization failed. Failed to find vector item.");
|
||||||
|
ZH_ERROR_CHECK(zh_vector_delete_item(&_vector, (uint16_t)index) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Vector delete item failed.");
|
||||||
|
uint16_t vector_size = 0;
|
||||||
|
ZH_ERROR_CHECK(zh_vector_get_size(&_vector, &vector_size) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Failed to get vector size.");
|
||||||
|
if (vector_size == 0)
|
||||||
{
|
{
|
||||||
vQueueDelete(_queue_handle);
|
vQueueDelete(_queue_handle);
|
||||||
|
_queue_handle = NULL;
|
||||||
vTaskDelete(zh_ttp229);
|
vTaskDelete(zh_ttp229);
|
||||||
|
zh_ttp229 = NULL;
|
||||||
|
ZH_ERROR_CHECK(zh_vector_free(&_vector) == ESP_OK, ESP_FAIL, NULL, "Touch pad deinitialization failed. Free vector failed.");
|
||||||
}
|
}
|
||||||
handle->is_initialized = false;
|
heap_caps_free(*handle);
|
||||||
--_pad_counter;
|
*handle = NULL;
|
||||||
for (uint8_t i = 0; i < sizeof(_pad_number_matrix); ++i)
|
|
||||||
{
|
|
||||||
if (_pad_number_matrix[i] == handle->device_number)
|
|
||||||
{
|
|
||||||
_pad_number_matrix[i] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ZH_LOGI("Touch pad deinitialization completed successfully.");
|
ZH_LOGI("Touch pad deinitialization completed successfully.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -130,9 +242,10 @@ static esp_err_t _zh_ttp229_validate_config(const zh_ttp229_init_config_t *confi
|
|||||||
ZH_ERROR_CHECK(config->rmt_tx_start_delay >= 15, ESP_ERR_INVALID_ARG, NULL, "Invalid RMT TX start delay.");
|
ZH_ERROR_CHECK(config->rmt_tx_start_delay >= 15, ESP_ERR_INVALID_ARG, NULL, "Invalid RMT TX start delay.");
|
||||||
ZH_ERROR_CHECK(config->work_mode == ZH_TTP229_8_PAD || config->work_mode == ZH_TTP229_16_PAD, ESP_ERR_INVALID_ARG, NULL, "Invalid touch pad work mode.");
|
ZH_ERROR_CHECK(config->work_mode == ZH_TTP229_8_PAD || config->work_mode == ZH_TTP229_16_PAD, ESP_ERR_INVALID_ARG, NULL, "Invalid touch pad work mode.");
|
||||||
ZH_ERROR_CHECK(config->device_number > 0, ESP_ERR_INVALID_ARG, NULL, "Invalid touch pad number.");
|
ZH_ERROR_CHECK(config->device_number > 0, ESP_ERR_INVALID_ARG, NULL, "Invalid touch pad number.");
|
||||||
for (uint8_t i = 0; i < sizeof(_pad_number_matrix); ++i)
|
if (_vector != NULL)
|
||||||
{
|
{
|
||||||
ZH_ERROR_CHECK(config->device_number != _pad_number_matrix[i], ESP_ERR_INVALID_ARG, NULL, "Touch pad number already present.");
|
int32_t index = 0;
|
||||||
|
ZH_ERROR_CHECK(zh_vector_find_item(&_vector, &config->device_number, &index) == ESP_ERR_NOT_FOUND, ESP_ERR_INVALID_ARG, NULL, "Touch pad number already present.");
|
||||||
}
|
}
|
||||||
handle->rmt_tx_start_delay = config->rmt_tx_start_delay;
|
handle->rmt_tx_start_delay = config->rmt_tx_start_delay;
|
||||||
handle->device_number = config->device_number;
|
handle->device_number = config->device_number;
|
||||||
@@ -151,9 +264,9 @@ static esp_err_t _zh_ttp229_gpio_init(const zh_ttp229_init_config_t *config, zh_
|
|||||||
ZH_ERROR_CHECK(gpio_config(&sdo_config) == ESP_OK, ESP_FAIL, NULL, "GPIO initialization failed.");
|
ZH_ERROR_CHECK(gpio_config(&sdo_config) == ESP_OK, ESP_FAIL, NULL, "GPIO initialization failed.");
|
||||||
esp_err_t err = gpio_install_isr_service(ESP_INTR_FLAG_LOWMED);
|
esp_err_t err = gpio_install_isr_service(ESP_INTR_FLAG_LOWMED);
|
||||||
ZH_ERROR_CHECK(err == ESP_OK || err == ESP_ERR_INVALID_STATE, ESP_FAIL,
|
ZH_ERROR_CHECK(err == ESP_OK || err == ESP_ERR_INVALID_STATE, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(gpio_reset_pin((gpio_num_t)config->sdo_gpio) == ESP_OK, ESP_FAIL, NULL, "Reset GPIO failed."), "Failed install isr service.");
|
{ZH_ERROR_CHECK(gpio_reset_pin(config->sdo_gpio) == ESP_OK, ESP_FAIL, NULL, "Reset GPIO failed.")}, "Failed install isr service.");
|
||||||
ZH_ERROR_CHECK(gpio_isr_handler_add((gpio_num_t)config->sdo_gpio, _zh_ttp229_isr_handler, handle) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(gpio_isr_handler_add(config->sdo_gpio, _zh_ttp229_isr_handler, handle) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(gpio_reset_pin((gpio_num_t)config->sdo_gpio) == ESP_OK, ESP_FAIL, NULL, "Reset GPIO failed."), "Interrupt initialization failed.");
|
{ZH_ERROR_CHECK(gpio_reset_pin(config->sdo_gpio) == ESP_OK, ESP_FAIL, NULL, "Reset GPIO failed.")}, "Interrupt initialization failed.");
|
||||||
handle->sdo_gpio = config->sdo_gpio;
|
handle->sdo_gpio = config->sdo_gpio;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@@ -175,10 +288,10 @@ static esp_err_t _zh_ttp229_rmt_init(const zh_ttp229_init_config_t *config, zh_t
|
|||||||
ZH_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel creation failed.");
|
ZH_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel creation failed.");
|
||||||
rmt_copy_encoder_config_t copy_encoder_config = {};
|
rmt_copy_encoder_config_t copy_encoder_config = {};
|
||||||
ZH_ERROR_CHECK(rmt_new_copy_encoder(©_encoder_config, &handle->copy_encoder) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(rmt_new_copy_encoder(©_encoder_config, &handle->copy_encoder) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete channel failed."), "Copy encoder creation failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete channel failed.")}, "Copy encoder creation failed.");
|
||||||
ZH_ERROR_CHECK(rmt_enable(handle->tx_channel) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(rmt_enable(handle->tx_channel) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.");
|
{ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete channel failed."), "Enable TX channel failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete channel failed.")}, "Enable TX channel failed.");
|
||||||
rmt_rx_channel_config_t rx_chan_config = {
|
rmt_rx_channel_config_t rx_chan_config = {
|
||||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||||
.gpio_num = config->sdo_gpio,
|
.gpio_num = config->sdo_gpio,
|
||||||
@@ -190,29 +303,31 @@ static esp_err_t _zh_ttp229_rmt_init(const zh_ttp229_init_config_t *config, zh_t
|
|||||||
.resolution_hz = 1000000,
|
.resolution_hz = 1000000,
|
||||||
};
|
};
|
||||||
ZH_ERROR_CHECK(rmt_new_rx_channel(&rx_chan_config, &handle->rx_channel) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(rmt_new_rx_channel(&rx_chan_config, &handle->rx_channel) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(rmt_disable(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel disable failed.");
|
{ZH_ERROR_CHECK(rmt_disable(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel disable failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.");
|
{ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete TX channel failed."), "TX channel creation failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete TX channel failed.")}, "TX channel creation failed.");
|
||||||
ZH_ERROR_CHECK(rmt_enable(handle->rx_channel) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(rmt_enable(handle->rx_channel) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(rmt_disable(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel disable failed.");
|
{ZH_ERROR_CHECK(rmt_disable(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel disable failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.");
|
{ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete TX channel failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete TX channel failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete RX channel failed."), "RX channel creation failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete RX channel failed.")}, "RX channel creation failed.");
|
||||||
rmt_rx_event_callbacks_t cbs = {
|
rmt_rx_event_callbacks_t cbs = {
|
||||||
.on_recv_done = _zh_ttp229_rmt_rx_done_callback,
|
.on_recv_done = _zh_ttp229_rmt_rx_done_callback,
|
||||||
};
|
};
|
||||||
ZH_ERROR_CHECK(rmt_rx_register_event_callbacks(handle->rx_channel, &cbs, handle) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(rmt_rx_register_event_callbacks(handle->rx_channel, &cbs, handle) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(rmt_disable(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel disable failed.");
|
{ZH_ERROR_CHECK(rmt_disable(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "TX channel disable failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_disable(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "RX channel disable failed.");
|
{ZH_ERROR_CHECK(rmt_disable(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "RX channel disable failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.");
|
{ZH_ERROR_CHECK(rmt_del_encoder(handle->copy_encoder) == ESP_OK, ESP_FAIL, NULL, "Delete encoder failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete TX channel failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel(handle->tx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete TX channel failed.")};
|
||||||
ZH_ERROR_CHECK(rmt_del_channel(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete RX channel failed."), "TX callback registar failed.");
|
{ZH_ERROR_CHECK(rmt_del_channel(handle->rx_channel) == ESP_OK, ESP_FAIL, NULL, "Delete RX channel failed.")}, "TX callback registar failed.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t _zh_ttp229_resources_init(const zh_ttp229_init_config_t *config)
|
static esp_err_t _zh_ttp229_resources_init(const zh_ttp229_init_config_t *config)
|
||||||
{
|
{
|
||||||
if (_pad_counter == 0)
|
uint16_t vector_size = 0;
|
||||||
|
zh_vector_get_size(&_vector, &vector_size);
|
||||||
|
if (vector_size == 1)
|
||||||
{
|
{
|
||||||
_queue_handle = xQueueCreate(config->queue_size, sizeof(zh_ttp229_queue_t));
|
_queue_handle = xQueueCreate(config->queue_size, sizeof(zh_ttp229_queue_t));
|
||||||
ZH_ERROR_CHECK(_queue_handle != NULL, ESP_FAIL, NULL, "Failed to create queue.");
|
ZH_ERROR_CHECK(_queue_handle != NULL, ESP_FAIL, NULL, "Failed to create queue.");
|
||||||
@@ -222,7 +337,9 @@ static esp_err_t _zh_ttp229_resources_init(const zh_ttp229_init_config_t *config
|
|||||||
|
|
||||||
static esp_err_t _zh_ttp229_task_init(const zh_ttp229_init_config_t *config)
|
static esp_err_t _zh_ttp229_task_init(const zh_ttp229_init_config_t *config)
|
||||||
{
|
{
|
||||||
if (_pad_counter == 0)
|
uint16_t vector_size = 0;
|
||||||
|
zh_vector_get_size(&_vector, &vector_size);
|
||||||
|
if (vector_size == 1)
|
||||||
{
|
{
|
||||||
ZH_ERROR_CHECK(xTaskCreatePinnedToCore(&_zh_ttp229_isr_processing_task, "zh_ttp229_isr_processing", config->stack_size, NULL, config->task_priority, &zh_ttp229, tskNO_AFFINITY) == pdPASS,
|
ZH_ERROR_CHECK(xTaskCreatePinnedToCore(&_zh_ttp229_isr_processing_task, "zh_ttp229_isr_processing", config->stack_size, NULL, config->task_priority, &zh_ttp229, tskNO_AFFINITY) == pdPASS,
|
||||||
ESP_FAIL, NULL, "Failed to create isr processing task.");
|
ESP_FAIL, NULL, "Failed to create isr processing task.");
|
||||||
@@ -235,16 +352,19 @@ static void IRAM_ATTR _zh_ttp229_isr_handler(void *arg)
|
|||||||
zh_ttp229_handle_t *ttp229_handle = (zh_ttp229_handle_t *)arg;
|
zh_ttp229_handle_t *ttp229_handle = (zh_ttp229_handle_t *)arg;
|
||||||
gpio_intr_disable(ttp229_handle->sdo_gpio);
|
gpio_intr_disable(ttp229_handle->sdo_gpio);
|
||||||
rmt_receive_config_t rx_receive_config = {.signal_range_min_ns = 100, .signal_range_max_ns = 2000000};
|
rmt_receive_config_t rx_receive_config = {.signal_range_min_ns = 100, .signal_range_max_ns = 2000000};
|
||||||
|
// Start RMT reception on SDO to capture touch data
|
||||||
if (rmt_receive(ttp229_handle->rx_channel, &ttp229_handle->rx_symbols, sizeof(ttp229_handle->rx_symbols), &rx_receive_config) != ESP_OK)
|
if (rmt_receive(ttp229_handle->rx_channel, &ttp229_handle->rx_symbols, sizeof(ttp229_handle->rx_symbols), &rx_receive_config) != ESP_OK)
|
||||||
{
|
{
|
||||||
++_stats.rmt_driver_error;
|
++_stats.rmt_driver_error;
|
||||||
}
|
}
|
||||||
|
// Toggle SDO: set output low then high to trigger the RMT RX start
|
||||||
gpio_set_direction(ttp229_handle->sdo_gpio, GPIO_MODE_OUTPUT);
|
gpio_set_direction(ttp229_handle->sdo_gpio, GPIO_MODE_OUTPUT);
|
||||||
gpio_set_level(ttp229_handle->sdo_gpio, 0);
|
gpio_set_level(ttp229_handle->sdo_gpio, 0);
|
||||||
gpio_set_level(ttp229_handle->sdo_gpio, 1);
|
gpio_set_level(ttp229_handle->sdo_gpio, 1);
|
||||||
gpio_set_direction(ttp229_handle->sdo_gpio, GPIO_MODE_INPUT);
|
gpio_set_direction(ttp229_handle->sdo_gpio, GPIO_MODE_INPUT);
|
||||||
|
// Generate SCL clock pulses via RMT transmit for the configured work mode
|
||||||
rmt_symbol_word_t scl_symbols[ttp229_handle->work_mode];
|
rmt_symbol_word_t scl_symbols[ttp229_handle->work_mode];
|
||||||
for (uint8_t i = 0; i < ttp229_handle->work_mode; ++i)
|
for (uint8_t i = 0; i < (uint8_t)ttp229_handle->work_mode; ++i)
|
||||||
{
|
{
|
||||||
scl_symbols[i] = (rmt_symbol_word_t){.duration0 = 2, .level0 = 0, .duration1 = 2, .level1 = 1};
|
scl_symbols[i] = (rmt_symbol_word_t){.duration0 = 2, .level0 = 0, .duration1 = 2, .level1 = 1};
|
||||||
}
|
}
|
||||||
@@ -258,11 +378,15 @@ static void IRAM_ATTR _zh_ttp229_isr_handler(void *arg)
|
|||||||
|
|
||||||
static void IRAM_ATTR _zh_ttp229_isr_processing_task(void *pvParameter) // -V2008
|
static void IRAM_ATTR _zh_ttp229_isr_processing_task(void *pvParameter) // -V2008
|
||||||
{
|
{
|
||||||
|
(void)pvParameter;
|
||||||
zh_ttp229_queue_t ttp229_queue = {0};
|
zh_ttp229_queue_t ttp229_queue = {0};
|
||||||
while (xQueueReceive(_queue_handle, &ttp229_queue, portMAX_DELAY) == pdTRUE)
|
while (xQueueReceive(_queue_handle, &ttp229_queue, portMAX_DELAY) == pdTRUE)
|
||||||
{
|
{
|
||||||
zh_ttp229_handle_t *ttp229_handle = ttp229_queue.handle;
|
zh_ttp229_handle_t *ttp229_handle = ttp229_queue.handle;
|
||||||
uint8_t pad_number = 0;
|
uint8_t pad_number = 0;
|
||||||
|
// Decode pad number from duration1: each pad has a unique range
|
||||||
|
// of (rmt_tx_start_delay + offset) values, with offset increasing
|
||||||
|
// by 2 per pad (pad N uses offset 2*(N-1)+1, ±1 tolerance)
|
||||||
if ((ttp229_handle->rx_symbols.duration1 == (ttp229_handle->rmt_tx_start_delay - 1)) ||
|
if ((ttp229_handle->rx_symbols.duration1 == (ttp229_handle->rmt_tx_start_delay - 1)) ||
|
||||||
(ttp229_handle->rx_symbols.duration1 == (ttp229_handle->rmt_tx_start_delay)) ||
|
(ttp229_handle->rx_symbols.duration1 == (ttp229_handle->rmt_tx_start_delay)) ||
|
||||||
(ttp229_handle->rx_symbols.duration1 == (ttp229_handle->rmt_tx_start_delay + 1)))
|
(ttp229_handle->rx_symbols.duration1 == (ttp229_handle->rmt_tx_start_delay + 1)))
|
||||||
@@ -364,12 +488,7 @@ static void IRAM_ATTR _zh_ttp229_isr_processing_task(void *pvParameter) // -V200
|
|||||||
zh_ttp229_event_on_isr_t ttp229_data = {0};
|
zh_ttp229_event_on_isr_t ttp229_data = {0};
|
||||||
ttp229_data.pad_number = pad_number;
|
ttp229_data.pad_number = pad_number;
|
||||||
ttp229_data.device_number = ttp229_handle->device_number;
|
ttp229_data.device_number = ttp229_handle->device_number;
|
||||||
esp_err_t err = esp_event_post(ZH_TTP229, 0, &ttp229_data, sizeof(zh_ttp229_event_on_isr_t), 1000 / portTICK_PERIOD_MS);
|
ZH_ERROR_CHECK_CONT(esp_event_post(ZH_TTP229, 0, &ttp229_data, sizeof(zh_ttp229_event_on_isr_t), 1000 / portTICK_PERIOD_MS) == ESP_OK, ++_stats.event_post_error, "Touch pad isr processing failed. Failed to post interrupt event.");
|
||||||
if (err != ESP_OK)
|
|
||||||
{
|
|
||||||
++_stats.event_post_error;
|
|
||||||
ZH_LOGE("Touch pad isr processing failed. Failed to post interrupt event.", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vTaskDelay(ttp229_handle->debounce_time / portTICK_PERIOD_MS);
|
vTaskDelay(ttp229_handle->debounce_time / portTICK_PERIOD_MS);
|
||||||
gpio_intr_enable(ttp229_handle->sdo_gpio);
|
gpio_intr_enable(ttp229_handle->sdo_gpio);
|
||||||
@@ -380,6 +499,7 @@ static void IRAM_ATTR _zh_ttp229_isr_processing_task(void *pvParameter) // -V200
|
|||||||
|
|
||||||
static bool IRAM_ATTR _zh_ttp229_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data)
|
static bool IRAM_ATTR _zh_ttp229_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data)
|
||||||
{
|
{
|
||||||
|
(void)edata;
|
||||||
zh_ttp229_handle_t *ttp229_handle = (zh_ttp229_handle_t *)user_data;
|
zh_ttp229_handle_t *ttp229_handle = (zh_ttp229_handle_t *)user_data;
|
||||||
zh_ttp229_queue_t ttp229_queue = {0};
|
zh_ttp229_queue_t ttp229_queue = {0};
|
||||||
ttp229_queue.handle = ttp229_handle;
|
ttp229_queue.handle = ttp229_handle;
|
||||||
|
|||||||
Reference in new issue
Block a user