AnsweredAssumed Answered

DMA Double Buffer Problem

Question asked by roroland on Jun 27, 2013
Latest reply on Oct 21, 2014 by Clive One
Hi there,

first of all, thanks for the useful information in this forum. You already helped me a lot for my first steps with the STM32F4 discovery board.

I set up SPI with an external ADC using DMA.
The STM32F4 is the SPI master.
SPI_Enable/Disable is triggered by an external interrupt.
DMA is working, when using a single buffer.

Here's the problem:
I now try to use the DMA double buffer mode, but it doesn't work as expected. As far as I understood from some posts and the manual, the active buffer should be switched automatically when the transfer complete flag is set. But in my case this does not happen.
For test purpose I make debug output in 
     DMA1_Stream3_IRQHandler (see below)
expecting the terminal to show alternating "*.*.*.", but in effect, I only get "*******" and only aRxBuffer[0] receives the data, whereas aRxBuffer[1] stays unaffected.
I don't see why. Can you help, please?

Kind regards,
Roland

Here is part of the code:


//##############
// used makros
//##############


     #define SPIadc                           SPI2
     #define SPIadc_IRQn                      SPI2_IRQn
     #define SPIadc_IRQHANDLER                SPI2_IRQHandler


     #define SPIadc_SCK_PIN                   GPIO_Pin_10
     #define SPIadc_SCK_GPIO_PORT             GPIOB
     #define SPIadc_SCK_GPIO_CLK              RCC_AHB1Periph_GPIOB
     #define SPIadc_SCK_SOURCE                GPIO_PinSource10
     #define SPIadc_SCK_AF                    GPIO_AF_SPI2


     #define SPIadc_MISO_PIN                  GPIO_Pin_14
     #define SPIadc_MISO_GPIO_PORT            GPIOB
     #define SPIadc_MISO_GPIO_CLK             RCC_AHB1Periph_GPIOB
     #define SPIadc_MISO_SOURCE               GPIO_PinSource14
     #define SPIadc_MISO_AF                   GPIO_AF_SPI2


     #define SPIadc_DMA                       DMA1
     #define SPIadc_DMA_CLK                   RCC_AHB1Periph_DMA1
     #define SPIadc_RX_DMA_CHANNEL            DMA_Channel_0
     #define SPIadc_RX_DMA_STREAM             DMA1_Stream3
     #define SPIadc_RX_DMA_FLAG_TCIF          DMA_FLAG_TCIF3
     #define SPIadc_DMA_IRQn                               DMA1_Stream3_IRQn


     //!Input to STM32 
     #define ADC_AD7665_BUSY_PIN                    GPIO_Pin_5
     #define ADC_AD7665_BUSY_PORT               GPIOE
     #define ADC_AD7665_BUSY_CLK                RCC_AHB1Periph_GPIOE


     #define EXTI9_5_Enable                          NVIC_EnableIRQ(EXTI9_5_IRQn)
     #define EXTI9_5_Disable                     NVIC_DisableIRQ(EXTI9_5_IRQn)


//##############
// global variable
//##############     
__IO uint16_t aRxBuffer[2][BUFFERSIZE];  
     


