Getting Started with FSMC on STM32: Interface External Memories Easily

Getting Started with FSMC on STM32: Interface External Memories Easily

STM32 FSMC Explained: Connect External SRAM, NOR Flash, and LCD Displays

Introduction

Embedded systems often require external memory or parallel display interfaces that offer higher speed and lower latency than serial buses like SPI or I2C. STM32 microcontrollers include a hardware peripheral called the FSMC (Flexible Static Memory Controller), designed specifically to interface with SRAM, NOR Flash, NAND Flash, PSRAM, and 8080/6800 parallel LCD controllers, using a flexible and programmable parallel bus.The FSMC allows the microcontroller to treat external devices like internal memory, mapping them into the MCU’s address space. This eliminates manual GPIO toggling and significantly increases data throughput.

The STM32F series chips use the FSMC peripheral to manage the extended memory. FSMC is the abbreviation of Flexible Static Memory Controller, which is translated into flexible static memory controller. It can be used to drive memory including SRAM, NOR FLASH and NAND FLSAH types.

Since the FSMC peripheral can be used to control the extended external memory, the operation of the MCU on the LCD screen is actually to write the display data into the video memory, which is very similar to the control memory, and the communication timing of the 8080 interface can completely use the FSMC peripheral. Therefore, it is very suiable to use the FSMC to control the LCD screen.

 FSMC on STM32

FSMC Block Diagram

Communication Pins Explains

On the right side of the block diagram are the control pins related to the FSMC peripherals. Since there are some different pins when controlling different types of memory, it seems that there are a lot of them. The address line FSMC_A and data line FSMC_D are shared by all controllers. of. The specific GPIO ports and pin numbers corresponding to these FSMC pins can be found in the "STM32F103 Specifications" and are listed here

 FSMC on STM32

STM32F1 FSMC pin diagram

The FSMC of STM32F1 divides external devices into 2 categories: NOR/PSRAM devices, NAND/PC card devices. They share signals such as the address data bus, but have different CSs to distinguish different devices. In the experiment in this chapter, we use the NOR/PSRAM memory controller part of the FSMC, that is, use the TFTLCD as a SRAM device. Why can TFTLCD be used as a SRAM device? First of all, we need to understand the interface signals of the NOR/PSRAM memory controller.

The interface signal functions are as follows:

 FSMC on STM32

It can be seen from the above figure that the control of external SRAM generally includes: address line (such as A0~A25), bidirectional data line (such as D0~D15), write signal (NWE), read signal (NOE), chip select signal (NE) [x]), and UB/LB signals if the SRAM supports byte control. The signals of TFTLCD were introduced in the previous section, including: RS, DB0-DB15, WR, RD, CS, RST, etc., among which the only ones that need to be used when operating the LCD are: RS, DB0-DB15, WR , RD, CS. In this way, their operation interface signals are completely similar, the only difference is that TFTLCD has RS signal, but no address signal.

TFTLCD determines whether the transmitted data is data or command through the RS signal, which can be understood as an address signal in essence. For example, if we connect RS to A0, then when the FSMC controller writes address 0, it will make A0 become 0, For TFTLCD, it is a write command. When FSMC writes address 1, A0 will become 1. For TFTLCD, it is to write data. In this way, data and commands are distinguished, and they are actually two consecutive addresses corresponding to SRAM operations. Of course, RS can also be connected to other address lines. Our STM32F1 development board connects RS to A10.

Knowing that TFTLCD can be used as a SRAM device, let's take a look at the external device address mapping of FSMC. From the perspective of FSMC, the external memory is divided into 4 fixed-size storage areas (Bank), and the size of each storage area is 256 MB for a total of 1GB of space.

 FSMC on STM32

Memory Storage

STM32’s FSMC Bank1 can connect up to 4 external memories, each controlled by a separate chip-select signal (NE1–NE4). Each area has 64MB of address space, so Bank1 provides 256MB total. In this chapter, we use Bank1 Area 4 (NE4), whose base address is 0x6C000000.

FSMC maps external memory into the MCU’s address bus (HADDR). However, the actual address lines used depend on the memory data width:

  • For 16-bit memory: External address = HADDR shifted right by 1. (FSMC uses HADDR 25 : 1 25:1 → FSMC_A 24 : 0 24:0)
  • For 8-bit memory: External address = HADDR directly. (FSMC uses HADDR 25 : 0 25:0 → FSMC_A 25 : 0 25:0)

But FSMC_A[0] must always connect to external A0, regardless of width. This shift is important when working with LCDs where RS (Register Select) or A10 line is used to differentiate command/data.

To configure Bank1, we mainly use these registers:

FSMC_BCRx: Enable memory + basic settings (type, width, etc.)
FSMC_BTRx: Read timing configuration
FSMC_BWTRx: Write timing configuration

FSMC supports:

  1. Synchronous burst mode (uses FSMC_CLK, adjustable via CLKDIV and DATLAT)
  2. Asynchronous mode (uses timing parameters: ADDSET, DATAST, ADDHLD)

