AnsweredAssumed Answered

STM32F429I-DISCO LCD + SPI DMA

Question asked by soroka.andrey on Feb 4, 2016
Latest reply on Feb 6, 2016 by soroka.andrey
How to use DMA with SPI? Im trying to send image from SDRAM via SPI to LCD on STM32F429i-disco board:

void LCD_ILI9341_SendImageFrame(uint8_t* data) {
    ILI9341_WRX_SET;
    ILI9341_CS_RESET;
    HAL_SPI_Transmit_DMA(&lcd_spi, data, (uint16_t)320*240*2);
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    lcd_refreshed = true;
    ILI9341_CS_SET;
}

...

while (1)
{
    if(lcd_refreshed == true)
    {
        LCD_ILI9341_SendImageFrame((uint8_t*)SDRAM_BANK_ADDR);
        lcd_refreshed = false;
    }
}

It displays part of the data (~ 1/6) and then triggers FIFO error in HAL_DMA_IRQHandler function:

/* FIFO Error Interrupt management ******************************************/
  if ((regs->ISR & (DMA_FLAG_FEIF0_4 << hdma->StreamIndex)) != RESET)
  {
    if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_FE) != RESET)
    {
      /* Disable the FIFO Error interrupt */
      __HAL_DMA_DISABLE_IT(hdma, DMA_IT_FE);

      /* Clear the FIFO error flag */
      regs->IFCR = DMA_FLAG_FEIF0_4 << hdma->StreamIndex;

      /* Update error code */
      hdma->ErrorCode |= HAL_DMA_ERROR_FE;

      /* Change the DMA state */
      hdma->State = HAL_DMA_STATE_ERROR;

      /* Process Unlocked */
      __HAL_UNLOCK(hdma);

      if(hdma->XferErrorCallback != NULL)
      {
        /* Transfer error callback */
        hdma->XferErrorCallback(hdma);
      }
    }
  }

If I change transmit dma size to less than 65530, it displays whole size, but still triggers FIFO error.

Its all ok without using DMA:

void LCD_ILI9341_SendImageFrame(uint8_t* data) {
    ILI9341_WRX_SET;
    ILI9341_CS_RESET;
    HAL_SPI_Transmit(&lcd_spi, data, ILI9341_SPI_IMAGE_BLOCK, 5000);
    ILI9341_CS_SET;
}

P.S.

It does not depend on the value of hdma_spi5_tx.Init.FIFOMode, disabled fifo still triggers error. SPI DMA initialization function:

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(hspi->Instance==SPI5)
  {
  /* USER CODE BEGIN SPI5_MspInit 0 */

  /* USER CODE END SPI5_MspInit 0 */
    /* Peripheral clock enable */
    __SPI5_CLK_ENABLE();
 
    /**SPI5 GPIO Configuration    
    PF7     ------> SPI5_SCK
    PF8     ------> SPI5_MISO
    PF9     ------> SPI5_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI5;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

    /* Peripheral DMA init*/
 
    hdma_spi5_tx.Instance = DMA2_Stream4;
    hdma_spi5_tx.Init.Channel = DMA_CHANNEL_2;
    hdma_spi5_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi5_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi5_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi5_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi5_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi5_tx.Init.Mode = DMA_NORMAL;
    hdma_spi5_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
    hdma_spi5_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_spi5_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_spi5_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_spi5_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&hdma_spi5_tx);

    __HAL_LINKDMA(hspi,hdmatx,hdma_spi5_tx);

  /* USER CODE BEGIN SPI5_MspInit 1 */

  /* USER CODE END SPI5_MspInit 1 */
  }

}

Outcomes