AnsweredAssumed Answered

STM32L152 ADC DMA restart question

Question asked by Mikk Leini on Aug 20, 2013
Latest reply on Aug 20, 2013 by Mikk Leini
Hi,

I'm trying to implement ADC multichannel scan (single sampling) with DMA on STM32L152 but there's a problem with conversions start. First SW conversion start takes the samples but following start command doesn't seem to have effect. I found a workaround by disabling and re-enabling DMA before starting following scans but it doesn't seem an elegant solution. Here'se the code:

/* Includes ------------------------------------------------------------------*/
#include "stm32l1xx.h"
#include "power.h"
 
/* Private define ------------------------------------------------------------*/
#define ADC1_DR_ADDRESS       ((uint32_t)0x40012458)
 
/* Private macro -------------------------------------------------------------*/
#define PWR_CTRL_PIN          GPIO_Pin_11
#define PWR_CTRL_GPIO_PORT    GPIOB
#define PWR_CTRL_GPIO_CLK     RCC_AHBPeriph_GPIOB
 
#define CHG_STAT_PIN          GPIO_Pin_9
#define CHG_STAT_GPIO_PORT    GPIOC
#define CHG_STAT_GPIO_CLK     RCC_AHBPeriph_GPIOC
 
#define UBAT_PIN              GPIO_Pin_1
#define UBAT_GPIO_PORT        GPIOB
#define UBAT_GPIO_CLK         RCC_AHBPeriph_GPIOB
#define UBAT_ADC_CHANNEL      ADC_Channel_9
 
/* Private variables ---------------------------------------------------------*/
static GPIO_InitTypeDef GPIO_InitStructure;
static DMA_InitTypeDef DMA_InitStructure;
static ADC_InitTypeDef  ADC_InitStructure;
static __IO uint16_t ADC_ConvertedValue[3];
static uint16_t Voltage;
static uint16_t Temperature;
static uint16_t RefVoltage;
 
/**
  * @brief  Power control initialization. 
  * @retval None
  */
void Power_Init(void)
{
  /* PWR_CTRL and CHG_STAT clock enable */
  RCC_AHBPeriphClockCmd(PWR_CTRL_GPIO_CLK |
            CHG_STAT_GPIO_CLK | UBAT_GPIO_CLK, ENABLE);
   
  /* PWR_CTRL   output pin configuration */
    GPIO_InitStructure.GPIO_Pin = PWR_CTRL_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz; 
  GPIO_Init(PWR_CTRL_GPIO_PORT, &GPIO_InitStructure);
     
    /* CHG_STAT input pin configuration */
    GPIO_InitStructure.GPIO_Pin = CHG_STAT_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_Init(CHG_STAT_GPIO_PORT, &GPIO_InitStructure);  
     
    /* UBAT input pin configuration */
    GPIO_InitStructure.GPIO_Pin = UBAT_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_Init(UBAT_GPIO_PORT, &GPIO_InitStructure);  
     
    /*------------------------ DMA1 configuration ------------------------------*/
   
    /* Enable DMA1 clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
     
  /* DMA1 channel1 configuration */
  DMA_DeInit(DMA1_Channel1);
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue[0];
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 3;
  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_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure); 
     
  /* Enable DMA1 channel1 */
  DMA_Cmd(DMA1_Channel1, ENABLE);
     
    /*----------------- ADC1 configuration with DMA enabled --------------------*/
     
    /* Enable The HSI (16Mhz) */
  RCC_HSICmd(ENABLE);
   
  /* Check that HSI oscillator is ready */
  while (!RCC_GetFlagStatus(RCC_FLAG_HSIRDY));
     
    /* Enable ADC1 clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
     
  /* ADC1 Configuration -----------------------------------------------------*/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_ExternalTrigConv = 0;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 3;
  ADC_Init(ADC1, &ADC_InitStructure);
     
    /* Enable temperature sensor and Vref */
    ADC_TempSensorVrefintCmd(ENABLE);
     
    /* ADC1 regular channel configuration */
  ADC_RegularChannelConfig(ADC1, UBAT_ADC_CHANNEL,       1, ADC_SampleTime_24Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, 2, ADC_SampleTime_24Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint,    3, ADC_SampleTime_24Cycles);
     
    /* Enable the request after last transfer for DMA Circular mode */
  //ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); /* Causes problem.. */
     
  /* Define delay between ADC1 conversions */
  ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_7Cycles);
   
  /* Enable ADC1 Power Down during Delay */
    ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE);  
         
  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);
 
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
     
    /* Wait until the ADC1 is ready */
  while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS));
}
 
 
/**
  * @brief  Power periodic task
  * @param  Period: Task execution period in milliseconds 
  */
void Power_Task(uint32_t Period)
{  
    /* Conversion done ? */
  if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
  {            
        Voltage     = (ADC_ConvertedValue[0] * 3300 * 2) / 4095;
        Temperature = ADC_ConvertedValue[1];
        RefVoltage  = ADC_ConvertedValue[2];
                 
        ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
         
        /* Reset DMA - not certain if this is the right way but it works */
        ADC_DMACmd(ADC1, DISABLE);
        ADC_DMACmd(ADC1, ENABLE);
  }
     
    /* Start ADC1 Software Conversion */
    ADC_SoftwareStartConv(ADC1);
}


I can't find any better solution from manual nor internet, does anybody know how to implement it properly? It's also strange that in task i have to continously call the SW start because if doing it once in initialization the conversion does not start...

Outcomes