For connecting TFT LCD, we use Asynchronous Mode A, because LCD controllers generally work like simple SRAM interfaces. The key is to choose proper timing values matching the LCD controller’s requirements.

 FSMC on STM32

SRAM Asynchronous mode A

Mode A allows separate timing settings for read and write operations. This is very useful when driving a TFT LCD, because reading is usually slower while writing can be faster. If read and write share the same timing, the write speed would be limited by the slower read timing, or we would need to frequently switch timing settings during operation, which is inconvenient. With independent read/write timing in Mode A, we configure the timing once during initialization and it will work efficiently for both read and write without further adjustments. The write timing of Mode A is shown in Figure

 FSMC on STM32

SRAM Asynchronous mode A

In Mode A, the ADDSET and DATAST timing for read and write operations are configured using different registers. Because of space limitations, the details of the FSMC registers are not fully explained here. You can refer to the "STM32F10x Reference Manual" – FSMC chapter for full register descriptions.

However, briefly speaking, the standard library does not use the names FSMC_BCRx, FSMC_BTRx, and FSMC_BWTRx directly. Instead:

  1. FSMC_BCRx and FSMC_BTRx are grouped together in the BTCR[8] array:
    • BTCR[0] = BCR1, BTCR[1] = BTR1
    • BTCR[2] = BCR2, BTCR[3] = BTR2
    • BTCR[4] = BCR3, BTCR[5] = BTR3
    • BTCR[6] = BCR4, BTCR[7] = BTR4
  2. FSMC_BWTRx is grouped into BWTR[7]:

FSMC is indeed complex internally, but since we are developing using library functions, we only need to configure the registers through the library APIs — no need to go deep into the register details right now.

FSMC configuration steps

Next, we will introduce how to use library functions to configure FSMC. This is also necessary to understand when writing programs. The specific steps are as follows:

NOTE:The FSMC related library functions are in stm32f10x_fsmc.c and stm32f10x_fsmc.h file

FSMC initialization:

The initialization of FSMC mainly configures three registers, FSMC_BCRx, FSMC_BTRx, and FSMC_BWTRx. The firmware library provides three initialization functions to configure these registers. FSMC initialization library function as follows:


    
FSMC_NORSRAMInit();

FSMC_NANDInit();

FSMC_PCCARDInit();
    

These three functions are used to initialize 4 types of memory respectively. Here it is good to judge the correspondence according to the name. The same function FSMC_NORSRAMInit() is used to initialize NOR and SRAM. So the FSMC initialization function we use later is FSMC_NORSRAMInit(). The initialization function prototype is:


    
void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct);
    

This function has only one parameter, which is a structure pointer variable. The structure type is FSMC_NORSRAMInitTypeDef, and there are many member variables in it, because there are many configuration items related to FSMC. Below we briefly introduce its members:


    
typedef struct{

uint32_t FSMC_Bank;
uint32_t FSMC_DataAddressMux;
uint32_t FSMC_MemoryType;
uint32_t FSMC_MemoryDataWidth;
uint32_t FSMC_BurstAccessMode;
uint32_t FSMC_AsynchronousWait;
uint32_t FSMC_WaitSignalPolarity;
uint32_t FSMC_WrapMode;
uint32_t FSMC_WaitSignalActive;
uint32_t FSMC_WriteOperation;
uint32_t FSMC_WaitSignal;
uint32_t FSMC_ExtendedMode;
uint32_t FSMC_WriteBurst;
FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct;
FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;
}FSMC_NORSRAMInitTypeDef;
    

From this structure, we can see that there are 13 member variables of basic type (unit32_t) in front. These 13 parameters are used to configure the chip select control register FSMC_BCRx. The last two FSMC_NORSRAMTimingInitTypeDef Pointer type member variable. As we mentioned earlier, FSMC has read timing and write timing, so here are the parameters used to set the read timing and write timing, that is to say, these two parameters are used to configure the registers FSMC_BTRx and FSMC_BWTRx, we will later explained.

