Forum: Mikrocontroller und Digitale Elektronik STM32 ADC vs CPU Last? Merkwürdiges Phänomen


von Ingo L. (corrtexx)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe folgendes Problem und einen Bugfix, den ich mir nicht erklären 
kann:

Ich habe einen STM32F4, bei dem mittels internem Timer der ADC gestartet 
wird, die Daten werden anschließend per DMA in ein Array geschaufelt. 
Der Timer feuert alle 25us (40kHz), und es werden je Timertrigger 3 
Werte aufgenommen. anschließend wird eine ISR aufgerufen und die Werte 
verarbeitet und 3 neue Werte daraus berechnet. Die Messung an sich ist 
völlig autonom sollte man meinen. Ich kann auch sicher stellen, dass die 
ISR planmäßig und zyklisch ausgeführt wird. Da gibt es keine Probleme. 
Des zu messende Signal ist ein Sinus mit 50Hz + DC-Offset.

Nun ist es allerding so, dass wenn ich im Sytick_Handler eine Taster 
drücke und diesen Entprelle (Debounce) der ADC sich geringfügig vermisst 
und sich der DC-Offset ändert (5mV mit DMM Typ Fluke 189 gemessen). Die 
5mV habe ich gefunden, indem ich die eingelesenen Werte direkt wieder 
über den DAC ausgebe. Diese 5mV verursachen eine Sprung im errechneten 
Signal, dieser Sprung klingt nach dem Entprellen wieder ab.

Nach langem Suchen bin ich darauf gestoßen, dass die CPU den ADC stört 
bzw. die CPU immer eine gewisse Grundlast haben muss.

main:
1
while( ON ){
2
3
    ////////////////////////////////////////////////////////////////////////////////
4
      // Handle serial Stuff
5
        if ( USART.RecieveCompleteFlag == OK ){
6
            InterpreteSerial();
7
      }
8
      else if ( USART.RecieveCompleteFlag == ERROR ){
9
          InterpreteSerialError();
10
      }
11
12
        ////////////////////////////////////////////////////////////////////////////////
13
        // Update LCD, Handle HMI
14
        if ( Flags.Update_LCD == ON ){ //19,53125 Updates/Second
15
          static uint32_t LCDReinitcounter = 0;
16
          if ( ++LCDReinitcounter >= 196 ){ // Reeinit each 196 Updates => 10,0352s, takes 800ms
17
          //  Init_EA_DOGM163();
18
            LCDReinitcounter = 0;
19
          }else{ // 2ms
20
            Update_Screen();
21
          }
22
          Flags.Update_LCD = OFF;
23
        }else{
24
        //  MyDelayMS( 2 );
25
        }
26
   }

Systick:
1
void SysTick_Handler( void )
2
{
3
    static uint32_t LCDCounter = 0;
4
5
   if ( LCDCounter % 4096 == 0 ){
6
    Flags.Cursorblinker ^= ON;
7
  //  Toggle_LED( LED_GREEN );
8
  }
9
10
  if ( LCDCounter % 512 == 0 ){
11
    Flags.Update_LCD = ON;
12
  }
13
14
  // Poll USART Interface
15
  USART_Handling();
16
17
    // Scan for Increments
18
    Scan_Encoder();
19
20
    // Encoderbutton
21
    if ( BUTTON_PRESSED && Debounce == 0 ){
22
      Debounce = DEBOUNCETIME;
23
      Flags.Buttonpressed = ON;
24
    }
25
26
    // Userbutton
27
    if ( USER_BUTTON_PRESSED && Debounce == 0 ){
28
      Debounce = DEBOUNCETIME;
29
      Flags.PSR_State = OFF;
30
    }
31
32
    // Set Hardware Enable at PSR
33
    Enable_PSR ( Flags.PSR_State );
34
35
    // diverse Counter
36
    LCDCounter++;
37
    if ( MSDelayCounter ) MSDelayCounter--;
38
    if ( Debounce ) {
39
      Debounce--;
40
      Set_LED( LED_GREEN );
41
    }else{
42
      Clear_LED( LED_GREEN );
43
    }
44
}

