Add basic touch panel driver.

Handle touch event in display app : draw a big square at the touch point coordinates.
This commit is contained in:
JF 2020-01-03 16:32:31 +01:00
parent 27d0e1e02f
commit ee530baaa0
8 changed files with 179 additions and 103 deletions

View file

@ -197,8 +197,6 @@ macro(nRF5x_setup)
"${NRF5_SDK_PATH}/components/libraries/strerror"
"${NRF5_SDK_PATH}/components/libraries/svc"
"${NRF5_SDK_PATH}/components/libraries/timer"
"${NRF5_SDK_PATH}/components/libraries/twi_mngr"
"${NRF5_SDK_PATH}/components/libraries/twi_sensor"
"${NRF5_SDK_PATH}/components/libraries/usbd"
"${NRF5_SDK_PATH}/components/libraries/usbd/class/audio"
"${NRF5_SDK_PATH}/components/libraries/usbd/class/cdc"
@ -325,6 +323,9 @@ macro(nRF5x_setup)
"${NRF5_SDK_PATH}/components/libraries/hardfault/nrf52/handler/hardfault_handler_gcc.c"
)
LIST(APPEND SDK_SOURCE_FILES
"${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_twi.c"
)
# adds target for erasing and flashing the board with a softdevice
add_custom_target(FLASH_SOFTDEVICE ALL

View file

@ -41,6 +41,7 @@ list(APPEND SOURCE_FILES
Components/Battery/BatteryController.cpp
Components/Ble/BleController.cpp
Components/DateTime/DateTimeController.cpp
drivers/Cst816s.cpp
)
set(INCLUDE_FILES
@ -57,6 +58,7 @@ set(INCLUDE_FILES
Components/Battery/BatteryController.h
Components/Ble/BleController.h
Components/DateTime/DateTimeController.h
drivers/Cst816s.h
)
nRF5x_addExecutable(pinetime-app "${SOURCE_FILES}")

View file

@ -8,6 +8,7 @@
#include "Components/Gfx/Gfx.h"
#include <queue.h>
#include <Components/DateTime/DateTimeController.h>
#include <drivers/Cst816s.h>
using namespace Pinetime::Applications;
@ -56,7 +57,6 @@ void DisplayApp::Process(void *instance) {
auto *app = static_cast<DisplayApp *>(instance);
NRF_LOG_INFO("DisplayApp task started!");
app->InitHw();
while (1) {
app->Refresh();
}
@ -101,6 +101,8 @@ void DisplayApp::InitHw() {
gfx->DrawString(10, 0, 0x0000, "BLE", &smallFont, false);
gfx->DrawString(20, 180, 0xffff, "", &smallFont, false);
touchPanel.Init();
}
void DisplayApp::Refresh() {
@ -148,6 +150,10 @@ void DisplayApp::Refresh() {
case Messages::UpdateBatteryLevel:
batteryLevelUpdated = true;
break;
case Messages::TouchEvent:
if(state != States::Running) break;
OnTouchEvent();
break;
}
}
}
@ -247,3 +253,13 @@ void DisplayApp::PushMessage(DisplayApp::Messages msg) {
// TODO : should I do something here?
}
}
static uint16_t pointColor = 0x07e0;
void DisplayApp::OnTouchEvent() {
auto info = touchPanel.GetTouchInfo();
if(info.isTouch) {
lcd->FillRectangle(info.x-10, info.y-10, 20,20, pointColor);
pointColor+=10;
}
}

View file

@ -10,6 +10,8 @@
#include <Components/Ble/BleController.h>
#include <Components/DateTime/DateTimeController.h>
#include "lcdfont14.h"
#include "../drivers/Cst816s.h"
extern const FONT_INFO lCD_70ptFontInfo;
@ -18,7 +20,7 @@ namespace Pinetime {
class DisplayApp {
public:
enum class States {Idle, Running};
enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel} ;
enum class Messages : uint8_t {GoToSleep, GoToRunning, UpdateDateTime, UpdateBleConnection, UpdateBatteryLevel, TouchEvent} ;
DisplayApp(Controllers::Battery &batteryController,
Controllers::Ble &bleController,
Controllers::DateTime& dateTimeController);
@ -59,11 +61,11 @@ namespace Pinetime {
bool batteryLevelUpdated = false;
static char const *DaysString[];
static char const *MonthsString[];
bool dateUpdated = false;
Pinetime::Drivers::Cst816S touchPanel;
void OnTouchEvent();
};
}
}

