Forum: Mikrocontroller und Digitale Elektronik STM32F4 ADC hängt


von Tom (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich kämpfe hier gerade mit dem ADC im STM32F4 (Sourcen anbei).
Ich habe das ADC Beispiel aus den Standardtreibern 
(STM32F4xx_StdPeriph_Examples\ADC\VBAT_Measurement) leicht abgewandelt 
(kein VBat, sondern PC1 als Analogeingang), aber bei der 2 Konvertierung 
wird nie das EOC Bit aktiv -->

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

wird nie fertig :(.

Wär toll wenn mir jemand einen Tipp geben könnte, was ich hier falsch 
gemacht habe.

Beste Grüße, Tom

von stm (Gast)


Lesenswert?

> ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

änder das mal zu:

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

von Thomas H. (flaretom)


Lesenswert?

Hallo,

Das hatte ich ursprünglich so (wie in dem StdPeriph ADC Beispiel) hat 
aber auch nicht funktioniert :(.
Jetzt noch mal mit ContinuousMode=ENABLE wiederholt --> eine 
Konvertierung klappt (EOC wird 1), bei der 2. bleibt EOC 0.
Beste Grüße, Tom

von stm (Gast)


Lesenswert?

hm...

lass mal die beiden Zeilen in deiner u16 ADCDriver-Funktion weg
wenn du den ContinuousMode=ENABLE hast.

ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, 
ADC_SampleTime_15Cycles);
  // Start the conversion
ADC_SoftwareStartConv(ADC1);

Im kontinuierlichen Modus muss man das nur 1 mal starten, wenn ich mich 
jetzt nicht schwer irre. Ehrlich gesagt rate ich jetzt ins Blaue. Ev. 
kennt sich da jemand besser aus.

von Thomas H. (flaretom)


Lesenswert?

Nee, hat leider auch nichts gebracht.
Schon komisch. Ist ja kaum anders als im Beispiel.

von Stefan O. (avrstefan)


Lesenswert?

Hab jetzt deinen Code nicht angeschaut, aber hier mal meine Funkion zum 
initialisieren des ADC und die Zum Einlesen eines Channels des ADC3s. 
Vielleicht hilft dir das weiter. Ist allerdings ohne DMA!

An den Kommentaren nicht stören die könnten noch falsch sein!
1
void Init_ADC3()
2
{
3
  /* Enable ADC1 Clocks ****************************************/
4
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
5
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
6
7
    GPIO_StructInit(&GPIO_InitStructure);
8
    /* Configure ADC1 Channel8 pin as analog input ******************************/
9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
11
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
12
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
13
    GPIO_Init(GPIOC, &GPIO_InitStructure);
14
15
16
    /* ADC Common Init **********************************************************/
17
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
18
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
19
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
20
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_14Cycles;
21
    ADC_CommonInit(&ADC_CommonInitStructure);
22
23
    ADC_StructInit(&ADC_InitStructure);
24
    /* ADC1 Init ****************************************************************/
25
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
26
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
27
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
28
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
29
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
30
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
31
    ADC_InitStructure.ADC_NbrOfConversion = 2;
32
    ADC_Init(ADC3, &ADC_InitStructure);
33
34
    /* ADC3 regular channel11 configuration *************************************/
35
    ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 1, ADC_SampleTime_15Cycles);
36
    /* ADC3 regular channel12 configuration *************************************/
37
    ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles);
38
39
    /* Enable ADC3 */
40
    ADC_Cmd(ADC3, ENABLE);
41
}

Hier noch die Funktion zum Auslesen des ADCs
1
uint16_t Get_Volatage(uint32_t samples)
2
{
3
  uint32_t value=0;
4
  int i=0;
5
6
  ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 1, ADC_SampleTime_15Cycles);
7
8
  for(i=0;i<samples;i++)
9
  {
10
    ADC_SoftwareStartConv(ADC3);
11
12
    while(ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC) != SET)
13
    {
14
15
    }
16
17
    value += ADC_GetConversionValue(ADC3);
18
  }
19
20
  return (value/samples);
21
}

In main einfach die Init aufrufen und dann die Get_Voltage

