AnsweredAssumed Answered

32F429IDISCOVERY SPI over DMA driven LCD

Question asked by machala.petr on Mar 15, 2015
Latest reply on Mar 17, 2015 by machala.petr
Hi,

I am struggling with implementation of SPI transfer with DMA. I have an application where I use DMA2 for transfering data from DCMI to SDRAM. Then because of LCD of the discovery board I need to rearrange the data to smooth travsfer over SPI. If I send the values to the LCD manually in a loop then everything is fine but when I try to use DMA1 (I use SPI2, I made a HW change) the LCD shows only 1/4 of the display. Bacically the DMA transfer stops after 1/4 of the data and I dont know why...Thanks very much for your help...

This is used for DCMI to SDRAM over DMA:
     // DMA config
     DMA_Cmd(DMA2_Stream1, DISABLE);
    DMA_DeInit(DMA2_Stream1);
     DMA_InitStructure.DMA_Channel = DMA_Channel_1;
    DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS;
    DMA_InitStructure.DMA_Memory0BaseAddr = SDRAM_START_ADR;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = IMG_ROWS*IMG_COLUMNS*BYTES_PER_PX/4;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    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;
    DMA_Init(DMA2_Stream1, &DMA_InitStructure);
     DMA_Cmd(DMA2_Stream1, ENABLE);

Then the SPI inicialization: 
void LCD_SPI_DMA_Init(void) {
     GPIO_InitTypeDef GPIO_InitStruct;
     SPI_InitTypeDef SPI_InitStruct;
     DMA_InitTypeDef  DMA_InitStructure;
     NVIC_InitTypeDef NVIC_InitStructure;

     //Common settings for all pins
     GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
     GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;

     //Enable clock
     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
     //Pinspack nr. 1             MOSI
     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
     GPIO_Init(GPIOC, &GPIO_InitStruct);
     //                           SCK
     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
     GPIO_Init(GPIOB, &GPIO_InitStruct);

     GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_SPI2);
     GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_SPI2);

     RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

     SPI_StructInit(&SPI_InitStruct);
     SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
     SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
     SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
     SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
     SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
     SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
     SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
     SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
     SPI_Init(SPI2, &SPI_InitStruct);

     //Enable clock
     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

     // DMA config
     DMA_Cmd(DMA1_Stream4, DISABLE);
    DMA_DeInit(DMA1_Stream4);
     DMA_InitStructure.DMA_Channel = DMA_Channel_0;
     DMA_InitStructure.DMA_Memory0BaseAddr = SDRAM_START_ADR2;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(ILI9341_SPI->DR);
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_BufferSize =  IMG_ROWS*IMG_COLUMNS*BYTES_PER_PX/4;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
    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_Init(DMA1_Stream4, &DMA_InitStructure);

     // DMA interrupt
     DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
     NVIC_Init(&NVIC_InitStructure);

     SPI_Cmd(SPI2, ENABLE);
     SPI_I2S_DMACmd(ILI9341_SPI, SPI_I2S_DMAReq_Tx, ENABLE);
}

And this works fine (manual approach):
void LCD_ILI9341_DisplayImage(void) {
     uint8_t i,j;
     uint32_t buffer, n;
     uint32_t *image = (uint32_t*) SDRAM_START_ADR;

     LCD_ILI9341_SetCursorPosition(0, 0, ILI9341_Opts.width - 1, ILI9341_Opts.height - 1);

     LCD_ILI9341_SendCommand(ILI9341_GRAM);

     ILI9341_WRX_SET;
     ILI9341_CS_RESET;

     for (n = 0; n < (IMG_ROWS*IMG_COLUMNS)/2; n++) {
        buffer = image[n];

        i = buffer >> 8;
          j = buffer & 0xFF;

          LCD_SPI_Send(ILI9341_SPI, i);
          LCD_SPI_Send(ILI9341_SPI, j);

          i = buffer >> 24;
          j = buffer >> 16;

          LCD_SPI_Send(ILI9341_SPI, i);
          LCD_SPI_Send(ILI9341_SPI, j);
     }

     ILI9341_CS_SET;
}

But this like I said only shows a 1/4 of the image:
if( frame_flag == true){
              uint32_t n,i,buffer;
            uint8_t j,k;
            uint32_t *image = (uint32_t*) SDRAM_START_ADR;
            uint32_t *image2 = (uint32_t*) SDRAM_START_ADR2;

            // Modify image
            i=0;
            for (n = 0; n < (IMG_ROWS*IMG_COLUMNS)/2; n++) {
                buffer = image[n];

                j = buffer >> 8;
                k = buffer & 0xFF;

                image2[i] = j;
                i++;
                image2[i] = k;
                i++;

                j = buffer >> 24;
                k = buffer >> 16;

                image2[i] = j;
                i++;
                image2[i] = k;
                i++;
            }

            // Prepare LCD for image
            LCD_ILI9341_Rotate(LCD_ILI9341_Orientation_Landscape_2);
            LCD_ILI9341_SetCursorPosition(0, 0, ILI9341_Options.width - 1, ILI9341_Options.height - 1);

            LCD_ILI9341_SendCommand(ILI9341_GRAM);

            // SPI send
            ILI9341_WRX_SET;
            ILI9341_CS_RESET;

            DMA_Cmd(DMA2_Stream1, DISABLE);
            DMA_Cmd(DMA1_Stream4, ENABLE);

               frame_flag = false;
          }

void DMA2_Stream1_IRQHandler(void){
     // DMA_DCMI complete
     if(DMA_GetITStatus(DMA2_Stream1,DMA_IT_TCIF1) != RESET){
          DMA_ClearITPendingBit(DMA2_Stream1,DMA_IT_TCIF1);


        frame_flag = true;
     }
}

void DMA1_Stream4_IRQHandler(void){
     // DMA_SPI complete
     if(DMA_GetITStatus(DMA1_Stream4,DMA_IT_TCIF4) != RESET){
          DMA_ClearITPendingBit(DMA1_Stream4,DMA_IT_TCIF4);


        while (SPI_I2S_GetFlagStatus(ILI9341_SPI, SPI_I2S_FLAG_BSY) == SET);


          ILI9341_CS_SET;
          DMA_Cmd(DMA1_Stream4, DISABLE);
          DMA_Cmd(DMA2_Stream1, ENABLE);
     }
}

Outcomes