AnsweredAssumed Answered

Help with I2S Rx and DMA configuration......output works fine

Question asked by Ronan on Oct 1, 2011
Latest reply on Oct 4, 2011 by Ronan
Hi all,
I'm using the I2S with DMA to transfer audio to and from a codec.
The transmit part on I2S2(SPI2) works fine with DMA, but when the dma is configured for the recieve channel I2S3 (on SPI3) the program seems to crash.

The JTAG output shows both DMA channels seem to be functioning and the I2S interfaces seem to be configured correctly. The IRQ handler for the recieve DMA is not entered at all and the code seems to hang. Are there other IRQ handlers I need to look at? I can't seem to find a complete list of the IRQ function names anywhere.

I'd really appreciate any help on this one as I'm not sure where to go next!


Here's the config code:


 


  /* Enable the DMA1 Channel 5 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable the DMA2 Channel 1 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);    
    //---------------------------------------------------------------------

  //SPI2 Configuration for Output
  SPI_I2S_DeInit(SPI2);  
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI2, &SPI_InitStructure);
  SPI_Cmd(SPI2, ENABLE);
  SPI_SSOutputCmd(SPI2, ENABLE);

  // I2S2 Configuration Setup (Output Master)
  I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx; // Configure as codec output
  I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;  
  I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_24b;     ///////////////////----------
  I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable; ////////////////--------------
  I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_44k;
  I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low; // Sets clock idle state to low
  I2S_Init(SPI2, &I2S_InitStructure);
 
  //---------------------------------------------------------------------
 
  // Configure DMA1
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(SPI2->DR));
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)outputbuffer;
  DMA_InitStructure.DMA_BufferSize = 4;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  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_M2M = DMA_M2M_Disable;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_Init(DMA1_Channel5, &DMA_InitStructure);
  DMA_Cmd(DMA1_Channel5, ENABLE);

  // trigger interrupt when transfer half complete/complete
  DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
  // Enable SPI2 Tx buffer empty interrupt
  SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE);
 
  // enable SPI interrupts to DMA
  I2S_Cmd(SPI2, ENABLE);
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

  Delay(0x000FFFFF);

  //---------------------------------------------------------------------
   
  //SPI3 Configuration for Input
  SPI_I2S_DeInit(SPI3);
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI3, &SPI_InitStructure);
  SPI_Cmd(SPI3, ENABLE);
  SPI_SSOutputCmd(SPI3, ENABLE);

  // I2S3 Configuration Setup (Input)
  I2S_InitStructure.I2S_Mode = I2S_Mode_MasterRx; // Configure as codec input
  I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;  
  I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_24b;    
  I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
  I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_44k;
  I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low; // Sets clock idle state to low
  I2S_Init(SPI3, &I2S_InitStructure);
  I2S_Cmd(SPI3, ENABLE);


  //------------------------------------------------------------------------------

  // Configure DMA2
  DMA_DeInit ( DMA2_Channel1);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(SPI3->DR));
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)inputbuffer;
  DMA_InitStructure.DMA_BufferSize = 4;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  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_M2M = DMA_M2M_Disable;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_Init(DMA2_Channel1, &DMA_InitStructure);
  DMA_Cmd(DMA2_Channel1, ENABLE);

  // trigger interrupt when transfer half complete/complete
  DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, ENABLE);
  // Enable SPI3 Rx buffer empty interrupt
  SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_RXNE, ENABLE);
 
  // enable SPI interrupts to DMA
  SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Rx, ENABLE);
 
  Delay(0x000FFFFF); 



And the Interrupt Handling:




// DMA1 Channel interrupt is triggered on both TC and HT interrupts
// I2S Send DMA interrupt
void DMA1_Channel5_IRQHandler(void)
{
  // toggle bit
  GPIOE->ODR ^= GPIO_Pin_8;

  if( DMA_GetITStatus(DMA1_FLAG_HT5) )
  {
    DMA_ClearITPendingBit(DMA1_IT_HT5); // Clear Transfer Complete Flag
  }

  if( DMA_GetITStatus(DMA1_FLAG_TC5) )
  {
    DMA_ClearITPendingBit(DMA1_IT_TC5); // Clear Transfer Complete Flag
    DMA_ClearITPendingBit(DMA1_IT_GL5);
  }

}

// DMA2 Channel interrupt is triggered on both TC and HT interrupts
// I2S Recieve DMA interrupt
void DMA2_Channel1_IRQHandler(void)
{
  // toggle bit
  GPIOE->ODR ^= GPIO_Pin_7;
 

  if( DMA_GetITStatus(DMA2_FLAG_HT1) )
  {
    DMA_ClearITPendingBit(DMA2_IT_HT1); // Clear Transfer Complete Flag
  }

  if( DMA_GetITStatus(DMA2_FLAG_TC1) )
  {
    DMA_ClearITPendingBit(DMA2_IT_TC1); // Clear Transfer Complete Flag
    DMA_ClearITPendingBit(DMA2_IT_GL1);
  }

}

I am using the bit toggles to see the IRQ behaviour on a scope. The Tx IRQ shows up fine.

Thanks in advance!

Outcomes