2020-08-06 12:05 PM
Hi! After some struggle I got my SSD1963 LCD working. It's very basic right now, I still don't have resistive touch and SPI flash for storage working.
I'm using an STM32F407 168MHz chinese development board. SDRAM is only 1MB 16-bit and my display resolution is 800x480 16-bit, which doesn't allow for a double buffer setup. I don't have any FPS measurement system yet, but screen refreshes are very slow.
I'm coming from Atmel AVR 8-bit and still learning how to work with the way more complex STM32 ARM MCUs. I was able to make my driver for this display and initialize it, transfer data to it and make it work with TouchGFX, which is really nice. Now I understand the basics of GPIO, NVIC, FSMC, how to interface to LCD though it, how a RTOS work, etc.
I'm curious to test using DMA to transfer data from external SRAM framebuffer (accessible by the address 0x68000000) to my display internal framebuffer (0x6C000000) and see how much offloading the CPU would help on getting faster transfers and higher framerates. I guess it would be done using memory-to-memory DMA transfers (found it snooping at MX/.ioc file DMA options) but I don't know how it should be done. Are there any example of this?
I'm really lost in here and any help would be very appreciated. Thanks in advance!
2020-08-07 12:46 AM
Hello,
I'm using DMA to copy data frome external SDRAM (0xC0000000) to FMC (0x60000000) like this:
void STM32HAL::copyFrameBufferBlockToLCD(const touchgfx::Rect rect)
{
uint16_t* ui16pfb = HAL::lockFrameBuffer();
uint16_t* ptrui16 = getClientFrameBuffer();
uint8_t bitDepth = HAL::lcd().bitDepth();
uint32_t ui32SrcAdr = (uint32_t)ptrui16;
/* Prepare to write to lcm RAM */
//set here LCM write data!!!
/* Try to take a display semaphore - Always free at this point */
OSWrappers::tryTakeFrameBufferSemaphore();
for(int i =0; i<rect.height; i++)
{
ptrui16 = getClientFrameBuffer() + rect.x + (i + rect.y) * "display width";
ui32SrcAdr = (uint32_t)ptrui16;
HAL_DMA_Start_IT(ptDmaHalHandle,ui32SrcAdr,"destination adress FMC", "len is display width in dependency of memaligned of DMA Here in Words") ....
/* Wait for the DMA transfer to complete */
OSWrappers::tryTakeFrameBufferSemaphore();
}
HAL::unlockFrameBuffer();
OSWrappers::giveFrameBufferSemaphore();
}
void DMA_INSTANCE_IRQHANDLER(void)
{
/* Check the interrupt and clear flag */
HAL_DMA_IRQHandler(&DmaHandle);
OSWrappers::giveFrameBufferSemaphoreFromISR();
}
/* config DMA */
/* always using DMA stream 2 for mem to mem copy!!! */
DMA_InitTypeDef tInitDma;
tInitDma.Channel = DMA_CHANNEL_0
tInitDma.Direction = DMA_MEMORY_TO_MEMORY;
tInitDma.PeriphInc = DMA_PINC_ENABLE;
tInitDma.MemInc = DMA_MINC_ENABLE;
tInitDma.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
tInitDma.MemDataAlignment = DMA_MDATAALIGN_WORD; //word alignment, 4 Bytes max. 65535
tInitDma.Mode = DMA_NORMAL;
tInitDma.Priority = DMA_PRIORITY_HIGH;
tInitDma.FIFOMode = DMA_FIFOMODE_ENABLE;
tInitDma.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
tInitDma.MemBurst = DMA_MBURST_SINGLE;
tInitDma.PeriphBurst = DMA_PBURST_SINGLE;
I'm copying the frame buffer line by line with DMA. I found out when I am copying the entire frambuffer to FMC it doesn't work. I don't know why. Maybe anybody here in the forum knows more about?
Greetz
2020-08-07 03:09 AM
The procedure how to use DMA is described in the DMA chapter in RM. Basically, after clearing the status bits after the previous transfer, you set source and destination address and number of transfers into the respective registers of any chosen stream of DMA2, enable FIFO with basically any threshold, in control register set both increments, sizes to word, noncircular, mem2mem, and enable. That's all.
JW
2020-08-07 03:11 AM
> I found out when I am copying the entire frambuffer to FMC it doesn't work.
Specify "doesn't work".
Couldn't the problem be in that you tried to set >65535 transfers?
JW
2020-08-07 03:48 AM
I mean "doesn't work" that not the entire buffer will be displayed on display. Some areas are keept blank. I tried like this:
uint32_t bufferSizeInBytes = lcd().framebufferStride() * FRAME_BUFFER_HEIGHT; // in my case 240*320px rgb 565 -> 240*320*2 = 153600 Bytes
uint32_t len = bufferSizeInBytes/4; // in my case Word alignment ->153600/4 = 38400 < 65535 -> should be ok
HAL_DMA_Start_IT("ptDmaHalHandle",ui32SrcAdr,ui32DstAdr,len)
But because of that i assume maybe i have any timing problems with FMC. Sometimes the data in FMC memory area for MCU is "dithering" (watching in memory window). I don't know how to solve it?
2020-08-07 05:19 AM
You mean, the readout of the SDRAM in debugger changes spontaneously?
I have only anecdotal experience with SDRAMs through STM32 FMC (basically just playing with a 'F429 Disco) - the errata didn't plant much confidence do we tried to avoid it in our designs so far ...
JW
2020-08-07 05:31 AM
Yes I mean that but not in SDRAM, rather in memory area in FMC. For example one color over the entire area is in frame buffer (located on SDRAM) ok. But after copying the data to FMC memory area there are some "corrupt data" which means the display area contains other data instead of the color.
See screenshoots
greetz
2020-08-07 02:26 PM
OK so it's the LCD controller side which is problematic, and if colour is incorrect, it will be at least the write (still may be read, too, and SDRAM read, too).
Hard to tell exactly what may be the reason with having the system physically at my bench... I have a working design with SSD1963 but was quite a challenge to get the it right, IIRC it did not exactly follow the timing in its datasheet and timing had to be relaxed. I don't remember the details (worked with several LCD controllers and the individual details tend to blur...)
OTOH, the screenshot indicates flipped bits, which might be also due to inadequate ground/return and/or crosstalk, so maybe some careful oscilloscope work might be useful, too.
And I don't use SDRAM which may be a factor, too.
JW
2020-08-10 04:08 AM
Crosstalk was my guess as well.
So thats why i putted the frame buffer from external SDRAM to internal RAM for testing. Lo and behold, it works. Running framebuffer from internal RAM is ok. No currupt data in memory and screen will be displayed witout any failure. Thats's why i would exclude timing problems from FMC and LCM controller (Sitronix ST7789V) od lcd display.
I assume that copying data via DMA from SDRAM to SRAM(LCD) which should be done simultaneously doesnt't work anyhow. By the way copying data manually via cpu clock doesn't work as well, because it takes way too long.
So now is the qeustion, how copying data works in this constilation?
The function call for DMA transfer looks like:
"HAL_DMA_Start_IT(ptDmaHalHandle,"adress framebuffer on SDRAM",ADRESS of NOR/SRAM for LCD,ui32Len)."
Does anybody know how exactly the DMA transfer this?
Enabling the FIFO of FMC (SRAM) also has no change..
My hardware configuration:
FMC SRAM (LCD):
SRAM_HandleTypeDef hsram1;
hsram1.Instance = FMC_NORSRAM_DEVICE;
hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
hsram1.Init.NSBank = FMC_NORSRAM_BANK1;
hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
hsram1.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
PD14 ------> FMC_D0
PD15 ------> FMC_D1
PD0 ------> FMC_D2
PD1 ------> FMC_D3
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
PD4 ------> FMC_NOE
PD5 ------> FMC_NWE
PD7 ------> FMC_NE1
PG3 ------> FMC_A13
FMC SDRAM:
SDRAM_HandleTypeDef hsdram1;
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
PF0 ------> FMC_A0
PF1 ------> FMC_A1
PF2 ------> FMC_A2
PF3 ------> FMC_A3
PF4 ------> FMC_A4
PF5 ------> FMC_A5
PF12 ------> FMC_A6
PF13 ------> FMC_A7
PF14 ------> FMC_A8
PF15 ------> FMC_A9
PG0 ------> FMC_A10
PG1 ------> FMC_A11
PC3 ------> FMC_SDCKE0
PA7 ------> FMC_SDNWE
PC4 ------> FMC_SDNE0
PF11 ------> FMC_SDNRAS
PD14 ------> FMC_D0
PD15 ------> FMC_D1
PD0 ------> FMC_D2
PD1 ------> FMC_D3
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
PG4 ------> FMC_BA0
PG5 ------> FMC_BA1
PG8 ------> FMC_SDCLK
PG15 ------> FMC_SDNCAS
PE0 ------> FMC_NBL0
PE1 ------> FMC_NBL1
DMA (DMA2)
DMA_InitTypeDef tInitDma;
tInitDma.Channel = DMA_CHANNEL_0;
tInitDma.Direction = DMA_MEMORY_TO_MEMORY;
tInitDma.PeriphInc = DMA_PINC_ENABLE;
tInitDma.MemInc = DMA_MINC_ENABLE;
tInitDma.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
tInitDma.MemDataAlignment = DMA_MDATAALIGN_WORD;
tInitDma.Mode = DMA_NORMAL;
tInitDma.Priority = DMA_PRIORITY_HIGH;
tInitDma.FIFOMode = DMA_FIFOMODE_ENABLE;
tInitDma.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
tInitDma.MemBurst = DMA_MBURST_SINGLE;
tInitDma.PeriphBurst = DMA_PBURST_SINGLE;
Adress line A0-A11 is connected to SDRAM, A13 is DC (data or command) pin for LCD. The data lines D0-D15 are shared form SDRAm and SRAM(LCD).
I'm working on STM32F750Z8. Reffered to errata, there is no description that static and dynmaic memories doesn't work simultaneously.
In contrast to STM32F429, there could be a problem. (reffered errata) (https://community.st.com/s/question/0D50X0000A1lTvV/repost-touchgfx-port-for-stm32f4xx-using-8080-if-ii-mode-communication).