cancel
Showing results for 
Search instead for 
Did you mean: 

REPOST: TouchGFX port for STM32F4xx (using 8080 I/F II Mode communication)

QUESTION - TouchGFX Community repost - Stefan Lindegger - Nov 08 2016

We intended to use the STMF429I-DISCOVERY Board as an electronics base for a proto (TouchGFX is already ported to this board).

We don’t want to use the (poor) TFT display of the board. We intend to use another TFT Display with the same controller (ILI 9341).

There’s one problem / challenge with the TFT we want to use. It cannot be connected via RGB Interface.

The TFT module can only be configured to communicate in 8080 I/F II Mode (CPU 16-bit I/F II or CPU 8-bit I/F II or CPU 18-bit I/F II or CPU 9-bit I/F II).

  • Is there a hardware layer port available which runs an STM32F429 (or similar) using the 8080 interface ?
  • If not: Can I port the hardware layer by myself (with a relatively low effort)?

Thanks for any response.

ANSWER - TouchGFX Community repost - Soren Pingel Dalsgaard - Nov 08 2016

Hi Stefan,

We do not have an 8080 implementation I'm afraid. I think you'll be able to get something running relatively quickly though. TouchGFX calls a hook function whenever something in the frame buffer changes, and you'll need to implement this so it transfers the updated region to the display using 8080. This is explained in more detail in this knowledge base article: https://touchgfx.zendesk.com/hc/en-us/articles/203642951-MCUs-without-TFT-controller

You can also check out this forum post: https://touchgfx.zendesk.com/hc/communities/public/questions/201481402-Porting-TouchGFX-to-8080-based-LCDs

Maybe John has some additional tips he can share.

ANSWER - TouchGFX Community repost - Stefan Lindegger - Nov 08 2016

Hi Søren

Thank's for your answer. I think with the descriptions in your linked articles, I should be able to port the HAL to 8080 interface.

Thanks a lot.

BR

Stefan

ANSWER - TouchGFX Community repost - Soren Pingel Dalsgaard - Nov 08 2016

You are welcome. I would also point out the hardware selection guide article (https://touchgfx.zendesk.com/hc/en-us/articles/203563602-Hardware-selection-guide) which might contain useful information if/when you are doing a custom board at some point.

ANSWER - TouchGFX Community repost - John Leung - Nov 08 2016

Stefan

Surely I could share the code for 8080 with FMC interface in this forum but it is sad to say, I am running into difficulty too!

I am using a bridge chip with 8080 interface which is similar to ILI9341 I believe, as long as they are both 8080. The pinout is summarized below:

//Pinout summary for FMC interfacing SSD2805 in 8080 16-bit IF

/** FMC GPIO Configuration

PF0 ------> FMC_A0 (DC)

PE7 ------> FMC_D4

PE8 ------> FMC_D5

PE9 ------> FMC_D6

PE10 ------> FMC_D7

PE11 ------> FMC_D8

PE12 ------> FMC_D9

PE13 ------> FMC_D10

PE14 ------> FMC_D11

PE15 ------> FMC_D12

PD8 ------> FMC_D13

PD9 ------> FMC_D14

PD10 ------> FMC_D15

PD14 ------> FMC_D0

PD15 ------> FMC_D1

PD0 ------> FMC_D2

PD1 ------> FMC_D3

PD4 ------> FMC_NOE (RD#)

PD5 ------> FMC_NWE (WR#)

PG9 ------> FMC_NE2 (CS#)

*/

The code works alone, in the sense tht this LCD interface works when no SDRAM got initialized.

Data read/write uses memory mapped IO as follows:

#define LCD_BANK_ADDR ((uint32_t)0x64000000) //bank2 address for FSMC SRAM

#define LCD_DC_CMD ((uint32_t)0x00) //DC line (FMC_A0(PF0)) for 8080-mode LCD

#define LCD_DC_DATA ((uint32_t)0x02)

#define writeData(ui16Data) (__IO uint16_t) (LCD_BANK_ADDR + LCD_DC_DATA) = ui16Data

#define writeCmd(ui16Cmd) (__IO uint16_t) (LCD_BANK_ADDR + LCD_DC_CMD) = ui16Cmd

The problem is that, this 8080-based using FMC interface to STM32F429. Whenever SDRAM got initialized, LCD is not working and vice versa.

How to make FMC for SDRAM and SRAM co-exist? This is the question.

Anyone has experience on this? Look forward to any suggestion.

John

ANSWER - TouchGFX Community repost - John Leung - Nov 08 2016

One more comment on this. From various application notes I do notice this statement regarding FSMC: "FSMC performs only one access at a time to an external device".

So, to make LCD in 8080 interface (SRAM interface) co-exists with SDRAM onboard of stm32f429-disco, does it mean we need to build a cache in internal memory of the MCU? Any DMA to copy directly data from SDRAM to SRAM of 8080-LCD?

ANSWER - TouchGFX Community repost - Soren Pingel Dalsgaard - Nov 08 2016

Hi John,

I have never tried using both SRAM and SDRAM simultaneously but I would be surprised if that did not work. I am basing this on that NOR+SDRAM certainly works, and NOR is the same principle as SRAM (static memory). Along the same lines I would guess that the "only one access at a time" statement simply means that a second access is delayed until first access completes. We certainly do not need a cache with simultaneous NOR+SDRAM.

There is an errata for MCU revisions Y and 1 of the STM32F429 which does not allow simulatenous static and dynamic memories. This was fixed in rev. 3. This could explain it, try checking your MCU rev.

Apart from that try posting on the ST forums. And keep us updated on this issue =)

