STM32CubeMX Tutorial: Integrating TouchGFX Using FSMC/FMC
Introduction
TouchGFX is a powerful graphics middleware framework designed specifically for embedded systems. It allows developers to create high-performance, visually appealing graphical user interfaces (GUIs) for microcontrollers, particularly the STM32 series. Unlike general software, TouchGFX is closely tied to the hardware resources of the MCU, making it essential to carefully configure your microcontroller to fully leverage its capabilities.
When using STM32CubeMX to set up TouchGFX, several hardware components and interfaces must be properly configured. These include the Flexible Memory Controller (FMC/FSMC) for external memory access, display interfaces like DSI or LTDC for rendering graphics on screens, and QSPI for fast external flash memory. Proper configuration ensures smooth GUI performance and efficient use of the MCU’s capabilities.
MCU Resources Mainly Used by TouchGFX
1Flexible Memory Controller (FMC/FSMC):
TouchGFX often requires access to external SRAM or SDRAM to store graphical assets and frame buffers. The FMC/FSMC interface of STM32 allows high-speed communication with these external memories, ensuring smooth rendering of animations and graphics.
2Display Interfaces (DSI / LTDC):
A complete display system includes an LCD panel, a capacitive touch panel, and a PCB backplane. The touch panel has a controller chip that processes touch signals, while the LCD panel displays graphics. Some PCBs include an LCD controller like the RA8875, which handles display rendering, allowing low-end MCUs to simply send data. STM32F429 MCUs have an integrated LCD controller, like a CPU with an internal graphics card, while STM32F1 MCUs need an external controller to drive the screen.
- LTDC (LCD-TFT Display Controller): Used for driving TFT LCD panels. It handles layers, color formats, and timing for smooth screen updates.
- DSI (Display Serial Interface): A high-speed serial interface for driving modern displays with fewer pins. TouchGFX relies on these interfaces to render the GUI efficiently.
3QSPI (Quad SPI Flash):
TouchGFX often requires access to external SRAM or SDRAM to store graphical assets and frame buffers. The FMC/FSMC interface of STM32 allows high-speed communication with these external memories, ensuring smooth rendering of animations and graphics.
4DMA (Direct Memory Access):
TouchGFX uses DMA channels to transfer graphical data between memory and the display controller efficiently, freeing up the CPU for other tasks and ensuring smooth animations.
5Timers and Interrupts:
Timers help manage frame rates and periodic tasks within the GUI, while interrupts can be used to handle touch inputs or synchronize display updates without blocking the main program flow.
6GPIOs (General Purpose Input/Output):
GPIO pins are used for interfacing touch controllers, buttons, LEDs, and other input/output devices that interact with the GUI.
Understanding FSMC (Flexible Static Memory Controller)
The FSMC (Flexible Static Memory Controller) is a dedicated hardware module within the STM32 MCU that simplifies communication with external peripherals like SRAM, NOR, NAND, or LCDs. Its main purpose is to provide a standardized, high-speed interface, making it easier and more reliable to connect external devices compared to manually controlling I/O pins.
nderstand FSMC better, consider the I²C bus as an example:
- One approach is bit-banging, where you use two GPIO pins to manually simulate the timing of I²C signals, writing all the necessary code yourself.
- The other, more standard approach, is to use the I²C controller integrated in the MCU. You configure control registers (easily done via STM32CubeMX) and then use HAL functions or interrupts to read/write data. This method is more stable, efficient, and convenient.
FSMC works in a very similar way for external memory and displays. Instead of manually toggling multiple pins, FSMC provides a dedicated interface with all the necessary signals, making peripheral communication much simpler and faster. The main FSMC signals include:
- Chip Select (CS): Activates the connected peripheral.
- Data Bus (D0–D15): Transfers data between the MCU and peripheral. FSMC supports 8-bit or 16-bit wide data buses.
- Address Bus:Specifies the memory or command location. It can be multiplexed with the data bus, and in LCD connections, it often carries command signals
- Read (RD) Signal: Indicates a read operation from the peripheral.
- Write (WR) Signal: Indicates a write operation to the peripheral.
By using FSMC, the MCU can communicate with external devices efficiently and reliably, without manually controlling every signal. This is especially useful when connecting displays with TouchGFX, as it allows smooth and high-speed GUI updates.
Technical Specifications
In this example, we will demonstrate how to use the STM32F103 microcontroller to drive an ILI9325 (or ILI9320) LCD display via the FSMC interface. Using FSMC allows the MCU to communicate efficiently with the LCD, handling both commands and data transfers without manually toggling individual pins.
The interface diagram below illustrates how the STM32F103 is connected to the ILI9325/ILI9320 display, showing the connections for the data bus, address lines, chip select, read, and write signals, which are all managed through the FSMC module for fast and reliable display control.
For the ILI9325, a reset signal is also required, a GPIO of the MCU is configured as an output mode, and it can be connected to the LCD.
Let’s take a closer look at the FSMC structure of the STM32F103, as shown in the screenshot below from the official user manual.
For simplicity, we only care about the NOR/SRAM part: Among them, the marked signal line is used in the example. The usage of these signal lines is described below with a specific example. This example is an STM32F103 connected to an ILI9325 LCD via FSMC. On the STM32F103 board, the MCU and LCD interface circuit is shown in the figure:
There is not much to say about the 16 data lines D0-D15. Here we focus on a few control signals:
The above table shows how the read, write and chip select signals correspond to the pin numbers of the MCU (it is the multiplexing function of the pins. When configuring the FSMC through CUBEMX, the multiplexing functions of these pins are automatically configured). The RS control signal needs to be explained separately: RS is used to tell the ILI9325 controller whether the data currently received from the MCU is "command" or "data" (see the ILI9325 data sheet for details), and there are two ways to connect the MCU to the RS signal. : One is to connect the RS with the GPIO of a MCU. Before each time the MCU sends data to the ILI9325, it sets the GPIO to 0 or 1 according to whether it is sending a command or data; the other method is to set an address of the MCU to The line (A16 in this case) is connected to RS, and the ILI9325 is accessed in the code using the "address" corresponding to that address line (A16) (the code below will detail how to do this). The corresponding pins of A16 are as follows:
Now, let’s begin configuring the FSMC interface for the STM32F103 using STM32CubeMX.
Using an external crystal:
Configuration of FSMC:
The NOR (here used to drive the LCD) block part of the FSMC is divided into 4 "sub-blocks":
Here, it’s important to understand the memory address mapping used by the FSMC interface. FSMC operates with 32-bit addressing, and different peripherals are assigned different base addresses. For example:
- When connecting to a NOR Flash, the internal address of the MCU starts at 0x6000 0000.
- When connecting to a NAND Flash, the address begins at 0x7000 0000.
Within the NOR address space, FSMC divides the memory into four regions, with the starting address determined by bits [27:26] of the 32-bit address, represented in binary as:
FSMC Address Mapping Example
The FSMC divides the NOR Flash address space into multiple banks, each with its own starting address:
- Bank1: 0110 0000 0000 0000 0000 0000 0000 0000 → 0x6000 0000
- Bank2: 0110 0100 0000 0000 0000 0000 0000 0000 → 0x6400 0000
- Bank3: 0110 1000 0000 0000 0000 0000 0000 0000 → 0x6800 0000
- Bank4: 0110 1100 0000 0000 0000 0000 0000 0000 → 0x6C00 0000
In this example, Bank1 is used, covering the address range 0x6000 0000 – 0x63FF FFFF, providing a total of 64 MB of addressable space. When accessing this region, FSMC automatically activates the NE1 chip select signal (corresponding to PD7 = 0, as shown in Figure).
Let’s take a closer look at a specific example address — 0x6002 0000: In binary, it is 0110 0000 0000 0010 0000 0000 0000 0000, where bit[17] is intentionally set to 1. FSMC uses byte addressing, meaning the address increments by one for each byte of data. The address sequence looks like this:
- 0x6000 0000, 0x6000 0001, 0x6000 0002, ... — totaling 64 MB of accessible memory.
However, when the FSMC is configured as 16-bit "address mode" (configured by the MWID bit of the FSMC control register FSMC_BCR1), obviously there should be only 32M addresses. At this time, FSMC makes a special process: "discard" the bit-0 of the address, and start counting the address from bit-1 (equivalent to only counting even addresses, there are 32M addresses in total), when the FSMC actually outputs the address, it will The value of the address is shifted to the right by one (equivalent to dividing by 2, which becomes an even address) and output to the actual address line. The F103 documentation says this:
Taking the address: 0x6002 0000 as an example, when the FSMC is in 16-bit mode, the 1 of the address bit[17] is shifted to the right by one bit and then output to the address line, that is, the pin corresponding to A16 (PD11, see Figure 7) will output 1, and also That is, the RS signal line will be 1. After talking so much, I actually want to explain one thing: when writing data to ILI9325, use address 0x6002 0000 to access; when writing commands to ILI9325, use address 0x6000 0000 to access!
Finally configure the reset pin of the LCD: Generate STM32IDE created code in CUBEMX, and add functions for ILI9325 read and write in main.c:
STM32Cube IDE Code Explain
Generate STM32IDE created code in CUBEMX, and add functions for ILI9325 read and write in main.c:
#define LCD_Data_Addr ((uint32_t)0x60020000) //write data address
#define LCD_Reg_Addr ((uint32_t)0x60000000) //write command address
//write index (command) register
void LCD_WriteIndex(unsigned int index)
{
*(volatile uint16_t *)(LCD_Reg_Addr) = index;
}
//read register
uint16_t LCD_ReadReg(uint16_t reg)
{
uint16_t ret;
LCD_WriteIndex(reg);
ret = *(volatile uint16_t *)(LCD_Data_Addr);
return ret;
}
After the program is initialized, reset the LCD, and then read the version of ILI9325. If the data "9325" can be read correctly, it means that the FSMC configuration is correct:
// reset LCD
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);
//read
tmp = LCD_ReadReg(0x0000); //0000 is the code, see ILI9325 manual for details
//tmp should be 0x9325 now!!!
if(tmp == 0x9325)
{
//led1 on
HAL_GPIO_WritePin(GPIOB , GPIO_PIN_8, GPIO_PIN_RESET);
}
else
{
//led2 on
HAL_GPIO_WritePin(GPIOB , GPIO_PIN_9, GPIO_PIN_RESET);
}
printf("ret=0x%x\n", tmp);
//Observe the variable value in KEIL through TM_SendChar(), see " STM32's ITM Tracking and Debugging Function Introduction and Implementation (1) KEIL " and " STM32's ITM Tracking and Debugging Function Introduction and Implementation (4) printf() " . ...... operation result:
This example is only to illustrate how to configure the FSMC, so only the read data to ILI9325 is implemented. After adding the initialization code for ILI9325, ILI9325 can easily display images.
Conclusion
With the basic knowledge of FSMC configuration, it will be convenient for us to further understand the configuration process of using FMC to access external DRAM on the STM32F746G-DISCO board. This content will be introduced in the next section-- STM32
0 comments:
Post a Comment