2021-08-08 05:39 AM
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 */
}
}
Solved! Go to Solution.
2021-08-08 06:35 AM
That 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
2021-08-08 05:51 AM
Read out and check/post SPI and relevant DMA registers content.
JW
2021-08-08 05:58 AM
Hello Jan.
Thanks for looking into my issue.
Here is contents for SPI/DMA registers after trying to sent byte over SPI with DMA:
2021-08-08 06:35 AM
That 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
2021-08-08 07:22 AM
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:
With DMA:
Bulk 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;
}
}
2021-08-08 07:35 AM
Please ignore last post, reason of the delay is due to bytes were sent in separate TX_DMA requests in another function.
Thanks Jan!
2021-08-08 07:46 AM
OK glad you've found it.
JW