ANSWER - TouchGFX Community repost - John Leung - Nov 08 2016

Soren

It seems the problem last time was due to some stupid mistake with RCC setup. Making a good progress as I can initialize both SDRAM and LCD as SRAM now. A further question regarding framebuffer data read/write.

Looking at the file stm32f429i_discovery_sdram.c and find this function:

SDRAM_ReadBuffer(uint32_t * pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize).

Is it the function used by TouchGFX or there is another one packed inside touchgfx_core.lib?

As far as I know TouchGFX uses up to16-bit color, that is half of the pBuffer data pointer width. Should I pack two pixels into one 32-bit data or simply ignore the higher 16-bit ?

John

7 REPLIES 7

ANSWER - TouchGFX Community repost - John Leung - Nov 08 2016

Part 1:

Standalone driver with FMC initialized for SRAM(LCD) and SDRAM seems OK now. With SDRAM (framebuffer) filled with a pure color of red, green, and blue, the LCD refreshed with main program as below.

There remains to get the driver down to flushFrameBuffer(const Rect &rect) and activate TE pin for Vsync.

/**

* main.c

*/

#include "stm32f4xx.h"

#include "SSD2805_S6D04D2.h"

#include "stm32f429i_discovery_sdram.h"

#include "tick.h"

//void MX_GPIO_Init(void);

void SDRAM_LoadPage(uint16_t color)

{

 uint32_t val;

  /* Disable write protection */

 FMC_SDRAMWriteProtectionConfig(FMC_Bank2_SDRAM, DISABLE);

 /* Wait until the SDRAM controller is ready */

 while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET)

 {

 }

 for(val = 0; val<115200UL; val+=2) //115200 = 240*240*2 bytes

 {

  *(uint32_t *) (SDRAM_BANK_ADDR + val) = color;

 }

}

int main(void)

{

 TICK_InitTick();

 SDRAM_Init();

 displayInit();

 displaySetArea(0, 0, 240, 240);

 for(;;)

 {

  SDRAM_LoadPage(0xF800); //Red

  displayXferFB(0, 0, 240, 240, SDRAM_BANK_ADDR);

  TICK_Delay(1000);

  SDRAM_LoadPage(0x07E0); //Green

  displayXferFB(0, 0, 240, 240, SDRAM_BANK_ADDR);

  TICK_Delay(1000);

  SDRAM_LoadPage(0x001F); //Blue

  displayXferFB(0, 0, 240, 240, SDRAM_BANK_ADDR);

  TICK_Delay(1000);

 }

}

/*******************************************************************************/

/**

* SSD2805_S6D04D2.c

*/

#include "SSD2805_S6D04D2.h"

#include "tick.h"

#define Swap(x) (((uint16_t)x<<8) | ((uint16_t)x>>8))

#define DelayMs(ms) TICK_Delay(ms)

