Working with STM32F429-discovery Display Part 3.2: STMPE811 Touch Controller, Display Touch location

In the previous guide (here), we took a look at the touch controller and its features, initialize the I2C peripheral and external interrupt. In second part of the touch controller on STM32F429 discovery, we shall initialize the controller and display the results on the display itself.

In this guide, we shall cover the following:

  • Developing the header file.
  • Developing the source file.
  • Main.c code.
  • Results.

1. Developing the header file:

We start off by creating new header file with name of STMPE811.h.

Within the header file, include the header guard as following:

#ifndef STMPE811_H_
#define STMPE811_H_



#endif /* STMPE811_H_ */

Within the header guard, include the standard integer library as following:

#include "stdint.h"

Define the address of the STMPE811 which is mentioned in the schematic as 0x41:

#define deviceAddress 0x41

Declare enum to handle the touch / no touch events:

typedef enum TouchDetect
{
	touched =1,
	no_touch=0

}TouchDetect_t;

Define the required registers to initialize and read the touch screen values:

#define STMPE811_REG_SYS_CTRL2 			0x04 /*Clock control*/
#define STMPE811_REG_SYS_CTRL1 			0x03 /*Reset control*/
#define STMPE811_REG_IO_AF              0x17 /*Alternate function register*/
#define STMPE811_REG_ADC_CTRL1          0x20 /*ADC control*/
#define STMPE811_REG_ADC_CTRL2          0x21 /*ADC control*/
#define STMPE811_REG_TSC_CFG            0x41 /*Touch Configuration*/
#define STMPE811_REG_FIFO_TH            0x4A /*FIFO threshold*/
#define STMPE811_REG_FIFO_STA           0x4B /*FIFO status*/
#define STMPE811_REG_TSC_FRACT_XYZ      0x56 /*Touchscreen controller FRACTION_Z*/
#define STMPE811_REG_TSC_I_DRIVE        0x58 /*Touchscreen controller drive*/
#define STMPE811_REG_TSC_CTRL           0x40 /*touchscreen controller control register*/
#define STMPE811_REG_INT_CTRL			0x09 /*Interrupt control register*/
#define STMPE811_REG_INT_EN				0x0A /*Interrupt enable register*/
#define STMPE811_REG_INT_STA            0x0B /*Interrupt status register*/
#define STMPE811_REG_TSC_DATA_INC       0x57 /*Touchscreen controller DATA Incremental*/
#define STMPE811_REG_TSC_DATA_NON_INC   0xD7 /*Touchscreen controller DATA Non-Incremental*/
#define STMPE811_REG_FIFO_SIZE          0x4C /*FIFO size*/

Necessary facilities:

/*IO expander facilities*/
#define STMPE811_ADC_FCT                0x01
#define STMPE811_TS_FCT                 0x02
#define STMPE811_IO_FCT                 0x04
#define STMPE811_TEMPSENS_FCT           0x08

Touch screen pins:

/* Touch Screen Pins definition */
#define STMPE811_TOUCH_YD               STMPE811_PIN_7
#define STMPE811_TOUCH_XD               STMPE811_PIN_6
#define STMPE811_TOUCH_YU               STMPE811_PIN_5
#define STMPE811_TOUCH_XU               STMPE811_PIN_4
#define STMPE811_TOUCH_IO_ALL           0x00

Control status and enable:

#define STMPE811_TS_CTRL_ENABLE         0x01
#define STMPE811_TS_CTRL_STATUS         0x80

Required functions:

STMPE811 Initialization function:

void STMPE811_Touch_Enable(void);

It takes no arguments and return nothing.

Is touch:

TouchDetect_t isToched(void);

It takes no argument and return the if the screen is touched or not.

Get touch:

void getTouchValue(uint16_t *X, uint16_t *Y);

It takes two arguments:

  • Pointer to store the X values.
  • Pointer to store the Y values.

And returns nothing.

Get ID function:

uint16_t getID(void);

It takes no argument and returns the ID value (Should always be 0x0811).

Hence the entire header file:

#ifndef STMPE811_H_
#define STMPE811_H_

#include "stdint.h"

#define deviceAddress 0x41


