0
votes

I am currently learning STM32F1xx using DMA and SPI with circular mode. My goal is let the STM32F1 to send out same data repeatedly.

I am using cubeMX generated code, setting up the SPI-DMA with circular mode and using HAL_SPI_Transmit_DMA() to activate DMA transmission.

I have a data buffer like here:

char dataBuf[10] = {'a','b','c','d','e','f','g','h','i','j'};

When I use HAL_SPI_Transmit_DMA(&hspi1,dataBuf,10); it works fine. STM32F1 send the characters repeatedly through SPI and I can use HAL_SPI_DMAStop(&hspi1); to stop it.

But If I want just to send 5 byte of dataBuf repeatedly, using HAL_SPI_Transmit_DMA(&hspi1,dataBuf,5), the STM32 can not react on that. It just hanged somewhere and doing nothing.

I am wondering why this is happening. Does the data amount need to be the same as the declared buffer array size (actually, this makes no sense for me)? How can I use circular mode to send desired data amount?

Update1

I should have to attach my SPI and DMA setting, here they are.

SPI setting:

/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
  _Error_Handler(__FILE__, __LINE__);
}

DMA setting:

hdma_spi1_tx.Instance = DMA1_Channel3;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_CIRCULAR;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
{
  _Error_Handler(__FILE__, __LINE__);
}

Update2

This is my test setup with code:

char spiDataBuf[10] = {'a','b','c','d','e','f','g','h','i','j'};
uint8_t runSPI = 0;

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  //HAL_Delay(500);
  if(HAL_GetTick()-lastTick > 1)
  {
      //calColor2Data(&statusColor, 1);
      //updateWs2812();
      if(runSPI)
      {
          HAL_SPI_Transmit_DMA(&hspi1,spiDataBuf,5); 
          // or HAL_SPI_Transmit_DMA(&hspi1,spiDataBuf,10);
          runSPI = 0;
      }
      else
      {
          runSPI = 1;
          HAL_SPI_DMAStop(&hspi1);
      }

      lastTick = HAL_GetTick();
  }



/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}

And logic output: When I set 10 bytes to send, it works fine, STM32 send a.b.c... repeatedly and make pause as intended. Logic capture please see follow images.

Send 10 bytes - Overview

Send 10 bytes - result

But When I send 5 bytes, it seems like that it can not be stopped..Logic capture please see follow images.

Send 5 bytes - Overview, can not be stopped

Send 5 bytes - result, but it did send 5 byte repeatedly

My question remains, why the DMA can not be stopped when I set 5 bytes to send?

I did test other number of bytes. 10, 9, 8 bytes work. But 7, 6, 5, 4, 3 ,2 ,1 bytes don't work. SPI DMA is those cases can not be stopped.

If more information needs to be provided, please let me know.

Thanks.

Best regards.

2

2 Answers

0
votes

Check your data sizes. The DMA and SPI works in 8bit/16/bit or 32bit mode. My guess is that your SPI is expecting 16bits for each transmission (or set in 16bit mode). Then, the 5th byte which your DMA sends doesn't fill the SPI's TX buffer. This means the SPI won't transmit the 16bits (as it is waiting for another byte), which means the TXE flag won't be set, which means it won't request the next byte from the DMA.

The fix: Set the SPI to 8bit mode.

0
votes

Just got the same issue. Debugging show that it skips HAL_SPI_TxCpltCallback, but still rising HAL_SPI_TxHalfCpltCallback. Lowering the speed of SPI worked for me. hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;