Files
mongoose-touch/libs/stmpe610/src/stmpe610.c
Pim van Pelt 4f64ed554a Initial commit
2017-11-25 01:14:04 +01:00

264 lines
8.3 KiB
C

/*
* Author: LoBo (loboris@gmail.com, loboris.github)
*
* Module supporting STMPE touch screen controller.
*
* HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS
* USING DIRECT or DMA SPI TRANSFER MODEs
*
*/
#include "mgos.h"
#include "lobo_spi.h"
#include "stmpe610.h"
#define SPI_BUS VSPI_HOST
#define STMPE_SPI_MODE 1
static spi_lobo_device_handle_t s_stmpe610_spi = NULL;
static mgos_stmpe610_event_t s_event_handler = NULL;
static enum mgos_stmpe610_rotation_t s_rotation = STMPE610_PORTRAIT;
static void IRAM_ATTR _spi_transfer_start(spi_lobo_device_handle_t spi_dev, int wrbits, int rdbits) {
// Load send buffer
spi_dev->host->hw->user.usr_mosi_highpart = 0;
spi_dev->host->hw->mosi_dlen.usr_mosi_dbitlen = wrbits-1;
spi_dev->host->hw->user.usr_mosi = 1;
if (rdbits) {
spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = rdbits;
spi_dev->host->hw->user.usr_miso = 1;
}
else {
spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = 0;
spi_dev->host->hw->user.usr_miso = 0;
}
// Start transfer
spi_dev->host->hw->cmd.usr = 1;
// Wait for SPI bus ready
while (spi_dev->host->hw->cmd.usr);
}
static void IRAM_ATTR stmpe610_write_reg(uint8_t reg, uint8_t val) {
spi_lobo_device_select(s_stmpe610_spi, 0);
s_stmpe610_spi->host->hw->data_buf[0] = (val << 8) | reg;
_spi_transfer_start(s_stmpe610_spi, 16, 0);
spi_lobo_device_deselect(s_stmpe610_spi);
}
static uint8_t IRAM_ATTR stmpe610_read_byte(uint8_t reg) {
spi_lobo_device_select(s_stmpe610_spi, 0);
s_stmpe610_spi->host->hw->data_buf[0] = (reg << 8) | (reg | 0x80);
_spi_transfer_start(s_stmpe610_spi, 16, 16);
uint8_t res = s_stmpe610_spi->host->hw->data_buf[0] >> 8;
spi_lobo_device_deselect(s_stmpe610_spi);
return res;
}
static uint16_t IRAM_ATTR stmpe610_read_word(uint8_t reg) {
spi_lobo_device_select(s_stmpe610_spi, 0);
s_stmpe610_spi->host->hw->data_buf[0] = ((((reg+1) << 8) | ((reg+1) | 0x80)) << 16) | (reg << 8) | (reg | 0x80);
_spi_transfer_start(s_stmpe610_spi, 32, 32);
uint16_t res = (uint16_t)(s_stmpe610_spi->host->hw->data_buf[0] & 0xFF00);
res |= (uint16_t)(s_stmpe610_spi->host->hw->data_buf[0] >> 24);
spi_lobo_device_deselect(s_stmpe610_spi);
return res;
}
static uint32_t stmpe610_getID()
{
uint16_t tid = stmpe610_read_word(0);
uint8_t tver = stmpe610_read_byte(2);
return (tid << 8) | tver;
}
static uint8_t stmpe610_bufferLength(void) {
return stmpe610_read_byte(STMPE_FIFO_SIZE);
}
static uint8_t stmpe610_readData(uint16_t *x, uint16_t *y, uint8_t *z) {
uint8_t samples, cnt;
uint32_t sum_sample_x = 0, sum_sample_y = 0;
uint16_t sum_sample_z = 0;
samples = cnt = stmpe610_bufferLength();
LOG(LL_DEBUG, ("Touch sensed with %d samples", samples));
if (samples == 0)
return 0;
while (cnt>0) {
uint16_t sample_x, sample_y;
uint8_t sample_z;
sample_x = stmpe610_read_word(0x4D);
sample_y = stmpe610_read_word(0x4F);
sample_z = stmpe610_read_byte(0x51);
sum_sample_x += sample_x;
sum_sample_y += sample_y;
sum_sample_z += sample_z;
LOG(LL_DEBUG, ("Sample at (%d,%d) pressure=%d, bufferLength=%d", sample_x, sample_y, sample_z, stmpe610_bufferLength()));
cnt--;
}
*x = sum_sample_x / samples;
*y = sum_sample_y / samples;
*z = sum_sample_z / samples;
stmpe610_write_reg(STMPE_FIFO_STA, STMPE_FIFO_STA_RESET); // clear FIFO
stmpe610_write_reg(STMPE_FIFO_STA, 0); // unreset
return samples;
}
static long map(long x, long in_min, long in_max, long out_min, long out_max)
{
if (x<in_min) x=in_min;
if (x>in_max) x=in_max;
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
static void stmpe610_map_rotation(uint16_t x, uint16_t y, uint16_t *x_out, uint16_t *y_out) {
switch(s_rotation) {
case STMPE610_LANDSCAPE:
*x_out = map(y, 150, 3800, 0, 4095);
*y_out = map(x, 250, 3700, 0, 4095);
break;
case STMPE610_PORTRAIT_FLIP:
*x_out = map(x, 250, 3800, 0, 4095);
*y_out = 4095-map(y, 150, 3700, 0, 4095);
break;
case STMPE610_LANDSCAPE_FLIP:
*x_out = 4095-map(y, 150, 3800, 0, 4095);
*y_out = 4095-map(x, 250, 3700, 0, 4095);
break;
default: // STMPE610_PORTRAIT
*x_out = 4095-map(x, 250, 3800, 0, 4095);
*y_out = map(y, 150, 3700, 0, 4095);
}
}
static void stmpe610_irq(int pin, void *arg) {
struct mgos_stmpe610_event_data ed;
uint16_t x, y;
uint8_t z;
if (stmpe610_bufferLength()==0) {
uint8_t i;
LOG(LL_DEBUG, ("Touch DOWN"));
for (i=0; i<10; i++) {
mgos_msleep(5);
if (stmpe610_bufferLength()>0) {
stmpe610_readData(&x, &y, &z);
LOG(LL_DEBUG, ("Touch DOWN at (%d,%d) pressure=%d, length=%d, iteration=%d", x, y, z, ed.length, i));
ed.length=1;
ed.direction = TOUCH_DOWN;
stmpe610_map_rotation(x, y, &ed.x, &ed.y);
ed.z = z;
if (s_event_handler)
s_event_handler(&ed);
break;
}
}
stmpe610_write_reg(STMPE_INT_STA, 0xFF); // reset all ints
return;
}
ed.length = stmpe610_readData(&x, &y, &z);
LOG(LL_DEBUG, ("Touch UP at (%d,%d) pressure=%d, length=%d", x, y, z, ed.length));
ed.direction = TOUCH_UP;
stmpe610_map_rotation(x, y, &ed.x, &ed.y);
ed.z = z;
if (s_event_handler)
s_event_handler(&ed);
stmpe610_write_reg(STMPE_INT_STA, 0xFF); // reset all ints
(void) pin;
(void) arg;
}
void mgos_stmpe610_set_handler(mgos_stmpe610_event_t handler) {
s_event_handler = handler;
}
void mgos_stmpe610_set_rotation(enum mgos_stmpe610_rotation_t rotation) {
s_rotation = rotation;
}
bool mgos_stmpe610_init(void) {
esp_err_t ret;
gpio_pad_select_gpio(mgos_sys_config_get_stmpe610_cs_pin());
gpio_set_direction(mgos_sys_config_get_stmpe610_cs_pin(), GPIO_MODE_OUTPUT);
spi_lobo_bus_config_t buscfg={
.miso_io_num=mgos_sys_config_get_spi_miso(),
.mosi_io_num=mgos_sys_config_get_spi_mosi(),
.sclk_io_num=mgos_sys_config_get_spi_sck(),
.quadwp_io_num=-1,
.quadhd_io_num=-1,
.max_transfer_sz = 6*1024,
};
spi_lobo_device_interface_config_t tsdevcfg={
.clock_speed_hz=1000000,
.mode=STMPE_SPI_MODE,
.spics_io_num=mgos_sys_config_get_stmpe610_cs_pin(), //Touch CS pin
.spics_ext_io_num=-1, //Not using the external CS
.flags = 0,
};
ret=spi_lobo_bus_add_device(SPI_BUS, &buscfg, &tsdevcfg, &s_stmpe610_spi);
assert(ret==ESP_OK);
ret = spi_lobo_device_select(s_stmpe610_spi, 1);
assert(ret==ESP_OK);
ret = spi_lobo_device_deselect(s_stmpe610_spi);
assert(ret==ESP_OK);
uint32_t tver = stmpe610_getID();
if (tver >> 8 != 0x0811) {
LOG(LL_ERROR, ("STMPE SPI init failed, disabling"));
return true;
}
LOG(LL_INFO, ("SPI init ok (cs=%d, speed=%u, ver=%04x, rev=%02x); irq=%d", mgos_sys_config_get_stmpe610_cs_pin(), spi_lobo_get_speed(s_stmpe610_spi),
tver>>8, tver&0xFF, mgos_sys_config_get_stmpe610_irq_pin()));
stmpe610_write_reg(STMPE_SYS_CTRL1, STMPE_SYS_CTRL1_RESET);
mgos_msleep(10);
for (uint8_t i=0; i<65; i++)
stmpe610_read_byte(i);
stmpe610_write_reg(STMPE_SYS_CTRL2, 0x0); // turn on clocks!
stmpe610_write_reg(STMPE_INT_EN, STMPE_INT_EN_TOUCHDET);
stmpe610_write_reg(STMPE_ADC_CTRL1, STMPE_ADC_CTRL1_10BIT | (0x6 << 4)); // 96 clocks per conversion
stmpe610_write_reg(STMPE_ADC_CTRL2, STMPE_ADC_CTRL2_6_5MHZ);
stmpe610_write_reg(STMPE_TSC_CFG, STMPE_TSC_CFG_4SAMPLE | STMPE_TSC_CFG_DELAY_1MS | STMPE_TSC_CFG_SETTLE_5MS);
stmpe610_write_reg(STMPE_TSC_FRACTION_Z, 0x6);
stmpe610_write_reg(STMPE_FIFO_TH, 1);
stmpe610_write_reg(STMPE_FIFO_STA, STMPE_FIFO_STA_RESET);
stmpe610_write_reg(STMPE_FIFO_STA, 0); // unreset
stmpe610_write_reg(STMPE_TSC_I_DRIVE, STMPE_TSC_I_DRIVE_50MA);
stmpe610_write_reg(STMPE_TSC_CTRL, 0x30); // X&Y&Z, 16 reading window
stmpe610_write_reg(STMPE_TSC_CTRL, 0x31); // X&Y&Z, 16 reading window, TSC enable
stmpe610_write_reg(STMPE_INT_STA, 0xFF); // reset all ints
stmpe610_write_reg(STMPE_INT_CTRL, STMPE_INT_CTRL_POL_LOW | STMPE_INT_CTRL_EDGE | STMPE_INT_CTRL_ENABLE);
mgos_gpio_set_mode(mgos_sys_config_get_stmpe610_irq_pin(), MGOS_GPIO_MODE_INPUT);
mgos_gpio_set_pull(mgos_sys_config_get_stmpe610_irq_pin(), MGOS_GPIO_PULL_UP);
mgos_gpio_set_int_handler(mgos_sys_config_get_stmpe610_irq_pin(), MGOS_GPIO_INT_EDGE_NEG, stmpe610_irq, NULL);
mgos_gpio_enable_int(mgos_sys_config_get_stmpe610_irq_pin());
return true;
}