AnsweredAssumed Answered

SSD1963 and DMA with FMC

Question asked by raggini.davide on May 10, 2015
Latest reply on May 23, 2015 by jj.sprague

Hi everyone,

i’m working on stm32f429-discovery and a 7” tft over ssd1963 in 565 color (BuyDisplay ER-TFTM070-4V2.1 + CPTouch), Coocox IDE. 

So far i’ve included a rich set of drivers for the on-board peripheral with no problem, but, right now, i’m facing a problem that i think i can’t solve by my own.. and maybe some of you can help.

“Manual” transfer from the embed 64Mb SDRAM to the SSD1963 over the FMC works great, no problem at all, i can show pretty much anything (text, bmp images from 16gb sdcard, and so on).


-The problem: 

When I transfer the frame with DMA, i get it all messed up ONLY if the frame contains colours near the absolute BLACK or the absolute WHITE (this problem doesn’t exists over “Manual” transfer).

The only way it works is if the darkest black is over 0x0C0C0C -> 0x0861 (in 565 format) and the brightest white is under 0xF0F0F0 -> 0xF79E (in 565 format).

When i put a colour outside this safe band, the DMA stream locks or mess all things up (garbage frame is displayed).


Just for saying: Right now the DMA is working very good with interrupts (nearly 60ms for every repaint) but only if the colours that i put in the frame are inside the safe band.


-These are the two function i use to read and write the SDRAM when composing the frame,
     are read pixel and write pixel low level.

                                   
                                                                        

#define SDRAM_START_ADR               (uint32_t)0xD0000000

           


           

           

void mySDRAM_Write16(uint32_t address, uint16_t value)

           

{

           

     *(uint16_t*) (SDRAM_START_ADR + address) = value;

           

}

           


           

           

uint16_t mySDRAM_Read16(uint32_t address)

           

{

           

     return *(uint16_t*)(SDRAM_START_ADR + address);

           

}

           

           
           



-This is the FMC init code for the SDRAM.

                                   
                                                                        

