Skip to main content
leogarberoglio
Associate III
June 3, 2015
Question

STM32F411 - HAL driver - I2S full duplex - ext_SD issue

  • June 3, 2015
  • 1 reply
  • 1238 views
Posted on June 04, 2015 at 01:18

Hi, I'm continue fighting with full-duplex configuration of STM32F4

I have an audio codec with MIC input and speaker output. I connect DOUT pin from the CODEC to PC3 (I2S_Dat) line. So it will be my Rx pin. Then I connect DIN from de codec to PC2 (I2S_ext) line. So it will be my Tx pin. I configure (with Cube MX) the I2S and DMA stream as follow:

/* I2S2 init function */
void MX_I2S2_Init(void)
{
hi2s2.Instance = SPI2;
hi2s2.Init.Mode = I2S_MODE_MASTER_RX;
hi2s2.Init.Standard = I2S_STANDARD_PHILLIPS;
hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B;
hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_44K;
hi2s2.Init.CPOL = I2S_CPOL_LOW;
hi2s2.Init.ClockSource = I2S_CLOCK_PLL;
hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;
HAL_I2S_Init(&hi2s2);
}
void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hi2s->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* Peripheral clock enable */
__SPI2_CLK_ENABLE();
/**I2S2 GPIO Configuration 
PC2 ------> I2S2_ext_SD
PC3 ------> I2S2_SD
PA6 ------> I2S2_MCK
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_LOW;
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_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &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_AF6_SPI2;
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_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral DMA init*/
hdma_spi2_rx.Instance = DMA1_Stream3;
hdma_spi2_rx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_spi2_rx.Init.Mode = DMA_NORMAL;
hdma_spi2_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi2_rx);
__HAL_LINKDMA(hi2s,hdmarx,hdma_spi2_rx);
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_NORMAL;
hdma_i2s2_ext_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_i2s2_ext_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_i2s2_ext_tx);
__HAL_LINKDMA(hi2s,hdmatx,hdma_i2s2_ext_tx);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
}
}

first questions: what

hi2s2.Init.Mode = I2S_MODE_MASTER_RX;

means? how do I choos between MASTER_RX and MASTER_TX?

Then my code is something like this:

int main(void)
{
/* 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_I2S2_Init();
/* USER CODE BEGIN 2 */
uint16_t i;
for(i=0;i<BufferSize;i++)
{
InputBuffer[i]=0xFFFF;
OutputBuffer[i]=0x0000;
}
HAL_I2SEx_TransmitReceive_DMA(&hi2s2, OutputBuffer, InputBuffer, BufferSize);
while (1)
{
}
}

just initialize the buffers to see changes and then call the first DMA transmit_receive. Finally I have code for each IRQ:

void DMA1_Stream3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi2_rx);
}
/**
* @brief This function handles DMA1 Stream4 global interrupt.
*/
void DMA1_Stream4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_i2s2_ext_tx);
}
/* USER CODE BEGIN 1 */
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
//Recivimos todos los datos del micrófono, enviémoslo a los parlantes
uint16_t i;
for(i=0;i<20000;i++)
{
OutputBuffer[i]=InputBuffer[i];
}
HAL_I2SEx_TransmitReceive_DMA(&hi2s2, OutputBuffer, InputBuffer, 20000);
// HAL_I2S_Receive_DMA(&hi2s2, InputBuffer, 10000);
}
void HAL_I2S_ext_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
// HAL_I2SEx_TransmitReceive_DMA(&hi2s2, OutputBuffer, InputBuffer, 10000);
}
void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
{
}

I put a breack point on each ISR. When I run the project I see that there is just two interrupts and then stops, I mean, there is no new interrupts, just to of them. Input buffer is filled. So, how do I need to do to obtain a continous stream of data using this HAL library? BR!
    This topic has been closed for replies.

    1 reply

    leogarberoglio
    Associate III
    June 4, 2015
    Posted on June 05, 2015 at 01:41

    I test blocking mode:

    /* I2S2 init function */
    void MX_I2S2_Init(void)
    {
    hi2s2.Instance = SPI2;
    hi2s2.Init.Mode = I2S_MODE_MASTER_RX;
    hi2s2.Init.Standard = I2S_STANDARD_PHILLIPS;
    hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B;
    hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
    hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_44K;
    hi2s2.Init.CPOL = I2S_CPOL_LOW;
    hi2s2.Init.ClockSource = I2S_CLOCK_PLL;
    hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;
    HAL_I2S_Init(&hi2s2);
    }
    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
    PA6 ------> I2S2_MCK
    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_LOW;
    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_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &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_AF6_SPI2;
    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_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    }
    }

    /* USER CODE BEGIN 0 */
    #define BufferSize 100*2*44100/500
    int16_t InputBuffer[BufferSize];
    int16_t OutputBuffer[BufferSize];
    /* USER CODE END 0 */
    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_I2S2_Init();
    /* USER CODE BEGIN 2 */
    uint16_t i;
    for(i=0;i<BufferSize;i++)
    {
    InputBuffer[i]=0xFFFF;
    }
    for(i=0;i<BufferSize;i+=2){
    OutputBuffer[i]=( sin(2*M_PI*(i/2)*500/44100) ) * 20000;
    OutputBuffer[i+1]=( sin(2*M_PI*(i/2)*500/44100) ) * 20000;
    }
    // HAL_I2S_Receive_DMA(&hi2s2, InputBuffer, 20000);
    while(__HAL_I2S_GET_FLAG(&hi2s2, I2S_FLAG_TXE) != 1);
    HAL_I2SEx_TransmitReceive(&hi2s2, OutputBuffer, InputBuffer, BufferSize, 1000);
    /* USER CODE END 2 */
    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    while(__HAL_I2S_GET_FLAG(&hi2s2, I2S_FLAG_TXE) != 1);
    for(i=0;i<BufferSize;i++)
    {
    OutputBuffer[i]=InputBuffer[i];
    }
    HAL_I2SEx_TransmitReceive(&hi2s2, OutputBuffer, InputBuffer, BufferSize, 1000);
    }
    /* USER CODE END 3 */
    }

    I have two buffer, one for input, one for output. I fill input buffer with 0xffff and outputbuffer with a 500Hz sine wave. Then wait for TXE flag and do a TransmitReceive. Then on the infinite loop just wait for TXE, copy Input to Output buffer and make another TransmitReceive. This way I can hear what I speak, with a litle delay So in blocking mode I2S_sd and I2Sext_sd works fine. But, just like hem (https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Java/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2FSTM32Java%2FHAL%20STM32F427%20Full%20Duplex%20I2S%20problems%20communicating%20with%20Audio%20Codec&FolderCTID=0x01200200770978C69A1141439FE559EB459D758000F9A0E3A95BA69146A17C2E80209ADC21&currentviews=117) once I try _IT or DMA, extSD line seems to not work... Any idea?