Let's take a look at these members:

  • FSMC_DataAddressMux: used to set the used memory block label and area code. In this chapter, we are using memory block 1 and area code 4, so the selected value is FSMC_Bank1_NORSRAM4.
  • FSMC_DataAddressMux: It is used to configure whether the data line and address line of FSMC are multiplexed. FSMC supports two modes of data and address line multiplexing or non-multiplexing. In non-multiplexing mode, 16-bit data lines and 26-bit address lines are used separately; in multiplexing mode, the lower 16-bit data/address lines are multiplexed, which is only valid for NOR and PSRAM. In multiplexed mode, address latches are recommended to distinguish data from addresses. In this experiment, FSMC is used to simulate 8080 timing, and only one address line A10 is used to provide the RS signal of 8080, so it does not need to be multiplexed, that is, set to FSMC_DataAddressMux_Disable.
  • FSMC_MemoryType: used to set the external memory type of FSMC, the optional types are NOR FLASH mode, PSARM mode and SRAM mode. We use TFTLCD as SRAM here, so the selected value is FSMC_MemoryType_SRAM.
  • FSMC_MemoryDataWidth: used to set the data width of the FSMC interface, you can choose 8-bit or 16-bit, here we are 16-bit data width, so the selected value is FSMC_MemoryDataWidth_16b.
  • FSMC_WriteOperation: used to configure the write operation enable, if the write operation is disabled, the FSMC will not generate a write sequence, but the data can still be read from the memory. This experiment needs to write data to the TFTLCD, so the write enable is required, and the configuration is FSMC_WriteOperation_Enable (write enable).
  • FSMC_ExtendedMode:Used to configure whether to use extended mode. In extended mode, read timing and write timing can use independent timing mode. For example, mode A is used for read timing, and mode B is used for write timing. These A, B, C, and D modes are actually not very different. The main reason is that when data/address line multiplexing is used, the timing generated by the FSMC signal is different.
  • FSMC_BurstAccessMode: Used to configure the access mode. FSMC access to memory is divided into asynchronous mode and burst mode (synchronous mode). In the asynchronous mode, a definite address needs to be generated each time the data is transferred, while the burst mode can provide an address at the beginning, and then write the data in groups continuously. This lab uses the asynchronous mode FSMC_BurstAccessMode_Disable.
  • FSMC_WaitSignalPolarity : (configure wait signal polarity), FSMC_WrapMode (configure whether to use non-alignment), FSMC_WaitSignalActive (configure when the wait signal is generated),
  • FSMC_WaitSignal : (configure whether to use wait signal), FSMC_WriteBurst (configure whether to allow burst write operation), these members need to be configured after burst mode is enabled. This experiment uses asynchronous mode, so the parameters of these members have no meaning.
  • FSMC_ReadWriteTimingStruct and FSMC_WriteTimingStruct: used to set the read and write timing. Both variables are of FSMC_NORSRAMTimingInitTypeDef structure pointer type. These two parameters are used to initialize the chip select control register FSMC_BTRx and the write operation timing control register FSMC_BWTRx respectively during initialization.

The FSMC_NORSRAMTimingInitTypeDef structure is as follows:


typedef struct{

uint32_t FSMC_AddressSetupTime;//Address setup time
uint32_t FSMC_AddressHoldTime;//Address hold time
uint32_t FSMC_DataSetupTime;//Data setup time
uint32_t FSMC_BusTurnAroundDuration;//Bus recovery time
uint32_t FSMC_CLKDivision;//Clock frequency division
uint32_t FSMC_DataLatency;//Data retention time
uint32_t FSMC_AccessMode;//Access mode
}FSMC_NORSRAMTimingInitTypeDef;

These parameters mainly control the address setup/hold time and data setup time, which are derived by dividing the FSMC clock from HCLK. The FSMC_CLKDivision and FSMC_AccessMode settings become effective only when Extended Mode is enabled. With Extended Mode, we can set different read and write timings. In this experiment, because the LCD requires different read and write speeds, Extended Mode is enabled and FSMC_DataSetupTime is configured separately for each.

These settings correspond to the FSMC_BTRx and FSMC_BWTRx registers. The values used here are based on the R61509V3 datasheet. During debugging, you can start with larger timing values and gradually reduce them to the minimum stable values for better display performance.

After understanding the function of structure members, you can configure it. The experimental configuration code in this is as follows:


FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef FSMC_ReadNORSRAMTiming;
FSMC_NORSRAMTimingInitTypeDef FSMC_WriteNORSRAMTiming;
FSMC_ReadTimingInitStructure.FSMC_AddressSetupTime = 0x01;//Address setup time (ADDSET) is 2 HCLK 1/36M=27ns
FSMC_ReadTimingInitStructure.FSMC_AddressHoldTime = 0x00;//Address hold time (ADDHLD) mode A is not used
FSMC_ReadTimingInitStructure.FSMC_DataSetupTime = 0x0f;//The data storage time is 16 HCLKs, because the reading speed of the LCD driver IC cannot be too fast, especially for the 1289 IC.
FSMC_ReadTimingInitStructure.FSMC_BusTurnAroundDuration = 0x00;
FSMC_ReadNORSRAMTiming.FSMC_CLKDivision = 0x00;
FSMC_ReadNORSRAMTiming.FSMC_DataLatency = 0x00;
FSMC_ReadNORSRAMTiming.FSMC_AccessMode = FSMC_AccessMode_A;//Mode A
FSMC_WriteNORSRAMTiming.FSMC_AddressSetupTime =0x00;//Address setup time (ADDSET) is 1 HCLK
FSMC_WriteNORSRAMTiming.FSMC_AddressHoldTime = 0x00;//ground
This part of the content FMSC Programming using CubeMX and TouchGFX AND can Here

0 comments:

Post a Comment