2018-11-27 12:39 AM
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).
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
2018-11-27 12:50 AM
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;
2018-11-27 12:51 AM
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);
2018-11-27 12:51 AM
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
2018-11-27 12:52 AM
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_
* ***************************************************************************************
2018-11-27 12:53 AM
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)
2018-11-27 12:53 AM
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
2018-11-27 12:53 AM
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.