static __inline void writeReg(uint8_t ui8Reg, uint16_t ui16Data)

{

 writeCmd(ui8Reg);

 //insert wait here for slow clock & 320MHz, this is set with Timing.AddressSetupTime = 1 with FMC init

 //because address hold time = 1 HCLK. Especially important when MCU running at 168MHz (1 HCLK = 5.9ns!)

 writeData(ui16Data);

}

static __inline void writeTDCSize(uint32_t ui32TDCSize)

{

 writeReg(MCS_PSCR1, (uint16_t)ui32TDCSize);

 writeReg(MCS_PSCR2, (uint16_t)(ui32TDCSize>>16));

}

static void gpioFMCConfig(void);

/*

void gpioCSConfig(void)

{

 GPIO_InitTypeDef GPIO_InitStruct;

 GPIO_InitStruct.GPIO_Pin = LCD_CS_PIN;

 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //output push-pull mode

 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;

 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;

 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;

 GPIO_Init(LCD_CS_BASE, &GPIO_InitStruct);

 GPIO_WriteBit(LCD_CS_BASE, LCD_CS_PIN, Bit_SET);

}

*/

void gpioResetConfig(void)

{

 GPIO_InitTypeDef GPIO_InitStruct;

 GPIO_InitStruct.GPIO_Pin = LCD_RST_PIN;

 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //output push-pull mode

 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;

 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;

 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_LCD_RST, ENABLE);

 GPIO_Init(LCD_RST_BASE, &GPIO_InitStruct);

 GPIO_WriteBit(LCD_RST_BASE, LCD_RST_PIN, Bit_SET); 

}

void gpioBacklightConfig(void)

{

 GPIO_InitTypeDef GPIO_InitStruct;

Part 2:

GPIO_InitStruct.GPIO_Pin = LCD_BACKLIGHT_PIN;

 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //output push-pull mode

 GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;

 GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;

 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_LCD_BACKLIGHT, ENABLE);

 GPIO_Init(LCD_BACKLIGHT_BASE, &GPIO_InitStruct);

 GPIO_WriteBit(LCD_BACKLIGHT_BASE, LCD_BACKLIGHT_PIN, Bit_RESET);

}

 /**

 * gpioFMCConfig() sets alternate function for GPIO pins for FMC

 * Pinout summary for FSMC interfacing SSD2805 in 8080 16-bit IF

 * FMC GPIO Configuration 

 PG9  ------> FMC_NE2 (CS#)

 PF0  ------> FMC_A0 (DC)

 PE7  ------> FMC_D4

 PE8  ------> FMC_D5

 PE9  ------> FMC_D6

 PE10  ------> FMC_D7

 PE11  ------> FMC_D8

 PE12  ------> FMC_D9

 PE13  ------> FMC_D10

 PE14  ------> FMC_D11

 PE15  ------> FMC_D12

 PD0  ------> FMC_D2

 PD1  ------> FMC_D3

 PD4  ------> FMC_NOE (RD#)

 PD5  ------> FMC_NWE (WR#)

 PD8  ------> FMC_D13

 PD9  ------> FMC_D14

 PD10  ------> FMC_D15

 PD14  ------> FMC_D0

 PD15  ------> FMC_D1

 */

static void gpioFMCConfig(void)

{

 GPIO_InitTypeDef GPIO_InitStructure;

 //GPIO clock enable

 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD |

 RCC_AHB1Periph_GPIOE |

 RCC_AHB1Periph_GPIOF |

 RCC_AHB1Periph_GPIOG, ENABLE);

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

 //PG9 configured as FMC function CS# (FMC_NE2)

 GPIO_PinAFConfig(GPIOG, GPIO_PinSource9, GPIO_AF_FMC);

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

 GPIO_Init(GPIOG, &GPIO_InitStructure);

 //PF0 configured as FMC function DC (FMC_A0)

 GPIO_PinAFConfig(GPIOF, GPIO_PinSource0, GPIO_AF_FMC);

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

 GPIO_Init(GPIOF, &GPIO_InitStructure); 

 //PE[7:15] configured as FMC data bus

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FMC);

 GPIO_InitStructure.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_Init(GPIOE, &GPIO_InitStructure);

 //PD0,1,4,5,8,9,10,14,15 configured as FMC data bus & WR#, RD#

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FMC);

 GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FMC);

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 |

                GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9 |

                GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;

                

 GPIO_Init(GPIOD, &GPIO_InitStructure);

}

