cancel
Showing results for 
Search instead for 
Did you mean: 

Need help with touch feature on STM32F429I-Discovery using new CubeIDE project and TouchGFX

Halfwit
Associate II

I want to create the TouchGFX demo 3 (the animated bubbles) for my STM32F429i-Discovery board by creating a new project within CubeIDE.

I'm a total noob to this STM32 stuff, but thanks to you folks here and on YouTube I've got it working apart from the touch feature. If I tap the screen on the button, nothing happens.

The hardware is fine as I have downloaded other demos (non CubeIDE ones) and they work OK.

Below is a walk-through of how I create the project ( sorry, its pretty long).

I created the project without a real-time OS, which I assume is OK for this demo.

Maybe someone can tell me what I've missed for implementing the touch control.

Using:

Board: STM32F429I-DISC1

STM32CubeIDE Ver 1.3.0

TouchGX 4.13.0

EDIT: DO NOT USE THIS WALK-THROUGH. See the one further down this post.

//	Creating a project in STM32CubeIDE with working display on STM32F429I-Discovery board.
//	--------------------------------------------------------------------------------------
//	
//	In CubeIDE Start a new project either through the Help/Information Center or File/New/STM32 Project
//	
//	In Board Selector tab pick 32F429IDISCOVERY and click next.
//	Add a project name and select C++ as the target language and click finish.
//	  Initialize all peripherals with their default mode ? click Yes
//	  also confirm yes to change perspective if shown.
//	  Once the project is created, the integral CubeMX designer appears.
//	  
//	System Core:
//	  select GPIO. Then in "Configuration" tab select "SPI", set "Maximum Output Speed" to "Very High" for each signal.
//	
//	In Connectivity:
//	  SPI5: Set Mode to Half-Duplex Master, then below in "Parameter Settings" tab/Clock Parameters, Select "Prescaler (for Baud Rate)" to 2 and Set "Clock Phase (CPHA)" 1 Edge                                
//	  
//	  USART1: Disable 
//	  USB_OTG_HS/Internal FS Phy: Disable 
//	  
//	In MultiMedia 
//	  LTDC: In the Layer Settings tab set "Alpha Constant" for both "Layer 0 - Blending Factor" 1 and 2
//	  DMS2D: In Parameter Settings/Color Mode = RGB565
//	 
//	
//	Middleware:
//	  FREERTOS: Interface: Disable
//	  USB_HOST: Disable
//	 
//	Select "Additional Software" tab at the top
//	Open up the tree view for "STMicroelectronics X-CUBE-TOUCHFX" until you see Application and select "TouchGFX Generator" then click OK
//	 
//	A new item "Additional Software" should now have appeared on the left. Open it and click on "STMicroelectronics X-CUBE-TOUCHFX"
//	In the adjacent section, tick "Graphics Application"
//	Now in the "TouchGFX Generator" tab under "Display" change "Interface" to Parallel RGB (LTDC)
//	Then change Buffer Location to "By Address" and set Start Address to "0xD0000000"
//	Then under "Driver" set "Application Tick Source" to LTDC and Real Time Operating System to No OS
//	
//	"Clock Configuration" tab
//	
//	  The HSE input frequency should already be set to 8 and selected as the souce
//	  then set /M = /4
//			   *N = X180
//			   /P = /2
//			   (/Q should be greyed out)
//	  then over to the right:
//			   APB1 Prescaler = /4
//			   APB2 Prescaler = /2
//	  now non of the boxes should be red and the output frequencies should be:
//			   180 Ethernet PTP Clock
//			   180 HCLK to AHB
//			   180 To Cortex system timer
//			   180 FCLK Cortex clocks
//				45 APB1 peripheral clocks
//				90 APB1 timer clocks
//				90 APB2 peripheral clocks
//			   180 APB2 timer clocks
//	  finally, at the bottom, in the PLL SAI section:
//			   *N = X54
//			   /R = /3
//			   PLLCDCLK = /4
//			   giving 9 as the "LCD-TFT clocks" output frequency
//			   
//			   
//	Now click "Generate Code" from the "Project" menu
//	Now close the tab with your project name.ioc, which will switch back to normal Eclipse perspective.
//	
//	Open the TouchGFX folder in the tree view and double click "ApplicationTemplate.touchgfx.part"
//	
//	This opens up TouchGFX designer (assuming it's installed)
//	Select "Matching UI Templates" and click on TouchGFX Demo 3" and click "Select" 
//	Then click "Generate Code" top right button. Once done close the App
//	Right click the Project and select refresh. You now see a file with your project name.touchgfx
//	
//	The project should now build without errors. Check by selecting: Project/Build All
//	However it will do nothing if you download to the board and you'd just get a white screen.
//	
//	Now modify Core/Src/main.c by adding the code shown below into the relevant sections.
//	Be sure to put the code only inside the commented sections, otherwise future code generation will delete it!
//			 
//	Once done you can build the project.
//	Now run it in debug: Right click the project, select "Debug As" and pick "STM32 Cortex M C/C++ Application"
//	Leave the defaults and just click "OK"
//	Once downloaded, the code will stop at HAL_Init();
//	Now just click the "resume" button and the display should show the demo screen.
//	
//	
//			 
//	in Main.c
 

