cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F2 FSMC ILI9341

Posted on October 12, 2015 at 10:30

Hi,

I want to control a TFT (with a ILI9341) display via the 16 bit FSMC interface of a STM32F205VET6. Therefore I am using the emWin library v5.30 provided by Keil. I got the application working and all the display content is drawn properly on the TFT. 

But now I want to use the blinking cursor functionality of the EDIT widget and therefore the emWin library performs a multiple read operation (µC reads from display GRAM). Here I get into trouble. It seems like I have some timing problems. If the code writes data to the TFT I immediately read back the written data but the read data differs from the written data in approx. 30% of the write attempts. I already played around with the FSMC timings but without any changes. I calculated the timings according to AN2790 DATAST = 355ns and ADDSET = 67ns. Which makes DATAST = 22 and ADDSET = 4 @ fFSMC = 60MHz.

Hope that anybody can help me.

Here is my initialization code.

void LCD_X_Init(void) {

  GPIO_InitTypeDef GPIO_InitStruct;

  FSMC_NORSRAMInitTypeDef hsram1;

  FSMC_NORSRAMTimingInitTypeDef Timing;

  /* GPIO Ports Clock Enable */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,    ENABLE);

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

  /** FSMC GPIO Configuration  

  PE7   ------> FSMC_D4

  PE8   ------> FSMC_D5

  PE9   ------> FSMC_D6

  PE10   ------> FSMC_D7

  PE11   ------> FSMC_D8

  PE12   ------> FSMC_D9

  PE13   ------> FSMC_D10

  PE14   ------> FSMC_D11

  PE15   ------> FSMC_D12

  PD8   ------> FSMC_D13

  PD9   ------> FSMC_D14

  PD10   ------> FSMC_D15

  PD11   ------> FSMC_A16

  PD14   ------> FSMC_D0

  PD15   ------> FSMC_D1

  PD0   ------> FSMC_D2

  PD1   ------> FSMC_D3

  PD4   ------> FSMC_NOE

  PD5   ------> FSMC_NWE

  PD7   ------> FSMC_NE1

  */

  /* GPIOE configuration */

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FSMC);

  

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10 

                          |GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14 

                          |GPIO_Pin_15;

  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_Init(GPIOE, &GPIO_InitStruct);

  

  /* GPIOD configuration */

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource7, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC);

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC);

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5| \

                             GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10| \

                             GPIO_Pin_11|GPIO_Pin_14|GPIO_Pin_15;

  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_Init(GPIOD, &GPIO_InitStruct);

  /* Configuration of the reset pin */

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;

  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; 

  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;

  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz;  

  GPIO_Init(GPIOD, &GPIO_InitStruct);

  

  GPIO_WriteBit(GPIOD, GPIO_Pin_13, Bit_RESET);

  

  /* Enable FSMC peripheral clock */

  RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);

  /* SRAM1 memory initialization */

  hsram1.FSMC_Bank = FSMC_Bank1_NORSRAM1;

  hsram1.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;

  hsram1.FSMC_MemoryType = FSMC_MemoryType_SRAM;

  hsram1.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;

  hsram1.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;

  hsram1.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;

  hsram1.FSMC_WrapMode = FSMC_WrapMode_Disable;

  hsram1.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;

  hsram1.FSMC_WriteOperation = FSMC_WriteOperation_Enable;

  hsram1.FSMC_WaitSignal = FSMC_WaitSignal_Disable;

  hsram1.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;

  hsram1.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;

  hsram1.FSMC_WriteBurst = FSMC_WriteBurst_Disable;

/* @todo: Check timing */

  Timing.FSMC_AddressSetupTime = 1;

  Timing.FSMC_AddressHoldTime = 4;

  Timing.FSMC_DataSetupTime = 22;

  Timing.FSMC_BusTurnAroundDuration = 0;

  Timing.FSMC_CLKDivision = 0;

  Timing.FSMC_DataLatency = 0;

  Timing.FSMC_AccessMode = FSMC_AccessMode_A;

  

  hsram1.FSMC_ReadWriteTimingStruct = &Timing;

  hsram1.FSMC_WriteTimingStruct = &Timing;

  FSMC_NORSRAMInit(&hsram1);

  

  /* Enable FSMC_Bank1_NORSRAM1 */

  FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);

  

  /* Turn LCD Backlight On, release display from reset */

  GPIO_WriteBit(GPIOC, GPIO_Pin_6, Bit_SET);

  GPIO_WriteBit(GPIOD, GPIO_Pin_13, Bit_SET);

}

regards Thomas

4 REPLIES 4
Posted on October 12, 2015 at 20:03

I don't exactly know what's your problem, but you might want to read the FSMC_BTR.BUSTURN field's description in the RM.

JW

Posted on October 13, 2015 at 07:20

Hi.

thank you for your response.

My problem is that I am not able to reliably read data back from the ILI9341.

So I guessed that maybe one of the forum users can provide a FSMC configuration which works with the ILI9341.

regards Thomas

jpeacock
Associate II
Posted on October 13, 2015 at 14:03

According to the ILI9341 datasheet the trcfm cycle time for a memory read is 450ns, about 3x as long as a register read.  The cycle time between reads is set by the trdh read pulse hi duration, 90ns. What do you have set for access time in the FSMC, and do you guarantee 90ns between reads?

  Jack Peacock
Posted on October 13, 2015 at 14:59

Hi Jack,

in the meantime I changed the FSMC configuration as follow:

  /* SRAM1 memory initialization */

  hsram1.FSMC_Bank = FSMC_Bank1_NORSRAM1;

  hsram1.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;

  hsram1.FSMC_MemoryType = FSMC_MemoryType_SRAM;

  hsram1.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;

  hsram1.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;

  hsram1.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;

  hsram1.FSMC_WrapMode = FSMC_WrapMode_Disable;

  hsram1.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;

  hsram1.FSMC_WriteOperation = FSMC_WriteOperation_Enable;

  hsram1.FSMC_WaitSignal = FSMC_WaitSignal_Disable;

  hsram1.FSMC_ExtendedMode = FSMC_ExtendedMode_Enable;

  hsram1.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;

  hsram1.FSMC_WriteBurst = FSMC_WriteBurst_Disable;

  /* FSMC read timing */

  ReadTiming.FSMC_AddressSetupTime = 4;

  ReadTiming.FSMC_AddressHoldTime = 0;

  ReadTiming.FSMC_DataSetupTime = 60;

  ReadTiming.FSMC_BusTurnAroundDuration = 12;

  ReadTiming.FSMC_CLKDivision = 0;

  ReadTiming.FSMC_DataLatency = 0;

  ReadTiming.FSMC_AccessMode = FSMC_AccessMode_A;

  hsram1.FSMC_ReadWriteTimingStruct = &ReadTiming;

  /* FSMC write timing */

  WriteTiming.FSMC_AddressSetupTime = 2;

  WriteTiming.FSMC_AddressHoldTime = 0;

  WriteTiming.FSMC_DataSetupTime = 5;

  WriteTiming.FSMC_BusTurnAroundDuration = 2;

  WriteTiming.FSMC_CLKDivision = 0;

  WriteTiming.FSMC_DataLatency = 0;  

  WriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;  

  hsram1.FSMC_WriteTimingStruct = &WriteTiming;

Now I am able to read from the ILI9341. 

I also realized that I must perform two read operations if I want to get a valid register value. Therefore a dummy read is necessary. 

Writing to and reading from the ILI9341 via the FSMC works great now. 

regards Thomas