void displayInit(void)

{

 FMC_NORSRAMInitTypeDef hsram1;

 /* Tick Init for 1msec clock tick for DelayMs() */

 //TICK_InitTick();

 /*-- FMC Configuration ------------------------------------------------------*/

 gpioFMCConfig();

 /* Enable the FMC/FSMC interface clock */

 //RCC->AHB3ENR        |= 0x00000001;

 RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);

/*

#if defined (STM32F427_437xx) || defined (STM32F429_439xx)

 // Configure and enable Bank1_SRAM2

 FMC_Bank1->BTCR[2] = 0x00001011;

 FMC_Bank1->BTCR[3] = 0x00000201;

 FMC_Bank1E->BWTR[2] = 0x0fffffff;

#endif // STM32F427_437xx || STM32F429_439xx

*/

 gpioResetConfig();   //configure reset line as gpio default high

 gpioBacklightConfig(); //configure backlight control as gpio default backlight off

 //Low level reset

 resetHigh();

 DelayMs(300);

 resetLow();

 DelayMs(10);

 resetHigh();

 DelayMs(10);​

​Part 3:

/**

 * Set PLL. Before PLL of SSD2805 is started, the min WRX period

 * is 6T with T=1/20MHz with an external TX_CLK = 20MHz OSC onboard.

 * The min peiod for WRX = 300ns.

 * RCC set for HSI RC @16MHz to output such long WRX strobe pulse

 * with original OSC and CLK configuration saved

 */

 RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);

 while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)!=SET)

  ;

 hsram1.FMC_Bank       = FMC_Bank1_NORSRAM2;

 hsram1.FMC_DataAddressMux  = FMC_DataAddressMux_Disable;

 hsram1.FMC_MemoryType    = FMC_MemoryType_SRAM ;

 hsram1.FMC_MemoryDataWidth  = FMC_NORSRAM_MemoryDataWidth_16b;

 hsram1.FMC_BurstAccessMode  = FMC_BurstAccessMode_Disable;

 hsram1.FMC_WaitSignalPolarity = FMC_WaitSignalPolarity_Low ;

 hsram1.FMC_WrapMode     = FMC_WrapMode_Disable;

 hsram1.FMC_WaitSignalActive = FMC_WaitSignalActive_BeforeWaitState;

 hsram1.FMC_WriteOperation  = FMC_WriteOperation_Enable;

 hsram1.FMC_WaitSignal    = FMC_WaitSignal_Disable;

 hsram1.FMC_ExtendedMode   = FMC_ExtendedMode_Disable;

 hsram1.FMC_AsynchronousWait = FMC_AsynchronousWait_Disable;

 hsram1.FMC_WriteBurst    = FMC_WriteBurst_Disable ;

 hsram1.FMC_ContinousClock  = FMC_CClock_SyncOnly;

 /**

 *Timing measured in HCLK with MCU's SYSCLK=16MHz.

 *Before PLL of SSD2805 has been started, the min WRX period

 *is 6T with T=1/20MHz. Therefore the min peiod for WRX = 300ns

 *with an external TX_CLK = 20MHz OSC onboard 

 */

 hsram1.FMC_WriteTimingStruct->FMC_AddressSetupTime   = 5;

 hsram1.FMC_WriteTimingStruct->FMC_AddressHoldTime    = 0;

 hsram1.FMC_WriteTimingStruct->FMC_DataSetupTime     = 5; //5*1/16MHz @ 312.5ns > 300ns

 hsram1.FMC_WriteTimingStruct->FMC_BusTurnAroundDuration = 0;

 hsram1.FMC_WriteTimingStruct->FMC_AccessMode      = FMC_AccessMode_A;

 hsram1.FMC_WriteTimingStruct->FMC_AddressSetupTime   = 5;

 FMC_NORSRAMInit(&hsram1);

 FMC_NORSRAMCmd(LCD_FMC_BANK, ENABLE);

 /**

 *PLL = clock*MUL/(PDIV*DIV)

 *   = clock*(BAh[7:0]+1)/((BAh[15:12]+1)*(BAh[11:8]+1))

 *   = 20*(0x0f+1)/1*1 = 20*16 = 320MHz

 *Remark: 350MHz >= fvco >= 225MHz for SSD2805 because the max. speed per lane is 350Mbps

 *Set PLL by writing a value 0x000f to MCS register at 0xBA

 */ 

 writeReg(MCS_PLCR, 0x000F);

 writeReg(MCS_PCR, 0x0001); //enable PLL

 DelayMs(2);         //wait 2ms for PLL start. 

 //Now switch it back to PLL clock for 180MHz

 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)!=SET)

  ;

 /**

 *

 * Now it is safe to set FMC running at higher speed.

 * Set clock control register for SYS_CLK & LP clock speed

 * SYS_CLK = TX_CLK/(BBh[7:6]+1), TX_CLK = external oscillator clock speed

 * In this case, SYS_CLK = 20MHz/(1+1)=10MHz. Measure SYS_CLK pin to verify it.

 * LP clock = PLL/(8*(BBh[5:0]+1)) = 320/(8*(4+1)) = 8MHz, conform to LG panel's spec, default LP = 8Mbps

 * S6D04D2 is the controller of LG 1.54" panel.

 */

 /**

 * Very important!!!

 * Compiler optimization level should be set for Level 1,2 with Optimize for Time enabled

 * Somehow, Optimization Level 3 doesn't work. Optimization for Time also required enable.

 *

 * This is important for the func writeReg(uint8_t ui8Reg, uint16_t ui16Data)

 * to insert a min. 9.4ns for PWcsh time in WR# even when SSD2805 running

 * at 320MHz, especially when Compiler optimization applied.

 * PWcsl at 9.4ns is the min. for SSD2805 at 320MHz PLL clock (3*T with T=3.125ns),

 * PWcsh also min. at 9.4ns.

 * For now, AddressSetupTime set 5 with PWcsh set 36ns, PWcsl set 12ns for a stable result.

 * Refresh time for a complete frame with 16-bit addressing for 240x240 pixels is calculated as :

 * Time = 240*240*(12+36)ns = 2.76ms. This update time is even less than the BSYNC (TE) blanking time

 * which is set to 5.6ms for frame update.

 */

 hsram1.FMC_WriteTimingStruct->FMC_AddressSetupTime = 5;//5*HCLK = 29.7ns 

 hsram1.FMC_WriteTimingStruct->FMC_DataSetupTime   = 2;//2*HCLK = 12ns

 FMC_NORSRAMInit(&hsram1);

 FMC_NORSRAMCmd(LCD_FMC_BANK, ENABLE);

 writeReg(MCS_CCR, 0x0044);     //Set LP Clock here with divider = 5, i.e. LP clock = PLL/(8*(4+1)) = 8MHz

                   //SYSD_CLK divider set to 01 for SYS_CLK=TX_CLK/2=10MHz

                   //output sys_clk for debug. Now check sys_clk pin for 10MHz signal

 writeReg(MCS_TR, 0x0100);     //Enable SYS_CLK output with END and CO set 0 for MIPI lane data

                   //endianness and color order set here

 DelayMs(100);            //don't know why, this long delay is required. This value found

 /**

 * Set MIPI packet format.

 * EOT packet enable, write operation, it is a DCS packet

 * HS clock is disabled, video mode disabled, in HS mode to send data

 */

 writeReg(MCS_CFGR, 0x0243);   

 writeReg(MCS_PSCR3,0x0400);   //MCS_PSCR3:Packet size threshold, min=2, max=0x400

 //Set Virtual Channel (VC) to use

 writeReg(MCS_VCR, 0x0000);

 //Now write DCS command to LG panel for system power-on upon reset

 writeTDCSize(0);

 writeCmd(DCS_SLPOUT);        //DCS sleep-out command     

