AnsweredAssumed Answered

STM32F4xx DMA w/ I2S2 (TX) + I2S3 (RX)

Question asked by carso.mike on Mar 3, 2014
Hi, I have an STM32F407VE6 and I've been working for the past week on trying to get my audio codec chip (ADC + DAC) UDA1380 (ref: http://www.nxp.com/documents/data_sheet/UDA1380.pdf) to interface with it but have not been able to successfully get the I2S3 RX (receiving data from the DAC) to work.

I am using the I2S2 as TX (master), with the MCLK being used as the Sysclock for the codec chip. The I2S3 is in Slave RX mode so that the codec chip supplies the 3 pins SDA/CLK/WS. 

I am hoping someone can check my configurations to see if I am missing anything. First is the GPIO followed by I2S2/I2S3 config, followed by DMA config. Anyone see something problematic in the code? Also is it a problem using two I2S that are on the same DMA channel (channel 0) they are different streams of course though...

Thanks!

void Codec_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
 
    /* PLLI2S clock used as I2S clock source */
  RCC->CFGR &= ~RCC_CFGR_I2SSRC;
 
  /* Configure PLLI2S */
  RCC->PLLI2SCFGR = (258 << 6) | (3 << 28);
 
  /* Enable PLLI2S */
  RCC->CR |= ((uint32_t)RCC_CR_PLLI2SON);
 
  /* Wait till PLLI2S is ready */
  while((RCC->CR & RCC_CR_PLLI2SRDY) == 0)
  {
  }
     
    /* Enable I2S and I2C GPIO clocks */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
     
    /*
    BOARD connections
    i2s2_ws -> PB9
    i2s2_SD ->PC3
    i2s2_CK-> PB10
    i2s2_MCK -> PC6
 
    i2s3_ws ->PA4
    i2s3_ck -> PB3
    i2s3_SD -> PB5
    I2s3_MCK -> PC7
    */
     
    //setup i2s2 (WS/CK)and i2s3_Ck/SD
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_9 | GPIO_Pin_10;
       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
       GPIO_Init(GPIOB, &GPIO_InitStructure);
     
     
    //setup i2s3 MCK & I2s2 SD/MCK
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
     
    //setup i2s3 ws
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
    /* Connect pins to I2S peripheral  */
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_SPI2);
     
    //connect to i2s3
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI3);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI3);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_SPI3);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI3);
 
    //Enable peripheral clocks
       RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 | RCC_APB1Periph_SPI3, ENABLE);
}
 
void Codec_AudioInterface_Init(uint32_t AudioFreq)
{
    I2S_InitTypeDef I2S_InitStructure;
      
 
    /* CODEC_I2S peripheral configuration for master TX */
    SPI_I2S_DeInit(SPI2);
    I2S_InitStructure.I2S_AudioFreq = AudioFreq;
    I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
    I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;//extended;
    I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
    I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
    I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
 
     
    /* Initialize the I2S main channel for TX */
    I2S_Init(SPI2, &I2S_InitStructure);
    SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
    /* Initialize the I2S extended channel for RX */
    //I2S_FullDuplexConfig(CODEC_I2S_EXT, &I2S_InitStructure);
     
 
    //initialize spi3
    SPI_I2S_DeInit(SPI3);
    I2S_InitStructure.I2S_AudioFreq = AudioFreq;
    I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
    I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
    I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
    I2S_InitStructure.I2S_Mode = I2S_Mode_SlaveRx;
    I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
 
    /* Initialize the I2S main channel for TX */
    I2S_Init(SPI3, &I2S_InitStructure);
    SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_RXNE, DISABLE);
 
}
 