von Stefan O. (avrstefan)


Lesenswert?

Ach noch was nimm für den ADC einen Impedanzwandler oder Opamp her sonst 
hast du damit nur probleme!

von m.n. (Gast)


Lesenswert?

Stefan O. schrieb:
> Ach noch was nimm für den ADC einen Impedanzwandler oder Opamp her sonst
> hast du damit nur probleme!

Und mit OpAmps doch auch, oder?
Beitrag "Re: STM32F4 ADC Problem"

von Stefan O. (avrstefan)


Lesenswert?

Stefan O. schrieb:
> Ach noch was nimm für den ADC einen Impedanzwandler oder Opamp her sonst
> hast du damit nur probleme!

Hab ich doch geschrieben mit Opamp :-)

von Thomas H. (flaretom)


Lesenswert?

Ok, probiere ich nachher mal aus.
Was den Impedanzwandler angeht: Ich will mit dem ADC nur eine 
Akkuspannung messen (nicht aufs mV genau, nur um Tiefentladung zu 
verhindern). Der Spannungsteiler hat ca. 5kOhm. Das sollte ich wohl 
keine extra Schaltung brauchen, oder?

von Thomas H. (flaretom)


Lesenswert?

@Stefan
Ich habe jetzt deine Kode 1:1 übernommen und trotzdem hängt die 
Konvertierung.
Mhhh...

von stm (Gast)


Lesenswert?

Thomas Horn schrieb:
> @Stefan
> Ich habe jetzt deine Kode 1:1 übernommen und trotzdem hängt die
> Konvertierung.
> Mhhh...

Sicher das da nicht irgendwo anders noch was im Argen liegt? Schon mal 
debugger laufen lassen? Viell. hängt dein Programm irgendwo in einer 
default interrupt funktion oder so. Check das mal.

von Stefan O. (avrstefan)


Lesenswert?

Was für eine IDE und Compiler verwendest du?

von Thomas H. (flaretom)


Lesenswert?

Benutze Eclipse CDT, arm-none-eabi-gcc . Breakpoints for und nach dem 
while. Wenn ich dann unterbreche, dann steckt der µC in der 
ADC_GetFlagStatus. Außerdem sehe ich  im ADC1->SR2 bzw ADC3->SR2 das das 
EOC nicht hochgeht.
Ich habe sicherheitshalber auch mal alle andere Sachen aus dem Programm 
rausgeschmissen, keine Änderung.

von Thomas H. (flaretom)


Lesenswert?

"vor" natürlich und es ist SR statt SR2
war wohl schon zu spät  ;)

von Stefan O. (avrstefan)


Lesenswert?

Bist du sicher das du die PLL richtig eingestellt hast und der Core und 
der Bus mit dem richtigen Clock läuft?

von Thomas H. (flaretom)


Lesenswert?

Hallo,
Ich habe für die Clock-Einstellung das ST Tool (so ein Excel-sheet) 
benutzt.
Naja, Prozessor läuft, Baudraten sind richtig, I2C Zeiten stimmen und in 
den Inits werden AHB1 bzw. AHB2 Takte eingestellt.
Und.... die erste Konvertierung funktioniert.
Im SR steht 0x30 , also OVR und STRT sind gesetzt. Könnte das etwas 
bedeuten, muss ich die evt. vorher löschen?

von Michael K. (damichl)


Lesenswert?

SystemInit() aufgerufen? Sonst kannst Du Clocks einstellen was Du 
willst, er läuft ohne immer mit dem HSI.


mfg

von Thomas W. (diddl)


Lesenswert?

Die aktuelle Clock Einstellung kann man übrigens auch auslesen und mit 
printf() anzeigen lassen ... ;-)

Hatte das Problem auch. Und zudem das Problem, dass 25MHz statt 8Mhz 
eingestellt war im Standard. Wo das printf() dann auch nicht hilft.

von Thomas H. (flaretom)


Lesenswert?

