244 lines
6.0 KiB
C
244 lines
6.0 KiB
C
/**
|
|
* @file xip2046.c
|
|
* @brief
|
|
*
|
|
* Copyright (c) 2021 Bouffalolab team
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
*/
|
|
|
|
#include "hal_spi.h"
|
|
#include "hal_gpio.h"
|
|
#include "bl702_spi.h"
|
|
#include "xpt2046.h"
|
|
// #include "lvgl.h"
|
|
|
|
#define CMD_Y_READ 0b10010000 // NOTE: XPT2046 data sheet says this is actually Y
|
|
#define CMD_X_READ 0b11010000 // NOTE: XPT2046 data sheet says this is actually X
|
|
#define CMD_Z1_READ 0b10110000
|
|
#define CMD_Z2_READ 0b11000000
|
|
|
|
struct device *touch_spi;
|
|
|
|
uint16_t avg_buf_x[XPT2046_AVG_NUM];
|
|
uint16_t avg_buf_y[XPT2046_AVG_NUM];
|
|
|
|
static void xpt2046_spi_read_reg(uint8_t reg, uint8_t *data, uint8_t byte_count)
|
|
{
|
|
gpio_write(TOUCH_PIN_CS, 0);
|
|
spi_transmit(touch_spi, ®, 1, 0);
|
|
spi_receive(touch_spi, data, byte_count, 0);
|
|
gpio_write(TOUCH_PIN_CS, 1);
|
|
}
|
|
|
|
// static void xpt2046_spi_write_reg(uint8_t reg, uint8_t* data, uint8_t byte_count)
|
|
// {
|
|
// gpio_write(TOUCH_PIN_CS,0);
|
|
// spi_transmit(touch_spi, ®, 1, 0);
|
|
// spi_transmit(touch_spi, data, byte_count,0);
|
|
// gpio_write(TOUCH_PIN_CS,1);
|
|
// }
|
|
|
|
static uint16_t xpt2046_cmd(uint8_t cmd)
|
|
{
|
|
uint8_t data[2];
|
|
xpt2046_spi_read_reg(cmd, data, 2);
|
|
uint16_t val = ((data[0] << 8) | data[1]) >> 3;
|
|
return val;
|
|
}
|
|
/******************************************************************************
|
|
* @brief xpt2046 touchpad init
|
|
*
|
|
* @param None
|
|
*
|
|
* @return None
|
|
*
|
|
*******************************************************************************/
|
|
void xpt2046_init(void)
|
|
{
|
|
gpio_set_mode(TOUCH_PIN_CS, GPIO_OUTPUT_MODE);
|
|
gpio_write(TOUCH_PIN_CS, 1);
|
|
touch_spi = device_find("spi0");
|
|
|
|
if (touch_spi) {
|
|
device_close(touch_spi);
|
|
} else {
|
|
spi_register(SPI0_INDEX, "spi0");
|
|
touch_spi = device_find("spi0");
|
|
}
|
|
|
|
if (touch_spi) {
|
|
device_open(touch_spi, DEVICE_OFLAG_STREAM_TX | DEVICE_OFLAG_STREAM_RX);
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* @brief xpt2046_touch_detect_t
|
|
*
|
|
* @param
|
|
*
|
|
* @return
|
|
*
|
|
*******************************************************************************/
|
|
static uint8_t xpt2048_is_touch_detected()
|
|
{
|
|
// check pressure if we are pressure or IRQ and pressure
|
|
uint16_t z1 = xpt2046_cmd(CMD_Z1_READ);
|
|
uint16_t z2 = xpt2046_cmd(CMD_Z2_READ);
|
|
|
|
// this is not what the confusing datasheet says but it seems to
|
|
// be enough to detect real touches on the panel
|
|
uint16_t z = z1 + 4096 - z2;
|
|
|
|
if (z > XPT2046_TOUCH_THRESHOLD) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* @brief xpt2046_ads_get
|
|
*
|
|
* @param
|
|
*
|
|
* @return
|
|
*
|
|
*******************************************************************************/
|
|
static uint8_t xpt2046_ads_get(int16_t *x, int16_t *y)
|
|
{
|
|
for (uint8_t i = 0; i < XPT2046_AVG_NUM; i++) {
|
|
if (xpt2048_is_touch_detected() == 0) {
|
|
return 0;
|
|
}
|
|
|
|
avg_buf_x[i] = xpt2046_cmd(CMD_X_READ);
|
|
avg_buf_y[i] = xpt2046_cmd(CMD_Y_READ);
|
|
}
|
|
|
|
int16_t x_min = avg_buf_x[0], x_max = avg_buf_x[0];
|
|
int16_t y_min = avg_buf_y[0], y_max = avg_buf_y[0];
|
|
int32_t x_sum = avg_buf_x[0], y_sum = avg_buf_y[0];
|
|
|
|
for (uint8_t i = 1; i < XPT2046_AVG_NUM; i++) {
|
|
if (x_min < avg_buf_x[i]) {
|
|
x_min = avg_buf_x[i];
|
|
}
|
|
|
|
if (x_max > avg_buf_x[i]) {
|
|
x_max = avg_buf_x[i];
|
|
}
|
|
|
|
if (y_min < avg_buf_y[i]) {
|
|
y_min = avg_buf_y[i];
|
|
}
|
|
|
|
if (y_max > avg_buf_y[i]) {
|
|
y_max = avg_buf_y[i];
|
|
}
|
|
|
|
x_sum += avg_buf_x[i];
|
|
y_sum += avg_buf_y[i];
|
|
}
|
|
|
|
if (x_max - x_min > 40 || y_max - y_min > 50) {
|
|
return 0;
|
|
}
|
|
|
|
*x = (x_sum - x_min - x_max) / (XPT2046_AVG_NUM - 2);
|
|
*y = (y_sum - y_min - y_max) / (XPT2046_AVG_NUM - 2);
|
|
return 2;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* @brief xpt2046_corr
|
|
*
|
|
* @param
|
|
*
|
|
* @return
|
|
*
|
|
*******************************************************************************/
|
|
static uint8_t xpt2046_adc2xy(int16_t *x, int16_t *y)
|
|
{
|
|
if ((*x) > XPT2046_X_MIN) {
|
|
(*x) -= XPT2046_X_MIN;
|
|
} else {
|
|
(*x) = 0;
|
|
}
|
|
|
|
if ((*y) > XPT2046_Y_MIN) {
|
|
(*y) -= XPT2046_Y_MIN;
|
|
} else {
|
|
(*y) = 0;
|
|
}
|
|
|
|
(*x) = (uint32_t)((uint32_t)(*x) * 240) /
|
|
(XPT2046_X_MAX - XPT2046_X_MIN);
|
|
|
|
(*y) = (uint32_t)((uint32_t)(*y) * 320) /
|
|
(XPT2046_Y_MAX - XPT2046_Y_MIN);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* @brief xpt2046_read
|
|
*
|
|
* @param
|
|
*
|
|
* @return
|
|
*
|
|
*******************************************************************************/
|
|
uint8_t xpt2046_read(int16_t *x, int16_t *y)
|
|
{
|
|
static int16_t xt = 0, yt = 0;
|
|
static uint8_t avg_last = 0;
|
|
int16_t x1, y1;
|
|
|
|
if (xpt2046_ads_get(&x1, &y1) == 0) {
|
|
goto end;
|
|
}
|
|
|
|
if (xpt2046_adc2xy(&x1, &y1) == 0) {
|
|
goto end;
|
|
}
|
|
|
|
if (avg_last == 0) {
|
|
avg_last = 1;
|
|
return 0;
|
|
} else {
|
|
avg_last = 2;
|
|
xt = x1;
|
|
*x = x1;
|
|
yt = y1;
|
|
*y = y1;
|
|
return 1;
|
|
}
|
|
|
|
end:
|
|
|
|
if (avg_last == 2) {
|
|
avg_last = 1;
|
|
*x = xt;
|
|
*y = yt;
|
|
return 1;
|
|
} else {
|
|
avg_last = 0;
|
|
return 0;
|
|
}
|
|
}
|