STM32_08.TFT_STM32F407_RootDev

TFT User Interface Example

TFT display project with graphical interface on STM32F407. Implementation of local data presentation and GUI handling in an embedded environment.

STM32F4CHALTFTDisplayEmbedded UILVGLTouchscreenSD CardJSONWiFiLoRaBMP280

Project facts

  • Repository: STM32_08.TFT_STM32F407_RootDev
  • Board / area: STM32F407 / TFT display
  • Category: Display / UI
  • Status: Public repository

Technical description

  • The code is focused on display handling and presenting information on a microcontroller.
  • The display layer runs directly on the microcontroller, so panel initialization, refresh strategy and UI drawing cost are important.
  • STM32F407 provides more resources than small MCUs, which fits a screen-based project.
  • STM32F407 provides more RAM, flash and processing headroom than small G0 controllers, which matters for graphics work.
  • The project extends typical control firmware with a local user-interface layer.
  • LVGL library is used for GUI management, SPI touchscreen support, SD card for configuration and data storage.
  • The system supports WiFi (ESP8266), LoRa and BMP280 sensor for temperature, pressure and humidity measurements.
  • Configuration data is stored in INI files on the SD card, and JSON data is used for NTP server communication.

What happens in the code

Selected key mechanisms from the project code. This is not a full repository dump, but an analysis of the parts responsible for the main firmware logic.

  • The project uses LVGL library for GUI management with features like buttons, text fields and UI elements.
  • Touchscreen handling is done via SPI using XPT2046 with calibration and coordinate filtering support.
  • SD card is used for storing configuration in INI files and system data.
  • WiFi communication is handled by ESP8266 with NTP synchronization support.
  • LoRa communication uses SX1276 module with send/receive message capabilities.
  • BMP280 sensor handles temperature, pressure and humidity measurements with state machine support.
  • The system uses cJSON for JSON data parsing and DataTime for time and date management.

Key code excerpts

The code is shortened to the parts that matter for understanding the project.

LVGL and touchscreen initialization

Core/Src/main.c
lv_init();
  lv_port_disp_init();
  lv_port_indev_init();

  LCD_BL_ON();

  if(HAL_GPIO_ReadPin(GPIOC, CardDetectPin_Pin) == GPIO_PIN_RESET)
  {
    CardDetectedInSlot = true;
    InitializeSDCard();
  }

  // ...existing code...
  
  initTouchScr(); //lcdInit();
  lcdFillRGB(COLOR_BLACK);
  lcdSetOrientation(LCD_ORIENTATION_LANDSCAPE);

LVGL and touchscreen initialization is done in the main file. LCD initialization, orientation setting and touch driver startup.

SPI touchscreen handling

Core/Src/SPITouchScreen.c
void Touch_ReadCoordinates(uint16_t* x, uint16_t* y)
{
    uint8_t tempXH, tempXL, tempYH, tempYL;

    Touch_Select(); // CS Low
    Touch_SPI_Transfer(XPT2046_CMD_X);  // Komenda dla odczytu X 0xD0
    tempXH = Touch_SPI_Transfer(0x00);  // Odczyt wyższego bajtu X
    tempXL = Touch_SPI_Transfer(0x00);  // Odczyt niższego bajtu X

    Touch_SPI_Transfer(XPT2046_CMD_Y);  // Komenda dla odczytu Y 0x90
    tempYH = Touch_SPI_Transfer(0x00);  // Odczyt wyższego bajtu Y
    tempYL = Touch_SPI_Transfer(0x00);  // Odczyt niższego bajtu Y

    Touch_Unselect(); // CS High

    *x = (tempXH << 8 | tempXL) >> 3;  // Usunięcie nieużywanych bitów
    *y = (tempYH << 8 | tempYL) >> 3;  // Usunięcie nieużywanych bitów
}

The function reads touch coordinates from the XPT2046 sensor via SPI bus. Values are processed and returned as X and Y coordinates.

SD card and configuration files handling

Core/Src/File_Handling.c
void InitializeSDCard()
{
  // ... initialization code ...
  
  hsd.Instance = SDIO;
  hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
  hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
  hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
  hsd.Init.ClockDiv = 2;

  hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
  if(HAL_SD_Init(&hsd)!= HAL_OK)
  {
    // Error handling
  }
  
  // ... existing code ...
}

FRESULT Mount_SD (const TCHAR* path)
{
  fresult = f_mount(&fs, path, 1);
  if (fresult != FR_OK)
  {
    Debug ("ERROR!!! in mounting SD CARD...");
  }
  else
  {
    // Success message
  }
  return fresult;
}

Functions initialize the SD card and handle mount/unmount operations of the file system. Configuration files are read from the SD card.

LoRa communication

Core/Src/LoRa.c
LoRa newLoRa(){
  LoRa new_LoRa;

  new_LoRa.frequency          = 433       ;
  new_LoRa.spredingFactor     = SF_7      ;
  new_LoRa.bandWidth          = BW_125KHz ;
  new_LoRa.crcRate            = CR_4_5    ;
  new_LoRa.power              = POWER_17db;
  new_LoRa.overCurrentProtection = 100       ;
  new_LoRa.preamble           = 8         ;

  return new_LoRa;
}

void LoRa_gotoMode(LoRa* _LoRa, int mode){
  uint8_t    read;
  uint8_t    data;

  read = LoRa_read(_LoRa, RegOpMode);
  data = read;

  if(mode == SLEEP_MODE){
    data = (read & 0xF8) | 0x00;
    _LoRa->current_mode = SLEEP_MODE;
  }else if (mode == STNBY_MODE){
    data = (read & 0xF8) | 0x01;
    _LoRa->current_mode = STNBY_MODE;
  }else if (mode == TRANSMIT_MODE){
    data = (read & 0xF8) | 0x03;
    _LoRa->current_mode = TRANSMIT_MODE;
  }else if (mode == RXCONTIN_MODE){
    data = (read & 0xF8) | 0x05;
    _LoRa->current_mode = RXCONTIN_MODE;
  }else if (mode == RXSINGLE_MODE){
    data = (read & 0xF8) | 0x06;
    _LoRa->current_mode = RXSINGLE_MODE;
  }

  LoRa_write(_LoRa, RegOpMode, data);
}

Functions initialize and configure the LoRa module. They set parameters such as frequency, bandwidth, coding rate and output power.

BMP280 sensor data measurement

Core/Src/BMP280.c
void ProcessBMPStateMachine()
{
    switch (bmpState)
    {
    	case BMP_INITIALIZE:
    		if((HAL_GetTick() - lastBMPSync) > DefaultTimeBMPFailSyncAfterMs)
    		{
				if(bmp280_init(&bmp280, &bmp280.params))
				{
					bmpState = BMP_MESURMENT;
					ErrorCount = 0;
					lastBMPSync = HAL_GetTick();
				}
				else
				{
					if(debugBMP)
					{
						Debug("BMP280 initialization failed...");
					}
					if(ErrorCount >9)
						bmpState = BMP_HW_RESET_REQUIRED;
					else
						ErrorCount++;
					lastBMPSync = HAL_GetTick();
				}
    		}
    		break;

    	case BMP_MESURMENT:
				if(HAL_GetTick() - lastBMPSync > CheckTSensorsBMPAfterMS)
				{
					if(bmp280_force_measurement(&bmp280) == true)
					{
						bmpState = BMP_DATA_READY;
					}
					else
					{
						ErrorCount++;
						lastBMPSync = HAL_GetTick();
					}
				}
				break;
    }
}

BMP280 state machine handles initialization, measurements and error handling. Depending on the state, appropriate operations are performed.