uint8_t myFMC_SDRAM_Init(void) {

           

     FMC_SDRAMInitTypeDef FMC_SDRAMInitDef;

           

     FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitDef;

           

     FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure;

           

     uint32_t timeout = SDRAM_TIMEOUT;

           


           

           

     /* Initialize FMC pins */

           

     mySDRAM_InitPins();

           


           

           

     /* Enable FMC clock */

           

     RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);

           


           

           

     /* FMC SDRAM device initialization sequence --------------------------------*/

           

     /* Step 1 ----------------------------------------------------*/

           

     /* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */

           

     /* TMRD: 2 Clock cycles */

           

     /* 1 clock cycle = 1 / 90MHz = 11.1ns */

           

     FMC_SDRAMTimingInitDef.FMC_LoadToActiveDelay         2;  //2

           

     /* TXSR: min=70ns (7x11.10ns) */

           

     FMC_SDRAMTimingInitDef.FMC_ExitSelfRefreshDelay      7;  //7

           

     /* TRAS: min=42ns (4x11.10ns) max=120k (ns) */

           

     FMC_SDRAMTimingInitDef.FMC_SelfRefreshTime                4;  //4

           

     /* TRC:  min=70 (7x11.10ns) */

           

     FMC_SDRAMTimingInitDef.FMC_RowCycleDelay             7;  //7

           

     /* TWR:  min=1+ 7ns (1+1x11.10ns) */

           

     FMC_SDRAMTimingInitDef.FMC_WriteRecoveryTime         2;  //2

           

     /* TRP:  20ns => 2x11.10ns */

           

     FMC_SDRAMTimingInitDef.FMC_RPDelay                        2;  //2

           

     /* TRCD: 20ns => 2x11.10ns */

           

     FMC_SDRAMTimingInitDef.FMC_RCDDelay                       2;  //2

           


           

           


           

           

     /* FMC SDRAM control configuration */

           

     FMC_SDRAMInitDef.FMC_Bank                               = FMC_Bank2_SDRAM;

           

     /* Row addressing: [7:0] */

           

     FMC_SDRAMInitDef.FMC_ColumnBitsNumber                = FMC_ColumnBits_Number_8b;

           

     /* Column addressing: [11:0] */

           

     FMC_SDRAMInitDef.FMC_RowBitsNumber                     = FMC_RowBits_Number_12b;

           

     FMC_SDRAMInitDef.FMC_SDMemoryDataWidth           = FMC_SDMemory_Width_16b;

           

     FMC_SDRAMInitDef.FMC_InternalBankNumber                = FMC_InternalBank_Number_4;

           

     /* CL: Cas Latency = 3 clock cycles */

           

     FMC_SDRAMInitDef.FMC_CASLatency                     = FMC_CAS_Latency_3;

           

     FMC_SDRAMInitDef.FMC_WriteProtection                     = FMC_Write_Protection_Disable;

           

     FMC_SDRAMInitDef.FMC_SDClockPeriod                     = FMC_SDClock_Period_2;

           

     FMC_SDRAMInitDef.FMC_ReadBurst                          = FMC_Read_Burst_Disable;

           

     FMC_SDRAMInitDef.FMC_ReadPipeDelay                     = FMC_ReadPipe_Delay_1;

           

     FMC_SDRAMInitDef.FMC_SDRAMTimingStruct                = &FMC_SDRAMTimingInitDef;

           

     /* FMC SDRAM bank initialization */

           

     FMC_SDRAMInit(&FMC_SDRAMInitDef);

           


           

           

     /* Configure a clock configuration enable command */

           

     FMC_SDRAMCommandStructure.FMC_CommandMode               = FMC_Command_Mode_CLK_Enabled;

           

     FMC_SDRAMCommandStructure.FMC_CommandTarget                = FMC_Command_Target_bank2;

           

     FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber           1;

           

     FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition           0;

           


           

           

     /* Wait until the SDRAM controller is ready */

           

     timeout = SDRAM_TIMEOUT;

           

     while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET && timeout--);

           

     /* Send the command */

           

     FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

           


           

           

     //delay_us(10);

           


           

           

     /* Configure a PALL (precharge all) command */

           

     FMC_SDRAMCommandStructure.FMC_CommandMode            = FMC_Command_Mode_PALL;

           

     FMC_SDRAMCommandStructure.FMC_CommandTarget          = FMC_Command_Target_bank2;

           

     FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber      = 1;

           

     FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;

           


           

           

     /* Wait until the SDRAM controller is ready */

           

     timeout = SDRAM_TIMEOUT;

           

     while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) && timeout--);

           

     /* Send the command */

           

     FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

           


           

           

     /* Configure a Auto-Refresh command */

           

     FMC_SDRAMCommandStructure.FMC_CommandMode            = FMC_Command_Mode_AutoRefresh;

           

     FMC_SDRAMCommandStructure.FMC_CommandTarget          = FMC_Command_Target_bank2;

           

     FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber      = 8;

           

     FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;

           


           

           

     /* Wait until the SDRAM controller is ready */

           

     timeout = SDRAM_TIMEOUT;

           

     while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) && timeout--);

           

     /* Send the command */

           

     FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

           


           

           

     /* Configure a load Mode register command */

           

     FMC_SDRAMCommandStructure.FMC_CommandMode            = FMC_Command_Mode_LoadMode;

           

     FMC_SDRAMCommandStructure.FMC_CommandTarget          = FMC_Command_Target_bank2;

           

     FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber      = 1;

           

     FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0x0231;

           


           

           

     /* Wait until the SDRAM controller is ready */

           

     timeout = SDRAM_TIMEOUT;

           

     while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) && timeout--);

           

     /* Send the command */

           

     FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

           


           

           

     /* Set the refresh rate counter */

           

     /* (7.81 us x Freq) - 20 = (7.81 * 90MHz) - 20 = 683 */

           

     /* Set the device refresh counter */

           

     FMC_SetRefreshCount(680);

           


           

           

     /* Wait until the SDRAM controller is ready */

           

     timeout = SDRAM_TIMEOUT;

           

     while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET && timeout--);

           


           

           

     /* Check if everything goes right */

           

     /* Write 0x10 at location 0x50 and check if result is the same on read operation */

           

     mySDRAM_Write16(0x500x10);

           

     if (mySDRAM_Read16(0x50) == 0x10) {

           

          //Initialized OK

           

          return 1;

           

     }

           

     //Not OK

           

     return 0;

           

}

           


-This is the FMC init code for the SSD1963, only the fast one (a slower one is used for init the SSD1963 registers).
     At the end i've placed the two functions i use to write data and commands to the driver.
The address is 0x60000000 if we have commands, and 0x60020000 for data.
This is because DATA/COMMAND is connected to this pin on the address line ( CAN THIS BE A PROBLEM?)

                                   
           