Ist das MyDelayMS(2) auskommentiert, habe ich die CPU-Lastabhängigen 
Beulen, die Schaltung nimmt sich 92mA

Mit dem Delay sind die Beulen weg, dass errechnete Signal ist stabil, 
die Schaltung nimmt sich 109mA.

Ich zwinge der CPU eine Grundlast auf, das scheint zu klappen. Auf den 
Bildern kann man erkennen, dass wenn die Variable "Debounce" != 0 ist 
(gelb), die Beule auftaucht (lila).

Hat jemand eine Erklärung dafür, ich habe nun 2 Tage gebraucht, alles 
auf Herz und Nieren geprüft, alle Spannungen und Signale gechecked. Das 
Eingangssignal am ADC ist sauber und stabil, der Fehler liegt scheinbar 
wirklich im Chip.


Hier noch die Delay-Funktion:
1
void MyDelayMS( uint32_t DelayInMS )
2
{
3
  MSDelayCounter = (DelayInMS * SYSTICK_IN_HZ) / 1000;
4
  while (MSDelayCounter);
5
}

von Ingo L. (corrtexx)


Lesenswert?

Schaut man sich "Ohne_Delay.jpg" genau an, sieht man auf der Hüllkurve 
der errechneten Signals zusätzlich zu der satten Beule eine 
Oberwelligkeit, die der Frequenz der LCD-Updates ("Update_Screen()") 
zeigt.

von St. D. (st_d)


Lesenswert?

Ingo L. schrieb:
> Des zu messende Signal ist ein Sinus mit 50Hz + DC-Offset.

Versuch es nur mit DC-Offset...

& Messe die Versorgung bzw. ADC-Ref. Spannung mit...

von Ingo L. (corrtexx)


Lesenswert?

St. D. schrieb:
> Versuch es nur mit DC-Offset...
Habe ich, auch dieser verschiebt sich aus Sicht des µC. Am ADC Pin ist 
alles sauber, lasse ich mir die eingelesenen Werte (auch nur den Offset) 
ausgeben, misst man eine Verschiebung. Dabei ist nicht immer 
reproduzierbar ob diese Verschiebung positiv oder negativ ist.

> & Messe die Versorgung bzw. ADC-Ref. Spannung mit...
Die Versorung ist auch stabil, ADC-Ref. gibt es bei diesem Modell nicht, 
es misst leider immer gegen seine VCC. Aber diese zuckt keine Stück.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Ich erinnere da dunkel was mit dem Flash-ACR vs. ADC, weiß aber 
nichtmehr, welcher STM32 das war. Versuch mal probehalber, beim 
System-Init die D/I-Caches abzuschalten (bzw. nicht anzuschalten) und 
teste neu.

von Ingo L. (corrtexx)


Lesenswert?

Nop schrieb:
> Versuch mal probehalber, beim
> System-Init die D/I-Caches abzuschalten (bzw. nicht anzuschalten) und
> teste neu.
Wenn ich die Caches abschalte bzw. garnicht erst einschalte tritt der 
Fehler (Beule beim Entprellen) wieder auf, sehr spannend!

von Karl (Gast)


Lesenswert?

Du korrigierst mit der internen vref?

von Ingo L. (corrtexx)


Lesenswert?

Karl schrieb:
> Du korrigierst mit der internen vref?
Nein, sollte ich das tun? Wenn ja, wie macht man das?

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ingo L. schrieb:
> es misst leider immer gegen seine VCC.
Und gegen GND. Wenn der zappelt, dann misst er Mist.

> Aber diese zuckt keine Stück.
Ist an allen Massepins tatsächlich der selbe Pegel?

Ingo L. schrieb:
> ich habe folgendes Problem
Mit welcher Hardware? Wie sieht das Layout aus? Im Besonderen ist hier 
die Versorgung interessant.

Ingo L. schrieb:
> Nun ist es allerding so, dass wenn ich im Sytick_Handler eine Taster
> drücke und diesen Entprelle (Debounce) der ADC sich geringfügig vermisst
Kommt dieser Fehler vom Taster allein oder von der Programmaktion, die 
du darauf folgend ausführst? Was passiert, wenn du "im Prinzip" die 
Hardware samt Taster gleich lässt und in der Software nicht auf den 
Taster reagierst? Löst der Taster sonst noch eine Aktion aus, die den 
Strombedarf ändert?

