cancel
Showing results for 
Search instead for 
Did you mean: 

Interference when using SSD1963 and SDRAM over FMC

davide
Associate II
Posted on September 19, 2014 at 23:43

Hi everyone, 

This is my first post on this community, that i found great, so before everything let me say thank you.

I'm currently working on a spare time project which involve some basic PID simulated control/process a simple graphic interface.

I'm starting from the display low level driver, the display is a 800x480 24bit (used as 16bit 565) driven by an SSD1963 [BuyDisplay ER-TFTM070-4V2.1 + CPTouch] over the FMC bus and no problem.

Next i wrote the driver for the SDRAM [64Mb embedded in the STM32F429i-Disco] and also here no problem.

Strange things are happening when i use the two things together; i'm planning to use SDRAM as a frame buffer which send data to the SSD1963 over the DMA mem-to-mem. 

To analyze the situation i made a simple main.c that initialize the SSD (OK) and then the SDRAM with a complete cycle of writing/reading and during this it seems like the /CS of the SSD never get down and all the fast data stuff that runs in the FMC Data bus are also delivered to the SSD. 

Maybe someone of you already had this problem and can help me, i've done pretty much everything but with none result, the strange behavior remains.

I'm here to answer to all your questions, and if you want to look the code i' ve posted the complete and working Coocox project. 

Thank you,

Davide Raggini 

#ssd1963-stm32f429-sdram-fmc
8 REPLIES 8
megahercas6
Senior
Posted on September 20, 2014 at 13:03

SSD1963 has on board RAM (that works just fine as frame ), why you need additional SDRAM for frame buffer?

davide
Associate II
Posted on September 20, 2014 at 13:47

Hikarpavicius.linas,

Thank you for your reply! I've seen that writing to the SDRAM is a lot more faster than write to the SSD1963 RAM, and then use DMA2 (mem-to-mem) for transfer the buffered frame without CPU use. This kind of approach will let me use, all the function of the DMA2D for creating a good looking buffered frame that can be sent to the SSD with DMA2, all with very little use of the CPU time [correct me if i'm wrong!]. Meantime i managed to correct the first problem, now i can write to the sdram and the ssd: I'm writing/reading the SDRAM with 16b function instead of 32b and no more interference. I'm able to execute this code in MAIN, and this is good:

 //24b Color -> 565 Color; color_array[i] has 137 unique 24b colors
 //build a background frame in SDRAM
 write = mySSD_ConvertColor(color_array[i]);
for(addr=0; addr < (800*480*2); addr+=2){
mySDRAM_Write16(addr, write);
}
 //Display the content of the SDRAM frame through the SSD 
uint16_t x,y = 800;
mySSD_SetPos(0,799,0,479);
addr = 0;
while(y--){
for(x=0; x<480; x++){
mySSD_Write_data(mySDRAM_Read16(addr));
addr +=2;
}
}
 //Increment the color lookup array
if(i<137){
i++;
}
else
i=0;

megahercas6
Senior
Posted on September 20, 2014 at 15:03

why not simply use normal RGB screen without any controller and use on board LTDC for screen ?

In that case you will create frame buffer inside sdram, and you will have all cool futures of TFT controller. SSD1963 is useless in this case

as example, i have all the code for HTC AMOLED screen, that can work with STM32F429

davide
Associate II
Posted on September 20, 2014 at 15:29

You are definitely right, i really don't need an SSD as a screen controller, but i have this screen assembly (CPTouch+TFT+SSD) laying around and i'd like to use it somehow. For a future project i'll go for a different solution, like you said, the HCT AMOLED is great, and i am really interested in the code if you want to share!

