AnsweredAssumed Answered

STM32L152ZD ADC+DMA makes random values!

Question asked by kupchyk.daniil on Jul 11, 2014
Latest reply on Jul 11, 2014 by kupchyk.daniil
Good day, I have to make ADC+DMA sequence to work with 3 regular channels in the continious circular scan mode. Measured data transfered to the buffer  uint16_t sw_ADC_BUFFER[sw_ADC_CHANNELS] by DMA, and when each transmission is completed DMA calls an interrupt in which buffered data copied to data array uint16_t sw_ADC_DATA[sw_ADC_CHANNELS][sw_ADC_OVER_SAMPLE].
When DMA fullfill data array, interrupt stops transfer.
  
In result array of random values is obtained. 
4095     1955     1735
1614     1901     1967
3635     2559     2219
676          1668     1788
4095     2846     2335
1622     1937     2016
4095     2673     2300
4095     2831     2329
1980     2232     2109
4095     1851     1890
0          1805     1975
4095     2735     2284
96          1803     2287
1715     1929     1991
2847     2429     2310
544          1856     2027
2704     2407     2314
4095     2846     2337
4095     2824     2325
2152     2143     2052

Only first ADC channel connected to the voltage source with value of 2.16 V, another are floating, measured data looks abnormal, no zeros for second and third ADC inputs. 

Can you help me to find mistakes?

My code:

Listing: "adc.h"

#ifndef __SW_ADC_H
#define __SW_ADC_H


#ifdef __cplusplus
 extern "C" {
#endif


#include "stm32l1xx.h"
#include "stm32l1xx_rcc.h"
#include "stm32l1xx_gpio.h"
#include "stm32l1xx_adc.h"
#include "stm32l1xx_dma.h"

#define sw_ADC_OVER_SAMPLE           32
#define sw_ADC_CHANNELS           3
#define sw_ADC_SAMPLING_TIME      ADC_SampleTime_384Cycles
#define sw_ADC_DELAY               ADC_DelayLength_7Cycles
#define ADC1_DR_ADDRESS              ((uint32_t)0x40012458)

uint32_t sw_ADC_CURRENT_SAMPLE;
uint16_t sw_ADC_BUFFER[sw_ADC_CHANNELS];
uint16_t sw_ADC_DATA[sw_ADC_CHANNELS][sw_ADC_OVER_SAMPLE];

void sw_adc_init(void);

#ifdef __cplusplus
}
#endif

#endif /* ___SW_ADC_H */

  
Listing "adc.c"

#include "sw_adc.h"

void sw_adc_init(void)
{
  /*
     PC0   ------> ADC_IN10    ------> ADC_1_1
     PC1   ------> ADC_IN11    ------> ADC_1_2
     PC2   ------> ADC_IN12    ------> ADC_1_3               
 */


/// [1]***********************************************************************
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

  GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;
  GPIO_Init(GPIOC, &GPIO_InitStruct);
/// [1] **********************************************************************

/// [2] *********************************************************************
    RCC_HSICmd(ENABLE);                                    
    while (!RCC_GetFlagStatus(RCC_FLAG_HSIRDY)); 
/// [2]**********************************************************************

/// [3] *********************************************************************
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    ADC_Cmd(ADC1, ENABLE);
    while( ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) != 1){};
/// [3]*********************************************************************

/// [4] *******************************************************************
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
/// [4] *******************************************************************

/// [5] *******************************************************************
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&sw_ADC_BUFFER[0];
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = sw_ADC_CHANNELS;
    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);

   DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, ENABLE);
/// [5] ********************************************************************

/// [6] ********************************************************************
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

       ADC_InitTypeDef ADC_InitStruct;
       ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
       ADC_InitStruct.ADC_ScanConvMode = ENABLE;
       ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
       ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
       ADC_InitStruct.ADC_ExternalTrigConv = 0;
       ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
       ADC_InitStruct.ADC_NbrOfConversion = sw_ADC_CHANNELS;
       ADC_Init(ADC1, &ADC_InitStruct);

       ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, sw_ADC_SAMPLING_TIME);
       ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, sw_ADC_SAMPLING_TIME);
       ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, sw_ADC_SAMPLING_TIME);

       ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
       ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_7Cycles);
       ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE);
       ADC_DMACmd(ADC1, ENABLE);// Enable ADC1 DMA
       ADC_Cmd(ADC1, ENABLE);// Enable ADC1

       while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS));

       ADC_SoftwareStartConv(ADC1);          
       DMA_Cmd(DMA1_Channel1, ENABLE);
/// [6] ******************************************************************

  sw_ADC_CURRENT_SAMPLE = 0;
}

void DMA1_Channel1_IRQHandler(void)
{
   if(DMA_GetITStatus(DMA1_IT_TC1))
   {
        DMA_ClearITPendingBit( DMA1_IT_TC1);
        DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, DISABLE);

        if(sw_ADC_CURRENT_SAMPLE < sw_ADC_OVER_SAMPLE)
        {
             sw_ADC_DATA[0][sw_ADC_CURRENT_SAMPLE] = sw_ADC_BUFFER[0];
             sw_ADC_DATA[1][sw_ADC_CURRENT_SAMPLE] = sw_ADC_BUFFER[1];
             sw_ADC_DATA[2][sw_ADC_CURRENT_SAMPLE] = sw_ADC_BUFFER[2];
        }
        sw_ADC_CURRENT_SAMPLE++;
        DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, ENABLE);

        if(sw_ADC_CURRENT_SAMPLE >= sw_ADC_OVER_SAMPLE)
        {
        DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, DISABLE);
        DMA_DeInit(DMA1_Channel1);
        ADC_DeInit(ADC1);
        }
   }

   if(DMA_GetITStatus(DMA1_IT_HT1))
      {
        DMA_ClearITPendingBit( DMA1_IT_HT1);
      }
}


Calls it in main:

int main(void)
{
     sw_adc_init();     
     while(1){}
}

Outcomes