STM32F4 Discovery ADC 2 Channel DMA

Gast #3066941
Lesenswert?

Hallo habe folgenden Code geschrieben zum Einlesen von ADC Werten von 2 
Kanälen. Leider wird im DMA Array immer nur der erste Wert beschrieben. 
Ich habe schon zig Beispiele durch und finde den Fehler bei mir nicht. 
Fällt jemanden was auf ?

Danke.

uint32_t ADC_BUFF[ADC_Buff_NoOfBytes];

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_PERIPH_GPIOB, ENABLE);

ADC_DeInit();

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

  GPIO_InitStructure.GPIO_Pin = Pin_0;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = Pin_1;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = 
ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = 0;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 2;
  ADC_Init(ADC1, &ADC_InitStructure);

  // ADC Common configuration
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = 
ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInitStructure.ADC_DMAAccessMode = 
ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInit(&ADC_CommonInitStructure);

  ADC_RegularChannelConfig(ADC1,ADC_Chanel_8,1,ADC_SampleTime_3Cycles);

  ADC_RegularChannelConfig(ADC1,ADC_Chanel_9,2,ADC_SampleTime_15Cycles);

  ADC_Cmd(ADC1, ENABLE);   // Enable ADC1

  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

  ADC_DMACmd(ADC1, ENABLE);
  ADC_SoftwareStartConv(ADC1);

    DMA_DeInit(DMA2_Stream4);
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &ADC_BUFF;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = (uint16_t) ADC_Buff_NoOfBytes;
    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_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream4, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream4, ENABLE);
Gast #3066978
Lesenswert?

Die Werte sollen ja ins ADC_BUFF[2] geschrieben werden. Ich 
initialisiere das Array mit {10,10}. Der erste Wert ändert sich dann und 
der zweite bleibt 10.

Also zumindest der Kanal 8 wird richtig ausgelesen.
Gast #3066986
Lesenswert?

Dann wird nur ein Wert übertragen, aso.

Dein Define von ADC_Buff_NoOfBytes wird wohl 2 sein und nicht 4. Das 
sind die Anzahl der Bytes und nicht Worte. Also pro Kanal 16Bit sind 4 
Bytes.
Und da du alles in Half-Words schreibst sollte dein Deklaration:

uint32_t ADC_BUFF[ADC_Buff_NoOfBytes];

uint16_t sein.


Hier ist ein laufendes Beispiel, weiter unten:

https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32F4DISCOVERY/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2FSTM32F4DISCOVERY%2F16%20bit%20result%20from%20ADC&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580002E3D0FFCC5A9AA4A9C29C3EECB7CCDBF&currentviews=1724
Gast #3067069
Lesenswert?

Danke für den Hinweis. Habe jetzt das Halfword in Word geändert und nu 
läufts korrekt ;-)
Der Name ADC_Buff_NoOfBytes war ein wenig verwirrend, eigentlich ist es 
nur die Anzahl der Elemente im enum ;-)
#3230584
Lesenswert?

Sternius schrieb:
> Danke für den Hinweis. Habe jetzt das Halfword in Word geändert und nu
> läufts korrekt ;-)
> Der Name ADC_Buff_NoOfBytes war ein wenig verwirrend, eigentlich ist es
> nur die Anzahl der Elemente im enum ;-)


Da Du den DMA2 verwendest, noch ein kleiner Hinweis:
http://www.st.com/st-web-ui/static/active/en/resource/technical/document/errata_sheet/DM00037591.pdf

DMA2 data corruption when managing AHB and APB peripherals in a
concurrent way
Description
When the DMA2 is managing AHB Peripherals (only peripherals embedding 
FIFOs) and
also APB transfers in a concurrent way, this generates a data corruption 
(multiple DMA
access).STM32F40x and STM32F41x silicon limitations STM32F40x and 
STM32F41x
14/38 Doc ID 022183 Rev 4
When this condition occurs:
• The data transferred by the DMA to the AHB peripherals could be 
corrupted in case of
a FIFO target.
• For memories, it will result in multiple access (not visible by the 
Software) and the data
is not corrupted.
• For the DCMI, a multiple unacknowledged request could be generated, 
which implies
an unknown behavior of the DMA.
AHB peripherals embedding FIFO are DCMI, CRYPTO, and HASH. On sales 
types without
CRYPTO, only the DCMI is impacted. External FIFO controlled by the FSMC 
is also
impacted.
Workaround
Avoid concurrent AHB (DCMI, CRYPTO, HASH, FSMC with external FIFO) and 
APB
transfer management using the DMA2.
Gast #3330139
Lesenswert?

