AnsweredAssumed Answered

STM32F427VIT I2S strange desync problem

Question asked by Ovidiu G on Jul 10, 2014
Latest reply on Jul 15, 2014 by bs

Hi everybody. This is my first post on this forum.

I'm currently testing I2S2 functionality on STM32F427VIT.
As a hardware I am using SRC4392 to read SPDIF input and convert it to I2S. I am using sample rate converter function from the chip to convert the SPDIF input to 48Khz sample rate. The SRC4392 is working fine.
I'm also using a 12.288Mhz TCXO for master clock and a stereo I2S, PCM1704 DAC ( based on the well known schematic from http://www.pavouk.org/hw/modulardac/en_pcm1704.html ) which is also working fine.

The STM32F427 has the following peripherials connected:
- 8 Mhz crystal for HSE
- I2C1 for controlling the SRC4392
- I2S2
- debug wires: SWD and Asynchronous Trace

As a software I am using STM32CubeMX to generate the code for Keil then add some of my own routines.
I will post my main.c code below.

The I2S2 port is configured as full duplex master transmit with the clock source taken from external audio clock pin from the 12.288Mhz TCXO.
The SRC4392 and DAC are configured as slaves.
The data and frame format is 32bit data on 32bit frame. Working frequency is set to 48Khz.
DMA for I2S2 is configured as circular buffer  with FIFO half full.

After I start the code on my MCU all works fine. I'm using the code just to copy receive buffer to the transmit buffer just to see it working.

With the MCU configured as Master Full Duplex, Mode Transmit and external clock:
For a while all is working good the SRC is working, the DAC is working too.
After a while (3-12 hours) the I2S transmit DATA pin starts to get desynchronized. I use the oscilloscope to probe the WS pin vs DATA pin.
The data is shifted about 16 bit right approx. (not sure exactly how much but 16bit most probably).
After another while(3-12hours) the data is shifted another 16bit and gets in sync again but this time the Right channel is playing on the Left channed and vice versa because of these shifts of data.

With the MCU configured the same(Master Full Duplex, Mode Transmit) except this time the clock is internal PLL I2S. None of this is happening. All is working good.

I tried replacing the 12.288Mhz TCXO with another one different manufacturer. I also tried different I2S,DMA settings but still nothing.

I really want to avoid the PLL clock and use an external one but as it looks now it seems to be unreliable.
Can someone confirm that I2S transmit or receive on any STM32 device with external master clock (full/half duplex doesn't matter) works for a long term use?
Please someone help me!

Here is main.c source code:
======================

int main(void)
{
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  /* Configure the system clock */
  SystemClock_Config();
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_I2S2_Init();
/* USER CODE BEGIN 2 */

 printf("START\r\n");

.............. I2C initialisation code here ....................

 printf("I2C DONE\r\n");

 //Start I2S Port 2
 //These are some tweaks that overrides or adds some of the STM32CubeMX settings in order for I2S to work
 HAL_I2S_DeInit(&hi2s2);
 MX_I2S2_Init();

  //Enable DMA and start I2S Port 2 for Full-Duplex transmission
 hdma_i2s2_ext_tx.Init.Channel = DMA_CHANNEL_0;
  HAL_DMA_Init(&hdma_i2s2_ext_tx);
  __HAL_LINKDMA(&hi2s2,hdmatx,hdma_i2s2_ext_tx);
 HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
  HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
 HAL_I2SEx_TransmitReceive_DMA(&hi2s2,I2S2_BUFFER_TX,I2S2_BUFFER_RX,AUDIO_BUFFER_LEN*2*2);

  while (1)
  {
  }

}

/** System Clock Configuration
*/
static void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/* I2C1 init function */
void MX_I2C1_Init(void)
{

  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
  HAL_I2C_Init(&hi2c1);

}

/* I2S2 init function */
void MX_I2S2_Init(void)
{

  hi2s2.Instance = SPI2;
  hi2s2.Init.Mode = I2S_MODE_MASTER_TX;
  hi2s2.Init.Standard = I2S_STANDARD_PHILLIPS;
  hi2s2.Init.DataFormat = I2S_DATAFORMAT_32B;
  hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
  hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_48K;
  hi2s2.Init.CPOL = I2S_CPOL_LOW;
  hi2s2.Init.ClockSource = I2S_CLOCK_EXTERNAL;
  hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;
  HAL_I2S_Init(&hi2s2);

}

/**
  * Enable DMA controller clock
  */
void MX_DMA_Init(void) {
  /* DMA controller clock enable */
  __DMA1_CLK_ENABLE();
}

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
     PC9   ------> I2S_CKIN
*/
void MX_GPIO_Init(void) {
  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOH_CLK_ENABLE();
  __GPIOC_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();

  /*Configure GPIO pin : PC9 */
  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

/* USER CODE BEGIN 4 */
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
 //refill buffer HALF - END
 if(hi2s->Instance == SPI2){
 }
}

void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
 //refill buffer BEGIN - HALF
 if(hi2s->Instance == SPI2){
 }
}