von Karl (Gast)


Lesenswert?

Ingo L. schrieb:
> Nein, sollte ich das tun? Wenn ja, wie macht man das?

Wenn es genau werden muss oder auch mangels besserer Alternativen.
Welchen f4 hast du? Beim f407 und f432 liegt die auf einem internen adc 
Kanal der ganz normal gemessen werden kann. Die Spannung der Referenz 
wird bei der Produktion gemessen und daraus kann dann vdd berechnet 
werden. Und damit wiederum die tatsächlich gemessene Spannung. Es gibt 
ne appnote dazu Und auch einen Abschnitt im Datenblatt und ref Manual.

von Ingo L. (corrtexx)


Angehängte Dateien:

Lesenswert?

Lothar M. schrieb:
> Und gegen GND. Wenn der zappelt, dann misst er Mist.
Ja, so sauber sieht das GND wirklich nicht aus, sehr viel Noisefloor...

Lothar M. schrieb:
> Ist an allen Massepins tatsächlich der selbe Pegel?
Ja

Lothar M. schrieb:
> Mit welcher Hardware? Wie sieht das Layout aus? Im Besonderen ist hier
> die Versorgung interessant.
Siehe Anhang. Ich habe bewusst auf eine Massefläche verzichtet, damit 
ich Analog-µC vom externen DAC trennen kann. Hoffentlich fällt es mir 
jetzt nicht auf die Füße...

Lothar M. schrieb:
> Kommt dieser Fehler vom Taster allein oder von der Programmaktion, die
> du darauf folgend ausführst? Was passiert, wenn du "im Prinzip" die
> Hardware samt Taster gleich lässt und in der Software nicht auf den
> Taster reagierst? Löst der Taster sonst noch eine Aktion aus, die den
> Strombedarf ändert?
Der Taster ohne Softwareaktion bewirkt garnichts. Es ist allein die 
Rechenzeit. Es ist reproduzierbar, wenn man statt des Taster einen 
Zähler hochzählt, der bei erreichen eines gewünschten Zählerstandes 
ebenfalls Debounce auslöst.

Karl schrieb:
> f407
Ich habe einen 405er.

> Die Spannung der Referenz
> wird bei der Produktion gemessen und daraus kann dann vdd berechnet
> werden
Du meinst quasi eine ratiometrische Messung?

von Ingo L. (corrtexx)


Lesenswert?

Wenn ich die Funktion "Init_EA_DOGM163()" rein nehme und diese etwa alle 
10s ausgeführt wird, sieht man die Beule auch ohne eine 
Benutzerinteraktion (ohne das Dummyload MyDelayMS(2)).  Mit der 
Dummyload ist alles ok. Offensichtlich generiert die CPU genug Noise um 
den ADC sauber zu stören...

von OMG (Gast)


Lesenswert?

Ingo L. schrieb:
> Board.PNG

Du hast ein klassisch beschissenes Layout.

Bei diesem Layout hast du niemals irgendwo einen
sauberen Massebezug.

von OMG (Gast)


Lesenswert?

Ingo L. schrieb:
> Offensichtlich generiert die CPU genug Noise um
> den ADC sauber zu stören...

Die CPU hast immer irgendeinen schwankenden Strombedarf.
Aufgrund der miesen Masse hebt und senkt sich der Bezugs-
pegel der CPU und damit ergeben sich schlichtweg (fast)
beliebige Fehlmessungen.

von Christian W. (orikson)


Lesenswert?

OMG schrieb:
> Du hast ein klassisch beschissenes Layout.

Seid nicht so hart, sieht aus wie Target. Da is ein beschissenes Layout 
quasi n Feature ;)

von (Gast)


Lesenswert?

Könnte es nicht auch sein dass vom DAC zum Oszi bzw. DMM irgendetwas die 
5mV last-abhängig reindrückt?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

OMG schrieb:
> Aufgrund der miesen Masse
Ground Bouncing war gleich mein erster Verdacht...