void I2S_Block_Init(void) 
{
    NVIC_InitTypeDef NVIC_InitStructure;
 
    /* Enable the DMA clock */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
 
    //Stream4 is I2S2 (TX)
    /* Configure the TX DMA Stream */
    DMA_Cmd(DMA1_Stream4, DISABLE);
    DMA_DeInit(DMA1_Stream4);
    /* Set the parameters to be configured */
    DMA_InitStructure.DMA_Channel = DMA_Channel_0; 
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR);
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0;      /* This field will be configured in play function */
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_BufferSize = (uint32_t)0xFFFE;      /* This field will be configured in play function */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 
    DMA_Init(DMA1_Stream4, &DMA_InitStructure); 
     
    /* Enable the I2S DMA request */
    SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
 
    /* Configure the RX DMA Stream */
    DMA_Cmd(DMA1_Stream0, DISABLE);
    DMA_DeInit(DMA1_Stream0);
     
    //Stream0 is I2S3 (RX)
    /* Set the parameters to be configured */
    DMA_InitStructure2.DMA_Channel = DMA_Channel_0; 
    DMA_InitStructure2.DMA_PeripheralBaseAddr = (uint32_t)&(SPI3->DR);
    DMA_InitStructure2.DMA_Memory0BaseAddr = (uint32_t)0;      /* This field will be configured in play function */
    DMA_InitStructure2.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure2.DMA_BufferSize = (uint32_t)0xFFFE;      /* This field will be configured in play function */
    DMA_InitStructure2.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure2.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure2.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure2.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure2.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure2.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure2.DMA_FIFOMode = DMA_FIFOMode_Disable;        
    DMA_InitStructure2.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
    DMA_InitStructure2.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure2.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 
    DMA_Init(DMA1_Stream0, &DMA_InitStructure2); 
    /* Enable the Half & Complete DMA interrupts  */
    DMA_ITConfig(DMA1_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
     
    /* I2S DMA IRQ Channel configuration */
    NVIC_EnableIRQ(DMA1_Stream0_IRQn);
 
    /* Enable the I2S DMA request */
    SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Rx, ENABLE);
     
    I2S_Cmd(SPI2, ENABLE);
    I2S_Cmd(SPI3, ENABLE);
     
}
 
/**
  * @brief  Starts playing & recording audio stream from/to the audio Media.
  * @param  None
  * @retval None
  */
void I2S_Block_PlayRec(uint32_t txAddr, uint32_t rxAddr, uint32_t Size)
{
 
    uint32_t i;
    /* save for IRQ svc  */
    txbuf = txAddr;
    rxbuf = rxAddr;
    szbuf = Size;
     
    /* Configure the tx buffer address and size */
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)txAddr;
    DMA_InitStructure.DMA_BufferSize = (uint32_t)Size;
 
    /* Configure the DMA Stream with the new parameters */
    DMA_Init(DMA1_Stream4, &DMA_InitStructure);
 
    /* Configure the rx buffer address and size */
    DMA_InitStructure2.DMA_Memory0BaseAddr = (uint32_t)rxAddr;
    DMA_InitStructure2.DMA_BufferSize = (uint32_t)Size;
 
    /* Configure the DMA Stream with the new parameters */
    DMA_Init(DMA1_Stream0, &DMA_InitStructure2);
 
    /* Enable the I2S DMA Streams */
    DMA_Cmd(DMA1_Stream4, ENABLE);  
    DMA_Cmd(DMA1_Stream0, ENABLE);  
 
    /* If the I2S peripheral is still not enabled, enable it */
    if ((SPI2->I2SCFGR & 0x0400) == 0)
    {
        I2S_Cmd(SPI2, ENABLE);
    }
    if ((SPI3->I2SCFGR & 0x0400) == 0)
    {
        I2S_Cmd(SPI3, ENABLE);
    }
    //enable rx receive flag
    SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_RXNE, ENABLE);
 
}
 
#define FLAG_RX (1 << 7) /* port B, pin 7 */
#define FLAG_TX (1 << 6) /* port B, pin 6 */
 
/**
  * @brief  This function handles I2S RX DMA block interrupt.
  * @param  None
  * @retval none
  */
void DMA1_Stream0_IRQHandler(void)
{
    int i;
    int16_t *src, *dst, sz;
 
    //activity flag
    //GPIOB->BSRRL = FLAG_RX;
    /* Transfer complete interrupt */
    if (DMA_GetFlagStatus(DMA1_Stream0, DMA_FLAG_TCIF0) != RESET)
    {
         
        /* Point to 2nd half of buffers */
        sz = szbuf/2;
        src = (int16_t *)(rxbuf) + sz;
        dst = (int16_t *)(txbuf) + sz;
 
        /* Handle 2nd half */ 
        I2S_RX_CallBack(src, dst, sz, 0);   //This just does some delaying of the audio samples before sending them back to the tx buffer. 
 
        /* Clear the Interrupt flag */
        DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_TCIF0);
    }
 
    /* Half Transfer complete interrupt */
    if (DMA_GetFlagStatus(DMA1_Stream0, DMA_FLAG_HTIF0) != RESET)
    {
        /* Point to 1st half of buffers */
        sz = szbuf/2;
        src = (int16_t *)(rxbuf);
        dst = (int16_t *)(txbuf);
         
        /* Handle 1st half */ 
        I2S_RX_CallBack(src, dst, sz, 1);   
 
        /* Clear the Interrupt flag */
        DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_HTIF0);   
    }
     
    /* Lower activity flag */
    //GPIOB->BSRRH = FLAG_RX;
}

Outcomes