typedef enum TouchDetect
{
	touched =1,
	no_touch=0

}TouchDetect_t;



#define STMPE811_REG_SYS_CTRL2 			0x04 /*Clock control*/
#define STMPE811_REG_SYS_CTRL1 			0x03 /*Reset control*/
#define STMPE811_REG_IO_AF              0x17 /*Alternate function register*/
#define STMPE811_REG_ADC_CTRL1          0x20 /*ADC control*/
#define STMPE811_REG_ADC_CTRL2          0x21 /*ADC control*/
#define STMPE811_REG_TSC_CFG            0x41 /*Touch Configuration*/
#define STMPE811_REG_FIFO_TH            0x4A /*FIFO threshold*/
#define STMPE811_REG_FIFO_STA           0x4B /*FIFO status*/
#define STMPE811_REG_TSC_FRACT_XYZ      0x56 /*Touchscreen controller FRACTION_Z*/
#define STMPE811_REG_TSC_I_DRIVE        0x58 /*Touchscreen controller drive*/
#define STMPE811_REG_TSC_CTRL           0x40 /*touchscreen controller control register*/
#define STMPE811_REG_INT_CTRL			0x09 /*Interrupt control register*/
#define STMPE811_REG_INT_EN				0x0A /*Interrupt enable register*/
#define STMPE811_REG_INT_STA            0x0B /*Interrupt status register*/
#define STMPE811_REG_TSC_DATA_INC       0x57 /*Touchscreen controller DATA Incremental*/
#define STMPE811_REG_TSC_DATA_NON_INC   0xD7 /*Touchscreen controller DATA Non-Incremental*/
#define STMPE811_REG_FIFO_SIZE          0x4C /*FIFO size*/

/*IO expander facilities*/
#define STMPE811_ADC_FCT                0x01
#define STMPE811_TS_FCT                 0x02
#define STMPE811_IO_FCT                 0x04
#define STMPE811_TEMPSENS_FCT           0x08



/* Touch Screen Pins definition */
#define STMPE811_TOUCH_YD               STMPE811_PIN_7
#define STMPE811_TOUCH_XD               STMPE811_PIN_6
#define STMPE811_TOUCH_YU               STMPE811_PIN_5
#define STMPE811_TOUCH_XU               STMPE811_PIN_4
#define STMPE811_TOUCH_IO_ALL           0x00

/* IO Pins definition */
#define STMPE811_PIN_0                  0x01
#define STMPE811_PIN_1                  0x02
#define STMPE811_PIN_2                  0x04
#define STMPE811_PIN_3                  0x08
#define STMPE811_PIN_4                  0x10
#define STMPE811_PIN_5                  0x20
#define STMPE811_PIN_6                  0x40
#define STMPE811_PIN_7                  0x80
#define STMPE811_PIN_ALL                0xFF

#define STMPE811_TS_CTRL_ENABLE         0x01
#define STMPE811_TS_CTRL_STATUS         0x80



void STMPE811_Touch_Enable(void);
TouchDetect_t isToched(void);
void getTouchValue(uint16_t *X, uint16_t *Y);
uint16_t getID(void);


#endif /* STMPE811_H_ */

Thats all for the header file.

Next the source file.

2. Developing the Source File:

Create new source file with name of STMPE811.c

With the source file, include the following:

#include "i2c3.h"
#include "STMPE811.h"
#include "delay.h"
#include "STM32F4xx.h"

Now, we shall populate the function:

We start with the initialization function:

void STMPE811_Touch_Enable(void)

Within the function:

Declare local variable to hold some temporary values:

uint8_t mode;

The soft reset the controller as following:

  • Soft reset the controller.
  • Delay for 10ms to ensure the reset is done.
  • Get out of soft reset.
  • Delay for 2ms.
	/* Power Down the stmpe811 */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL1, 2);

	/* Wait for a delay to ensure registers erasing */
	delay(10);

	/* Power On the Codec after the power off => all registers are reinitialized */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL1, 0);

	/* Wait for a delay to ensure registers erasing */
	delay(2);

Disable clock access to the GPIO by reading the Clock control register, set the GPIO clock to zero then write the new value:

	/*Disable clock access to GPIO*/
	
	i2c3_readByte(deviceAddress, STMPE811_REG_SYS_CTRL2, &mode);

	mode &= ~(STMPE811_IO_FCT);

	/* Write the new register value */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL2, mode);