Ingo L. schrieb:
> damit ich Analog-µC vom externen DAC trennen kann.
Das geht aber so nicht. Sondern da macht man eine Massefläche unter dem 
uC, an die alle GND Pins direkt angeschlossen sind. Und trennt dann 
Analog und Digital räumlich auf der Platine. Nicht umsonst steht im 
Datenblatt an allen GND Pins das selbe Signal. Dann muss da auch an 
allen Pins das selbe Potential sein. Jegliche Abweichung verändert bzw. 
verschlechtert irgendwas...

Wenn da so ein Strom irgendwo in dem uC fließt, dann muss er auch wieder 
raus. Und wenn er an einem GND Pin rausfließt und über diese 
hochimpedante Masse zurück zur Quelle, dann hebt dieser Strom den GND 
Pin um ein paar mV an. Und wenn dieser GND Pin auch noch was mit dem ADC 
zu tun hat, dann verfälscht dieser Strom das Messergebnis.

BTW: die schlecht platzierten Blockkondensatoren verbessern die Sachlage 
dann nicht im Mindesten...

von Theor (Gast)


Lesenswert?

@ INgo

Vielleicht könntest Du ja nochmal mit dem Oszi nachmessen, wie sich die 
Versorgungsspannung VDDA gegen VSSA verhält. Und zwar direkt an den 
Pins. Es wäre vielleicht nützlich weil überzeugend, wenn man das 
Ground-Bouncing direkt sieht und wie es mit der CPU-Last zusammenhängt.

Ich fürchte allerdings auch, dass Du das Layout nochmal gründlich 
überarbeiten musst.

von Ingo L. (corrtexx)


Lesenswert?

Christian W. schrieb:
> Seid nicht so hart, sieht aus wie Target. Da is ein beschissenes Layout
> quasi n Feature ;)
So ein Unsinn...

Ich vermute auch das die Masseführung scheisse is, ich werde die Masse 
mal etwas verstärken...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ingo L. schrieb:
> ich werde die Masse mal etwas verstärken...
Damit sind die Blockkondensatoren noch immer nicht an der richten 
Stelle.

Die gehören direkt an den Pin. Und da geht es um Millimeter, wenn es 
dir um mV geht. Nicht umsponst haben es die Chipdesigner geschafft, die 
Vcc und GND Pins paarweise auftreten zu lassen: VDDA+VSSA = 12+13, 
VSS-VDD = 18+19 und 63+64. Genau dorthin  an diese Pins müssen die 
Blockkondensatoren. Die müssen auch nicht so megamäßig groß und sogar 
auf der anderen Seite sein. 100nF gibt es auch in 0402 oder noch 
wesentlich kleiner.

Blockkondensatoren müssen den Strom für schnelle interne 
Schaltaktivitäten bereitstellen. Fahre einfach mal den Weg von einem 
Blokkondensatoranschluss über die VCC-VDD Anschlüsse des µC und schau 
wie lang der Weg und entsprechend wirkungslos der Kondensator ist.

BTW: Vias im Pad sind eine ganz schlechte Idee. Ein EMS Dienstleister 
(Elektronikfertiger) würde dir dieses Layout als "nicht fertigbar" oder 
"auf eigene Gefahr" bewerten. Und der DRC sollte dir da einen Fehler 
vorwerfen...

von Ingo L. (corrtexx)


Angehängte Dateien:

Lesenswert?

Lothar M. schrieb:
> Die müssen auch nicht so megamäßig groß und sogar
> auf der anderen Seite sein. 100nF gibt es auch in 0402 oder noch
> wesentlich kleiner.
ich verwende bereits 0603, so groß ist das garnicht.

Lothar M. schrieb:
> VDDA+VSSA = 12+13,
> VSS-VDD = 18+19 und 63+64.
63/64 und 18/19 sind meiner Meinung nach sehr kurz angebunden, 12/13 
sind eher suboptimal, stimmt.

Ich werde glaube ich im nächsten Aufguss auf einen externen ADC setzen 
um ganz sicher zu gehen...