77
src/drivers/Cst816s.cpp Normal file
View file

@ -0,0 +1,77 @@
#include <FreeRTOS.h>
#include <task.h>
#include <nrfx_log.h>
#include <legacy/nrf_drv_gpiote.h>
#include "Cst816s.h"
using namespace Pinetime::Drivers;
/* References :
* This implementation is based on this article : https://medium.com/@ly.lee/building-a-rust-driver-for-pinetimes-touch-controller-cbc1a5d5d3e9
* Touch panel datasheet (weird chinese translation) : https://wiki.pine64.org/images/5/51/CST816S%E6%95%B0%E6%8D%AE%E6%89%8B%E5%86%8CV1.1.en.pdf
*
* TODO : we need a complete datasheet and protocol reference!
* */
void Pinetime::Drivers::Cst816S::Init() {
nrf_gpio_cfg_output(pinReset);
nrf_gpio_pin_clear(pinReset);
vTaskDelay(20);
nrf_gpio_pin_set(pinReset);
vTaskDelay(200);
nrfx_twi_config_t config;
config.frequency = NRF_TWI_FREQ_400K;
config.scl = 7;
config.sda = 6;
config.interrupt_priority = NRFX_TWI_DEFAULT_CONFIG_IRQ_PRIORITY;
config.hold_bus_uninit = NRFX_TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT;
// Configure TWI in blocking mode (event_handler = nullptr)
auto ret = nrfx_twi_init(&twi, &config, nullptr, this);
nrfx_twi_enable(&twi);
}
void Cst816S::Probe() {
nrfx_err_t ret;
for(int i = 0; i < 127; i++) {
uint8_t data;
ret = nrfx_twi_rx(&twi, i, &data, 1);
if(ret == NRFX_SUCCESS) {
NRF_LOG_INFO("I2C device detected at address %d", i);
}
}
}
Cst816S::TouchInfos Cst816S::GetTouchInfo() {
Cst816S::TouchInfos info;
nrfx_twi_rx(&twi, address, touchData, 63);
auto nbTouchPoints = touchData[2] & 0x0f;
uint8_t i = 0;
uint8_t pointId = (touchData[touchIdIndex + (touchStep * i)]) >> 4;
if(nbTouchPoints == 0 && pointId == lastTouchId) return info;
// We fetch only the first touch point (the controller seems to handle only one anyway...)
info.isTouch = true;
auto xHigh = touchData[touchXHighIndex + (touchStep * i)] & 0x0f;
auto xLow = touchData[touchXLowIndex + (touchStep * i)];
uint16_t x = (xHigh << 8) | xLow;
auto yHigh = touchData[touchYHighIndex + (touchStep * i)] & 0x0f;
auto yLow = touchData[touchYLowIndex + (touchStep * i)];
uint16_t y = (yHigh << 8) | yLow;
auto action = touchData[touchEventIndex + (touchStep * i)] >> 6; /* 0 = Down, 1 = Up, 2 = contact*/
auto finger = touchData[touchIdIndex + (touchStep * i)] >> 4;
auto pressure = touchData[touchXYIndex + (touchStep * i)];
auto area = touchData[touchMiscIndex + (touchStep * i)] >> 4;
info.x = x;
info.y = y;
info.action = action;
return info;
}

47
src/drivers/Cst816s.h Normal file
View file

