Skip to main content
akosodry
Associate III
January 17, 2019
Question

stm32h7 i2s dma transfer issue

  • January 17, 2019
  • 13 replies
  • 5591 views

Hello STM32 Community!

My I2S dma transfer worked perfectly on stm32f7x in the past, but due to time critical calculations i just started to continue the development on the advanced stm32h7 system.

I use the same code, same initialization procedure and same HAL function calls (as i did on stm32f7) but the H7 stops executing the code after the HAL_I2S_Transmit_DMA function call.

I am aware that the peripheral bus can't access ITCM and DTCM, therefore i placed all memory to D1 domain, as it is written here (https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices, e.g., IRAM2 0x24000000 0x80000)

Did anyone successfully use the I2S peripheral with DMA on H7 system?

Here is the code for the clock setup i use:

PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART3|RCC_PERIPHCLK_USART1
 |RCC_PERIPHCLK_SPI3;
 PeriphClkInitStruct.PLL2.PLL2M = 8;
 PeriphClkInitStruct.PLL2.PLL2N = 192;
 PeriphClkInitStruct.PLL2.PLL2P = 2;
 PeriphClkInitStruct.PLL2.PLL2Q = 2;
 PeriphClkInitStruct.PLL2.PLL2R = 2;
 PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_1;
 PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
 PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
 PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL2;
 PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
 PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
 {
 Error_Handler();
 }
 HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_PLL2PCLK, RCC_MCODIV_5);

The following is the code for the I2S3 initialization:

