Skip to content
Snippets Groups Projects
captouch.c 18.7 KiB
Newer Older
//#include <stdio.h>
//#include <string.h>
#include "esp_log.h"
#include "driver/i2c.h"
moon2's avatar
moon2 committed
#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);
}

moon2's avatar
moon2 committed
void manual_captouch_readout(uint8_t top)
{
    struct ad714x_chip* chip = top ? (&chip_top) : (&chip_bot);
moon2's avatar
moon2 committed
    xQueueSend(gpio_evt_queue, &chip, NULL);
moon2's avatar
moon2 committed
}

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;
        }
    }
}

moon2's avatar
moon2 committed
static uint8_t top_map[] = {2, 2, 2, 0, 0, 8, 8, 8, 6, 6, 4, 4};
static uint8_t bot_map[] = {1, 1, 3, 3, 5, 5, 7, 7, 9, 9};

uint16_t read_captouch(){
    uint16_t petals = 0;
    uint16_t top = pressed_top;
    uint16_t bot = pressed_bot;
moon2's avatar
moon2 committed
    for(int i=0; i<12; i++) {
        if(top  & (1 << i)) {
moon2's avatar
moon2 committed
            petals |= (1<<top_map[i]);
        }
    }

    for(int i=0; i<10; i++) {
        if(bot  & (1 << i)) {
moon2's avatar
moon2 committed
            petals |= (1<<bot_map[i]);
        }
    }

    return petals;
}

moon2's avatar
moon2 committed
void captouch_force_calibration(){
    ad714x_i2c_write(&chip_top, 2, (1 << 14));
    ad714x_i2c_write(&chip_bot, 2, (1 << 14));
}

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);
    }

moon2's avatar
moon2 committed
    captouch_force_calibration();

    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);

moon2's avatar
moon2 committed
    // gpio_isr_handler_add(chip->gpio, gpio_isr_handler, (void *)chip);
moon2's avatar
moon2 committed
    //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,
                                                 });
moon2's avatar
moon2 committed

    gpio_evt_queue = xQueueCreate(10, sizeof(const struct ad714x_chip*));
    xTaskCreate(gpio_event_handler, "gpio_event_handler", 2048 * 2, NULL, configMAX_PRIORITIES - 2, NULL);
}

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;
}