@ -0,0 +1,47 @@
#pragma once
#include <nrfx_twi.h>
namespace Pinetime {
namespace Drivers {
class Cst816S {
public :
struct TouchInfos {
uint16_t x;
uint16_t y;
uint8_t action;
uint8_t finger;
uint8_t pressure;
uint8_t area;
bool isTouch = false;
};
void Init();
void Probe();
TouchInfos GetTouchInfo();
private:
static constexpr uint8_t pinIrq = 28;
static constexpr uint8_t pinReset = 10;
static constexpr uint8_t address = 0x15;
static constexpr uint8_t lastTouchId = 0x0f;
static constexpr uint8_t touchPointNumIndex = 2;
static constexpr uint8_t touchMiscIndex = 8;
static constexpr uint8_t touchXYIndex = 7;
static constexpr uint8_t touchEventIndex = 3;
static constexpr uint8_t touchXHighIndex = 3;
static constexpr uint8_t touchXLowIndex = 4;
static constexpr uint8_t touchYHighIndex = 5;
static constexpr uint8_t touchYLowIndex = 6;
static constexpr uint8_t touchIdIndex = 5;
static constexpr uint8_t touchStep = 6;
uint8_t touchData[63];
// TODO TWI (i²C) should be created outside and injected into this class
// It will be needed when implementing other I²C devices
// (0x15 = touch, 0x18 = accelerometer, 0x44 = HR sensor)
nrfx_twi_t twi = NRFX_TWI_INSTANCE(1); // Use instance 1, because instance 0 is already used by SPI
};
}
}

View file