static void MX_I2S3_Init(void)
{
 
 /* USER CODE BEGIN I2S3_Init 0 */
 
 /* USER CODE END I2S3_Init 0 */
 
 /* USER CODE BEGIN I2S3_Init 1 */
 
 /* USER CODE END I2S3_Init 1 */
 hi2s3.Instance = SPI3;
 hi2s3.Init.Mode = I2S_MODE_MASTER_TX;
 hi2s3.Init.Standard = I2S_STANDARD_PHILIPS;
 hi2s3.Init.DataFormat = I2S_DATAFORMAT_32B;
 hi2s3.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
 hi2s3.Init.AudioFreq = I2S_AUDIOFREQ_48K;
 hi2s3.Init.CPOL = I2S_CPOL_LOW;
 hi2s3.Init.FirstBit = I2S_FIRSTBIT_MSB;
 hi2s3.Init.WSInversion = I2S_WS_INVERSION_DISABLE;
 hi2s3.Init.IOSwap = I2S_IO_SWAP_DISABLE;
 hi2s3.Init.Data24BitAlignment = I2S_DATA_24BIT_ALIGNMENT_RIGHT;
 hi2s3.Init.FifoThreshold = I2S_FIFO_THRESHOLD_01DATA;
 hi2s3.Init.MasterKeepIOState = I2S_MASTER_KEEP_IO_STATE_DISABLE;
 hi2s3.Init.SlaveExtendFREDetection = I2S_SLAVE_EXTEND_FRE_DETECTION_DISABLE;
 if (HAL_I2S_Init(&hi2s3) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN I2S3_Init 2 */
 
 /* USER CODE END I2S3_Init 2 */
 
}

And this is the MSP initialization:

if(hi2s->Instance==SPI3)
 {
 /* USER CODE BEGIN SPI3_MspInit 0 */
 
 /* USER CODE END SPI3_MspInit 0 */
 /* Peripheral clock enable */
 __HAL_RCC_SPI3_CLK_ENABLE();
 
 __HAL_RCC_GPIOA_CLK_ENABLE();
 __HAL_RCC_GPIOC_CLK_ENABLE();
 /**I2S3 GPIO Configuration 
 PA15 (JTDI) ------> I2S3_WS
 PC10 ------> I2S3_CK
 PC12 ------> I2S3_SDO 
 */
 GPIO_InitStruct.Pin = GPIO_PIN_15;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
 GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
 /* I2S3 DMA Init */
 /* SPI3_TX Init */
 hdma_spi3_tx.Instance = DMA1_Stream5;
 hdma_spi3_tx.Init.Request = DMA_REQUEST_SPI3_TX;
 hdma_spi3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
 hdma_spi3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_spi3_tx.Init.MemInc = DMA_MINC_ENABLE;
 hdma_spi3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
 hdma_spi3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
 hdma_spi3_tx.Init.Mode = DMA_CIRCULAR;
 hdma_spi3_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
 hdma_spi3_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
 if (HAL_DMA_Init(&hdma_spi3_tx) != HAL_OK)
 {
 Error_Handler();
 }
 
 __HAL_LINKDMA(hi2s,hdmatx,hdma_spi3_tx);
 
 /* I2S3 interrupt Init */
 HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(SPI3_IRQn);
 /* USER CODE BEGIN SPI3_MspInit 1 */
 
 /* USER CODE END SPI3_MspInit 1 */
 }

Everything works until i call the transmit function

HAL_I2S_Transmit_DMA(&hi2s3, (uint16_t*) signalTable, (uint16_t) SIGNAL_TABLE_SIZE/2);

I generated the initialization code with the latest CubeMX and STM32Cube_FW_H7_V1.3.0.

Thank you for the reply in advance

This topic has been closed for replies.

13 replies

WMinH
Visitor II
January 28, 2019

I'm having the same issue... did you solved the problem?

akosodry
akosodryAuthor
Associate III
January 28, 2019

no, unfortunately i did not.

i should have dig myself into the debugging of the hal api for which i did not have time.

i am waiting for the STM32Cube_FW_H7 1.4.....

TChat
Visitor II
February 4, 2019

Hi, same issue here... Found any solution ?

Thanks!

HHuyn.19
Visitor II
April 16, 2019

Fix HAL Lib.

In stm32h7_hal_i2s.c replace function "HAL_I2S_Transmit_DMA(...)" by below.

Today, i had the same issue. And I solved it. STM32H7xx_HAL_... maybe update lib to fix this issue.

I hope useful to anyone got this issue.

HAL_StatusTypeDef HAL_I2S_Transmit_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
 /* Check Mode parameter */
 assert_param(IS_I2S_TX_MODE(hi2s->Init.Mode));
 
 if((pData == NULL) || (Size == 0U))
 {
 return HAL_ERROR;
 }
 
 /* Process Locked */
 __HAL_LOCK(hi2s);
 
 if(hi2s->State == HAL_I2S_STATE_READY)
 {
 hi2s->pTxBuffPtr = pData;
 hi2s->State = HAL_I2S_STATE_BUSY_TX;
 hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
 
 if(((hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN)) == I2S_DATAFORMAT_24B)||\
 ((hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN)) == I2S_DATAFORMAT_32B))
 {
 hi2s->TxXferSize = (Size << 1U);
 hi2s->TxXferCount = (Size << 1U);
 }
 else
 {
 hi2s->TxXferSize = Size;
 hi2s->TxXferCount = Size;
 }
 
 /* Set the I2S Tx DMA Half transfert complete callback */
 hi2s->hdmatx->XferHalfCpltCallback = I2S_DMATxHalfCplt;
 
 /* Set the I2S Tx DMA transfert complete callback */
 hi2s->hdmatx->XferCpltCallback = I2S_DMATxCplt;
 
 /* Set the DMA error callback */
 hi2s->hdmatx->XferErrorCallback = I2S_DMAError;
 
 /* Clear TXDMAEN bit*/
 CLEAR_BIT(hi2s->Instance->CFG1, SPI_CFG1_TXDMAEN);
 
 /* Enable the Tx DMA Channel */
 HAL_DMA_Start_IT(hi2s->hdmatx, (uint32_t)hi2s->pTxBuffPtr, (uint32_t)&hi2s->Instance->TXDR, hi2s->TxXferSize);
 
 /* Set the number if data at current transfer */
 if (hi2s->hdmatx->Init.Mode == DMA_CIRCULAR)
 {
 MODIFY_REG(hi2s->Instance->CR2, SPI_CR2_TSIZE, 0);
 }
 else
 {
 MODIFY_REG(hi2s->Instance->CR2, SPI_CR2_TSIZE, Size);
 }
 
 /* Check if the I2S Tx request is already enabled */ 
 if(HAL_IS_BIT_CLR(hi2s->Instance->CFG1, SPI_CFG1_TXDMAEN))
 {
 /* Check if the SPI2S is disabled to edit CFG1 register */
 if ((hi2s->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
 {
 /* Enable Tx DMA Request */
 SET_BIT(hi2s->Instance->CFG1, SPI_CFG1_TXDMAEN);
 /* Enable SPI peripheral */
 __HAL_I2S_ENABLE(hi2s);
 }
 else
 {
 /* Disable SPI peripheral */
 __HAL_I2S_DISABLE(hi2s);
 
 /* Enable Tx DMA Request */
 SET_BIT(hi2s->Instance->CFG1, SPI_CFG1_TXDMAEN);
 
 /* Enable SPI peripheral */
 __HAL_I2S_ENABLE(hi2s);
 }
 }
 
 /* Master transfer start */
 SET_BIT(hi2s->Instance->CR1, SPI_CR1_CSTART);
 
 /* Process Unlocked */
 __HAL_UNLOCK(hi2s);
 
 return HAL_OK;
 }
 else
 {
 /* Process Unlocked */
 __HAL_UNLOCK(hi2s);
 return HAL_BUSY;
 }
}

stanley
Associate II
September 6, 2019

deleted!

stanley
Associate II
September 24, 2019

Hi, I'm having the same issue... did you solved the problem?

uprogc
Associate II
April 29, 2019

Hi,

I have the "same" problem, but with RX. I'm using the I2S3 in master RX mode.