void I2S2_RX_ProcessBuffer(uint32_t posbegin, uint32_t posend){
 int32_t audiosample;
 float volume;
 volume=0.5;

 for(int i=posbegin;i<posend;i++){
   audiosample=(I2S2_BUFFER_RX[i*4+0] << 16) | I2S2_BUFFER_RX[i*4+1];

  audiosample=audiosample * volume;
 
  I2S2_BUFFER_TX[i*4+0]=(audiosample >> 16);
  I2S2_BUFFER_TX[i*4+1]=audiosample;
 

   audiosample=(I2S2_BUFFER_RX[i*4+2] << 16) | I2S2_BUFFER_RX[i*4+3];
 
  audiosample=audiosample * volume;

  I2S2_BUFFER_TX[i*4+2]=(audiosample >> 16);
  I2S2_BUFFER_TX[i*4+3]=audiosample;

  //((int32_t*)I2S2_BUFFER_TX)[i*2+0]=((int32_t*)I2S2_BUFFER_RX)[i*2+0];
  //((int32_t*)I2S2_BUFFER_TX)[i*2+1]=((int32_t*)I2S2_BUFFER_RX)[i*2+1];
 }
}

void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
 //refill buffer HALF - END
 if(hi2s->Instance == SPI2){
  I2S2_RX_ProcessBuffer(AUDIO_BUFFER_LEN,AUDIO_BUFFER_LEN*2);
 }
 
}

void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
 //refill buffer BEGIN - HALF
 if(hi2s->Instance == SPI2){
  I2S2_RX_ProcessBuffer(0,AUDIO_BUFFER_LEN);
 }
 
}

void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
{
 if(hi2s->Instance == SPI2){
 }
}

 

these are the initialisation functions from stm32f4xx_hal_msp.c
================================================================

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c){
  GPIO_InitTypeDef GPIO_InitStruct;
  if(hi2c->Instance==I2C1)
  {
    /* Peripheral clock enable */
    __I2C1_CLK_ENABLE();
 
  /**I2C1 GPIO Configuration 
  PB6   ------> I2C1_SCL
  PB7   ------> I2C1_SDA
  */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  }
}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c){
  if(hi2c->Instance==I2C1)
  {
    /* Peripheral clock disable */
    __I2C1_CLK_DISABLE();
 
  /**I2C1 GPIO Configuration 
  PB6   ------> I2C1_SCL
  PB7   ------> I2C1_SDA
  */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);

  }
}

void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s){
  GPIO_InitTypeDef GPIO_InitStruct;
  if(hi2s->Instance==SPI2)
  {
    /* Peripheral clock enable */
    __SPI2_CLK_ENABLE();
 
  /**I2S2 GPIO Configuration 
  PC2   ------> I2S2_ext_SD
  PC3   ------> I2S2_SD
  PB10   ------> I2S2_CK
  PB12   ------> I2S2_WS
  */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
    GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &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_FAST;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* Peripheral DMA init*/
 
    hdma_i2s2_ext_tx.Instance = DMA1_Stream4;
    hdma_i2s2_ext_tx.Init.Channel = DMA_CHANNEL_2;
    hdma_i2s2_ext_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_i2s2_ext_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2s2_ext_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2s2_ext_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_i2s2_ext_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_i2s2_ext_tx.Init.Mode = DMA_CIRCULAR;
    hdma_i2s2_ext_tx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_i2s2_ext_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_i2s2_ext_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    hdma_i2s2_ext_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_i2s2_ext_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&hdma_i2s2_ext_tx);

    __HAL_LINKDMA(hi2s,hdmatx,hdma_i2s2_ext_tx);

    hdma_i2s2_ext_rx.Instance = DMA1_Stream3;
    hdma_i2s2_ext_rx.Init.Channel = DMA_CHANNEL_3;
    hdma_i2s2_ext_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_i2s2_ext_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2s2_ext_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2s2_ext_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_i2s2_ext_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_i2s2_ext_rx.Init.Mode = DMA_CIRCULAR;
    hdma_i2s2_ext_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_i2s2_ext_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_i2s2_ext_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    hdma_i2s2_ext_rx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_i2s2_ext_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    HAL_DMA_Init(&hdma_i2s2_ext_rx);

    __HAL_LINKDMA(hi2s,hdmarx,hdma_i2s2_ext_rx);

  }
}

void HAL_I2S_MspDeInit(I2S_HandleTypeDef* hi2s){
  if(hi2s->Instance==SPI2)
  {
    /* Peripheral clock disable */
    __SPI2_CLK_DISABLE();
 
  /**I2S2 GPIO Configuration 
  PC2   ------> I2S2_ext_SD
  PC3   ------> I2S2_SD
  PB10   ------> I2S2_CK
  PB12   ------> I2S2_WS
  */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2|GPIO_PIN_3);

    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_12);

    /* Peripheral DMA DeInit*/
     HAL_DMA_DeInit(hi2s->hdmatx);
     HAL_DMA_DeInit(hi2s->hdmarx);
  }
}

Outcomes