AnsweredAssumed Answered

DMA and Direct Mode

Question asked by price.andrew on Aug 7, 2013
Latest reply on Apr 21, 2016 by wired
I'm confused about the FIFO error flag (FEIF) when I set up DMA for direct mode transfers.  As I understand it, in direct mode the FIFO is disabled.  But for some reason, if I enable the FE interrupt in the DMA_SxFCR register then shortly after I enable DMA I see the FIFO error flag get set.  Any ideas why?  Is this flag a don't care in direct mode?

To give you an idea of the application, I store a bunch of data in a SPI flash that I send to a codec over I2S.  The I2S transfer happens using DMA.  The code I'm using to set everything up is below.

/* Initialize I2S GPIOs - follow procedure in stm32f4xx_spi.c
 *  I2S_SCLK - Port B, Pin 10 (pin13)
 *  I2S_WS - Port B, Pin 12
 *  I2S_SDO - Port C, Pin 3 (Port B, Pin 15)
 *  I2S_SDI - (Port B, Pin 14)
 *  I2S_MCLK - Port C, Pin 6
*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOC, &GPIO_InitStructure);
 
GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_SPI2);
 
/* Initialize the I2S Peripheral */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
 
SPI_I2S_DeInit(SPI2);
I2S_InitStructure.I2S_AudioFreq = SAMPLING_RATE;
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_MasterTx;
I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
I2S_Init(SPI2, &I2S_InitStructure);
 
RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S);
RCC_PLLI2SCmd(ENABLE);
while(!RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY));
 
/* Configure DMA for I2S transactions */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
DMA_Cmd(DMA1_Stream4, DISABLE);
DMA_DeInit(DMA1_Stream4);
 
/* Set the parameters to be configured */
DMA_InitStructure_Tx.DMA_Channel = DMA_Channel_0;
DMA_InitStructure_Tx.DMA_PeripheralBaseAddr = 0x4000380C;
DMA_InitStructure_Tx.DMA_Memory0BaseAddr = (uint32_t)0;
DMA_InitStructure_Tx.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure_Tx.DMA_BufferSize = (uint32_t)0xFFFF;
DMA_InitStructure_Tx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure_Tx.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure_Tx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure_Tx.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure_Tx.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure_Tx.DMA_Priority = DMA_Priority_High;
DMA_InitStructure_Tx.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure_Tx.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
DMA_InitStructure_Tx.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure_Tx.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream4, &DMA_InitStructure_Tx);
 
/* Enable the DMA interrupts */
DMA_ITConfig(DMA1_Stream4, DMA_IT_TC | DMA_IT_TE | DMA_IT_FE | DMA_IT_DME, ENABLE);
 
/* I2S DMA IRQ Channel configuration */
NVIC_EnableIRQ(DMA1_Stream4_IRQn);
 
/* Enable the I2S DMA request */
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

Then later to actually enable DMA I have the following:
/* Set the memory address and size for DMA transfer
     * NOTE: Stream must be disabled to change these parameters! */
    DMA_InitStructure_Tx.DMA_Memory0BaseAddr = dma_addr0;
    DMA_InitStructure_Tx.DMA_BufferSize = dma_size;
    DMA_DoubleBufferModeConfig(DMA1_Stream4, dma_addr1, 0);
    DMA_DoubleBufferModeCmd(DMA1_Stream4, ENABLE);
    DMA_Init(DMA1_Stream4, &DMA_InitStructure_Tx);
 
   // PRINT OUT REGISTERS & TOGGLE GPIO
 
    /* Enable DMA Stream and I2S Peripheral */
    DMA_Cmd(DMA1_Stream4, ENABLE);
    if ((SPI2->I2SCFGR & 0x0400) == 0) {
        I2S_Cmd(SPI2, ENABLE);
    }

I print out all the DMA/I2S registers right before I enable them and everything looks the way it should:
DMA Regs
LISR: 0x00000000
HISR: 0x00000000
LIFCR: 0x00000000
HIFCR: 0x00000000
CR: 0x00062D56
NDTR: 0x00000200
PAR: 0x4000380C
M0AR: 0x20001464
M1AR: 0x20001864
FCR: 0x000000A0

I2S Regs
CR2: 0x00000002
SR: 0x00000002
DR: 0x00000000
I2SCFGR: 0x00000A00
I2SPR: 0x00000204

Outcomes