uint8_t myFMC_SSD_FAST_Init(void){

           

     FMC_NORSRAMInitTypeDef  FMC_NORSRAMInitDef;

           

     FMC_NORSRAMTimingInitTypeDef  FMC_NORSRAMTimingInitDef_Write, FMC_NORSRAMTimingInitDef_Read;

           


           

           

     /* Enable FMC clock */

           

     RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);

           


           

           

     /* FMC SSD1963 as a NORSRAM device initialization sequence ---*/

           

     /* Step 1 ----------------------------------------------------------*/

           

     /* Timing configuration for 84 Mhz of SD clock frequency (168Mhz/2) */

           

     FMC_NORSRAMTimingInitDef_Write.FMC_AddressSetupTime               0x02;      //0x0F

           

     FMC_NORSRAMTimingInitDef_Write.FMC_AddressHoldTime               0x00;

           

     FMC_NORSRAMTimingInitDef_Write.FMC_DataSetupTime                    0x02;      //0x0F

           

     FMC_NORSRAMTimingInitDef_Write.FMC_BusTurnAroundDuration            0x00;

           

     FMC_NORSRAMTimingInitDef_Write.FMC_CLKDivision                        0x00;  //0x01

           

     FMC_NORSRAMTimingInitDef_Write.FMC_DataLatency                          0x00;

           

     FMC_NORSRAMTimingInitDef_Write.FMC_AccessMode                       = FMC_AccessMode_A;

           


           

           

     /* Timing configuration for 84 Mhz of SD clock frequency (168Mhz/2) */

           

     FMC_NORSRAMTimingInitDef_Read.FMC_AddressSetupTime               0x02;  //0x0A

           

     FMC_NORSRAMTimingInitDef_Read.FMC_AddressHoldTime               0x00;

           

     FMC_NORSRAMTimingInitDef_Read.FMC_DataSetupTime               0x02;      //0x0A

           

     FMC_NORSRAMTimingInitDef_Read.FMC_BusTurnAroundDuration           0x00;

           

     FMC_NORSRAMTimingInitDef_Read.FMC_CLKDivision                        0x00;  //0x01

           

     FMC_NORSRAMTimingInitDef_Read.FMC_DataLatency                          0x00;

           

     FMC_NORSRAMTimingInitDef_Read.FMC_AccessMode                           = FMC_AccessMode_A;

           


           

           

     /* FMC SDRAM control configuration */

           

     FMC_NORSRAMInitDef.FMC_Bank                               = FMC_Bank1_NORSRAM1;

           

    FMC_NORSRAMInitDef.FMC_DataAddressMux                     = FMC_DataAddressMux_Disable;

           

     FMC_NORSRAMInitDef.FMC_MemoryType                          = FMC_MemoryType_SRAM;

           

     FMC_NORSRAMInitDef.FMC_MemoryDataWidth                = FMC_NORSRAM_MemoryDataWidth_16b;

           

     FMC_NORSRAMInitDef.FMC_BurstAccessMode                     = FMC_BurstAccessMode_Disable;

           

     FMC_NORSRAMInitDef.FMC_AsynchronousWait                = FMC_AsynchronousWait_Disable;

           

     FMC_NORSRAMInitDef.FMC_WaitSignalPolarity                     = FMC_WaitSignalPolarity_Low;

           

     FMC_NORSRAMInitDef.FMC_WrapMode                          = FMC_WrapMode_Disable;

           

     FMC_NORSRAMInitDef.FMC_WaitSignalActive                     = FMC_WaitSignalActive_BeforeWaitState;

           

     FMC_NORSRAMInitDef.FMC_WriteOperation                     = FMC_WriteOperation_Enable;

           

     FMC_NORSRAMInitDef.FMC_WaitSignal                              = FMC_WaitSignal_Disable;

           

     FMC_NORSRAMInitDef.FMC_ExtendedMode                     = FMC_ExtendedMode_Disable;

           

     FMC_NORSRAMInitDef.FMC_WriteBurst                          = FMC_WriteBurst_Disable;

           

     FMC_NORSRAMInitDef.FMC_ContinousClock                     = FMC_CClock_SyncOnly;  //FMC_CClock_SyncAsync

           

     FMC_NORSRAMInitDef.FMC_ReadWriteTimingStruct               = &FMC_NORSRAMTimingInitDef_Read;

           

     FMC_NORSRAMInitDef.FMC_WriteTimingStruct                    = &FMC_NORSRAMTimingInitDef_Write;

           

     /* DISABLING THE NORSRAM BANK WHILE CHANGING SPEED */

           

     FMC_NORSRAMCmd(FMC_Bank1_NORSRAM1, DISABLE);

           

     /* FMC NORSRAM bank initialization */

           

     FMC_NORSRAMInit(&FMC_NORSRAMInitDef);

           

     /* FMC NORSRAM bank enable */

           

     FMC_NORSRAMCmd(FMC_Bank1_NORSRAM1, ENABLE);

           


           

           

     return 1;

           

}

           


           

           

void mySSD_Write_cmd(uint16_t value) {

           

     *(uint16_t*) (0x60000000) = value;

           

}

           


           

           

void mySSD_Write_data(uint16_t value) {

           

     *(uint16_t*) (0x60020000) = value;

           

}

             


