In this tutorial we will add LCD and touch screen drivers to our project.
We first need to create directories for the files we need.
We need to create BSP folder with subfolders inside Drivers folder as on following image and Utilities folder for fonts:
Now let’s add the files. We need to copy:
stm32f429i_discovery.c
stm32f429i_discovery_io.c
stm32f429i_discovery_lcd.c
stm32f429i_discovery_sdram.c
stm32f429i_discovery_ts.c
from folder:
C:\Users\…\STM32Cube\Repository\STM32Cube_FW_F4_V1.19.0\Drivers\BSP\STM32F429I-Discovery
to folder src under BSP folder
we also need to copy header files:
stm32f429i_discovery.h
stm32f429i_discovery_io.h
stm32f429i_discovery_lcd.h
stm32f429i_discovery_sdram.h
stm32f429i_discovery_ts.h
from folder:
C:\Users\…\STM32Cube\Repository\STM32Cube_FW_F4_V1.19.0\Drivers\BSP\STM32F429I-Discovery
to folder inc under BSP folder:
We need to copy folders with files for display and touch screen ICs to components folder from:
C:\Users\…\STM32Cube\Repository\STM32Cube_FW_F4_V1.19.0\Drivers\BSP\Components
to Components Folder:
We also need:
io.
lcd.h
ts.h
from folder:
C:\Users\…\STM32Cube\Repository\STM32Cube_FW_F4_V1.19.0\Drivers\BSP\Components\Common
to Common subfolder inside Components:
And last ones are fonts, from folder:
C:\Users\…\STM32Cube\Repository\STM32Cube_FW_F4_V1.19.0\Utilities
to Utilities subfolder in our project:
Now we need to tell our compiler where to find all these files. We need to right click on our project and select Properties:
Next we go to C/C++ General -> Paths and Symbols -> GNU C:
We click on Add… and add all the paths as in following screenshot and click OK:
Now we are ready to start coding.
First we need to include BSP headers. We add include files between USER CODE BEGIN Includes and USER CODE END Includes. We ALWAYS write code between USER CODE BEGIN… and USER CODE END… , because these are parts that are not changed when regenerating files from CubeMX.
1 2 3 4 |
/* USER CODE BEGIN Includes */ #include "stm32f429i_discovery.h" #include "stm32f429i_discovery_lcd.h" /* USER CODE END Includes */ |
We add a little test code to test if all works:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* USER CODE BEGIN 2 */ BSP_LCD_Init(); BSP_LED_Init(LED3); BSP_LED_Init(LED4); /* Layer2 Init */ BSP_LCD_LayerDefaultInit(1, LCD_FRAME_BUFFER); /* Set Foreground Layer */ BSP_LCD_SelectLayer(1); /* Clear the LCD */ BSP_LCD_Clear(LCD_COLOR_WHITE); BSP_LCD_SetColorKeying(1, LCD_COLOR_WHITE); BSP_LCD_SetLayerVisible(1, DISABLE); /* Layer1 Init */ BSP_LCD_LayerDefaultInit(0, LCD_FRAME_BUFFER + 0x130000); /* Set Foreground Layer */ BSP_LCD_SelectLayer(0); /* Enable The LCD */ BSP_LCD_DisplayOn(); /* Clear the LCD */ BSP_LCD_Clear(LCD_COLOR_GREEN); BSP_LCD_DisplayStringAt(10, 10,(uint8_t*) "Hello world!", LEFT_MODE); /* USER CODE END 2 */ |
We compile the code and upload it to our discovery board and we should see green screen with our usual “Hello world!”.
When we upload it for the first time we need to right click our project and select Run As -> 1 Ac6 STM32 C/C++ Application (marked red). After that we can just select our program under green circle with arrow inside in top menu (marked blue), or if it was current program we selected last, we can just click it.
This is the end of second part of our tutorial. Next part won’t be soon because I have a lot of problems with it, but I finished this one because we need it to test SkinMan and KnobMan. You can read about them here. Well we are not done yet. As I was reading this article by myself I saw I din’t finished it, there is no touch screen support here yet.
Well, let’s do that now.
We already added all the needed files, now we need to include them, initialize the touch screen and write routines for it.
First we need to add include for touch screen (#include “stm32f429i_discovery_ts.h”):
1 2 3 4 5 |
/* USER CODE BEGIN Includes */ #include "stm32f429i_discovery.h" #include "stm32f429i_discovery_lcd.h" #include "stm32f429i_discovery_ts.h" /* USER CODE END Includes */ |
Next we need to initialize it (BSP_TS_Init(240, 320);):
1 2 3 4 5 6 7 8 9 |
/* USER CODE BEGIN 2 */ BSP_LCD_Init(); BSP_LED_Init(LED3); BSP_LED_Init(LED4); BSP_TS_Init(240, 320); /* Layer2 Init */ BSP_LCD_LayerDefaultInit(1, LCD_FRAME_BUFFER); /* Set Foreground Layer */ ... |
We also need some way of checking if screen was touched and where. For this we will create new function called BSP_Touch_Update().
Here is the code and I will try to explain simply what it does:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* USER CODE BEGIN 4 */ void BSP_Touch_Update(void) { static TS_StateTypeDef prev_state; TS_StateTypeDef ts; uint16_t xDiff, yDiff; BSP_TS_GetState(&ts); if(ts.TouchDetected > 0) ts.TouchDetected = 1; if((ts.X < 240) && (ts.Y < 320)) { xDiff = (prev_state.X > ts.X) ? (prev_state.X - ts.X) : (ts.X - prev_state.X); yDiff = (prev_state.Y > ts.Y) ? (prev_state.Y - ts.Y) : (ts.Y - prev_state.Y); if((prev_state.TouchDetected != ts.TouchDetected ) && ((xDiff > 3 ) || (yDiff > 3))) { if(ts.TouchDetected > 0) ts.TouchDetected = 1; if(((ts.X > 59) && (ts.X < 181)) && ((ts.Y > 79) && (ts.Y < 121))) ts_changed = 1; if(((ts.X > 59) && (ts.X < 181)) && ((ts.Y > 159) && (ts.Y < 201))) ts_changed = 2; } } prev_state = ts; } /* USER CODE END 4 */ |
First we define a few variables, one of them as static, this means that variable stays alive while program runs, even when program runs outside this routine.
After that we call BSP_TS_GetState(&ts); which gets data from touch screen controller.
With if(ts.TouchDetected > 0) we check if screen was touched and if it was we do following:
- xDiff = (prev_state.X > ts.X) ? (prev_state.X – ts.X) : (ts.X – prev_state.X); here we check if prev_state.X > ts.X if so we do prev_state.X – ts.X else we do ts.X – prev_state.X
- then we check if difference from previous touch was more than 3 in either direction, with this we avoid multiple detection of one touch
- with if(ts.TouchDetected > 0) and ts.TouchDetected = 1; we tell the routine to just take one touch data if multiple has been detected
- then we check if our touch was inside a window we chose and we set the ts_changed value to one or two to let the main program know what we detected, if ts_changed == 0 it means that there was no touch detected
- at the end we set prev_state to new values
we also need to define variable ts_changed and set it’s value to 0 (no touch detected):
1 2 3 4 5 |
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ PID_STATE ts; volatile uint8_t ts_changed = 0; /* USER CODE END PV */ |
for this we also need to create structure inside main.h:
1 2 3 4 5 6 7 8 |
/* USER CODE BEGIN Private defines */ typedef struct { int x,y; unsigned char Pressed; unsigned char Layer; } PID_STATE; /* USER CODE END Private defines */ |
and we need to define private function:
1 2 3 4 |
/* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ void BSP_Touch_Update(void); /* USER CODE END PFP */ |
now we can start to read our touches. For this we will add calls to BSP_Touch_Update() inside our while loop inside main and we will toggle red LED if we get back ts_changed value as 1:
1 2 3 4 5 6 7 8 9 10 11 |
/* USER CODE BEGIN WHILE */ while (1) { BSP_Touch_Update(); HAL_Delay(10); if(ts_changed == 1) { ts_changed = 0; BSP_LED_Toggle(LED4); } /* USER CODE END WHILE */ |
We also need to add one line of code to draw rectangle on display, so that we will know where to touch:
1 2 3 |
BSP_LCD_Clear(LCD_COLOR_GREEN); BSP_LCD_DrawRect(80, 80, 80, 40); /* USER CODE END 2 */ |
We put BSP_LCD_DrawRect(80, 80, 80, 40); in our program.
Now when we run our program, we see green screen with dark rectangle. If we touch inside it, red LED will toggle for each touch.
Now that touch works, we are done with this article.
Thank you, for following me along!