Set the pins to be GPIO/Touch as following:

	/*Select TSC pins in TSC alternate mode */

	I2C3_WriteByte(deviceAddress, STMPE811_REG_IO_AF, STMPE811_TOUCH_IO_ALL);

Turn on the touch:

	mode&= ~(STMPE811_TS_FCT | STMPE811_ADC_FCT);

	/* Write the new register value */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL2, mode);

Set the sample resolution and settling time:

	/* Select Sample Time, bit number and ADC Reference */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_ADC_CTRL1, 0x49);

Wait for 2ms:

	/* Wait for 2 ms */
	delay(2);

Set the ADC clock to 3.25MHz

	/* Select the ADC clock speed: 3.25 MHz */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_ADC_CTRL2, 0x01);

Configure the touch screen with the following parameters:

  • Touch average control: 4 samples.
  • Touch delay time: 500uS.
  • Panel Driver settling time: 500uS.

	/* Select 2 nF filter capacitor */
	/* Configuration:
	- Touch average control    : 4 samples
	- Touch delay time         : 500 uS
	- Panel driver setting time: 500 uS
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_CFG, 0x9A);

Set threshold reading to be single reading:

	/* Configure the Touch FIFO threshold: single point reading */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_TH, 0x01);

Clear the FIFO and put the FIFO back in the operation mode:

	/* Clear the FIFO memory content. */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x01);

	/* Put the FIFO back into operation mode  */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x00);

Set the range and accuracy of z measurement:

  • Fractional Range: 7
  • Whole part: 1

	/* Set the range and accuracy pf the pressure measurement (Z) :
	- Fractional part :7a
	- Whole part      :1
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_FRACT_XYZ, 0x07);

Set the current to be 50mA:

	/* Set the driving capability (limit) of the device for TSC pins: 50mA */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_I_DRIVE, 0x01);

Configure the touch controller with the following:

  • No window tracking index.
  • XYZ acquisition mode.
	/* Touch screen control configuration (enable TSC):
	- No window tracking index
	- XYZ acquisition mode
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_CTRL, 0x01);

Clear any pending flag (if any):

	/*  Clear all the status pending bits if any */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_INT_STA, 0xFF);

Delay by 5ms:

	delay(5);

Hence the function as following:

void STMPE811_Touch_Enable(void)
{

	uint8_t mode;
	
	/* Power Down the stmpe811 */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL1, 2);

	/* Wait for a delay to ensure registers erasing */
	delay(10);

	/* Power On the Codec after the power off => all registers are reinitialized */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL1, 0);

	/* Wait for a delay to ensure registers erasing */
	delay(2);

	/*Disable clock access to GPIO*/
	
	i2c3_readByte(deviceAddress, STMPE811_REG_SYS_CTRL2, &mode);

	mode &= ~(STMPE811_IO_FCT);

	/* Write the new register value */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL2, mode);


	/*Select TSC pins in TSC alternate mode */

	I2C3_WriteByte(deviceAddress, STMPE811_REG_IO_AF, STMPE811_TOUCH_IO_ALL);


	mode&= ~(STMPE811_TS_FCT | STMPE811_ADC_FCT);

	/* Write the new register value */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL2, mode);



	/* Select Sample Time, bit number and ADC Reference */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_ADC_CTRL1, 0x49);

	/* Wait for 2 ms */
	delay(2);

	/* Select the ADC clock speed: 3.25 MHz */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_ADC_CTRL2, 0x01);



	/* Select 2 nF filter capacitor */
	/* Configuration:
	- Touch average control    : 4 samples
	- Touch delay time         : 500 uS
	- Panel driver setting time: 500 uS
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_CFG, 0x9A);

	/* Configure the Touch FIFO threshold: single point reading */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_TH, 0x01);

	/* Clear the FIFO memory content. */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x01);

	/* Put the FIFO back into operation mode  */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x00);

	/* Set the range and accuracy pf the pressure measurement (Z) :
	- Fractional part :7a
	- Whole part      :1
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_FRACT_XYZ, 0x07);

	/* Set the driving capability (limit) of the device for TSC pins: 50mA */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_I_DRIVE, 0x01);

	/* Touch screen control configuration (enable TSC):
	- No window tracking index
	- XYZ acquisition mode
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_CTRL, 0x01);

	/*  Clear all the status pending bits if any */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_INT_STA, 0xFF);


	/*Delay for 5ms*/

	delay(5);

}

In order to check if there is a touch or not:

  • Read Touch Control Register.
  • Check if touch is detected or not.
  • If yes, Check the fifo if there is any data and return touched state.
  • If no, clear the FIFO and put it back into operation and return no touch state.
TouchDetect_t isToched(void)
{

	uint8_t state=0;
	uint8_t value=0;

	i2c3_readByte(deviceAddress, STMPE811_REG_TSC_CTRL, &value);

	value&=STMPE811_TS_CTRL_STATUS;

	state=(value&STMPE811_TS_CTRL_STATUS)==0x80;

	if(value==STMPE811_TS_CTRL_STATUS)
	{
		i2c3_readByte(deviceAddress,STMPE811_REG_FIFO_SIZE, &value);
		if(value>0)
		{
			return touched;
		}
	}

	else
	{
		/* Clear the FIFO memory content. */
		I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x01);

		/* Put the FIFO back into operation mode  */
		I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x00);
	}



	return no_touch;
}

To get the touch values:

  • Burst read 4 bytes from Touchscreen controller DATA in non-increment mode.
  • Calculate the position of XY.
  • Reset the FIFO.
  • Put FIFO back into operation mode.

void getTouchValue(uint16_t *X, uint16_t *Y)
{
	uint32_t uldataXYZ;
	uint8_t  dataXYZ[4];
	uint8_t mode;

	I2C3_ReadMultiByte(deviceAddress, STMPE811_REG_TSC_DATA_NON_INC, dataXYZ, 4) ;

	/* Calculate positions values */
	uldataXYZ = (dataXYZ[0] << 24)|(dataXYZ[1] << 16)|(dataXYZ[2] << 8)|(dataXYZ[3] << 0);
	*X = (uldataXYZ >> 20) & 0x00000FFF;
	*Y = (uldataXYZ >>  8) & 0x00000FFF;

	/* Reset FIFO */
	mode=0x01;
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, mode);

	/* Enable the FIFO again */
	mode=0x00;
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, mode);

}

To get the ID, burst read of two bytes from register 0x00:

  • Address 0x00 contains the higher bits of the ID.
  • Address 0x01 contains the lower buts of the ID.
uint16_t getID(void)
{
	uint8_t data[2];
	I2C3_ReadMultiByte(deviceAddress, 0x00, data, 2);
	uint16_t data_re=data[0]<<8|data[1];
	return (data_re);

}

Hence, the source file as following:

#include "i2c3.h"
#include "STMPE811.h"
#include "delay.h"
#include "STM32F4xx.h"


void STMPE811_Touch_Enable(void)
{

	uint8_t mode;
	
	/* Power Down the stmpe811 */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL1, 2);

	/* Wait for a delay to ensure registers erasing */
	delay(10);

	/* Power On the Codec after the power off => all registers are reinitialized */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL1, 0);

	/* Wait for a delay to ensure registers erasing */
	delay(2);

	/*Disable clock access to GPIO*/
	
	i2c3_readByte(deviceAddress, STMPE811_REG_SYS_CTRL2, &mode);

	mode &= ~(STMPE811_IO_FCT);

	/* Write the new register value */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL2, mode);


	/*Select TSC pins in TSC alternate mode */

	I2C3_WriteByte(deviceAddress, STMPE811_REG_IO_AF, STMPE811_TOUCH_IO_ALL);


	mode&= ~(STMPE811_TS_FCT | STMPE811_ADC_FCT);

	/* Write the new register value */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_SYS_CTRL2, mode);



	/* Select Sample Time, bit number and ADC Reference */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_ADC_CTRL1, 0x49);

	/* Wait for 2 ms */
	delay(2);

	/* Select the ADC clock speed: 3.25 MHz */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_ADC_CTRL2, 0x01);



	/* Select 2 nF filter capacitor */
	/* Configuration:
	- Touch average control    : 4 samples
	- Touch delay time         : 500 uS
	- Panel driver setting time: 500 uS
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_CFG, 0x9A);

	/* Configure the Touch FIFO threshold: single point reading */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_TH, 0x01);

	/* Clear the FIFO memory content. */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x01);

	/* Put the FIFO back into operation mode  */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x00);

	/* Set the range and accuracy pf the pressure measurement (Z) :
	- Fractional part :7a
	- Whole part      :1
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_FRACT_XYZ, 0x07);

	/* Set the driving capability (limit) of the device for TSC pins: 50mA */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_I_DRIVE, 0x01);

	/* Touch screen control configuration (enable TSC):
	- No window tracking index
	- XYZ acquisition mode
	*/
	I2C3_WriteByte(deviceAddress, STMPE811_REG_TSC_CTRL, 0x01);

	/*  Clear all the status pending bits if any */
	I2C3_WriteByte(deviceAddress, STMPE811_REG_INT_STA, 0xFF);


	/*Delay for 5ms*/

	delay(5);

}



