cancel
Showing results for 
Search instead for 
Did you mean: 

How to properly change I2S clock.

leonardo
Associate III
Posted on October 06, 2016 at 00:37

Hi, I'm using a STM32F411 on a product that uses I2S to stream some sound to an audio codec.

I use this function to configure oscillator:

void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
__PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
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 = 6;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
//22050 Hz original del final_09_DPOAE_05_Apexar
// PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
// PeriphClkInitStruct.PLLI2S.PLLI2SN = 192;
// PeriphClkInitStruct.PLLI2S.PLLI2SM = 12;
// PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
// HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
//44100Hz
// PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
// PeriphClkInitStruct.PLLI2S.PLLI2SN = 271;
// PeriphClkInitStruct.PLLI2S.PLLI2SM = 12;
// PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
// HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
/*
* Esta configuracion es para tener buen % trabajando a 22KHz
*/
// PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
// PeriphClkInitStruct.PLLI2S.PLLI2SN = 429;
// PeriphClkInitStruct.PLLI2S.PLLI2SM = 12;
// PeriphClkInitStruct.PLLI2S.PLLI2SR = 4;
// HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
/*
* Esta configuracion es para tener buen % trabajando a 96KHz
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
PeriphClkInitStruct.PLLI2S.PLLI2SN = 344;
PeriphClkInitStruct.PLLI2S.PLLI2SM = 12;
PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

As you can see I have 4 diferent blocks on I2S clock. I need to use 2 of them on my firmware. I need to know how can I change just I2S clock frecuency. Could I write just this:

PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
PeriphClkInitStruct.PLLI2S.PLLI2SN = 344;
PeriphClkInitStruct.PLLI2S.PLLI2SM = 12;
PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

on any part of my code and it will change I2S clock? Thank
3 REPLIES 3
slimen
Senior
Posted on October 11, 2016 at 12:42

Hello,

Review I2S working example under STM32CubeF4, this may help you to develop your project:

STM32Cube_FW_F4_V1.13.0\Projects\STM324xG_EVAL\Examples\I2S\I2S_Audio

Regards

leonardo
Associate III
Posted on October 18, 2016 at 01:09

I saw the example code and it is a good starting point.

But it is not clear to me the correct way to properly do this:
  1. Configure I2S peripheral for working with 22050 Hz
  2. Configure DMA channels
  3. Configure AudioCodec
  4. Start I2S stream using DMA (full duplex)
  5. Stop I2S stream
  6. Re Configure I2S peripheral for working with 22050 Hz
  7. re Configure DMA Channels
  8. re Configure Audio Codec
  9. Start I2S stream using DMA (F D )
  10. Stop I2S

I'm using CubeMx generated code for some parts of that flowchart.

So, for point 1 I have:

/* I2S2 init function */
void MX_I2S2_Init(uint32_t SampleFreq)
{
 hi2s2.State = HAL_I2C_STATE_RESET; // To be sure that HAL_I2S_MspInit is executed on point 6 
hi2s2.Instance = SPI2;
hi2s2.Init.Mode = I2S_MODE_MASTER_TX;
hi2s2.Init.Standard = I2S_STANDARD_PHILLIPS;
hi2s2.Init.DataFormat = I2S_DATAFORMAT_24B;
hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
hi2s2.Init.AudioFreq = SampleFreq;
hi2s2.Init.CPOL = I2S_CPOL_LOW;
hi2s2.Init.ClockSource = I2S_CLOCK_PLL;
hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;
HAL_I2S_Init(&hi2s2);
}

HAL_I2S_MspInit has part of point 2 and is called by HAL_I2S_Init

void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hi2s->Instance==SPI2)
{
/* Peripheral clock enable */
__SPI2_CLK_ENABLE();
/**I2S2 GPIO Configuration 
PB12 ------> I2S2_WS
PB13 ------> I2S2_CK
PB14 ------> I2S2_ext_SD
PB15 ------> I2S2_SD
PC6 ------> I2S2_MCK 
*/
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* Peripheral DMA init*/
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_LOW;
hdma_i2s2_ext_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_i2s2_ext_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
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);
hdma_spi2_tx.Instance = DMA1_Stream4;
hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_spi2_tx.Init.Mode = DMA_CIRCULAR;
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_spi2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_spi2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_spi2_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
HAL_DMA_Init(&hdma_spi2_tx);
__HAL_LINKDMA(hi2s,hdmatx,hdma_spi2_tx);
}
}

for point 2 I have:

void MX_DMA_Init(void) 
{
__DMA2_CLK_ENABLE();
__DMA1_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}

Then I config my codec. Here there is no problem. I already test my codec initialization and output/input sound and it is ok. Then for pint 4 I write:

HAL_I2SEx_TransmitReceive_DMA(&hi2s2, (uint16_t *)OutputBuffer, (uint16_t *)InputBuffer, SOUND_BUFF_SIZE);

with output/input buffers configured. Then after a few seconds I call HAL_I2S_DMAStop(&hi2s2); It is something like this:

MX_DMA_Init(); // Canales de comunicacion DMA
MX_I2S2_Init(); // I2S para comunicacion de sonidos con Codec de Audio
Codec_Init_DPEOAE();
HAL_Delay(2000);
// Reseteo la bandera de mitad de buffer lleno
f_mitad_buffer=0;
HAL_I2SEx_TransmitReceive_DMA(&hi2s2, (uint16_t *)OutputBuffer, (uint16_t *)InputBuffer, SOUND_BUFF_SIZE);
HAL_Delay(2000);
HAL_I2S_DMAStop(&hi2s2);

All of this is working well. But the problem is that I need to execute previouse code several times. And the second time I run that code the sound is not well. So, I would like to know what should I do to put I2S and DMA as it was when uC run for the first time after reset. Thank
slimen
Senior
Posted on October 18, 2016 at 18:19

Hi,

I suggest you calling I2S_DeInit to deInitializes the I2S peripheral.

Regards