cancel
Showing results for 
Search instead for 
Did you mean: 

Touchscreen sending phantom clicks

Hey there,

I am using a touchscreen with a GT911 controller on a custom ST board. We initially architected it such that a touch generates an interrupt, and in that interrupt we do two I2C reads and one write. Bad practice to do anything long in an interrupt, I know, but we were following guidance that we found elsewhere. This is what our ISR did:

// Function to read out touch coordinates when a rising edge is detected on CTP_INT.
// This is called from the CTP_INT GPIO ISR.
bool Touch_Callback(void) {
	uint8_t number_of_coordinates;
	uint8_t point_info;

	// Read the touchpoint information register
	bool success = _ReadReg(&point_info, GT911_POINT_INFO);
	//Check the buffer status bit to see if coordinate information is ready to read
	if (success && (point_info & TOUCHPOINT_COORD_READY_MASK) != 0) {
		// Find the number of coordinates available
		number_of_coordinates = point_info & TOUCHPOINT_NUMBER_RCVD_MASK;
		// We're set up to read 1 coordinate. TouchGFX does not support multi-touch.
		if (number_of_coordinates != 0 && _ReadTouchPoint(GT911_POINT_1, &coordinate_x, &coordinate_y)) {
			// Let's TouchGFX know there is data available to be read
			touch_data_available = true;
		}
		// Need to call this to clear the buffer status bit
		success &= _WriteReg(GT911_POINT_INFO, 0x00);
	}
	return success;
}

We're now trying to resolve this goof by setting a boolean flag in the interrupt, but only reading and clearing the registers in a separate task. This task has a lower priority (2) than the TouchGFX task (24) because as far as I remember TouchGFX needs to be the highest priority. New code:

// Function called from the CTP_INT GPIO ISR.
// This function should only set a flag - no I2C operations allowed in ISR.
void Touch_Callback(void) {
	// Simply set the flag to indicate processing is needed
	// The actual I2C operations will be done in Touch_ProcessLoop
	touch_interrupt_pending = true;
}

// Function called continuously from main task to process touch interrupts
// This is where all I2C operations are performed
void Touch_ProcessLoop(void)
{
	// Check if we have a pending touch interrupt to process
	if (touch_interrupt_pending) {
		uint8_t number_of_coordinates;
		uint8_t point_info;

		touch_interrupt_pending = false;

		// Read the touchpoint information register
		bool success = _ReadReg(&point_info, GT911_POINT_INFO);
		// Check the buffer status bit to see if coordinate information is ready to read
		if (success && (point_info & TOUCHPOINT_COORD_READY_MASK) != 0) {
			// Find the number of coordinates available
			number_of_coordinates = point_info & TOUCHPOINT_NUMBER_RCVD_MASK;
			// We're set up to read 1 coordinate. TouchGFX does not support multi-touch.
			if (number_of_coordinates != 0 && _ReadTouchPoint(GT911_POINT_1, &coordinate_x, &coordinate_y)) {
				// Let's TouchGFX know there is data available to be read
				touch_data_available = true;
			}
			// Need to call this to clear the buffer status bit
			_WriteReg(GT911_POINT_INFO, 0x00);
		}
	}
}

 and `Touch_ProcessLoop` gets called from the I2C3 task, as such:

portTASK_FUNCTION(_I2C3ManagerTask, pvParameters)
{
    (void) pvParameters;

    while (1)
    {
        Touch_ProcessLoop();
        OtherI2C3Thing_ProcessLoop();

        osDelay(I2C3MANAGER_TASK_RATE_MSEC / portTICK_PERIOD_MS);
    }
}

I understand that the TouchGFX task is running every 16ms, so I optimistically thought perhaps I could run this task at 15ms or 8ms and be able to service TouchGFX every tick in STM32TouchController.cpp, but that's not the case.

Even as the highest priority task (that isn't TouchGFX), and running every 8ms, there's an easy failure case - touching and holding the screen. TouchGFX will occassionally return false from sampleTouch and the touch will be considered a click and processed by the system. The Setting's screen's 'X' (cancel) button leads to the home screen, and in that same location on the home sceen is a 'Settings' button, so if I hold my finger on that spot the screens will awkwardly cycle.

Here's the remainder of the code,

// Function called by TouchGFX to determine if there is touch data ready to read
bool Touch_Detected(void) {
	if (touch_data_available) {
		touch_data_available = false;
		return true;
	} else {
		return false;
	}
}

// Function called by TouchGFX to read out coordinate data
void Touch_GFXGetData(int32_t *x, int32_t *y) {
	*x = (int32_t) coordinate_x;
	*y = (int32_t) coordinate_y;
}
bool STM32TouchController::sampleTouch(int32_t& x, int32_t& y)
{
    /**
     * By default sampleTouch returns false,
     * return true if a touch has been detected, otherwise false.
     *
     * Coordinates are passed to the caller by reference by x and y.
     *
     * This function is called by the TouchGFX framework.
     * By default sampleTouch is called every tick, this can be adjusted by HAL::setTouchSampleRate(int8_t);
     *
     */

	int32_t xdata;
	int32_t ydata;

	// If a touch has been detected then read the coordinates and pass them to TouchGFX
	if (Touch_Detected())
	{
		Touch_GFXGetData(&xdata, &ydata);
		x = xdata;
		y = ydata;
		return true;
	}
	else
	{
		return false;
	}
}

 How is everyone else solving this? I feel like I must be missing something trivial. 

0 REPLIES 0