//##############
// SPI & DMA Configuration
//##############
  GPIO_InitTypeDef GPIO_InitStructure;
  DMA_InitTypeDef  DMA_InitStructure;
     SPI_InitTypeDef  SPI_InitStructure;
     NVIC_InitTypeDef NVIC_InitStructure;


  /* Peripheral Clock Enable -------------------------------------------------*/
  
     /* Enable the SPI clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
  
  /* Enable GPIO clocks */
  RCC_AHB1PeriphClockCmd(SPIadc_SCK_GPIO_CLK  | SPIadc_MISO_GPIO_CLK, ENABLE);
  
  /* Enable DMA clock */
  RCC_AHB1PeriphClockCmd(SPIadc_DMA_CLK, ENABLE);


  /* SPI GPIO Configuration --------------------------------------------------*/
 
  /* Connect SPI pins to AF5 */  
  GPIO_PinAFConfig(SPIadc_SCK_GPIO_PORT,  SPIadc_SCK_SOURCE,  SPIadc_SCK_AF);
      GPIO_PinAFConfig(SPIadc_MISO_GPIO_PORT, SPIadc_MISO_SOURCE, SPIadc_MISO_AF);


  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;


  /* SPI SCK pin configuration */
  GPIO_InitStructure.GPIO_Pin = SPIadc_SCK_PIN;
  GPIO_Init(SPIadc_SCK_GPIO_PORT, &GPIO_InitStructure);
  
      /* SPI  MISO pin configuration */
  GPIO_InitStructure.GPIO_Pin =  SPIadc_MISO_PIN;
  GPIO_Init(SPIadc_MISO_GPIO_PORT, &GPIO_InitStructure);
 
  /* SPI configuration -------------------------------------------------------*/
  SPI_I2S_DeInit(SPIadc);
     SPI_StructInit(&SPI_InitStructure);
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;
  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_2;
  SPI_InitStructure.SPI_FirstBit  = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_InitStructure.SPI_Mode            = SPI_Mode_Master;
  SPI_Init(SPIadc, &SPI_InitStructure);
  
  //! DMA configuration 
  //! Deinitialize DMA Streams 
  DMA_DeInit(SPIadc_RX_DMA_STREAM);
  
  //! Configure DMA Initialization Structure 
     DMA_StructInit(&DMA_InitStructure);
  DMA_InitStructure.DMA_BufferSize                          = BUFFERSIZE ;
  DMA_InitStructure.DMA_FIFOMode                               = DMA_FIFOMode_Disable ;
  DMA_InitStructure.DMA_FIFOThreshold                = DMA_FIFOThreshold_1QuarterFull ;
  DMA_InitStructure.DMA_MemoryBurst                  = DMA_MemoryBurst_Single ;
  DMA_InitStructure.DMA_MemoryDataSize                = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryInc                          = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_Mode                                        = DMA_Mode_Circular;
  DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t) (&(SPIadc->DR)) ;
  DMA_InitStructure.DMA_PeripheralBurst           = DMA_PeripheralBurst_Single;
  DMA_InitStructure.DMA_PeripheralDataSize      = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_PeripheralInc                = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_Priority                               = DMA_Priority_High;
  //!  Configure RX DMA 
  DMA_InitStructure.DMA_Channel                               = SPIadc_RX_DMA_CHANNEL ;
  DMA_InitStructure.DMA_DIR                                         = DMA_DIR_PeripheralToMemory ;
  DMA_InitStructure.DMA_Memory0BaseAddr           = (uint32_t)&aRxBuffer[0] ; 
     DMA_Init(SPIadc_RX_DMA_STREAM, &DMA_InitStructure);


     //! Configure DMA Double Buffer     
     DMA_DoubleBufferModeConfig(SPIadc_RX_DMA_CHANNEL, (uint32_t)&aRxBuffer[1], DMA_Memory_0);
  DMA_DoubleBufferModeCmd(SPIadc_RX_DMA_CHANNEL, ENABLE);


     NVIC_InitStructure.NVIC_IRQChannel                                               = SPIadc_DMA_IRQn;
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
     NVIC_InitStructure.NVIC_IRQChannelSubPriority                 = 0;
     NVIC_InitStructure.NVIC_IRQChannelCmd                                     = ENABLE;
     NVIC_Init(&NVIC_InitStructure);
      
  //! Enable the GPIO for ADC_AD7665_BUSY signal
  RCC_AHB1PeriphClockCmd(ADC_AD7665_BUSY_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin   = ADC_AD7665_BUSY_PIN;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADC_AD7665_BUSY_PORT, &GPIO_InitStructure);     


//##############
// startup inside main:
//############## 


     //!SPIadc will be enabled by some interrupt
     SPI_Cmd(SPIadc, DISABLE); 
     
     //!Enable DMA Rx Stream for SPIadc 
     DMA_Cmd(SPIadc_RX_DMA_STREAM,ENABLE);  
     
     //!Enable DMA transfer complete interrupt
     DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);
     
     //!Enable SPIadc DMA Rx Request
     SPI_I2S_DMACmd(SPIadc, SPI_I2S_DMAReq_Rx, ENABLE);
     
     if(DMA_GetCmdStatus == DISABLE)
     {
          printf("DMA_GetCmdStatus = DISABLED \n\r");
          while(DMA_GetCmdStatus == DISABLE)
                    {/*wait for the stream to be enabled */;}
     }
     printf("DMA_GetCmdStatus = ENABLED \n\r");


//##############
// DMA transfer complete interrupt:
//############## 
     
void DMA1_Stream3_IRQHandler(void)
{
     if (DMA_GetITStatus(DMA1_Stream3, DMA_FLAG_TCIF3) == RESET)
     {
          STM_EVAL_LEDToggle(LED3);
          
          EXTI9_5_Disable;
     
          DMA_ClearFlag(DMA1_Stream3, DMA_FLAG_TCIF3);
          DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
          
          if (DMA_GetCurrentMemoryTarget(DMA1_Stream3) == 0)
          {
               printf("*");
               // always ends up here
          }
          else
          {
               printf(".");
               // never gets here
          }
          EXTI9_5_Enable;
     }     
}     

Outcomes