2014-09-19 02:43 PM
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-fmc2014-09-20 04:03 AM
SSD1963 has on board RAM (that works just fine as frame ), why you need additional SDRAM for frame buffer?
2014-09-20 04:47 AM
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;
2014-09-20 06:03 AM
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 STM32F4292014-09-20 06:29 AM
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;
}
2014-09-21 03:28 PM
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);
}
2014-09-21 07:26 PM
start += 0x1FFFE; // surely?
2014-09-22 06:37 AM
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).
2014-09-23 03:13 AM
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);
}