​Part 4:

DelayMs(100);            //wait for LG panel after sleep out 

 //Now configuration parameters sent to LG

 writeTDCSize(1);           //define TDC size to be 1

 writeReg(DCS_COLMOD, 0x0005);        //DCS command to set pixel format for 16-bit RGB

 //Turn on BSYNC pin (like TE), set to 5.6ms high pulse for frame update interval

 writeTDCSize(2);

 writeReg(0xF1, 0x5A5A);        //unlock MCS

 writeTDCSize(12);

 writeCmd(0xF2);

 writeData(0xF000);

 writeData(0x5603);

 writeData(0x0008);

 writeData(0x0001);

 writeData(0x0000);

 writeData(0x0356);

 writeTDCSize(2);

 writeReg(0xF1, 0xA5A5);        //lock MCS

 //Turn on Display

 writeTDCSize(0);  

 writeCmd(DCS_DISPON);         //display ON DCS command to LG panel

 DelayMs(1);              //from a blind trial!!!

 backlightOn();

}

void displaySetArea(uint16_t x, uint16_t y, uint16_t width, uint16_t height)

{

 uint16_t ec, ep; //ec=end column, ep=end page

 uint32_t tdcSize; //specific for SSD2805

 if (!width || !height) return;

 tdcSize = 4;

 writeTDCSize(tdcSize);

 writeCmd(DCS_CASET); //column address set

 writeData(Swap(x));  //set SC; swapping hibyte:lowbyte required

 ec = x + width -1;

 writeData(Swap(ec)); //set EC

 writeCmd(DCS_PASET); //page address set

 writeData(Swap(y));  //set SP

 ep = y + height - 1;

 writeData(Swap(ep)); //set EP

}