By now i have added the support for the DMA2_Stream0 from the SDRAM to the SSD. In the main i am calling (outside the while loop, so it's one shot) the function DMA_Write() that should stream the first 320*240 element stored in the SDRAM in to the SSD. I really don't know where i get it wrong, for simplicity i've used a polling structure, instead of an interrupt one... have any hint?

void DMA_Write()
{
DMA_InitTypeDef DMA_InitStructure;
//Set a portion of the screen screen to be written in the SSD1963
mySSD_SetPos(0,320,0,240);
//ENABLE the clock
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);
//DeInit the DMA2_Stream1 from previous transfers
DMA_DeInit(DMA2_Stream0);
while(DMA_GetCmdStatus(DMA2_Stream0) != DISABLE);
//Fill the Init structure with current parameters
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(0xD0000000); //Embedded SDRAM 
DMA_InitStructure.DMA_Memory0BaseAddr = ((uint32_t)(0x60020000)); // SSD1963
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;
DMA_InitStructure.DMA_BufferSize = (uint16_t)(320*240); //Portion of the screen
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
//Pass the structure to the Init function
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
//INTERRUPT ABILITATION
/*
DMA_ClearFlag(DMA2_Stream0, DMA_IT_TC);
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA2_Stream0, ENABLE);
*/
//Enable the DMA stream without the interrupts
DMA_Cmd(DMA2_Stream0, ENABLE);
//Wait the start of the STREAM
while(DMA_GetCmdStatus(DMA2_Stream0) == DISABLE) {
GPIO_ToggleBits(GPIOG, LED_RED);
delay_ms(100);
}
GPIOG->BSRRH = LED_RED;
//Wait the end of the STREAM
while( DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0) == RESET) {
GPIOG->BSRRL = LED_RED;
DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0);
}
GPIOG->BSRRH = LED_RED;
}

davide
Associate II
Posted on September 22, 2014 at 00:28

I managed to get the DMA work, there was a minor change in the init, and now everything is fine... i attach the code.

I was wondering if there is a way to fasten the process (obviously the next step is to use interrupts), i am sure that the way i do it now (call 6 time the DMA stream with a source address increment) isn't the smart way... have any hint?? Thank You!

void DMA_Write()
{
uint32_t start = 0xD0000000;
uint8_t i = 0;
//Set a portion of the screen screen to be written in the SSD1963
mySSD_SetPos(0,800,0,480);
//ENABLE the clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_CHANNEL;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)start;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0x60020000;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;
DMA_InitStructure.DMA_BufferSize = (uint16_t)0xFFFF;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
for(i=0; i<6; i++){
DMA_DeInit(DMA_STREAM);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)start;
DMA_Init(DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(DMA_STREAM, ENABLE);
while(DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0) == RESET);
start += 0x10000;
}
//DeInit the DMA2_Stream0 from previous transfers
DMA_Cmd(DMA_STREAM, DISABLE);
}

Posted on September 22, 2014 at 04:26

start += 0x1FFFE; // surely?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
davide
Associate II
Posted on September 22, 2014 at 15:37

This is a rapid video of my results, the whole screen in repainted with the new frame in about 100ms, this is gaving me 10fps of ''continuos'' frame rate (the actual program launch a screen redraw every 1s). 

https://www.youtube.com/watch?v=XK5_N8gDZMo

davide
Associate II
Posted on September 23, 2014 at 12:13

Hi everyone,

I managed to implement a Interrupt coding for the DMA, all is working perfectly but i am facing a loss in FPS, from 10 to 5 so the 6 chunks of Stream that compose one frame are more and more visible. Any of you know if there is a way to transfer one frame in a single stream or at least make the address increment over 16bit a little more slim (CPU speaking)? Along with the code there will be a slow-mo video of the screen refresh.

https://www.youtube.com/watch?v=BPS8Vnqf4jI

void myDMA_WriteTFT(void){
//Set a portion of the screen screen to be written in the SSD1963
mySSD_SetPos(0,799,0,479);
start=0xD0000000;
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)start;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA2_Stream0, ENABLE);
}
void DMA2_Stream0_IRQHandler(void){
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TC);
if(start<0xD00BB800){
start+=0x1F400;
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)start;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA2_Stream0, ENABLE);
}
else{
DMA_DeInit(DMA2_Stream0);
}
}
void myDMA_InitTFT(void){
//ENABLE the clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
//DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0xD0000000;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0x60020000;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;
DMA_InitStructure.DMA_BufferSize = (uint16_t)0xFA00;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
//NVIC Interrupts setup for DMA to SSD setup
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void myDMA_DisableTFT(void){
DMA_Cmd(DMA2_Stream0, DISABLE);
}