-This is the function I use for "Manual" write the frame from the SDRAM to the SSD.
     The last two functions are for a better understanding of what is what.

                                   
           

void mySSD_fromSDRAM(void){

           

     uint32_t i=0;

           

     uint32_t k=0;

           

     uint32_t j=0;

           

     for(j=0; j<(800*480*2);j+=2){

           

          if(i>799){

           

               i=0;//x

           

                       k++;

           

              }

           

              mySSD_WritePixel(i,k, mySDRAM_Read16(j) );

           

              i++;

           

     }     

           

}

             
           
           

void mySSD_WritePixel(uint32_t x, uint32_t y, uint16_t color){

           

     mySSD_SetPos(x,x,y,y);

           

        mySSD_Write_data(color);

           

}

           
           
           

void mySSD_SetPos(uint16_t xs, uint16_t xe, uint16_t ys, uint16_t ye){

           

     //SET ROWS ADDRESS

           

     mySSD_Write_cmd(0x2A);

           

     mySSD_Write_data((xs>>8)&0x00FF);          //Highest byte SC

           

     mySSD_Write_data(xs & 0x00FF);          //Lowest byte SC, Start Column

           

     mySSD_Write_data((xe>>8)&0x00FF);          //Highest byte EC

           

     mySSD_Write_data(xe & 0x00FF);          //Lowest byte EC, End Column

           

     //SET COLUMN ADDRESS

           

     mySSD_Write_cmd(0x2B);

           

     mySSD_Write_data((ys>>8)&0x00FF);          //Highest byte SP

           

     mySSD_Write_data(ys & 0x00FF);          //Lowest byte SP, Start Page

           

     mySSD_Write_data((ye>>8)&0x00FF);          //Highest byte EP

           

     mySSD_Write_data(ye & 0x00FF);          //Lowest byte EP, End Page

           

     //WRITE MEMORY START

           

     mySSD_Write_cmd(0x2C);

           

}

           
           


-This last chunk of code is the one i think is causing all the problems i have,
the DMA frame transfer & setup, i really appreciate if someone look into it, 
because i'm out of luck with him working in the good way.


                                   
                                                                        

void myDMA_InitTFT(){

           

     //ENABLE the clock

           

     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

           


           

           

     //Set up the interrupts

           

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

           


           

           

     NVIC_InitStruct.NVIC_IRQChannel                     = DMA2_Stream0_IRQn;

           

     NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE;

           

        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority      0;

           

        NVIC_InitStruct.NVIC_IRQChannelSubPriority           0;

           

        NVIC_Init(&NVIC_InitStruct);

           


           

           

    //Come back to default configuration for the DMA2_Stream0

           

     DMA_DeInit(DMA2_Stream0);

           


           

           

     //Set up the DMA_InitStructur to take care of the frame transfer

           

     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;             //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;

           


           

           

     DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);

           


           

           

     DMA_Init(DMA2_Stream0, &DMA_InitStructure);

           


           

           

}

           


           

           

void myDMA_WriteTFT(){

           

     if(DMA_BUSY_FLAG!=0x00){

           

          //Do nothing, the bus is BUSY, in order to prevent undesired

           

          //lock of the system we simply skip the display redraw

           

          //return;

           

     }

           

     else{

           

          myDMA_InitTFT();

           


           

           

          DMA_BUSY_FLAG=0xFF;

           

          //Start the writing sequence again
                      //Set a portion of the screen screen to be written in the SSD1963
           

           

          mySSD_SetPos(0,799,0,479);

           

          start=0xD0000000;

           

          DMA_InitStructure.DMA_PeripheralBaseAddr      = (uint32_t)start;

           

          DMA_Init(DMA2_Stream0, &DMA_InitStructure);

           

          DMA_Cmd(DMA2_Stream0, ENABLE);

           

     }

           

}

           


           

           

void DMA2_Stream0_IRQHandler(void) {

           


           

           

     if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))

           

       {

           

          DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

           

          start+=0xFA00*2;

           

          if(start<0xD00BB800){

           

               DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)start;

           

               DMA_Init(DMA2_Stream0, &DMA_InitStructure);

           

               DMA_Cmd(DMA2_Stream0, ENABLE);

           

          }

           

          else {

           

               DMA_BUSY_FLAG = 0x00;

           

          }

           

       }

           

}

           


           

           

void myDMA_DisableTFT(){

           

     DMA_Cmd(DMA2_Stream0, DISABLE);

           

}

           

           
           

Thank you again, and sorry for the long post, the really problematic part here is only the DMA settings, I think...
I hope that someone will find this code of helpful too.
I've read so much about that topic but i was not able to find a complete solution.

Davide

Outcomes