AnsweredAssumed Answered

STM32f4 ADC & DMA multi channel - problem with reading the values

Question asked by mueller.johannes.001 on Dec 23, 2014
Latest reply on Dec 24, 2014 by mueller.johannes.001
Hi everybody. I'm new here in this forum and also new in working with a STM32f4 Disco.

I got a small question about using ADC and DMA. I did already read the threads on this forum about problem with ADC & DMA but got not the right result for my usage.

About my projekt: I want to read 5 or 7 different voltages from sensors. The voltage is between 0 V and 3 V so it should not be a big problem. To test it I want to read the voltages, convert them and print them on the display.

I decided to use ADC1 and DMA2 (stream0) and want to work with a regular channel group.

On my display there are 5 values now. If no voltage is at the pins all values are about 0.
The problem is that if i connect one pin with a value between 0 V and 3 V the value of the other channels are increasing aswell.

For example if i put 3 V on pin 1 he will show me a value about 4095 (12 bit). But also the next pin will give me a value of 3500-4000. 

I already switched pins because I realized that some pins are already occupied with other functions.

The pins I used are:
PA1 (IN1)
PA2 (IN2)
PA3 (IN3)
PC1 (IN11)
PC2 (IN12)

the datasheet says those pins are NOT used.


Maybe anyone got an idea what I did wrong and can help me with a solution. 

This would be great.

Otherwise I wish you all a merry christmas :-)


Best regards



Here my code:


...


//Struktur für Values
typedef struct ADCValues{
     int16_t channel_1 ;
     int16_t channel_2 ;
     int16_t channel_3 ;
     int16_t channel_11 ;
     int16_t channel_12 ;
} ADCValues_t;



// der DMA Stream schreibt hier rein
volatile ADCValues_t ADCRead;


//Variablen in denen ausgegebener Wert gespeichert wird
static int16_t ADC_Result_1 = 0;
static int16_t ADC_Result_2 = 0;
static int16_t ADC_Result_3 = 0;
static int16_t ADC_Result_4 = 0;
static int16_t ADC_Result_5 = 0;


//--------------------------------------------------------------
// Einsprungpunkt des Programms
//--------------------------------------------------------------
int main(void)
{

  SystemInit(); // Quarz Einstellungen aktivieren

  //Initialisierung der Ports
  InitGPIOA();
  InitGPIOC();

  //Initialisierung des ADC1 und DMA2
  Init_ADCandDMA();

...     
 
  while(1)


  {


  }
}




//--------------------------------------------------------------
// Initialisierung der GPIO PORTS
//--------------------------------------------------------------

void Initclock_GPIO (void)
    {
         RCC_HSEConfig(RCC_HSE_ON);
         while(!RCC_WaitForHSEStartUp());
    }

//
//Initialisierung von GPIOA
//
void InitGPIOA (void)
     {
          //Input definieren für drei der fünf analoge Eingänge PA1(IN1), PA2(IN2), PA3(IN3)
         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);


         GPIO_InitTypeDef GPIO_InitStructure;
                         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2| GPIO_Pin_3;     //Pins für ADC Eingänge
                         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                              // _IN  _AF:Alternate  _AN:Analog
                         //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                         // _2MHz  _10MHz  _25MHz  _50MHz  _100MHz
                         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                             // _PP:Push/Pull _OD:OpenDrain
                         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                    // _No Pull       _UP   _DOWN
         GPIO_Init(GPIOA,&GPIO_InitStructure);
     }

/
//Initialisierung von GPIOC
//
void InitGPIOC(void)
     {
          //Input definieren für zwei der fünf analoge Eingänge PC1(IN11), PC2(IN12)
          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);


          GPIO_InitTypeDef GPIO_InitStructure;
                         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;           //GPIO_Pin_0 ist USB
                         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                    // _IN  _AF:Alternate  _OUT:Output
                         //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;          // _2MHz  _10MHz  _25MHz  _50MHz  _100MHz
                         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                    // _PP:Push/Pull _OD:OpenDrain
                         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;               // _No Pull       _UP   _DOWN
          GPIO_Init(GPIOC, &GPIO_InitStructure);
     }

//--------------------------------------------------------------
//Initialisierung des ADC's
//--------------------------------------------------------------