> Und der DRC sollte dir da einen Fehler
> vorwerfen...
Je nachdem was man einstellt ;).

von Nop (Gast)


Lesenswert?

Ingo L. schrieb:

>         // Update LCD, Handle HMI
>         if ( Flags.Update_LCD == ON ){ //19,53125 Updates/Second

Mal noch was anderes: wozu sollte man ein Textdisplay mit 20 Hz updaten? 
Das kann man eh nicht sehen. Mehr als einmal oder allerhöchstens zweimal 
pro Sekunde ist sinnlos.

>           if ( ++LCDReinitcounter >= 196 ){ // Reeinit each 196 Updates
> => 10,0352s, takes 800ms

Und wozu sollte man alle zehn Sekunden das Display neu initialisieren?

von TestX (Gast)


Lesenswert?

Pack die 100nF Kondensatoren direkt an die Pins auf dem gleichen Layer 
und spendiere der Controller ein komplette Massefläche.

Dein Layout ist für langsame, digitale Signale o.k. Aber nicht für etwas 
analoges mit <10mV Auflösung.

Ein externer ADC muss auch entsprechend gut gelayoutet werden sonst 
kommt es zu genauso lustigen Effekten..

von Ingo L. (corrtexx)


Lesenswert?

Nop schrieb:
> Mehr als einmal oder allerhöchstens zweimal
> pro Sekunde ist sinnlos.
Naja, ich finde es sehr unergonomisch, wenn man Werte per 
Incrementalgeber ändert und diese sich optisch nur sekündlich ändern. 
Aber wenn du keinen Wert auf Ergonomie legst, brauchs du das auch nicht 
häufiger machen.

Nop schrieb:
> Und wozu sollte man alle zehn Sekunden das Display neu initialisieren?
Ich verstehe den Zusammenhang zwischen meinem Problem und deiner Frage 
nicht...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ingo L. schrieb:
> 63/64 und 18/19 sind meiner Meinung nach sehr kurz angebunden
Stimmt, dank "Via-In-Pad" Technik.

> 12/13 sind eher suboptimal, stimmt.
Und was war jetzt nochmal die Funktion dieser Pads? Irgendwas mit 
"Analog"? ;-)

> ich verwende bereits 0603, so groß ist das garnicht.
Für die paar Blockkondensatoren pro IC nehme ich tatsächlich 0201. Die 
sind aber echt mickrig.

Ingo L. schrieb:
> Naja, ich finde es sehr unergonomisch, wenn man Werte per
> Incrementalgeber ändert und diese sich optisch nur sekündlich ändern.
Man muss dann ja nicht das ganze Bild neu zeichnen. Ein paar anders 
positionierte Pixel verändern eine Zahl grundlegend. Man darf sich da 
runih mal anschauen, wie andere das machen: ein schlechtes 
(Windows-)Programm zeichnet bei jeder Änderung den ganzen Bildschirm 
neu. Das bessere und schnellere zeichnet nur den Bereich, der sich 
ändert.

> Aber wenn du keinen Wert auf Ergonomie legst, brauchs du das auch nicht
> häufiger machen.
Obacht Retourkutsche:
Aber wenn man die Rechenleistung hat und nicht drüber grübeln will, wie 
es besser und schneller geht, kann man auch immer den ganzen Screen neu 
malen.   ;-)

: Bearbeitet durch Moderator
von Nop (Gast)


Lesenswert?

Ingo L. schrieb:

> Naja, ich finde es sehr unergonomisch, wenn man Werte per
> Incrementalgeber ändert und diese sich optisch nur sekündlich ändern.

Ablesen kannst Du das sowieso nicht so schnell, das verschwimmt auf dem 
Display nur und erzeugt unnütz CPU-Last. Wobei das im Systick mit dem 
LCDCounter % 512 doch begrenzt wird, hatte ich nicht gesehen. :-)

> Ich verstehe den Zusammenhang zwischen meinem Problem und deiner Frage
> nicht...

Es sieht nach einem weiteren Problem mit notdürftigem Workaround aus, 
denn Textdisplays stürzen normalerweise nicht dauernd ab, so daß man sie 
neu initialisieren müßte. Die kann man stundenlang so betreiben, sofern 
man bei der Anbindung mit dem Flachbandkabel nichts verkehrt gemacht 
hat.

