cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F405 SPI Transmit using DMA not working

dimkyy
Associate II

I have a problem transmitting a byte with SPI using DMA and asking for your help to solve this issue.

Used uC: STM32F405RGT6

Target: Display ST7789

Project generated with STM32CubeIDE

Toolchain/IDE: Keil uVision

SPI 2 used/configured as "transmit only, master".

When I'm transmitting in basic blocking mode then everything works fine (but slow):

static void ST7789_WriteCommand(uint8_t cmd)
{
   ST7789_DC_Clr();
   HAL_SPI_Transmit(&ST7789_SPI_PORT, &cmd, 1, HAL_MAX_DELAY);
   while(HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY){}
}

But nothing works when I'm trying to transmit using DMA:

static void ST7789_WriteCommand(uint8_t cmd)
{
   ST7789_DC_Clr();
   HAL_SPI_Transmit_DMA(&ST7789_SPI_PORT, &cmd, 1);
   while(HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY){}
}

Silence on the bus, checked with scope.

HAL_SPI_GetState always returns HAL_SPI_STATE_READY so program does not stuck into while loop waiting for SPI to finish transmitting.

HAL_SPI_ErrorCallback shows 0x10 (HAL_SPI_ERROR_DMA) error in SPI.

Why this happens, any clues please?

DMA 1 Initialization (before SPI init):

void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Stream4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
}

SPI 2 Initialization:

void MX_SPI2_Init(void)
{
  /* USER CODE BEGIN SPI2_Init 0 */
  /* USER CODE END SPI2_Init 0 */
  /* USER CODE BEGIN SPI2_Init 1 */
  /* USER CODE END SPI2_Init 1 */
  
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
 
  /* USER CODE BEGIN SPI2_Init 2 */
  /* USER CODE END SPI2_Init 2 */
}
 
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */
  /* USER CODE END SPI2_MspInit 0 */
   /* SPI2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
 
    /**SPI2 GPIO Configuration
    PC3     ------> SPI2_MOSI
    PB10     ------> SPI2_SCK
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* SPI2 DMA Init */
    /* SPI2_TX Init */
    hdma_spi2_tx.Instance = DMA1_Stream4;
    hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi2_tx.Init.Mode = DMA_NORMAL;
    hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;    
 
    if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi2_tx);
 
    /* SPI2 interrupt Init */
    HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SPI2_IRQn);
  /* USER CODE BEGIN SPI2_MspInit 1 */
  /* USER CODE END SPI2_MspInit 1 */
  }
}

1 ACCEPTED SOLUTION

Accepted Solutions

0693W00000D1pjkQAB.pngThat address is in CCMRAM, and in 'F4, DMA does not have access to CCMRAM. Allocate the buffer in SRAM1..3 (i.e. at addresses 0x200xxxxx).

JW

View solution in original post

6 REPLIES 6

Read out and check/post SPI and relevant DMA registers content.

JW

dimkyy
Associate II

Hello Jan.

Thanks for looking into my issue.

Here is contents for SPI/DMA registers after trying to sent byte over SPI with DMA:

0693W00000D1peVQAR.png0693W00000D1peQQAR.png

0693W00000D1pjkQAB.pngThat address is in CCMRAM, and in 'F4, DMA does not have access to CCMRAM. Allocate the buffer in SRAM1..3 (i.e. at addresses 0x200xxxxx).

JW

dimkyy
Associate II

Jan, that really helps, thanks!

However, another question arises. Why there is so big gap between bytes transmission in DMA mode comparing with basic blocking mode when sending array of data?

Please see attached scope screenshots:

Without DMA:

0693W00000D1pouQAB.pngWith DMA:

0693W00000D1pozQAB.pngBulk data sending function is implemented this way:

static void ST7789_WriteData(uint8_t *buff, size_t buff_size)
{	
	ST7789_DC_Set();
	
	while (buff_size > 0)
	{
				uint16_t chunk_size = buff_size > 65535 ? 65535 : buff_size;
					
				HAL_SPI_Transmit(&ST7789_SPI_PORT, buff, chunk_size, HAL_MAX_DELAY);
				//HAL_SPI_Transmit_DMA(&ST7789_SPI_PORT, buff, chunk_size);
 
				while(HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);
 
				buff += chunk_size;
				buff_size -= chunk_size;
	}	
}

dimkyy
Associate II

Please ignore last post, reason of the delay is due to bytes were sent in separate TX_DMA requests in another function.

Thanks Jan!

OK glad you've found it.

JW