void Init_ADCandDMA(void)
     {
     ADC_DeInit();                                                                           //Resetet alle ADC Einstellungen


     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);


     ADC_CommonInitTypeDef ADC_CommonInitStructure;
               ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
               ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;          //AHB2 = 42 MHz     Div2 -> 21 MHz
               ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles;
               ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
     ADC_CommonInit(&ADC_CommonInitStructure);


     ADC_InitTypeDef ADC_InitStructure;
               ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                    //Eingangsspannung in 12bit Wert mit max. Wert von 4096
               ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                    //Kontinuierliche Auswertung aller Regular-Kanäle (in Schleife)
               ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                    //wird _left _right bündig in 16 Bit Register abgespeichert
               ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;          //Signal welches die Wandlung auslösen soll
               ADC_InitStructure.ADC_ExternalTrigConv = 0;
               ADC_InitStructure.ADC_NbrOfConversion = 5;                                   //Anzahl der Kanäle in der "Regular Channel Groupe"
               ADC_InitStructure.ADC_ScanConvMode = ENABLE;                         // ENABLE: Mehrere Kanäle werden im Scan-Modus gewandelt
               ADC_AutoInjectedConvCmd(ADC1, DISABLE);                              //ENABLE: Nach abgearbeiteter Regular Group wird automatisch Injected Group angetriggert
     ADC_Init(ADC1, &ADC_InitStructure);


     //Kanäle werden manuell der Regular Group (bis 16 Kanäle) zugefügt (ADCx, Kanal, Reihenfolge zum Durchlaufen,Sample Time)
     ADC_RegularChannelConfig(ADC1, ADC_Channel_1  ,1 , ADC_SampleTime_144Cycles);     //Wählt Kanal 11 aus (PA1)
     ADC_RegularChannelConfig(ADC1, ADC_Channel_2  ,2 , ADC_SampleTime_144Cycles);     //Wählt Kanal 12 aus (PA2)
     ADC_RegularChannelConfig(ADC1, ADC_Channel_3  ,3 , ADC_SampleTime_144Cycles);     //Wählt Kanal 13 aus (PA3)
     ADC_RegularChannelConfig(ADC1, ADC_Channel_11 ,4 , ADC_SampleTime_144Cycles);     //Wählt Kanal 14 aus (PC1)
     ADC_RegularChannelConfig(ADC1, ADC_Channel_12 ,5 , ADC_SampleTime_144Cycles);     //Wählt Kanal 15 aus (PC2)

     DMA_DeInit(DMA2_Stream0);                                                 //Resetet alle DMA Einstellungen


     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);


     DMA_InitTypeDef       DMA_InitStructure;
          DMA_StructInit(&DMA_InitStructure);
          DMA_InitStructure.DMA_Channel = DMA_Channel_0;
          DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCRead;                    // result memory location
          DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t)&(ADC1->DR);                // source struct
          //DMA_InitStructure.DMA_PeripheralBaseAddr =  (uint32_t)ADC1;                     // source struct
          DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                       // from Peripheral to RAM
          DMA_InitStructure.DMA_BufferSize = 5;                                  /               / 5 vorhandene Kanäle mit CNY 70 Sensor
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                      // Source stays same address
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                         // Destination will be incremented
          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;      // 16 bit results
          DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;      // yeah same size -> 16 bit
          DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                // Wrap around the destination address
          DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                                 //
          DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
          DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
          DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
          DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
     DMA_Init(DMA2_Stream0, &DMA_InitStructure);                                                // Init the stuff finally



     DMA_Cmd(DMA2_Stream0,ENABLE);                         //Aktiviert DMA


     while(DMA_GetCmdStatus(DMA2_Stream0)==DISABLE){};


     ADC_DMACmd(ADC1, ENABLE);
     ADC_Cmd(ADC1, ENABLE);                                   //Aktiviert Wandler ADC1
     ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);


     ADC_ContinuousModeCmd(ADC1,ENABLE);


     ADC_SoftwareStartConv(ADC1);                                   //Triggert erste Wandlung


     }




//--------------------------------------------------------------
// ADC Value read
//--------------------------------------------------------------


void TSK_ADCValue(void *pvParameters)
{
     char buf[20];


     ADC_Result_1 = 0;
     ADC_Result_2 = 0;
     ADC_Result_3 = 0;
     ADC_Result_4 = 0;
     ADC_Result_5 = 0;


     while(1)
     {


     ADC_Result_1 = ADCRead.channel_1;
    sprintf(buf,"Voltage Sensor #1 = %5d",ADC_Result_1);
    GUI_DispStringAt(buf, 50, 80);
    buf [0] = '\0' ;


    ADC_Result_2 = ADCRead.channel_2;
    sprintf(buf,"Voltage Sensor #2 = %5d",ADC_Result_2);
    GUI_DispStringAt(buf, 50, 100);
    buf [0] = '\0' ;


    ADC_Result_3 = ADCRead.channel_3;
    sprintf(buf,"Voltage Sensor #3 = %5d",ADC_Result_3);
    GUI_DispStringAt(buf, 50, 120);
    buf [0] = '\0' ;


    ADC_Result_4 = ADCRead.channel_11;
    sprintf(buf,"Voltage Sensor #4 = %5d",ADC_Result_4);
    GUI_DispStringAt(buf, 50, 140);
    buf [0] = '\0' ;


    ADC_Result_5 = ADCRead.channel_12;
    sprintf(buf,"Voltage Sensor #5 = %5d",ADC_Result_5);
    GUI_DispStringAt(buf, 50, 160);
    buf [0] = '\0' ;


    vTaskDelay(100);


     }
}

Attachments

Outcomes