captouch.c 18.28 KiB
//#include <stdio.h>
//#include <string.h>
#include "esp_log.h"
#include "driver/i2c.h"
#include <stdint.h>
static const char *TAG = "captouch";
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define AD7147_BASE_ADDR 0x2C
#define AD7147_REG_PWR_CONTROL 0x00
#define AD7147_REG_STAGE_CAL_EN 0x01
#define AD7147_REG_STAGE_HIGH_INT_ENABLE 0x06
#define AD7147_REG_DEVICE_ID 0x17
#define TIMEOUT_MS 1000
struct ad714x_chip {
uint8_t addr;
uint8_t gpio;
int afe_offsets[13];
int stages;
};
static const struct ad714x_chip chip_top = {.addr = AD7147_BASE_ADDR + 1, .gpio = 48, .afe_offsets = {24, 12, 16, 33, 30, 28, 31, 27, 22, 24, 18, 19, }, .stages=12};
static const struct ad714x_chip chip_bot = {.addr = AD7147_BASE_ADDR, .gpio = 3, .afe_offsets = {3, 2, 1, 1 ,1, 1, 1, 1, 2, 3}, .stages=10};
static esp_err_t ad714x_i2c_write(const struct ad714x_chip *chip, const uint16_t reg, const uint16_t data)
{
const uint8_t tx[] = {reg >> 8, reg & 0xFF, data >> 8, data & 0xFF};
ESP_LOGI(TAG, "AD7147 write reg %X-> %X", reg, data);
return i2c_master_write_to_device(I2C_MASTER_NUM, chip->addr, tx, sizeof(tx), TIMEOUT_MS / portTICK_PERIOD_MS);
}
static esp_err_t ad714x_i2c_read(const struct ad714x_chip *chip, const uint16_t reg, uint16_t *data, const size_t len)
{
const uint8_t tx[] = {reg >> 8, reg & 0xFF};
uint8_t rx[len * 2];
esp_err_t ret = i2c_master_write_read_device(I2C_MASTER_NUM, chip->addr, tx, sizeof(tx), rx, sizeof(rx), TIMEOUT_MS / portTICK_PERIOD_MS);
for(int i = 0; i < len; i++) {
data[i] = (rx[i * 2] << 8) | rx[i * 2 + 1];
}
return ret;
}
struct ad7147_stage_config {
unsigned int cinX_connection_setup[13];
unsigned int se_connection_setup:2;
unsigned int neg_afe_offset_disable:1;
unsigned int pos_afe_offset_disable:1;
unsigned int neg_afe_offset:6;
unsigned int neg_afe_offset_swap:1;
unsigned int pos_afe_offset:6;
unsigned int pos_afe_offset_swap:1;
unsigned int neg_threshold_sensitivity:4;
unsigned int neg_peak_detect:3;
unsigned int pos_threshold_sensitivity:4;
unsigned int pos_peak_detect:3;
};
#define CIN CDC_NONE 0
#define CIN_CDC_NEG 1
#define CIN_CDC_POS 2
#define CIN_BIAS 3
static const uint16_t bank2 = 0x80;
static void ad714x_set_stage_config(const struct ad714x_chip *chip, const uint8_t stage, const struct ad7147_stage_config * config)
{
const uint16_t connection_6_0 = (config->cinX_connection_setup[6] << 12) | (config->cinX_connection_setup[5] << 10) | (config->cinX_connection_setup[4] << 8) | (config->cinX_connection_setup[3] << 6) | (config->cinX_connection_setup[2] << 4) | (config->cinX_connection_setup[1] << 2) | (config->cinX_connection_setup[0] << 0);
const uint16_t connection_12_7 = (config->pos_afe_offset_disable << 15) | (config->neg_afe_offset_disable << 14) | (config->se_connection_setup << 12) | (config->cinX_connection_setup[12] << 10) | (config->cinX_connection_setup[11] << 8) | (config->cinX_connection_setup[10] << 6) | (config->cinX_connection_setup[9] << 4) | (config->cinX_connection_setup[8] << 2) | (config->cinX_connection_setup[7] << 0);
const uint16_t afe_offset = (config->pos_afe_offset_swap << 15) | (config->pos_afe_offset << 8) | (config->neg_afe_offset_swap << 7) | (config->neg_afe_offset << 0);
const uint16_t sensitivity = (config->pos_peak_detect << 12) | (config->pos_threshold_sensitivity << 8) | (config->neg_peak_detect << 4) | (config->neg_threshold_sensitivity << 0);
//ESP_LOGI(TAG, "Stage %d config-> %X %X %X %X", stage, connection_6_0, connection_12_7, afe_offset, sensitivity);
//ESP_LOGI(TAG, "Config: %X %X %X %X %X %X %X %X %X", config->pos_afe_offset_disable, config->pos_afe_offset_disable, config->se_connection_setup, config->cinX_connection_setup[12], config->cinX_connection_setup[11], config->cinX_connection_setup[10], config->cinX_connection_setup[9], config->cinX_connection_setup[8], config->cinX_connection_setup[7]);
ad714x_i2c_write(chip, bank2 + stage * 8, connection_6_0);
ad714x_i2c_write(chip, bank2 + stage * 8 + 1, connection_12_7);
ad714x_i2c_write(chip, bank2 + stage * 8 + 2, afe_offset);
ad714x_i2c_write(chip, bank2 + stage * 8 + 3, sensitivity);
}
struct ad7147_device_config {
unsigned int power_mode:2;
unsigned int lp_conv_delay:2;
unsigned int sequence_stage_num:4;
unsigned int decimation:2;
unsigned int sw_reset:1;
unsigned int int_pol:1;
unsigned int ext_source:1;
unsigned int cdc_bias:2;
unsigned int stage0_cal_en:1;
unsigned int stage1_cal_en:1;
unsigned int stage2_cal_en:1;
unsigned int stage3_cal_en:1;
unsigned int stage4_cal_en:1;
unsigned int stage5_cal_en:1;
unsigned int stage6_cal_en:1;
unsigned int stage7_cal_en:1;
unsigned int stage8_cal_en:1;
unsigned int stage9_cal_en:1;
unsigned int stage10_cal_en:1;
unsigned int stage11_cal_en:1;
unsigned int avg_fp_skip:2;
unsigned int avg_lp_skip:2;
unsigned int stage0_high_int_enable:1;
unsigned int stage1_high_int_enable:1;
unsigned int stage2_high_int_enable:1;
unsigned int stage3_high_int_enable:1;
unsigned int stage4_high_int_enable:1;
unsigned int stage5_high_int_enable:1;
unsigned int stage6_high_int_enable:1;
unsigned int stage7_high_int_enable:1;
unsigned int stage8_high_int_enable:1;
unsigned int stage9_high_int_enable:1;
unsigned int stage10_high_int_enable:1;
unsigned int stage11_high_int_enable:1;
};
static void ad714x_set_device_config(const struct ad714x_chip *chip, const struct ad7147_device_config * config)
{
const uint16_t pwr_control = (config->cdc_bias << 14) | (config->ext_source << 12) | (config->int_pol << 11) | (config->sw_reset << 10) | (config->decimation << 8) | (config->sequence_stage_num << 4) | (config->lp_conv_delay << 2) | (config->power_mode << 0);
const uint16_t stage_cal_en = (config->avg_lp_skip << 14) | (config->avg_fp_skip << 12) | (config->stage11_cal_en << 11) | (config->stage10_cal_en << 10) | (config->stage9_cal_en << 9) | (config->stage8_cal_en << 8) | (config->stage7_cal_en << 7) | (config->stage6_cal_en << 6) | (config->stage5_cal_en << 5) | (config->stage4_cal_en << 4) | (config->stage3_cal_en << 3) | (config->stage2_cal_en << 2) | (config->stage1_cal_en << 1) | (config->stage0_cal_en << 0);
const uint16_t stage_high_int_enable = (config->stage11_high_int_enable << 11) | (config->stage10_high_int_enable << 10) | (config->stage9_high_int_enable << 9) | (config->stage8_high_int_enable << 8) | (config->stage7_high_int_enable << 7) | (config->stage6_high_int_enable << 6) | (config->stage5_high_int_enable << 5) | (config->stage4_high_int_enable << 4) | (config->stage3_high_int_enable << 3) | (config->stage2_high_int_enable << 2) | (config->stage1_high_int_enable << 1) | (config->stage0_high_int_enable << 0);
ad714x_i2c_write(chip, AD7147_REG_PWR_CONTROL, pwr_control);
ad714x_i2c_write(chip, AD7147_REG_STAGE_CAL_EN, stage_cal_en);
ad714x_i2c_write(chip, AD7147_REG_STAGE_HIGH_INT_ENABLE, stage_high_int_enable);
}
static struct ad7147_stage_config ad714x_default_config(void)
{
return (struct ad7147_stage_config) {
.cinX_connection_setup={CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS, CIN_BIAS},
.se_connection_setup=0b01,
.pos_afe_offset=0,
};
}
#define ESP_INTR_FLAG_DEFAULT 0
static QueueHandle_t gpio_evt_queue = NULL;
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
struct ad714x_chip* chip = (struct ad714x_chip *) arg;
xQueueSendFromISR(gpio_evt_queue, &chip, NULL);
}
void manual_captouch_readout(uint8_t top)
{
struct ad714x_chip* chip = top ? (&chip_top) : (&chip_bot);
xQueueSendFromISR(gpio_evt_queue, &chip, NULL);
}
void espan_handle_captouch(uint16_t pressed_top, uint16_t pressed_bot);
static uint16_t pressed_top, pressed_bot;
void gpio_event_handler(void* arg)
{
static unsigned long counter = 0;
struct ad714x_chip* chip;
uint16_t pressed;
while(true) {
if(xQueueReceive(gpio_evt_queue, &chip, portMAX_DELAY)) {
ad714x_i2c_read(chip, 9, &pressed, 1);
ESP_LOGI(TAG, "Addr %x, High interrupt %X", chip->addr, pressed);
pressed &= ((1 << chip->stages) - 1);
if(chip == &chip_top) pressed_top = pressed;
if(chip == &chip_bot) pressed_bot = pressed;
espan_handle_captouch(pressed_top, pressed_bot);
}
}
}
static void captouch_init_chip(const struct ad714x_chip* chip, const struct ad7147_device_config device_config)
{
uint16_t data;
ad714x_i2c_read(chip, AD7147_REG_DEVICE_ID, &data, 1);
ESP_LOGI(TAG, "DEVICE ID = %X", data);
ad714x_set_device_config(chip, &device_config);
for(int i=0; i<chip->stages; i++) {
struct ad7147_stage_config stage_config;
stage_config = ad714x_default_config();
stage_config.cinX_connection_setup[i] = CIN_CDC_POS;
stage_config.pos_afe_offset=chip->afe_offsets[i];
ad714x_set_stage_config(chip, i, &stage_config);
}
// Force calibration
ad714x_i2c_write(chip, 2, (1 << 14));
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << chip->gpio);
io_conf.pull_up_en = 1;
io_conf.pull_down_en = 0;
gpio_config(&io_conf);
gpio_evt_queue = xQueueCreate(10, sizeof(const struct ad714x_chip*));
xTaskCreate(gpio_event_handler, "gpio_event_handler", 2048 * 2, NULL, configMAX_PRIORITIES - 2, NULL);
gpio_isr_handler_add(chip->gpio, gpio_isr_handler, (void *)chip);
}
void captouch_init(void)
{
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
captouch_init_chip(&chip_top, (struct ad7147_device_config){.sequence_stage_num = 11,
.decimation = 1,
.stage0_cal_en = 1,
.stage1_cal_en = 1,
.stage2_cal_en = 1,
.stage3_cal_en = 1,
.stage4_cal_en = 1,
.stage5_cal_en = 1,
.stage6_cal_en = 1,
.stage7_cal_en = 1,
.stage8_cal_en = 1,
.stage9_cal_en = 1,
.stage10_cal_en = 1,
.stage11_cal_en = 1,
.stage0_high_int_enable = 1,
.stage1_high_int_enable = 1,
.stage2_high_int_enable = 1,
.stage3_high_int_enable = 1,
.stage4_high_int_enable = 1,
.stage5_high_int_enable = 1,
.stage6_high_int_enable = 1,
.stage7_high_int_enable = 1,
.stage8_high_int_enable = 1,
.stage9_high_int_enable = 1,
.stage10_high_int_enable = 1,
.stage11_high_int_enable = 1,
});
captouch_init_chip(&chip_bot, (struct ad7147_device_config){.sequence_stage_num = 11,
.decimation = 1,
.stage0_cal_en = 1,
.stage1_cal_en = 1,
.stage2_cal_en = 1,
.stage3_cal_en = 1,
.stage4_cal_en = 1,
.stage5_cal_en = 1,
.stage6_cal_en = 1,
.stage7_cal_en = 1,
.stage8_cal_en = 1,
.stage9_cal_en = 1,
.stage0_high_int_enable = 1,
.stage1_high_int_enable = 1,
.stage2_high_int_enable = 1,
.stage3_high_int_enable = 1,
.stage4_high_int_enable = 1,
.stage5_high_int_enable = 1,
.stage6_high_int_enable = 1,
.stage7_high_int_enable = 1,
.stage8_high_int_enable = 1,
.stage9_high_int_enable = 1,
});
}
static void captouch_print_debug_info_chip(const struct ad714x_chip* chip)
{
uint16_t data[12] = {0,};
uint16_t ambient[12] = {0,};
const int stages = chip->stages;
#if 1
for(int stage=0; stage<stages; stage++) {
ad714x_i2c_read(chip, 0x0FA + stage * (0x104 - 0xE0), data, 1);
ESP_LOGI(TAG, "stage %d threshold: %X", stage, data[0]);
}
ad714x_i2c_read(chip, 0xB, data, stages);
ESP_LOGI(TAG, "CDC results: %X %X %X %X %X %X %X %X %X %X %X %X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
for(int stage=0; stage<stages; stage++) {
ad714x_i2c_read(chip, 0x0F1 + stage * (0x104 - 0xE0), &ambient[stage], 1);
ESP_LOGI(TAG, "stage %d ambient: %X diff: %d", stage, ambient[stage], data[stage] - ambient[stage]);
}
#endif
#if 1
ad714x_i2c_read(chip, 8, data, 1);
ESP_LOGI(TAG, "Low interrupt %X", data[0]);
ad714x_i2c_read(chip, 9, data, 1);
ESP_LOGI(TAG, "High interrupt %X", data[0]);
ad714x_i2c_read(chip, 0x42, data, 1);
ESP_LOGI(TAG, "Proximity %X", data[0]);
//ESP_LOGI(TAG, "CDC result = %X", data[0]);
//if(data[0] > 0xa000) {
//ESP_LOGI(TAG, "Touch! %X", data[0]);
//}
#endif
}
void captouch_print_debug_info(void)
{
captouch_print_debug_info_chip(&chip_top);
captouch_print_debug_info_chip(&chip_bot);
}
void captouch_get_cross(int paddle, int *x, int *y)
{
uint16_t data[12] = {0,};
uint16_t ambient[12] = {0,};
int result[2] = {0, 0};
float total = 0;
#if 0
if(paddle == 2) {
ad714x_i2c_read(&chip_top, 0xB, data, 3);
//ESP_LOGI(TAG, "CDC results: %X %X %X %X %X %X %X %X %X %X %X %X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
for(int stage=0; stage<3; stage++) {
ad714x_i2c_read(&chip_top, 0x0F1 + stage * (0x104 - 0xE0), &ambient[stage], 1);
//ESP_LOGI(TAG, "stage %d ambient: %X diff: %d", stage, ambient[stage], data[stage] - ambient[stage]);
}
int vectors[][2] = {{0, 0}, {0,240}, {240, 120}};
total = (data[0] - ambient[0]) + (data[1] - ambient[1]) + (data[2] - ambient[2]);
result[0] = vectors[0][0] * (data[0] - ambient[0]) + vectors[1][0] * (data[1] - ambient[1]) + vectors[2][0] * (data[2] - ambient[2]);
result[1] = vectors[0][1] * (data[0] - ambient[0]) + vectors[1][1] * (data[1] - ambient[1]) + vectors[2][1] * (data[2] - ambient[2]);
}
if(paddle == 8) {
ad714x_i2c_read(&chip_top, 0xB + 5, data + 5, 3);
//ESP_LOGI(TAG, "CDC results: %X %X %X %X %X %X %X %X %X %X %X %X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
for(int stage=5; stage<8; stage++) {
ad714x_i2c_read(&chip_top, 0x0F1 + stage * (0x104 - 0xE0), &ambient[stage], 1);
//ESP_LOGI(TAG, "stage %d ambient: %X diff: %d", stage, ambient[stage], data[stage] - ambient[stage]);
}
int vectors[][2] = {{240, 240}, {240, 0}, {0, 120}};
total = (data[5] - ambient[5]) + (data[6] - ambient[6]) + (data[7] - ambient[7]);
result[0] = vectors[0][0] * (data[5] - ambient[5]) + vectors[1][0] * (data[6] - ambient[6]) + vectors[2][0] * (data[7] - ambient[7]);
result[1] = vectors[0][1] * (data[5] - ambient[5]) + vectors[1][1] * (data[6] - ambient[6]) + vectors[2][1] * (data[7] - ambient[7]);
}
*x = result[0] / total;
*y = result[1] / total;
//ESP_LOGI(TAG, "x=%d y=%d\n", *x, *y);
#endif
const int paddle_info_1[] = {
4,
0,
1,
2,
11,
4,
9,
7,
6,
9,
};
const int paddle_info_2[] = {
3,
1,
0,
3,
10,
5,
8,
6,
5,
8,
};
struct ad714x_chip* chip;
if (paddle % 2 == 0) {
chip = &chip_top;
} else {
chip = &chip_bot;
}
ad714x_i2c_read(chip, 0xB, data, 12);
//ESP_LOGI(TAG, "CDC results: %X %X %X %X %X %X %X %X %X %X %X %X", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
for(int stage=0; stage<12; stage++) {
ad714x_i2c_read(chip, 0x0F1 + stage * (0x104 - 0xE0), &ambient[stage], 1);
//ESP_LOGI(TAG, "stage %d ambient: %X diff: %d", stage, ambient[stage], data[stage] - ambient[stage]);
}
int diff1 = data[paddle_info_1[paddle]] - ambient[paddle_info_1[paddle]];
int diff2 = data[paddle_info_2[paddle]] - ambient[paddle_info_2[paddle]];
ESP_LOGI(TAG, "%10d %10d", diff1, diff2);
int vectors[][2] = {{240, 240}, {240, 0}, {0, 120}};
total = ((diff1) + (diff2));
result[0] = vectors[0][0] * (diff1) + vectors[1][0] * (diff2);
result[1] = vectors[0][1] * (diff1) + vectors[1][1] * (diff2);
*x = result[0] / total;
*y = result[1] / total;
}