@ -32,6 +32,10 @@ Pinetime::Controllers::Battery batteryController;
Pinetime::Controllers::Ble bleController;
Pinetime::Controllers::DateTime dateTimeController;
static constexpr uint8_t pinButton = 13;
static constexpr uint8_t pinTouchIrq = 28;
extern "C" {
void vApplicationIdleHook() {
logger.Resume();
@ -43,6 +47,11 @@ extern "C" {
}
void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
if(pin == pinTouchIrq) {
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::TouchEvent);
if(!isSleeping) return;
}
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xTimerStartFromISR(debounceTimer, &xHigherPriorityTaskWoken);
// TODO should I do something if xHigherPriorityTaskWoken == pdTRUE?
@ -74,7 +83,7 @@ void SystemTask(void *) {
debounceTimer = xTimerCreate ("debounceTimer", 200, pdFALSE, (void *) 0, DebounceTimerCallback);
nrf_gpio_cfg_sense_input(13, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t)GPIO_PIN_CNF_SENSE_High);
nrf_gpio_cfg_sense_input(pinButton, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t)GPIO_PIN_CNF_SENSE_High);
nrf_gpio_cfg_output(15);
nrf_gpio_pin_set(15);
@ -85,7 +94,17 @@ void SystemTask(void *) {
pinConfig.sense = (nrf_gpiote_polarity_t)NRF_GPIOTE_POLARITY_HITOLO;
pinConfig.pull = (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pulldown;
nrfx_gpiote_in_init(13, &pinConfig, nrfx_gpiote_evt_handler);
nrfx_gpiote_in_init(pinButton, &pinConfig, nrfx_gpiote_evt_handler);
nrf_gpio_cfg_sense_input(pinTouchIrq, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t)GPIO_PIN_CNF_SENSE_Low);
pinConfig.skip_gpio_setup = true;
pinConfig.hi_accuracy = false;
pinConfig.is_watcher = false;
pinConfig.sense = (nrf_gpiote_polarity_t)NRF_GPIOTE_POLARITY_HITOLO;
pinConfig.pull = (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pullup;
nrfx_gpiote_in_init(pinTouchIrq, &pinConfig, nrfx_gpiote_evt_handler);
vTaskSuspend(nullptr);
}

View file

@ -3644,7 +3644,7 @@
// <e> NRFX_PRS_ENABLED - nrfx_prs - Peripheral Resource Sharing module
//==========================================================
#ifndef NRFX_PRS_ENABLED
#define NRFX_PRS_ENABLED 1
#define NRFX_PRS_ENABLED 0
#endif
// <q> NRFX_PRS_BOX_0_ENABLED - Enables box 0 in the module.
@ -4281,7 +4281,7 @@
// <e> NRFX_SAADC_ENABLED - nrfx_saadc - SAADC peripheral driver
//==========================================================
#ifndef NRFX_SAADC_ENABLED
#define NRFX_SAADC_ENABLED 0
#define NRFX_SAADC_ENABLED 1
#endif
// <o> NRFX_SAADC_CONFIG_RESOLUTION - Resolution
@ -5236,7 +5236,7 @@
// <e> NRFX_TWI_ENABLED - nrfx_twi - TWI peripheral driver
//==========================================================
#ifndef NRFX_TWI_ENABLED
#define NRFX_TWI_ENABLED 0
#define NRFX_TWI_ENABLED 1
#endif
// <q> NRFX_TWI0_ENABLED - Enable TWI0 instance
@ -5249,7 +5249,7 @@
#ifndef NRFX_TWI1_ENABLED
#define NRFX_TWI1_ENABLED 0
#define NRFX_TWI1_ENABLED 1
#endif
// <o> NRFX_TWI_DEFAULT_CONFIG_FREQUENCY - Frequency
@ -6729,94 +6729,6 @@
// </e>
// <e> TWI_ENABLED - nrf_drv_twi - TWI/TWIM peripheral driver - legacy layer
//==========================================================
#ifndef TWI_ENABLED
#define TWI_ENABLED 0
#endif
// <o> TWI_DEFAULT_CONFIG_FREQUENCY - Frequency
// <26738688=> 100k
// <67108864=> 250k
// <104857600=> 400k
#ifndef TWI_DEFAULT_CONFIG_FREQUENCY
#define TWI_DEFAULT_CONFIG_FREQUENCY 26738688
#endif
// <q> TWI_DEFAULT_CONFIG_CLR_BUS_INIT - Enables bus clearing procedure during init
#ifndef TWI_DEFAULT_CONFIG_CLR_BUS_INIT
#define TWI_DEFAULT_CONFIG_CLR_BUS_INIT 0
#endif
// <q> TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT - Enables bus holding after uninit
#ifndef TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT
#define TWI_DEFAULT_CONFIG_HOLD_BUS_UNINIT 0
#endif
// <o> TWI_DEFAULT_CONFIG_IRQ_PRIORITY - Interrupt priority
// <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest)
// <1=> 1
// <2=> 2
// <3=> 3
// <4=> 4
// <5=> 5
// <6=> 6
// <7=> 7
#ifndef TWI_DEFAULT_CONFIG_IRQ_PRIORITY
#define TWI_DEFAULT_CONFIG_IRQ_PRIORITY 6
#endif
// <e> TWI0_ENABLED - Enable TWI0 instance
//==========================================================
#ifndef TWI0_ENABLED
#define TWI0_ENABLED 0
#endif
// <q> TWI0_USE_EASY_DMA - Use EasyDMA (if present)
#ifndef TWI0_USE_EASY_DMA
#define TWI0_USE_EASY_DMA 0
#endif
// </e>
// <e> TWI1_ENABLED - Enable TWI1 instance
//==========================================================
#ifndef TWI1_ENABLED
#define TWI1_ENABLED 0
#endif
// <q> TWI1_USE_EASY_DMA - Use EasyDMA (if present)
#ifndef TWI1_USE_EASY_DMA
#define TWI1_USE_EASY_DMA 0
#endif
// </e>
// <q> TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED - Enables nRF52 anomaly 109 workaround for TWIM.
// <i> The workaround uses interrupts to wake up the CPU by catching
// <i> the start event of zero-frequency transmission, clear the
// <i> peripheral, set desired frequency, start the peripheral, and
// <i> the proper transmission. See more in the Errata document or
// <i> Anomaly 109 Addendum located at https://infocenter.nordicsemi.com/
#ifndef TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED
#define TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 0
#endif
// </e>
// <e> UART_ENABLED - nrf_drv_uart - UART/UARTE peripheral driver - legacy layer
//==========================================================
@ -8540,15 +8452,15 @@
// <e> NRF_LOG_ENABLED - nrf_log - Logger
//==========================================================
#ifndef NRF_LOG_ENABLED
#define NRF_LOG_ENABLED 0
#define NRF_LOG_ENABLED 1
#endif
#ifndef NRF_LOG_BACKEND_RTT_ENABLED
#define NRF_LOG_BACKEND_RTT_ENABLED 0
#define NRF_LOG_BACKEND_RTT_ENABLED 1
#endif
#ifndef NRF_LOG_BACKEND_SERIAL_USES_RTT
#define NRF_LOG_BACKEND_SERIAL_USES_RTT 0
#define NRF_LOG_BACKEND_SERIAL_USES_RTT 1
#endif
// <h> Log message pool - Configuration of log message pool