Forum: Mikrocontroller und Digitale Elektronik STM32F4DiscoveryBoard und ADC


von opcode (Gast)


Lesenswert?

Sehr geehrte Forummitglieder,

ich möchte mit dem STM32F4DiscoveryBoard (Controller: STM32F407VGT) ein 
analoges Signal abtasten. Dazu habe ich mir die Beispiele in den 
Libraries auf der Website von STMicroelectronis angeschaut. Da ich das 
Signal schnell abtasten muss, dachte ich an die Lösung mit Dual bzw. 
Triple Interleaved Mode with DMA2mode. Mit diesen Einstellungen kann ich 
mit mehr als 2MSPS abtasten. Sofern ich den unten angeführten 
Beispielcode verstanden habe, wird einmalig mit den drei ADC's im 
Controller der eine Kanal abgetastet und die drei Werte werden per DMA 
direkt in Speicher geladen, ohne die CPU zu unterbrechen. Ich möchte nun 
nicht nur einmal abtasten, sondern min. 4096 oder 8192. Gibt es eine 
Möglichkeit die Anzahl der Abtastungen direkt vorzugeben und alle diese 
Werte in den Speicher zu laden ohne mit Interrupts in der CPU zu 
arbeiten, wo quasi kontrolliert wird, wie viel Werte schon abgetastet 
wurden sind ?!

Ich bin für jede Hilfe dankbar und wünsche allen einen guten Rutsch ins 
neue Jahr.

mfGruß,
opcode
1
#include "stm32f4xx.h"
2
#include "stm32f4xx_adc.h"
3
#include "stm32f4xx_dma.h"
4
#include "stm32f4xx_gpio.h"
5
#include "stm32f4xx_rcc.h"
6
7
8
#define ADC_CDR_ADDRESS    ((uint32_t)0x40012308)
9
__IO uint32_t ADCTripleConvertedValue[3];
10
11
ADC_InitTypeDef       ADC_InitStructure;
12
ADC_CommonInitTypeDef ADC_CommonInitStructure;
13
DMA_InitTypeDef       DMA_InitStructure;
14
GPIO_InitTypeDef      GPIO_InitStructure;
15
16
17
int main(void)
18
{
19
20
  /******************************************************************************/
21
  /*               ADCs interface clock, pin and DMA configuration              */
22
  /******************************************************************************/
23
24
    /* Enable peripheral clocks */
25
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOC, ENABLE);
26
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 |
27
                           RCC_APB2Periph_ADC3, ENABLE);
28
29
    /* Configure ADC Channel 12 pin as analog input */
30
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
31
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
32
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
33
    GPIO_Init(GPIOC, &GPIO_InitStructure);
34
35
    /* DMA2 Stream0 channel0 configuration */
36
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
37
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;
38
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValue;
39
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
40
    DMA_InitStructure.DMA_BufferSize = 3;
41
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
42
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
43
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
44
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
45
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
46
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
47
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
48
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
49
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
50
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
51
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
52
53
    /* DMA2_Stream0 enable */
54
    DMA_Cmd(DMA2_Stream0, ENABLE);
55
56
57
    /******************************************************************************/
58
    /*  ADCs configuration: triple interleaved with 5cycles delay to reach 6Msps  */
59
    /******************************************************************************/
60
61
      /* ADC Common configuration *************************************************/
62
      ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;
63
      ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
64
      ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;
65
      ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
66
      ADC_CommonInit(&ADC_CommonInitStructure);
67
68
      /* ADC1 regular channel 12 configuration ************************************/
69
      ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
70
      ADC_InitStructure.ADC_ScanConvMode = DISABLE;
71
      ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
72
      ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
73
      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
74
      ADC_InitStructure.ADC_NbrOfConversion = 1;
75
      ADC_Init(ADC1, &ADC_InitStructure);
76
77
      ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 1, ADC_SampleTime_3Cycles);
78
      /* Enable ADC1 DMA */
79
      ADC_DMACmd(ADC1, ENABLE);
80
81
      /* ADC2 regular channel 12 configuration ************************************/
82
      ADC_Init(ADC2, &ADC_InitStructure);
83
      /* ADC2 regular channel12 configuration */
84
      ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 1, ADC_SampleTime_3Cycles);
85
86
      /* ADC3 regular channel 12 configuration ************************************/
87
      ADC_Init(ADC3, &ADC_InitStructure);
88
      /* ADC3 regular channel12 configuration */
89
      ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_3Cycles);
90
91
      /* Enable DMA request after last transfer (multi-ADC mode) ******************/
92
      ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
93
94
      /* Enable ADC1 **************************************************************/
95
      ADC_Cmd(ADC1, ENABLE);
96
97
      /* Enable ADC2 **************************************************************/