void displayXferFB(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t frameBufferStart)

{

 __IO uint32_t write_pointer = (uint32_t)(DISP_HOR_RESOLUTION*y + x);

 uint32_t _area = (uint32_t)width*height;

 uint32_t tdcSize = (uint32_t)2*width; //SSD2805 specific, set payload in bytes

 writeTDCSize(tdcSize);        //SSD2805 specific

 //set DCS write command (write command DCS_RAMWR)

 writeCmd(DCS_RAMWR);         //8080-IF with DCS_RAMWR to start writing to SRAM of SSD2805

 while(_area--)

 {

  writeData(*(__IO uint16_t *)(frameBufferStart + write_pointer));

  write_pointer+=2;

 }

}

/************************************************************************/

/**

* SSD2805_S6D04D2.h

*/

/**

* Prerequisite:

* 1. include search path ..\..\..\touchgfx\framework\include\platform\hal\ST\mcu\stm32f4x9\vendor

* for non-Cube driver provided by TouchGFX

* 2. include stm32f4xx_fmc.c, stm32f4xx_gpio.c, & stm32f4xx_rcc.c src code in project

* 3. tick timer for 1ms interval for DelayMs(ms)

*/

#ifndef SSD2805_S6D04D2_H_

#define SSD2805_S6D04D2_H_

#ifdef __cplusplus