von Ingo L. (corrtexx)


Lesenswert?

Lothar M. schrieb:
> Man muss dann ja nicht das ganze Bild neu zeichnen.
Wer sagt das ich das tue? Ist im übrigen ein Text-LCD, ich muss nicht 
"malen" ;)

> Und was war jetzt nochmal die Funktion dieser Pads? Irgendwas mit
> "Analog"? ;-)
Ja, leider. 0402 oder gar 0201 gebe ich mir nicht ;)

Nop schrieb:
> Es sieht nach einem weiteren Problem mit notdürftigem Workaround aus,
Nein, ist kein Workaround. Es ist inzwischen auch raus. Das war halt zu 
provozieren der Beule ganz gut geeignet.

Lothar M. schrieb:
> Stimmt, dank "Via-In-Pad" Technik.
Da ich keine maschinelle Bestückun habe komme ich damit gut zurecht.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ingo L. schrieb:
> Ist im übrigen ein Text-LCD, ich muss nicht "malen" ;)
Bei Text-Displays male ich pro Timertick (üblicherweise der übliche 1ms 
Interrupt oder beim STM32 der Systemtimertick) einen einzigen Buchstaben 
vom µC-Display-Buffer ins Display. Bei einem 4x20 Display bin ich dann 
nach 80ms fertig mit dem Screen-Update. Und eine Neuinitialisierung des 
Display mache ich nur 1 einziges Mal beim Powerup. Wenn du öfters mal 
eine Neuinitialisierung brauchst, dann hast du vermutlich noch 
weitere/andere EMV-Probleme im Design.

> 0201 gebe ich mir nicht ;)
Trotzdem gut, wenn man da ein paar "zur Hand" hat. Denn die kann man 
immer mal schnell zum Test irgendwo dazwischenlöten. Und die nehmen ja 
im Prinzip keinen Platz weg.

Ingo L. schrieb:
> if ( ++LCDReinitcounter >= 196 ){ // Reeinit each 196 Updates
> => 10,0352s, takes 800ms
Mein Vorschlag: denk nicht so menschlich in Zehnerpotenzen, die CPU ist 
binär sortiert. Wenn du hier das Update erst nach 256 Durchläufen statt 
den willkürlichen 196 (vermutlich um die "menschlichen" 10,0 Sekunden zu 
erreichen) machen würdest, reicht es, das Byte zu inkrementieren und 
danach das Zero-Flag abzufragen...

> //19,53125 Updates/Second
So genau und stabil ist dein Quarz gar nicht...  ;-)

: Bearbeitet durch Moderator
von Ingo L. (corrtexx)


Lesenswert?

Lothar M. schrieb:
> Wenn du öfters mal
> eine Neuinitialisierung brauchst, dann hast du vermutlich noch
> weitere/andere EMV-Probleme im Design.

Ingo L. schrieb:
> Das war halt zum
> Provozieren der Beule ganz gut geeignet.

> Mein Vorschlag: denk nicht so menschlich in Zehnerpotenzen, die CPU ist
> binär sortiert. Wenn du hier das Update erst nach 256 Durchläufen statt
> den willkürlichen 196 (vermutlich um die "menschlichen" 10,0 Sekunden zu
> erreichen) machen würdest, reicht es, das Byte zu inkrementieren und
> danach das Zero-Flag abzufragen...
Kann man machen

von OMG (Gast)


Lesenswert?

Als Nachtrag:

"... und täglich grüsst das Murmeltier"

Immer wieder kommt diese Struktur auf:

Zuerst ins Verderben rennen (erst mal drauf los und irgend-
eine Hardware zusammenschustern) und dann hier im Forum
rumjammern.

Dabei wäre es doch so einfach sich erst im Forum bezüglich
Schaltung und Layout beraten zu lassen und dann hinterher
nicht ins Verderben zu rennen sondern durchzustarten.

Der TO ist lang genug hier dabei um diese Erkenntnis schon
gewonnen haben zu können.

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.