1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 12:28:09 +00:00

feat(core): optimize touch controller communication

This commit is contained in:
tychovrahe 2022-07-21 22:22:37 +02:00 committed by Ondrej Mikle
parent cba74272e1
commit f538547d5b
3 changed files with 69 additions and 32 deletions

View File

@ -0,0 +1 @@
Optimize touch controller communication

View File

@ -0,0 +1 @@
Optimize touch controller communication

View File

@ -39,6 +39,9 @@
#define Y_POS_MSB (touch_data[5] & 0x0FU) #define Y_POS_MSB (touch_data[5] & 0x0FU)
#define Y_POS_LSB (touch_data[6]) #define Y_POS_LSB (touch_data[6])
#define EVENT_OLD_TIMEOUT_MS 50
#define EVENT_MISSING_TIMEOUT_MS 50
static I2C_HandleTypeDef i2c_handle; static I2C_HandleTypeDef i2c_handle;
static void touch_default_pin_state(void) { static void touch_default_pin_state(void) {
@ -91,11 +94,12 @@ static void touch_active_pin_state(void) {
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input // PC4 capacitive touch panel module (CTPM) interrupt (INT) input
GPIO_InitStructure.Mode = GPIO_MODE_INPUT; GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStructure.Pull = GPIO_PULLUP; GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_4; GPIO_InitStructure.Pin = GPIO_PIN_4;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
__HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_4);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET); // release CTPM reset HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET); // release CTPM reset
HAL_Delay(310); // "Time of starting to report point after resetting" min is HAL_Delay(310); // "Time of starting to report point after resetting" min is
@ -199,9 +203,9 @@ static void _i2c_cycle(void) {
} }
void touch_set_mode(void) { void touch_set_mode(void) {
// set register 0xA4 G_MODE to interrupt polling mode (0x00). basically, CTPM // set register 0xA4 G_MODE to interrupt trigger mode (0x01). basically, CTPM
// keeps this input line (to PC4) low while a finger is on the screen. // generates a pulse when new data is available
uint8_t touch_panel_config[] = {0xA4, 0x00}; uint8_t touch_panel_config[] = {0xA4, 0x01};
ensure( ensure(
sectrue * (HAL_OK == HAL_I2C_Master_Transmit( sectrue * (HAL_OK == HAL_I2C_Master_Transmit(
&i2c_handle, TOUCH_ADDRESS, touch_panel_config, &i2c_handle, TOUCH_ADDRESS, touch_panel_config,
@ -229,9 +233,19 @@ void touch_power_off(void) {
} }
void touch_init(void) { void touch_init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
// I2C device interface configuration // I2C device interface configuration
_i2c_init(); _i2c_init();
// PC4 capacitive touch panel module (CTPM) interrupt (INT) input
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = GPIO_PIN_4;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
__HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_4);
touch_set_mode(); touch_set_mode();
touch_sensitivity(0x06); touch_sensitivity(0x06);
} }
@ -248,30 +262,62 @@ void touch_sensitivity(uint8_t value) {
uint32_t touch_is_detected(void) { uint32_t touch_is_detected(void) {
// check the interrupt line coming in from the CTPM. // check the interrupt line coming in from the CTPM.
// the line goes low when a touch event is actively detected. // the line make a short pulse, which sets an interrupt flag when new data is
// reference section 1.2 of "Application Note for FT6x06 CTPM". // available.
// we configure the touch controller to use "interrupt polling mode". // Reference section 1.2 of "Application Note for FT6x06 CTPM". we
return GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4); // configure the touch controller to use "interrupt trigger mode".
uint32_t event = __HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_4);
if (event != 0) {
__HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_4);
}
return event;
}
uint32_t check_timeout(uint32_t prev, uint32_t timeout) {
uint32_t current = hal_ticks_ms();
uint32_t diff = current - prev;
if (diff >= timeout) {
return 1;
}
return 0;
} }
uint32_t touch_read(void) { uint32_t touch_read(void) {
static uint8_t touch_data[TOUCH_PACKET_SIZE], static uint8_t touch_data[TOUCH_PACKET_SIZE];
previous_touch_data[TOUCH_PACKET_SIZE];
static uint32_t xy; static uint32_t xy;
static int touching; static uint32_t last_check_time = 0;
static uint32_t last_event_time = 0;
static int touching = 0;
uint32_t detected = touch_is_detected();
if (detected == 0) {
last_check_time = hal_ticks_ms();
if (touching && check_timeout(last_event_time, EVENT_MISSING_TIMEOUT_MS)) {
// we didn't detect an event for a long time, but there was an active
// touch: send END event, as we probably missed the END event
touching = 0;
return TOUCH_END | xy;
}
int last_packet = 0;
if (!touch_is_detected()) {
// only poll when the touch interrupt is active.
// when it's inactive, we might need to read one last data packet to get to
// the TOUCH_END event, which clears the `touching` flag.
if (touching) {
last_packet = 1;
} else {
return 0; return 0;
} }
if ((touching == 0) &&
(check_timeout(last_check_time, EVENT_OLD_TIMEOUT_MS))) {
// we have detected an event, but it might be too old, rather drop it
// (only dropping old events if there was no touch active)
last_check_time = hal_ticks_ms();
return 0;
} }
last_check_time = hal_ticks_ms();
uint8_t outgoing[] = {0x00}; // start reading from address 0x00 uint8_t outgoing[] = {0x00}; // start reading from address 0x00
int result = HAL_I2C_Master_Transmit(&i2c_handle, TOUCH_ADDRESS, outgoing, int result = HAL_I2C_Master_Transmit(&i2c_handle, TOUCH_ADDRESS, outgoing,
sizeof(outgoing), 1); sizeof(outgoing), 1);
@ -285,11 +331,7 @@ uint32_t touch_read(void) {
return 0; // read failure return 0; // read failure
} }
if (0 == memcmp(previous_touch_data, touch_data, TOUCH_PACKET_SIZE)) { last_event_time = hal_ticks_ms();
return 0; // polled and got the same event again
} else {
memcpy(previous_touch_data, touch_data, TOUCH_PACKET_SIZE);
}
const uint32_t number_of_touch_points = const uint32_t number_of_touch_points =
touch_data[2] & 0x0F; // valid values are 0, 1, 2 (invalid 0xF before touch_data[2] & 0x0F; // valid values are 0, 1, 2 (invalid 0xF before
@ -309,13 +351,6 @@ uint32_t touch_read(void) {
} }
} }
if (last_packet) {
// interrupt line is inactive, we didn't read valid touch data, and as far
// as we know, we never sent a TOUCH_END event.
touching = 0;
return TOUCH_END | xy;
}
return 0; return 0;
} }