Skip to main content
PFlor.2
Senior II
November 15, 2024
Solved

STM32H563 and SPI DMA Transfer issue

  • November 15, 2024
  • 2 replies
  • 3283 views

I'm having an issue when using the DMA with SPI.  I'm using the SPI for a 320x240 LCD and want the DMA to help with blocking while transferring large amounts of data with touchGFX.

I'm able to paint the screen one color just using the SPI but when I try to use the hdmatx I can't get it to complete and hangs on waiting for the DMA state to be READY (see below)....

 

void ST7789v_Fill_Color(uint16_t color)
{
 uint16_t i;

 ST7789v_SetWindow(0, 0, ST7789_WIDTH - 1, ST7789_HEIGHT - 1);

 CS_L();

 uint32_t size = ST7789_WIDTH * ST7789_HEIGHT * 2;
 uint16_t chunk_size;
 uint16_t buffer[size/2];
 uint8_t *buf;

 memset(buffer, color, sizeof(buffer));

 if (size > 0) {
 DC_H();

 LCD_WR_REG(ST7789_CMD_RAMWR);

 while (size > 0) {
 buf = (uint8_t *)buffer;
 chunk_size = size > 8192 ? 8192 : size;

 if (DMA_MIN_SIZE <= size) {
 if (HAL_SPI_Transmit_DMA(&hspi3, buf, chunk_size ) != HAL_OK) {
 Error_Handler();
 }
 while (hspi3.hdmatx->State != HAL_DMA_STATE_READY);
 }
 else {
 if (HAL_SPI_Transmit(&hspi3, buf, chunk_size, HAL_MAX_DELAY) != HAL_OK) {
 Error_Handler();
 }
 }
 buf += chunk_size;
 size -= chunk_size;
 }
 }
 CS_H();
}

 

This code hangs at while (hspi3.hdmatx->State != HAL_DMA_STATE_READY); and the state still shows busy.

below is my SPI and DMA configuration.

 

/* SPI3 init function */
void MX_SPI3_Init(void)
{

 /* USER CODE BEGIN SPI3_Init 0 */

 /* USER CODE END SPI3_Init 0 */

 /* USER CODE BEGIN SPI3_Init 1 */

 /* USER CODE END SPI3_Init 1 */
 hspi3.Instance = SPI3;
 hspi3.Init.Mode = SPI_MODE_MASTER;
 hspi3.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
 hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
 hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
 hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
 hspi3.Init.NSS = SPI_NSS_SOFT;
 hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
 hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
 hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
 hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
 hspi3.Init.CRCPolynomial = 0x7;
 hspi3.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
 hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
 hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
 hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
 hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
 hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
 hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
 hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;
 hspi3.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
 hspi3.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
 if (HAL_SPI_Init(&hspi3) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN SPI3_Init 2 */

 /* USER CODE END SPI3_Init 2 */
}


 /* SPI3 DMA Init */
 /* GPDMA1_REQUEST_SPI3_TX Init */
 handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
 handle_GPDMA1_Channel0.Init.Request = GPDMA1_REQUEST_SPI3_TX;
 handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 handle_GPDMA1_Channel0.Init.Direction = DMA_MEMORY_TO_PERIPH;
 handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_INCREMENTED;
 handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_FIXED;
 handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel0.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT;
 handle_GPDMA1_Channel0.Init.SrcBurstLength = 1;
 handle_GPDMA1_Channel0.Init.DestBurstLength = 1;
 handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
 handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL;
 if (HAL_DMA_Init(&handle_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(spiHandle, hdmatx, handle_GPDMA1_Channel0);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }

 /* SPI3 interrupt Init */
 HAL_NVIC_SetPriority(SPI3_IRQn, 5, 0);
 HAL_NVIC_EnableIRQ(SPI3_IRQn);
 /* USER CODE BEGIN SPI3_MspInit 1 */

 /* USER CODE END SPI3_MspInit 1 */
 }

 

 Can anyone help me identify what I'm missing??

 

Thanks!

This topic has been closed for replies.
Best answer by Saket_Om

Hello @PFlor.2 

 I would like to suggest the following possible solutions:

  1. Configuring Interrupt Priorities:

Please try configuring the interrupt priorities as follows:

 

/* Enable and set SPIx Interrupt */
HAL_NVIC_SetPriority(SPIx_IRQn, 0x01, 0);
HAL_NVIC_EnableIRQ(SPIx_IRQn);

/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(GPDMA1_Channeltx_IRQn, 0x02, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channeltx_IRQn);

/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(GPDMA1_Channelrx_IRQn, 0x02, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channelrx_IRQn);

 

  1. Changing the While Loop Check:

In addition to checking the DMA state, please add a check on the SPI state to ensure that the SPI communication is complete before proceeding.

 Alos, add a check on the transmit return value of  HAL_SPI_Transmit_DMA() to ensure it is equal to HAL_OK.

 

if (HAL_SPI_Transmit_DMA(&hSPIx, ...) != HAL_OK) {
 /* Handle error */
}
while (hSPIx.hdmatx->State != HAL_DMA_STATE_READY);
while (hSPIx.State == HAL_SPI_STATE_BUSY_TX); /* wait end of transfer */

 

  1. Lowering the SPI Baud Rate:

Please try lowering the SPI baud rate to match the slave device specifications.

2 replies

ST Technical Moderator
November 20, 2024

Hello @PFlor.2 

Could you share with us the content of error flags on the DMA and SPI sides?

Additionally, did you enable the NVIC DMA interrupt?

 

 HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);

 

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
PFlor.2
PFlor.2Author
Senior II
November 20, 2024

There are no errors that occur, in the code snippet below the Error_Handler() is not reached (returns HAL_OK).  The code hangs on the while loop waiting for the DMA state to change from BUSY to READY.

 if (HAL_SPI_Transmit_DMA(&hspi3, buf, chunk_size ) != HAL_OK) {
 Error_Handler();
 }
 while (hspi3.hdmatx->State != HAL_DMA_STATE_READY);

both the SPI3 and DMA interrupts are enabled and set to priority 5, that's the lowest the .ioc allows them to be set.

 

If I just use the SPI as seen below without the DMA, data is transmitted to LCD just fine...

 if (HAL_SPI_Transmit(&hspi3, buf, chunk_size, HAL_MAX_DELAY) != HAL_OK) {
 Error_Handler();
 }

 

December 7, 2024

Hello

Was your problem solved?

PFlor.2
PFlor.2Author
Senior II
December 9, 2024

Yes, once I removed the code above and added a task to call the signalVSync() functions at the appropriate interval then the TouchGFX interface worked for single framebuffer.