AnsweredAssumed Answered

I2S DMA Problems

Question asked by rohrauer.manuel on May 28, 2013
Latest reply on Nov 16, 2016 by w.johan
Hi guys,

I'm in a bit of a crisis to get I2S working with DMA.
I want to transfer Data from a TxBuffer array to the SPI3->DR Peripheral

My setup is:
       
  • I2S3 Interface
  •    
  • DMA Dir Mem2Peripheral
  •    
  • DMA Interrupt on DMA_IT_TC
  •    
  • DMA in Double Buffered Mode
  •    
  • No Fifo
The Problem is, that the Interrupt is never called, so I guess the DMA isn't working and the DMACounter isn'T counting to zero (so no interrupt is called can be called)
Here is my Code:

Defines:
#define Audio_DMA_I2S3_Stream           DMA1_Stream5
#define Audio_DMA_I2S3ext_Stream        DMA1_Stream2
#define Audio_DMA_I2S3_Channel          DMA_Channel_0
#define Audio_DMA_I2S3ext_Channel       DMA_Channel_2
#define Audio_DMA_I2S3_IRQ              DMA1_Stream5_IRQn
#define Audio_DMA_I2S3ext_IRQ           DMA1_Stream2_IRQn


Initialization:
GPIO_Configuration();
I2S_Configuration();
DMA_Configuration();


GPIO_Coinfiguration:
GPIO_InitTypeDef GPIO_InitStructure;
 
// Enable peripheral clocks
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);  // TODO: fix, enable alternate function clock
 
// Configure alternative functions for I2S3 pins
GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_SPI3);  // I2S3_WS
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7,  GPIO_AF_SPI3);  // I2S3_MCK
GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SPI3);  // I2S3_CK
GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SPI3);  // I2S3_ext_SD
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SPI3);  // I2S3_SD
 
//GPIO_PinAFConfig(GPIOC, GPIO_PinSource9,  GPIO_AF_SPI3); /* I2S_CKIN - needed?? */
 
// Configure pins as alternate function
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // TODO: fix
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOA, &GPIO_InitStructure);
 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_Init(GPIOC, &GPIO_InitStructure);


I2S_Configuration:
I2S_InitTypeDef I2S_InitStructure;
 
// Enable SPI3/I2S3
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
 
// I2S3 peripheral configuration
SPI_I2S_DeInit(SPI3);
I2S_InitStructure.I2S_Standard    = I2S_Standard_Phillips;
I2S_InitStructure.I2S_DataFormat  = I2S_DataFormat_16b;
I2S_InitStructure.I2S_AudioFreq   = I2S_AudioFreq_8k;
I2S_InitStructure.I2S_CPOL        = I2S_CPOL_Low;
I2S_InitStructure.I2S_MCLKOutput  = I2S_MCLKOutput_Enable;
I2S_InitStructure.I2S_Mode        = I2S_Mode_MasterTx;
I2S_Init(SPI3, &I2S_InitStructure);
I2S_FullDuplexConfig(I2S3ext, &I2S_InitStructure);
 
// Hook up I2S3 to DMA buffers
SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE);
SPI_I2S_DMACmd(I2S3ext, SPI_I2S_DMAReq_Rx, ENABLE);


DMA_Configuration:
DMA_InitTypeDef DMA_InitStructure;
 NVIC_InitTypeDef NVIC_InitStructure;
    
 // Enable DMA
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
 
 // Common initialization
 DMA_InitStructure.DMA_BufferSize = AUDIO_BUFFER_SIZE;
 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_MemoryBurst = DMA_MemoryBurst_Single;
 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
 
 
 /* DMA configuration for input & output if I2S data. Configure each DMA channel to use double-buffered mode
  * in circular mode. This allows the software codec read/write operation form the one memory while the DMA
  * is reading/writing to the other memory. */
 
 // I2S3 - DMA configuration for sending data to the codec/speaker
 DMA_Cmd(Audio_DMA_I2S3_Stream, DISABLE);   
 DMA_DeInit(Audio_DMA_I2S3_Stream);
 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
 DMA_InitStructure.DMA_Channel = Audio_DMA_I2S3_Channel; 
 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &SPI3->DR;  // SPI data register for sending
 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &audio_Tx_Buffer[AUDIO_BUFFER_0][0];
  
 DMA_DoubleBufferModeConfig(Audio_DMA_I2S3_Stream, (uint32_t) &audio_Tx_Buffer[AUDIO_BUFFER_1][0], DMA_Memory_0);
 DMA_DoubleBufferModeCmd(Audio_DMA_I2S3_Stream, ENABLE);
 DMA_Init(Audio_DMA_I2S3_Stream, &DMA_InitStructure);
 
 // I2S3ext - DMA configuration for reading data from the codec/microphone
 DMA_Cmd(Audio_DMA_I2S3ext_Stream, DISABLE);       
 DMA_DeInit(Audio_DMA_I2S3ext_Stream);  
 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
 DMA_InitStructure.DMA_Channel = Audio_DMA_I2S3ext_Channel; 
 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &I2S3ext->DR;
 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &audio_Rx_Buffer[AUDIO_BUFFER_0][0];
  
 DMA_DoubleBufferModeConfig(Audio_DMA_I2S3ext_Stream, (uint32_t) &audio_Rx_Buffer[AUDIO_BUFFER_1][0], DMA_Memory_0);
 DMA_DoubleBufferModeCmd(Audio_DMA_I2S3ext_Stream, ENABLE);
 DMA_Init(Audio_DMA_I2S3ext_Stream, &DMA_InitStructure);
 
 // NVIC: Configure the DMA interrupt priority
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  
 // DMA interrupt for sending data to speaker
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannel = Audio_DMA_I2S3_IRQ;
 NVIC_Init(&NVIC_InitStructure);
 
 // DMA interrupt for reading data from microphone
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
 NVIC_InitStructure.NVIC_IRQChannel = Audio_DMA_I2S3ext_IRQ;
 NVIC_Init(&NVIC_InitStructure);


ISR: (It is never called)
extern "C" void DMA1_Stream5_IRQHandler(void) { 
  uint32_t memory = DMA_GetCurrentMemoryTarget(Audio_DMA_I2S3_Stream);
  DMA_ClearITPendingBit(Audio_DMA_I2S3_Stream, DMA_FLAG_TCIF5);
}

To start the DMA transfer I call:
DMA_ITConfig(Audio_DMA_I2S3_Stream, DMA_IT_TC, ENABLE);   // Enable/Disable DMA Interrupts
DMA_Cmd(Audio_DMA_I2S3_Stream, ENABLE);                   // Enable/Disable DMA
I2S_Cmd(SPI3, ENABLE);                                    // Enable/Disable I2S


I really hope you guys can help me. I read the datasheet carefully and I thought I haven't made a mistake.
Unfortunately anythere must be one. I hope someone could find it.

Thanks a lot & Best Regards,
Manuel

Outcomes