8 REPLIES 8
Martin KJELDSEN
Chief III

You're probably missing an implementation for your touch controller to propagate touch coordinates to the TouchGFX Engine (which distributes it to the active screen). Are you able to check if you have implemented sampleTouch() function for some class that implements the TouchController interface?

/Martin

Halfwit
Associate II

Hmm, I created a second post with the rest of the walk-through, as it was too long, but it seems to have disappeared. Here is the rest of it again:

EDIT: DO NOT USE THIS WALK-THROUGH. See the one further down this post. 

in Main.c
 
 
/* USER CODE BEGIN PV */
#define REFRESH_COUNT        1386
 
#define SDRAM_TIMEOUT                            ((uint32_t)0xFFFF)
#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)
 
static FMC_SDRAM_CommandTypeDef Command;
/* USER CODE END PV */
 
 
/* USER CODE BEGIN PFP */
void writeReg(uint8_t);
void writeData(uint8_t);
/* USER CODE END PFP */
  
  
  /* USER CODE BEGIN SPI5_Init 2 */
  writeReg(0xCA);
  writeData(0xC3);
  writeData(0x08);
  writeData(0x50);
  writeReg(0xCF);
  writeData(0x00);
  writeData(0xC1);
  writeData(0x30);
  writeReg(0xED);
  writeData(0x64);
  writeData(0x03);
  writeData(0x12);
  writeData(0x81);
  writeReg(0xE8);
  writeData(0x85);
  writeData(0x00);
  writeData(0x78);
  writeReg(0xCB);
  writeData(0x39);
  writeData(0x2C);
  writeData(0x00);
  writeData(0x34);
  writeData(0x02);
  writeReg(0xF7);
  writeData(0x20);
  writeReg(0xEA);
  writeData(0x00);
  writeData(0x00);
  writeReg(0xB1);
  writeData(0x00);
  writeData(0x1B);
  writeReg(0xB6);
  writeData(0x0A);
  writeData(0xA2);
  writeReg(0xC0);
  writeData(0x10);
  writeReg(0xC1);
  writeData(0x10);
  writeReg(0xC5);
  writeData(0x45);
  writeData(0x15);
  writeReg(0xC7);
  writeData(0x90);
  writeReg(0x36);
  writeData(0xC8);
  writeReg(0xF2);
  writeData(0x00);
  writeReg(0xB0);
  writeData(0xC2);
  writeReg(0xB6);
  writeData(0x0A);
  writeData(0xA7);
  writeData(0x27);
  writeData(0x04);
 
  /* Colomn address set */
  writeReg(0x2A);
  writeData(0x00);
  writeData(0x00);
  writeData(0x00);
  writeData(0xEF);
  /* Page address set */
  writeReg(0x2B);
  writeData(0x00);
  writeData(0x00);
  writeData(0x01);
  writeData(0x3F);
  writeReg(0xF6);
  writeData(0x01);
  writeData(0x00);
  writeData(0x06);
 
  writeReg(0x2C);
  HAL_Delay(200);
 
  writeReg(0x26);
  writeData(0x01);
 
  writeReg(0xE0);
  writeData(0x0F);
  writeData(0x29);
  writeData(0x24);
  writeData(0x0C);
  writeData(0x0E);
  writeData(0x09);
  writeData(0x4E);
  writeData(0x78);
  writeData(0x3C);
  writeData(0x09);
  writeData(0x13);
  writeData(0x05);
  writeData(0x17);
  writeData(0x11);
  writeData(0x00);
  writeReg(0xE1);
  writeData(0x00);
  writeData(0x16);
  writeData(0x1B);
  writeData(0x04);
  writeData(0x11);
  writeData(0x07);
  writeData(0x31);
  writeData(0x33);
  writeData(0x42);
  writeData(0x05);
  writeData(0x0C);
  writeData(0x0A);
  writeData(0x28);
  writeData(0x2F);
  writeData(0x0F);
 
  writeReg(0x11);
  HAL_Delay(200);
  writeReg(0x29);
  /* GRAM start writing */
  writeReg(0x2C);
  /* USER CODE END SPI5_Init 2 */
  
  
  
  
  /* USER CODE BEGIN FMC_Init 2 */
  __IO uint32_t tmpmrd = 0;
 
  /* Step 1: Configure a clock configuration enable command */
  Command.CommandMode            = FMC_SDRAM_CMD_CLK_ENABLE;
  Command.CommandTarget          =  FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = 0;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
 
  /* Step 2: Insert 100 us minimum delay */
  /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
  HAL_Delay(100);
 
  /* Step 3: Configure a PALL (precharge all) command */
  Command.CommandMode            = FMC_SDRAM_CMD_PALL;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = 0;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
 
  /* Step 4: Configure an Auto Refresh command */
  Command.CommandMode            = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 4;
  Command.ModeRegisterDefinition = 0;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
 
  /* Step 5: Program the external memory mode register */
  tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |\
                     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |\
                     SDRAM_MODEREG_CAS_LATENCY_3           |\
                     SDRAM_MODEREG_OPERATING_MODE_STANDARD |\
                     SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
 
  Command.CommandMode            = FMC_SDRAM_CMD_LOAD_MODE;
  Command.CommandTarget          = FMC_SDRAM_CMD_TARGET_BANK2;
  Command.AutoRefreshNumber      = 1;
  Command.ModeRegisterDefinition = tmpmrd;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
 
  /* Step 6: Set the refresh rate counter */
  /* Set the device refresh rate */
  HAL_SDRAM_ProgramRefreshRate(&hsdram1, REFRESH_COUNT);
  /* USER CODE END FMC_Init 2 */
 
 