Ja, wird in der startup_stm32f4xx.s aufgerufen (sonst würden ja auch die 
anderen Zeiten zB. (serielle Baudraten) nicht stimmen.
1
/* Call the clock system intitialization function.*/
2
  bl  SystemInit   
3
/* Call static constructors */
4
    bl __libc_init_array
5
/* Call the application's entry point.*/
6
  bl  main
7
  bx  lr    
8
.size  Reset_Handler, .-Reset_Handler

von Ingo (Gast)


Lesenswert?

Ich habe das selbe Problem, eine AD-Wandlung geht, die zweite nicht bzw. 
hier hängt er in der while-Schleife.


Hast du eine Lösung gefunden?




Ingo

von Star K. (starkeeper)


Lesenswert?

Also das gleiche Problem hatte ich auch mal. Ich habe den ADC nicht im 
continouous mode laufen gehabt sondern zum einzeln anstossen.

Damit das mehr als nur einmal funktioniert musste ich vor dem erneuten 
Startem von ADC und DMA alle Flags löschen:
1
ADC_ClearFlag((ADC_TypeDef*)(AdcPort), ADC_FLAG_AWD | ADC_FLAG_EOC | ADC_FLAG_JEOC | ADC_FLAG_JSTRT | ADC_FLAG_STRT | ADC_FLAG_OVR);
2
3
DMA_ClearFlag(DmaChannelAddr, DMA_FLAG_TCIF0);
4
DMA_ClearFlag(DmaChannelAddr, DMA_FLAG_HTIF0);
5
DMA_ClearFlag(DmaChannelAddr, DMA_FLAG_TEIF0);

Erst danach ging es, was etwas merkwürdig ist, da die DMA-Flags garnicht 
aktiviert waren und nur für Interrupts gedacht sind die ich auch nicht 
genutzt habe.

Ich glaube es kam hauptsächlich auf die DMA-Flags an, die ADC-Flags 
wurden nur zur Sicherheit mit gelöscht.

von Thomas H. (flaretom)


Lesenswert?

Hallo,
@Ingo
Nein, ich hatte auf den Teil dann erst mal in der SW verzichtet und bin 
seitdem nicht mehr zum Testen gekommen.

@Star Keeper
Das wäre ja recht komisch, wenn die DMA Flags diesen Einfluss auf den 
ADC haben.
Ich muss im Laufe des Monats mal wieder an den STM32 ran, dann werde ich 
das auch mal in meine SW einbauen. Ich melde dann, wie es gewirkt hat.

Beste Grüße, Tom

von Ingo (Gast)


Lesenswert?

So, ich hab den Fehler:
1
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
2
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
3
4
  ADC_InitTypeDef       ADC_InitStructure;
5
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
6
  GPIO_InitTypeDef      GPIO_InitStructure;
7
8
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
9
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
10
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
11
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
12
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
13
  GPIO_Init(GPIOC, &GPIO_InitStructure);
14
15
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
16
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;
17
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
18
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
19
  ADC_CommonInit(&ADC_CommonInitStructure);
20
21
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
22
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
23
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
24
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
25
  ADC_InitStructure.ADC_ExternalTrigConv = 0;
26
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
27
  ADC_InitStructure.ADC_NbrOfConversion = 1;
28
  ADC_Init(ADC3, &ADC_InitStructure);
29
30
  ADC_EOCOnEachRegularChannelCmd( ADC3, ENABLE );
31
  ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 1, ADC_SampleTime_3Cycles);
32
  ADC_Cmd(ADC3, ENABLE);
Ganz wichtig ist offensichtlich, dass alle Mitglieder der Struct 
initialisiert werden. Nehme ich
1
ADC_InitStructure.ADC_ExternalTrigConv = 0;
raus, gehts nicht mehr. Ich hoffe jemand kann was damit anfangen.
Ich wüsste gern mal wo sowas geschrieben steht!!!

Ingo

von Ingo (Gast)


Lesenswert?

Achso, wichtig ist das der ADC bereits initialisiert ist bevor man ihn 
benutzt. Das ist z.B. nicht der Fall, wenn der ADC durch Timerinterrupts 
getriggert wird. Hierzu sollte man sich ein Flag erstellen, welches nach 
der ADC-Initialisierung gesetzt wird. Erst wenn das Flag gesetzt ist, 
darf man auf den ADC zugreifen.



