cancel
Showing results for 
Search instead for 
Did you mean: 

DMA and Direct Mode

andprice
Associate II
Posted on August 07, 2013 at 21:21

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 #dma-fe-error
7 REPLIES 7
Amel NASRI
ST Employee
Posted on September 12, 2013 at 12:13

Hi Andrew,

In your case, try to disable all interrupts and keep only the needed one(s).

Then you have to check in the ISR that the flag you use is enabled.

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

isaac23
Associate
Posted on June 20, 2014 at 23:57

Mayla,

Your advice, of course, is good... you only want to enable interrupts that you can/want to use.

I would observe, however, that the Cube firmware takes much of that choice away from the developer.  In particular, if you look at stm32f4xx_hal_dma.c near line 400, you will see that DMA_IT_FE is always enabled, whether FIFOMODE was enabled or not.

My application shows the same sort of problems as described in the original post here... an endless stream of FE interrupts, even though FIFOMODE is not even enabled.

The HAL code needs to be corrected to do something like:

  if (hdma->Init.FIFOMode == DMA_FIFOMODE_ENABLE)

  {

     __HAL_DMA_ENABLE_IT(hdma, DMA_IT_FE);

  }

Looking a bit beyond that simple HAL bugfix, though, one has to ask: why is the DMA controller sending this endless stream of FE interrupts when you've explicitly told it that you don't want FIFOMODE?  This sounds like a bug in the DMA controller itself.

jpeacock2399
Associate II
Posted on June 21, 2014 at 00:23

The FE error you see is a signal that the FIFO has dropped below the threshold.  Why this occurs in direct mode doesn't make a lot of sense.  Look at the DMA_SxFCR register, fields FS and FTH.  If FS is below the FTH setting then FE can be ignored.

  Jack Peacock
isaac23
Associate
Posted on June 23, 2014 at 16:20

Jack,

That's the sort of thing I did in my first pass at a fix to my code.  Spurious interrupts take resources, though.  It's the HAL code that should be amended.  Obviously, I've done that in my version, but the distribution version should also be corrected.

jpeacock2399
Associate II
Posted on June 24, 2014 at 15:45

In direct mode you disable FE interrupt and enable DME so it's not really a spurious interrupt.  The FE bit is set but can safely be ignored in direct mode.

  Jack Peacock

kevin2399
Associate III
Posted on April 21, 2016 at 23:35

After spending the last two days (and nights) trying to figure out why my SPI DMA transfers were only delivering up to five bytes, I finally stumbled upon the right keywords to find this thread.

''Surely ST would have corrected their Cube code generator by now, since it's almost been a year since this was reported (and acknowledged)...'', I said to myself.  However the problem still exists for F7 generated code using version 1.3.1 (current as of today).

I even looked at the example in the package for the F746-DISCO that showed SPI DMA full duplex communications.  Note to everyone who tries to use this model to communicate with a device that actually uses a chip select (conveniently not used in this example) - if you rely on their wTransferComplete flag to set NSS high, you will sometimes see CS go high early, cutting off the last byte.  If you ALSO wait for the HAL_SPI_GetState(&hspi) to return HAL_SPI_STATE_READY, you will still sometimes issue your NSS high before the data is clocked out (verified on scope with protocol analyzer).

At least I am no longer having my spi streams cut off early after making sure the FIFO error interrupt didn't get enabled.  I not have yet another section of code that needs to be modified every time I update my cube configuration and regenerate code.  Lots of fun.

Now if I can only figure out what to monitor before taking my NSS high... 

EStei.3
Associate III

Dear ST-Support,

are you kidding me???
This bug was reported in 2013 and I found the thread because it is still present in the most recent HAL version (STM32F7xx_HAL_Driver v1.17.1).
That's 11 years!
And isaac23 even gave you a fix.

I hope you'll finally fix it, now that I brought it up again, but as history shows it, will most likely be ignored...