extern "C"{

#endif

#include "stm32f4xx.h"

//#include "stm32f4xx_hal.h"

/*

 * ***************************************************************************************

 * Display Command Set (DCS) is a set of common commands for controlling

 * the display device in compliance with the DSI standard. Each command

 * is an eight-bit code with 00h to AFh assigned to the User Command Set

 * and all other codes assigned to the Manufacturer Command Set.

 * DCS defined here with prefix DCS_ and MCS with MCS_

 * ***************************************************************************************

Part 5:

*/

#define DCS_NOP                0x00  //no operation. This is an empty command

#define DCS_SWRESET            0x01   //soft reset

#define DCS_RDNUMED       0x05  //read number of errors on DSI

#define DCS_RDDPM              0x0A   //Read display power mode

#define DCS_RDDMADCTL          0x0B   //Read display MADCTL for column address order, RGB/BGR order etc

#define DCS_RDDCOLMOD          0x0C   //Read display display pixel format

#define DCS_RDDIM              0x0D   //Read display image mode

#define DCS_RDDSM              0x0E   //Read display signal mode

#define DCS_RDDSDR             0x0F   //Read display self-diagnostic result

#define DCS_SLPIN              0x10  //sleep in command to enter the min. power mode

#define DCS_SLPOUT             0x11  //sleep out command to turn off sleep mode

#define DCS_NORON              0x13   //Normal display mode on

#define DCS_INVOFF             0x20  //Display inversion off

#define DCS_INVON              0x21  //Display inversion on

#define DCS_DISPOFF            0x28  //Display off with a blank page inserted. No change of frame memory content

#define DCS_DISPON             0x29  //Display on to recover from Display Off Mode

#define DCS_CASET          0x2A  //Column Address Set to define area of frame memory where MPU can access

                  //Parameters are inclusive, that means from SC[15:0] = 0 to EC[15:0] = 239

                  //for the panel resolution of 240 pixels in width

#define DCS_PASET          0x2B  //Page Address Set, similar to DCS_CASET, this command for SP[15:0] and EP[15:0]

#define DCS_RAMWR          0x2C   //command to transfer data from MPU to frame memory

                  //It is important to note that when this command is accepted, the column &

                  //page registers are reset to the Start Column/Start Page defined in DCS_CASET &

                  //DCS_PASET

#define DCS_RAMRD          0x2E  //This command is used to transfer data from display's frame memory back to MPU.

                  //When this command is accepted, the column & page registers are reset to the Start

                  //Column.Start Page defined in DCS_CASET & DCS_PASET

#define DCS_TEOFF          0x34  //Tearing effect line OFF

#define DCS_TEON           0x35  //Tearing effect line ON

#define DCS_MADCTL         0x36   //memory access control for frame buffer scanning direction etc

#define DCS_IDMOFF       0x38  //This command is used to recover from idle mode on

#define DCS_IDMON         0x39  //This command is used to enter into idle mode to reduce to 8 color depth

#define DCS_COLMOD         0x3A   //interface pixel format set

#define DCS_RAMWRC         0x3C   //This command continues writing to memory after DCS_RAMWR. When this command

                  //is accepted, no column/page registers are reset. This command is good for

                  //writing data to frame memory in block for speed optimization

#define DCS_RAMRDC      0x3E  //Counterpart for DCS_RAMWRC to "block read" from frame memory to MPU

#define DCS_RDDDBS     0xA1  //Returns supplier ID

#define DCS_RDDDBC     0xA8  //continue reading supplier's ID after DCS_RDDDBS has been interrupted

//SSD2805 specific registers

#define MCS_CFGR    0xB7 //configuration register

#define MCS_VCR     0xB8 //VC control register to set virtual channel

#define MCS_PCR     0xB9 //PLL control register

#define MCS_PLCR    0xBA //PLL config register

#define MCS_CCR     0xBB //Clock control register

#define MCS_PSCR1    0xBC //Packet size control register 1, specifies the total number of data bytes (in byte)

               //to be transmitted by SSD2805 in the next operation.

#define MCS_PSCR2    0xBD //Packet size control register 2

#define MCS_PSCR3    0xBE //Packet size threshold, min=2, max=0x400

#define MCS_TR     0xD6 //Test register

//physical dimension of the display

#define DISP_HOR_RESOLUTION 240

#define DISP_VER_RESOLUTION 240

//#define LCD_CS_BASE  GPIOG

//#define LCD_CS_PIN  GPIO_Pin_9

#define LCD_RST_BASE GPIOD

#define LCD_RST_PIN  GPIO_Pin_2

#define RCC_AHB1Periph_LCD_RST RCC_AHB1Periph_GPIOD

#define LCD_TE_BASE         GPIOA

#define LCD_TE_PIN         GPIO_Pin_9

#define LCD_TE_EXTI         EXTI_Line9            //this is to match GPIOA9, level shifted by a mosfet from 1.8V -> 3.3V

#define LCD_TE_IRQn         EXTI9_5_IRQn           //this is to match GPIOA9 interrupt handler number to line 5 to 9

#define EXTI_IRQHandler       EXTI9_5_IRQHandler //this is to match EXTI_IRQ handler in BoardConfiguration.cpp

#define LCD_TE_RCC_AHB1Periph_GPIO RCC_AHB1Periph_GPIOA

#define LCD_TE_PortSourceGPIO    EXTI_PortSourceGPIOA

#define LCD_TE_PinSource      EXTI_PinSource9

#define LCD_BACKLIGHT_BASE GPIOD

#define LCD_BACKLIGHT_PIN  GPIO_Pin_7

#define RCC_AHB1Periph_LCD_BACKLIGHT RCC_AHB1Periph_GPIOD

#define LCD_BANK_ADDR   ((uint32_t)0x64000000) //bank2 address for FSMC SRAM

#define LCD_FMC_BANK   FMC_Bank1_NORSRAM2   //hardware specific with NE2 wired to CS# of SSD2805

#define LCD_DC_CMD     ((uint32_t)0x00)    //DC line (FMC_A0(PF0)) for 8080-mode LCD

#define LCD_DC_DATA    ((uint32_t)0x02) 

​Part 6:

/** GPIO pins

 PD2  ------> RESET

 PD7  ------> Backlight enable

 */

//Pinout summary for FSMC interfacing SSD2805 in 8080 16-bit IF

 /** FMC GPIO Configuration 

 PF0  ------> FMC_A0 (DC)

 PE7  ------> FMC_D4

 PE8  ------> FMC_D5

 PE9  ------> FMC_D6

 PE10  ------> FMC_D7

 PE11  ------> FMC_D8

 PE12  ------> FMC_D9

 PE13  ------> FMC_D10

 PE14  ------> FMC_D11

 PE15  ------> FMC_D12

 PD8  ------> FMC_D13

 PD9  ------> FMC_D14

 PD10  ------> FMC_D15

 PD14  ------> FMC_D0

 PD15  ------> FMC_D1

 PD0  ------> FMC_D2

 PD1  ------> FMC_D3

 PD4  ------> FMC_NOE (RD#)

 PD5  ------> FMC_NWE (WR#)

 PG9  ------> FMC_NE2 (CS#)

 */

/* Read/Write Buffers */

//extern uint16_t FrameBuffer[DISP_VER_RESOLUTION][DISP_HOR_RESOLUTION];

/**

* @func  extern void DisplayCSConfig(void)

* @brief This function is required to over-ride FSMC NEx Alternate function

     for CS# strobe. FSMC NEx strobes in every data/command write cycle.

     On the contrary, SSD2805 requires single CS# strobe for multiple

     command data.

* @param None

* @return None

*/

//extern void gpioCSConfig(void);

extern void gpioResetConfig(void);

extern void gpioBacklightConfig(void);

extern void displayInit(void);

extern void displaySetArea(uint16_t x, uint16_t y, uint16_t width, uint16_t height);

extern void displayXferFB(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t frameBufferStart);

/**

* @func flushFrameBuffer(const Rect &rect)

* @brief In order to transfer the contents of the frame buffer to the display,

*     override the function HAL::flushFrameBuffer(const Rect&).

*     This function is called at the end of each frame,

*     with the parameter Rect describing the area of the frame

*     buffer that was changed.

*     This area must then be transferred to the display using the

*     appropriate communication protocol.

* @param const Rect& rect pass by reference for a rectangle

* @return None

*/

//extern void flushFrameBuffer(const Rect& rect);

//#define csLow()         GPIO_WriteBit(LCD_CS_BASE, LCD_CS_PIN, Bit_RESET)

//#define csHigh()        GPIO_WriteBit(LCD_CS_BASE, LCD_CS_PIN, Bit_SET)

#define resetHigh()       GPIO_WriteBit(LCD_RST_BASE, LCD_RST_PIN, Bit_SET)

#define resetLow()       GPIO_WriteBit(LCD_RST_BASE, LCD_RST_PIN, Bit_RESET)

#define backlightOff()     GPIO_WriteBit(LCD_BACKLIGHT_BASE, LCD_BACKLIGHT_PIN, Bit_RESET)

#define backlightOn()      GPIO_WriteBit(LCD_BACKLIGHT_BASE, LCD_BACKLIGHT_PIN, Bit_SET)

#define writeData(ui16Data)   *(__IO uint16_t*) (LCD_BANK_ADDR + LCD_DC_DATA) = ui16Data

#define writeCmd(ui16Cmd)    *(__IO uint16_t*) (LCD_BANK_ADDR + LCD_DC_CMD) = ui16Cmd

#ifdef __cplusplus

}

#endif

#endif

ANSWER - TouchGFX Community repost - Soren Pingel Dalsgaard - Nov 08 2016

Thanks for sharing this!

As for your questions, the SDRAM_ReadBuffer() function is not used by TouchGFX. We have our own function (HAL::blockCopy) which handles unaligned transfers in a more optimal way.

The frame buffer format is packed, so an aligned 32-bit word will contain data for two pixels.