Hallo alle zusammen, ich habe den Quelltext von fast eins zu eins 
übernommen und weiterhin viele weite Beispiele aus dem Internet 
ausprobiert aber ich bekomme den DMA nicht zum laufen. Die ADC 
Umwandlung funktioniert selbst funktioniert bereits. Es wird aber kein 
einziger wert vom DMA übertragen. Hat hier vielleicht noch jemand einen 
Hinweis?

Hier der Quelltext:

void init_adc_test(void)
{
/*********************************************************************** 
*******************************
 *Create structures and initalize them [OK]
 ************************************************************************ 
******************************/

  GPIO_InitTypeDef     GPIO_InitStructure;
  ADC_InitTypeDef   ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef   DMA_InitStructure;

  GPIO_StructInit(&GPIO_InitStructure);
  ADC_StructInit(&ADC_InitStructure);
  ADC_CommonStructInit(&ADC_CommonInitStructure);
  DMA_StructInit(&DMA_InitStructure);

/*********************************************************************** 
*******************************
 * 2.0 Set up the clocks are needed for the ADC [??]
 ************************************************************************ 
******************************/

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);

/*********************************************************************** 
*******************************
 * 3.0 Initialization of the GPIO Pins [OK]
 ************************************************************************ 
******************************/

  /* Analog channel 12 configuration : PC.01    PC.02  PC.04  PC.05 
*/
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | 
GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

 /*********************************************************************** 
*******************************
 * 4.0 Config the ADC1 [OK: Conversation is running (checked the memory 
of the data register)]
 ************************************************************************ 
******************************/

   ADC_DeInit();
   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//data 
converted will be shifted to right
   ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//Input voltage 
is converted into a 12bit number giving a maximum value of 4096
   ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //the conversion 
is continuous, the input data is converted more than once
   ADC_InitStructure.ADC_ExternalTrigConv = 
ADC_ExternalTrigConvEdge_None;
   ADC_InitStructure.ADC_NbrOfConversion = 4;//I think this one is clear 
:p
   ADC_InitStructure.ADC_ScanConvMode = ENABLE;//The scan is configured 
in one channel
   ADC_Init(ADC1,&ADC_InitStructure);//Initialize ADC with the previous 
configuration

   ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
   ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
   ADC_CommonInitStructure.ADC_TwoSamplingDelay = 
ADC_TwoSamplingDelay_5Cycles;
   ADC_CommonInitStructure.ADC_DMAAccessMode = 
ADC_DMAAccessMode_Disabled;
   ADC_CommonInit(&ADC_CommonInitStructure);

   ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1,ADC_SampleTime_3Cycles);
   ADC_RegularChannelConfig(ADC1,ADC_Channel_12,2,ADC_SampleTime_3Cycles);
   ADC_RegularChannelConfig(ADC1,ADC_Channel_14,3,ADC_SampleTime_3Cycles);
   ADC_RegularChannelConfig(ADC1,ADC_Channel_15,4,ADC_SampleTime_3Cycles);

   ADC_Cmd(ADC1, ENABLE);   // Enable ADC1
   ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
   ADC_Cmd(ADC1, ENABLE);   // Enable ADC1
   ADC_SoftwareStartConv(ADC1);

 /*********************************************************************** 
*******************************
 * 5.0 Configure the DMA [ERROR: no transport of the values]
 ************************************************************************ 
******************************/

   //==Configure DMA2 - Stream 4
  DMA_DeInit(DMA2_Stream4); //Set DMA registers to default values
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; 
//Address of peripheral the DMA must map to
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) & 
ADCConvertedValue; //Variable to which ADC values will be stored
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 4; //Buffer size (4 because we 
using two 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_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream4, &DMA_InitStructure); //Initialise the DMA
  DMA_Cmd(DMA2_Stream4, ENABLE); //Enable the DMA2 - Stream 0

}
Gast #3330300
Lesenswert?

Habe noch einen kleinen Fehler gefunden. Ich hatte vergessen den 
foglenden Befehl einzutragen.

   ADC_Cmd(ADC1, ENABLE);   // Enable ADC1
   ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
   ADC_DMACmd(ADC1, ENABLE); //Enable ADC1 DMA           <--Fehlte
   ADC_SoftwareStartConv(ADC1);

Jetzt läuft der DMA. Aber es wird nur ein Wert übertragen. Danach hält 
der ADC an und es wird kein weiterer Wert konvertiert. Idee?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren