This repository has been archived on 2023-07-17. You can view files and clone it, but cannot push or open issues or pull requests.
bl_mcu_sdk/bsp/bsp_common/touch/xpt2046.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, &reg, 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, &reg, 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;
}
}