Ingo

von Helfender (Gast)


Lesenswert?

Was bezeichnest Du als "Initialisierung"?
(Einschalten der Clks, GPIO vorbereiten, Modes einstellen...,
oder bereits das Starten eine Wandlung?)
Warum initialisiert man ihn nicht bereits nach dem Hochfahren
des Systems (einmalig)?

ADC_InitTypeDef       ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
GPIO_InitTypeDef      GPIO_InitStructure;

Gibt es vielleicht etwas wie InitStructureAdc(&InitStructure)?
(bei Windows wird so etwas benutzt)
Oder vielleicht hilft auch einfach ein
memset(&InitStructure, 0, sizeof(InitStructure));
damit die ganzen Felder einen Default-Wert (?) haben?

von Ingo (Gast)


Lesenswert?

Helfender schrieb:
> Was bezeichnest Du als "Initialisierung"?
> (Einschalten der Clks, GPIO vorbereiten, Modes einstellen...,
> oder bereits das Starten eine Wandlung?)
Ja, genau das.

Helfender schrieb:
> Warum initialisiert man ihn nicht bereits nach dem Hochfahren
> des Systems (einmalig)?
Macht man doch

von Helfender (Gast)


Lesenswert?

> Ja, genau das.

A oder B?

> Macht man doch

Wenn man den ADC initialisiert, bevor ein Timer überhaupt laufen kann
oder zuschlagen kann, braucht man an dieser Stelle auch nicht
aufpassen oder ein Flag, um sich dies zu merken?

Sollte nicht erst einmal alles vorbereitet werden
und am Schluss gibt es ein "GO", mit dem das System zum Laufen
gebracht wird? Sonst hat man ja eine Unmenge an Fälle, die
man behandeln muss...

von Star K. (starkeeper)


Lesenswert?

Es gibt für jedes Struct der STM32Lib auch eine Funktion die dieses 
struct initialisiert. Diese Funktion sollte man natürlich benutzen, wenn 
man nicht selber alle Werte setzt. Woher soll die Library denn nun 
wissen welche Teile des struct korrekte Werte enthalten und welche 
nicht...

von Ingo (Gast)


Lesenswert?

Helfender schrieb:
> Wenn man den ADC initialisiert, bevor ein Timer überhaupt laufen kann
> oder zuschlagen kann, braucht man an dieser Stelle auch nicht
> aufpassen oder ein Flag, um sich dies zu merken?

Also ich persönlich initialisiere hier z.B. ein neben einem EAGOGM163, 
einen U2270, ein MCP3901, einen Pegelwandler und ein Modem, sowie 
diverse Peripherie des Controllers. Beim LCD z.B. läuft der Systick 
Timer schon, damit ich schöde Delays sauber einhalten kann. Es war wie 
gesagt nur eine Möglichkeit, letztendlich kann das jeder machen wie er 
will...

Star Keeper schrieb:
> Es gibt für jedes Struct der STM32Lib auch eine Funktion die dieses
> struct initialisiert. Diese Funktion sollte man natürlich benutzen, wenn
> man nicht selber alle Werte setzt.

Meinst du die DeInit?

Ingo

von Star K. (starkeeper)


Lesenswert?

Nein ich meine diese hier:
ADC_StructInit(..)
DMA_StructInit(..)
...

Gibt es für jede Peripherie die von der Library über structs genutzt 
wird.

von Ingo (Gast)


Lesenswert?

Was macht diese Funktion? Kannst du mal ein konkretes Codebeispiel 
posten?

von Helfender (Gast)


Lesenswert?

Hier ist ein Beispiel:
http://www.keil.com/forum/12076/

von Thomas H. (flaretom)


Lesenswert?

Hallo Ingo,
Das wäre ja der Hammer. Bei allen anderen Sachen (GPIO, Timer) hatte ich 
die xxx_StructInit genutzt, nur beim ADC nicht, da so aus 
STM32F4xx_StdPeriph_Examples\ADC\VBAT_Measurement (TrueStudio?) kopiert.

Beste Grüße, Tom

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.