I modified the CubeMX generated HAL_I2S_Receive_DMA ( ) function (see below), because the SPE bit in CR1 register was 0 , but still not working

I'm looking with oscilloscope on I2S clock and ws pins but no signal.

HAL_StatusTypeDef HAL_I2S_Receive_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
 /* Check Mode parameter */
 assert_param(IS_I2S_RX_MODE(hi2s->Init.Mode));
 
 if((pData == NULL) || (Size == 0U))
 {
 return HAL_ERROR;
 }
 
 /* Process Locked */
 __HAL_LOCK(hi2s);
 
 if(hi2s->State == HAL_I2S_STATE_READY)
 {
 hi2s->pRxBuffPtr = pData;
 hi2s->State = HAL_I2S_STATE_BUSY_RX;
 hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
 
 if(((hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN)) == I2S_DATAFORMAT_24B)||\
 ((hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN)) == I2S_DATAFORMAT_32B))
 {
 hi2s->RxXferSize = (Size << 1U);
 hi2s->RxXferCount = (Size << 1U);
 }
 else
 {
 hi2s->RxXferSize = Size;
 hi2s->RxXferCount = Size;
 }
 
 /* Set the I2S Rx DMA Half transfert complete callback */
 hi2s->hdmarx->XferHalfCpltCallback = I2S_DMARxHalfCplt;
 
 /* Set the I2S Rx DMA transfert complete callback */
 hi2s->hdmarx->XferCpltCallback = I2S_DMARxCplt;
 
 /* Set the DMA error callback */
 hi2s->hdmarx->XferErrorCallback = I2S_DMAError;
 
 /* Check if Master Receiver mode is selected */
 if((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_RX)
 {
 /* Clear the Overrun Flag by a read operation to the SPI_DR register followed by a read
 access to the SPI_SR register. */ 
 __HAL_I2S_CLEAR_OVRFLAG(hi2s);
 }
 
 /* Enable the Rx DMA Channel */
 HAL_DMA_Start_IT(hi2s->hdmarx, (uint32_t)&hi2s->Instance->RXDR, (uint32_t)hi2s->pRxBuffPtr, hi2s->RxXferSize);
 
		/* Set the number if data at current transfer */
 if (hi2s->hdmatx->Init.Mode == DMA_CIRCULAR)
 {
 MODIFY_REG(hi2s->Instance->CR2, SPI_CR2_TSIZE, 0);
 }
 else
 {
 MODIFY_REG(hi2s->Instance->CR2, SPI_CR2_TSIZE, Size);
 } 
 
 /* Check if the I2S Rx request is already enabled */ 
 if(HAL_IS_BIT_CLR(hi2s->Instance->CFG1, SPI_CFG1_RXDMAEN))
 {
 /* Check if the SPI2S is disabled to edit CFG1 register */
 if ((hi2s->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
 {
 /* Enable Rx DMA Request */
 SET_BIT(hi2s->Instance->CFG1, SPI_CFG1_RXDMAEN);
 
				/* Enable SPI peripheral */
 __HAL_I2S_ENABLE(hi2s);
 }
 else
 {
 /* Disable SPI peripheral */
 __HAL_I2S_DISABLE(hi2s);
 
 /* Enable Rx DMA Request */
 SET_BIT(hi2s->Instance->CFG1, SPI_CFG1_RXDMAEN);
 
 /* Enable SPI peripheral */
 __HAL_I2S_ENABLE(hi2s);
 }
 }
 
		/* Master transfer start */
 SET_BIT(hi2s->Instance->CR1, SPI_CR1_CSTART);
		
 /* Process Unlocked */
 __HAL_UNLOCK(hi2s);
 
 return HAL_OK;
 }
 else
 {
 /* Process Unlocked */
 __HAL_UNLOCK(hi2s);
 return HAL_BUSY;
 }
}

Regards,

uprog

eeyurdakul
Associate II
December 22, 2019

Any solution so far with HAL v1.5? I can do polling and interrupt mode successfully, but stops with dma mode? It is very critical for my project. I would be pleased, if you have any solution or suggestion for this issue?

KWest.1
Associate II
May 2, 2021

I had a very similar issue.

First call to HAL_I2S_Transmit_DMA worked. If i called it again in the completion handler also ok.

Every now and then due to other things going on i did not process the interrupt in time so I had some recovery code that re-initiated the transmit by calling HAL_I2S_Transmit_DMA again ... but although it returned ok the completion handler was never called.

Rather than change the HAL (because who knows what new versions will do) I added the following 2 lines just before I call HAL_I2S_Transmit_DMA.

CLEAR_BIT(hi2sWav.Instance->CFG1, SPI_CFG1_TXDMAEN);

__HAL_I2S_DISABLE(&hi2sWav);

These seem to be ok because HAL_I2S_Transmit_DMA checks if these are in the right state and if not sets them again.

With this change it seems to be working.