98
      ADC_Cmd(ADC2, ENABLE);
99
100
      /* Enable ADC3 **************************************************************/
101
      ADC_Cmd(ADC3, ENABLE);
102
103
      /* Start ADC1 Software Conversion */
104
      ADC_SoftwareStartConv(ADC1);
105
106
    while(1)
107
    {
108
    }
109
}

von Hansi-Bansi (Gast)


Lesenswert?

> wird einmalig

Ich glaube nicht (Irrtum jedoch möglich)
so wie ich das sehe, läuft der ADC im continuierlichen Modus und die DMA 
im circular Modus. Das bedeutet, dass die drei Werte im Array ständig 
aktualisiert werden (endlos), sobald einmalig die Zeile 
"ADC_SoftwareStartConv(ADC1);" gestartet wurde.

An diesen Zeilen sieht man es:

circular Modus (Buffer immer wieder von Beginn an neu beschreiben (im 
Kreis also)):
1
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

Der ADC rödelt endlos vor sich hin, sobald einmal ausgelöst wurde 
(kontinuierlich ohne Trigger).
1
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

-------------------------------------------------------------

Wenn ich mich nicht täusche, so musst du im Code lediglich folgende 
Zeilen abändern, damit mehr Werte im Buffer landen:

Hier einfach die Buffergröße auf ein Vielfaches von 3 aufblasen (zB. 9)
1
__IO uint32_t ADCTripleConvertedValue[9];

Hier musst du dem DMA bescheid geben, dass der Buffer nun größer ist. 
Also die gleiche Zahl hintippen die auch dein Buffer als Größe hat:
1
DMA_InitStructure.DMA_BufferSize = 9;

Das sollte es eigentlich gewesen sein?! Irrtümer sind eingeschlossen. 
Ich habe zwar schon was mit dem ADC + DMA gemacht, aber ein absoluter 
Experte bin ich nicht. Ausprobieren macht schlau.

lg
Hansi

von veryBo (Gast)


Lesenswert?

>Hier einfach die Buffergröße auf ein Vielfaches von 3 aufblasen (zB. >9)__IO 
uint32_t ADCTripleConvertedValue[9];

Nein.

DMA macht erst richtig Spass mit einem richtig fetten Puffer.
Sonst ist der Durchsatz nicht erreichbar. Daten einlesen ist ja kein 
Selbstzweck, sie müssen auch verarbeitet werden.
Bei einer Puffergrösse von 9 müsste die CPU jeweils nach
9 Werten ran. Wenn man das in einem Interrupt macht, könnte
man sich DMA gleich schenken.
Bei 2000 Werten sieht's schon anders aus.

von opcode (Gast)


Lesenswert?

Bin jetzt verwirrt.

Kann ich jetzt das jetzt so machen wie Hansi es beschrieben hat ?!
Einfach die Buffergröße vergrößern ?!

von Hansi-Bansi (Gast)


Lesenswert?

veryBo schrieb:
> DMA macht erst richtig Spass mit einem richtig fetten Puffer.
> Sonst ist der Durchsatz nicht erreichbar. Daten einlesen ist ja kein
> Selbstzweck, sie müssen auch verarbeitet werden.
> Bei einer Puffergrösse von 9 müsste die CPU jeweils nach
> 9 Werten ran. Wenn man das in einem Interrupt macht, könnte
> man sich DMA gleich schenken.
> Bei 2000 Werten sieht's schon anders aus.

Die Zahl 9 war auch nur ein Beispiel. Da erkennt man schön, dass es sich 
um ein Vielfaches von 3 handelt...

> Kann ich jetzt das jetzt so machen wie Hansi es beschrieben hat ?!
> Einfach die Buffergröße vergrößern ?!

Würde mich auch interessieren. 100% sicher bin ich mir nämlich nicht...

von veryBo (Gast)


Lesenswert?

opcode schrieb:
> Bin jetzt verwirrt.
>
> Kann ich jetzt das jetzt so machen wie Hansi es beschrieben hat ?!
> Einfach die Buffergröße vergrößern ?!

JAHAAA!

Manche DMA-Controller haben allerdings eine Beschränkung,
hinsichtlich der Maximalgrösse eines einzelnen
Transfers (z.B. 8K oder 16K oder...).
Weiss allerdings nicht, ob das für den STM32F4 zutrifft.
Aber das steht sicher im Datenblatt.
Bist Du jetzt noch mehr verwirrt :-)?

von opcode (Gast)


Lesenswert?

Jaaaaaaaaa, ich bin jetzt total verwirrt!!! ;-)

Danke für eure Hilfe !

Wünsche euch einen guten Rutsch ins neue Jahr!

mfGruß,
opcode

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.