Skip to main content
akosodry
Associate III
Jan 17, 2019 4:18 PM UTC
Question

stm32h7 i2s dma transfer issue

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
Jan 28, 2019 10:27 AM UTC

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

akosodry
akosodryAuthor
Associate III
Jan 28, 2019 10:42 AM UTC

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
Feb 4, 2019 2:28 PM UTC

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

Thanks!

HHuyn.19
Visitor II
Apr 16, 2019 9:47 AM UTC

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
Sep 6, 2019 3:22 AM UTC

deleted!

stanley
Associate II
Sep 24, 2019 8:13 AM UTC

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

uprogc
Associate II
Apr 29, 2019 8:43 AM UTC

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
Dec 22, 2019 5:37 PM UTC

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 1:30 AM UTC

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.