Forum: Mikrocontroller und Digitale Elektronik STM32F4 Discovery ADC 2 Channel DMA


von Sternius (Gast)


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);

von Terra (Gast)


Lesenswert?

Moin,

> Leider wird im DMA Array immer nur der erste Wert beschrieben.

Was meinst du damit genau?

Hast du den ADC mal per Hand ausgelesen ob die Werte wirklich ankommen?

von Sternius (Gast)


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.

von Terra (Gast)


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

von Terra (Gast)


Lesenswert?

Nachtrag:

Die 4 Byte brauchst du bei der Initialisierung der DMA:

DMA_InitStructure.DMA_BufferSize = (uint16_t) (ADC_Buff_NoOfBytes*2);

von Sternius (Gast)


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 ;-)

von Ma K. (mk_munich)


Lesenswert?

Hallo, mich interessiert, wie schnell die Werte ausgelesen werden 
können? Kann man evt. eine Zahl in Samples pro Sekunde ermitteln?
Gruss
MK_Munich

von Norbert (Gast)


Lesenswert?

Ma Kra schrieb:
> Hallo, mich interessiert, wie schnell die Werte ausgelesen werden
> können? Kann man evt. eine Zahl in Samples pro Sekunde ermitteln?
> Gruss
> MK_Munich

Muß man nicht ermitteln, ist aus dem Datenblatt ersichtlich.

von Liker (Gast)


Lesenswert?

Und das wäre?

von Ma K. (mk_munich)


Lesenswert?

Im STM32F405xx, STM32F407xx Datenblatt stehen in der Tat einige Werte 
(siehe Tabelle 65)...
Sie gehen von 2 Msps bis 6 Msps bei fADC = 30 MHz und tS = 3 ADC cycles. 
Die 6 Msps werden nur bei 12-bit resolution Interleave Triple ADC mode 
erreicht. (Wie auch immer dies geht... Ich muss noch viel lesen.)
Gruss MK_Munich

von Heiko J. (heiko_j)


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.

von Matthias (Gast)


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

}

von Matthias (Gast)


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?

von Matthias (Gast)


Lesenswert?

Ah, progress. Meld mich gleich nochmal

von Dummy (Gast)


Lesenswert?

Hat schonmal jemand Video mit dem Teil gesampled? Bekommt man es dann 
auf ein gängiges 320x240 TFT? Wird wohl schwierig?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.