/* USER CODE BEGIN 4 */
 
void writeReg(uint8_t reg)
{
	HAL_GPIO_WritePin(WRX_DCX_GPIO_Port, WRX_DCX_Pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(CSX_GPIO_Port, CSX_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi5, &reg, 1, 10);
	HAL_GPIO_WritePin(CSX_GPIO_Port, CSX_Pin, GPIO_PIN_SET);
}
 
void writeData(uint8_t data)
{
	HAL_GPIO_WritePin(WRX_DCX_GPIO_Port, WRX_DCX_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(CSX_GPIO_Port, CSX_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi5, &data, 1, 10);
	HAL_GPIO_WritePin(CSX_GPIO_Port, CSX_Pin, GPIO_PIN_SET);
}
 
/* USER CODE END 4 */

Thanks Martin, That is exactly where I am needing some help.

I found in: <project_root>/TouchGFX/target/STM32TouchController.cpp

 it created two empty methods:

void STM32TouchController::init()
{
    /**
     * Initialize touch controller and driver
     *
     */
}
 
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);
     *
     */
    return false;
}

but it is not clear to me if this is where I need to add something, or what that would be.

I looked in a project generated entirely be TouchGFX designer and found a file:

<project_root>\Project\TouchGFX\target\ResistiveTouchController.cpp

that contains this code:

void ResistiveTouchController::init()
{
    BSP_TS_Init(LCD_GetXSize(), LCD_GetYSize());
}
 
bool ResistiveTouchController::sampleTouch(int32_t& x, int32_t& y)
{
    TS_StateTypeDef state;
    BSP_TS_GetState(&state);
    if (state.TouchDetected)
    {
        x = state.X;
        y = state.Y;
        return true;
    }
    return false;
}

but I can't find any declarations/definitions of anything even remotely like that code anywhere in the project generated in CubeIDE, so obviously that just throws errors if I try to use it.

Okay, this may be difficult to imagine, but CubeIDE/CubeMX do not help you with BSP (e.g. touch, sdram, display - e.g. the most recent post you made etc).

So what you need to do is use that touchcontroller code, find the Board support package for the 429-disco and include the *_ts.c file, at least to get access to the BSP_TS* functions.

You can take a look at the f429-disco application template from the designer to see which files are in that project.

/Martin

Exactly, just link (drag&drop) files from Firmware package, remove unnecesary ones...

0690X00000DYLhQQAX.png

This worked for me:

#include <STM32TouchController.hpp>
#include "stm32f429i_discovery_ts.h"
#include "main.h"
 
void STM32TouchController::init()
{
    /**
     * Initialize touch controller and driver
     *
     */
     BSP_TS_Init(240, 320);
}
 
bool STM32TouchController::sampleTouch(int32_t& x, int32_t& y)
{
    	TS_StateTypeDef state = { 0 };
 
	BSP_TS_GetState(&state);
	if(state.TouchDetected) {
		x = state.X;
		y = state.Y;
		return true;
	}
        return false;
}
 

Thanks guys. My noob assumption was it copied all that was needed.

@JKlok Thanks so much for posting that code snippet.

I had the line:

BSP_TS_Init(BSP_LCD_GetXSize(), BSP_LCD_GetYSize());

But the code crashed, ending up in function: HardFault_Handler()

But when I tried your line:

BSP_TS_Init( 240, 320 );

everything worked fine :)

I turns out that the GetSize calls rely on LcdDrv which is currently pointing to NULL. I'll look into why, but for now I'm happy I have it functioning. Thanks.

Ok, I figured out the null pointer:

#include <STM32TouchController.hpp>
#include "stm32f429i_discovery_ts.h"
#include "stm32f429i_discovery_lcd.h"
 
void STM32TouchController::init()
{
    /**
     * Initialize touch controller and driver
     *
     */
  BSP_LCD_Init();
  BSP_TS_Init(BSP_LCD_GetXSize(), BSP_LCD_GetYSize());
}

Halfwit
Associate II

I have updated my walk-through and attached it here as it may benefit other noobs just starting out with STM32.

Critique welcome if anyone knows of any error / omissions, or better / more future proof method etc.

file is attached..