TouchDetect_t isToched(void)
{

	uint8_t state=0;
	uint8_t value=0;

	i2c3_readByte(deviceAddress, STMPE811_REG_TSC_CTRL, &value);

	value&=STMPE811_TS_CTRL_STATUS;

	state=(value&STMPE811_TS_CTRL_STATUS)==0x80;

	if(value==STMPE811_TS_CTRL_STATUS)
	{
		i2c3_readByte(deviceAddress,STMPE811_REG_FIFO_SIZE, &value);
		if(value>0)
		{
			return touched;
		}
	}

	else
	{
		/* Clear the FIFO memory content. */
		I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x01);

		/* Put the FIFO back into operation mode  */
		I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, 0x00);
	}



	return no_touch;
}




void getTouchValue(uint16_t *X, uint16_t *Y)
{
	uint32_t uldataXYZ;
	uint8_t  dataXYZ[4];
	uint8_t mode;

	I2C3_ReadMultiByte(deviceAddress, STMPE811_REG_TSC_DATA_NON_INC, dataXYZ, 4) ;

	/* Calculate positions values */
	uldataXYZ = (dataXYZ[0] << 24)|(dataXYZ[1] << 16)|(dataXYZ[2] << 8)|(dataXYZ[3] << 0);
	*X = (uldataXYZ >> 20) & 0x00000FFF;
	*Y = (uldataXYZ >>  8) & 0x00000FFF;

	/* Reset FIFO */
	mode=0x01;
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, mode);

	/* Enable the FIFO again */
	mode=0x00;
	I2C3_WriteByte(deviceAddress, STMPE811_REG_FIFO_STA, mode);

}



uint16_t getID(void)
{
	uint8_t data[2];
	I2C3_ReadMultiByte(deviceAddress, 0x00, data, 2);
	uint16_t data_re=data[0]<<8|data[1];
	return (data_re);

}

Thats all for the source file.

3. Main.c Code:

In main.c:

#include "LCD_Pins.h"
#include "ILI9341.h"
#include "i2c3.h"
#include "STMPE811.h"
#include "exti.h"
#include "stdio.h"

uint16_t TouchX,TouchY;

char lcd_data[50];

int main(void)
{
	delay_init(180000000);

	i2c3_init();
	STMPE811_Touch_Enable();

	LCD_Pin_Init();
	LCD_SPI_Init();
	ILI9341_Init();
	ILI9341_setRotation(1);
	ILI9341_Fill(COLOR_WHITE);


	while(1)
	{


		if (isToched()==touched)
		{
			getTouchValue(&TouchX,&TouchY);
			sprintf(lcd_data,"X-axis %d      ",TouchX);
			ILI9341_DrawString(1,1,lcd_data,COLOR_BLACK,COLOR_WHITE,2);
			sprintf(lcd_data,"Y-axis %d      ",TouchY);
			ILI9341_DrawString(1,2,lcd_data,COLOR_BLACK,COLOR_WHITE,2);



		}

	}
}

4. Results:

You should get the following once you upload the code:

Happy coding 🙂

Add Comment

Your email address will not be published. Required fields are marked *