cancel
Showing results for 
Search instead for 
Did you mean: 

stm32h7 i2s dma transfer issue

akosodry
Associate II

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

13 REPLIES 13
WMinH
Associate

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

akosodry
Associate II

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
Associate II

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

Thanks!

HHuyn.19
Associate

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;
  }
}

uprogc
Associate II

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

deleted!

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

Hi , I follow your suggestion to modify HAL_I2S_Transmit_DMA function. But it seems still not working. Has anyone actually been successful with this ?

Hi, I have solved the I2S DMA RX/TX for double buffer.