Forum: Mikrocontroller und Digitale Elektronik Probleme mit free-running ADC


von Sepp -. (sepp_o)


Angehängte Dateien:

Lesenswert?

Salve

Aus irgend einem Grund bekomme ich den Free-running-Mode des ADC's
nicht zum Laufen.

Ich schreibe die Asembler Programme mit AVR-Studio.

Ich hab sogar alle nicht benötigten Programmteile aus dem Testprogamm
rausgenommen und es wird trotzdem kein Interrupt gesendet.

Wenn ich aber den Interrupt der anzeigt dass die ADC-Wandlung fertig
ist manuell setze, wird die Interuptroutine abgearbeitet.

Kann mir bitte jemand sagen wo ich beim Setzen der Flags für die
ADC-Wandlung oder sonst irgendwo einen Fehler gemacht habe?


mfg Sepp

von Bernhard S. (bernhard)


Lesenswert?

Hi Sepp,

ich kann Dein Programm nur schwerlich lesen

Bsp:

ldi  R30,0xE0
out  ADMUX,R30

besser wäre:

ldi temp, 0<<REFS1 | 0<<REFS0
out ADMUX, temp


denn so sieht man sofort welches Bit wie gesetzt ist, ansonsten müssen
wir erst mühesam hex umrechnen und  uns die Datenblätter heraussuchen
und das kostet kostbare Zeit.

Schreib Dein Code einfach mal um, vielleicht findest Du den Fehler
sogar selber, ansonsten nochmal fragen.


Bernhard

von Christian Rötzer (Gast)


Lesenswert?

Hm, komisch. Freilaufend habe ich's auch noch nie versucht, allerdings
initialisiere ich meinen ADC und setze erst dann in einem eigenen
letzten Schritt das ADSC-Bit im ADCSR-Register.

von Hannes L. (hannes)


Lesenswert?

>  ldi  R30,0xCF
> ; ldi  R30,0xFF
>  out  ADCSR,R30

Erkläre uns mal bitte, wie du mit $CF in ADCSR den Free-Run-Mode
aktivierst? (ADATE???)

Was die Lesbarkeit des Programms angeht, hat Bernhard gar nicht so
unrecht. Schmunzeln muss ich immer über '0x00', eine einfache '0'
tuts da auch, sieht aber vermutlich zu einfach aus...
Schau mal hier:
http://www.hanneslux.de/avr/mobau/7ksend/7ksend02.html
Das ist zwar auch nicht das Nonplusultra, aber doch immerhin etwas
lesbarer.

Free-Run und Interrupt hatte ich noch nicht gebraucht. Wenn ich
Interrupt nutze, dann brauche ich doch kein Free-Run. Oder checke ich
jetzt was nicht? Beispiel:
http://www.hanneslux.de/avr/divers/melody/melody04.html

...

von Christian Rötzer (Gast)


Lesenswert?

@HanneS

> Schmunzeln muss ich immer über '0x00', eine einfache '0' tuts da
auch, sieht aber vermutlich zu einfach aus...

He! Mit dieser Aussage triffst Du nicht nur einen Programmierer!  Die
Strukturierung eines Quelltextes ist ja häufig das Geheimnis seines
Programmierers. Daher mag eine '0x00' statt der '0' Informationen
verbergen, die Du nicht siehst. Krasses Extrembeispiel ist ja auch eine
Version von Bernhard:

ldi temp, 0<<REFS1 | 0<<REFS0

Braucht mehr Platz, hat aber auch mehr Informationsgehalt. Aber so hat
jeder seine Gewohnheiten:

 sub volt0,volt             ;1/256 vom Mittelwert
 sbc volt,null              ;incl. Übertrag subtrahieren
 add volt0,wl               ;1/256 des eingelesenen Wertes
 adc volt,null              ;mit Übertrag addieren

Ich kann keine '0' entdecken.

schmunzel

von Andy (Gast)


Lesenswert?

Hallo,

Habe mir deinen Code mal näher angesehen. Damit der free running mode
funktioniert muss im SFIOR Register die ADTS2, ADTS1 ADTS0 Bits cleared
sein, was du ja auch getan hast. Aber laut datenblatt hat diese
Einstellung keinen Effekt wenn im ADCSRA Register das ADATE Bit nicht
gesetzt ist. Und dies ist in deinem Fall nicht gesetzt.

Teste es mal, vielleicht geht es.

Gruß, Andy

von Hannes L. (hannes)


Lesenswert?

@Christian:

> Krasses Extrembeispiel ist ja auch eine
> Version von Bernhard:
>
> ldi temp, 0<<REFS1 | 0<<REFS0

Nunja, das ist sehr unglücklich, da extrem wirkungslos. Mit 'ldi'
lädt man normalerweise die geshifteten Einsen, die Nullen bleiben von
alleine übrig. Ich habe das aber nicht kommentiert, da ich das für
einen Schreibfehler hielt.

Ich schreibe die Konstanten eigentlich immer so, dass ich (und auch
Andere) verstehen kann, was gemeint ist. Handelt es sich um
I/O-Register für Spezialhardware, dann schreibe ich die Bits mit den
Bitnamen laut Datenblatt. Bei Zählschleifen setze ich Dezimalzahlen
ein, ebenso bei Zahlen unter 10, da wirkt das '0x0..' lächerlich.
Hexzahlen gebe ich meist mit $ als Präfix ein, ist Gewohnheitssache vom
6502-Assembler. Gelegentlich schreibe ich Konstanten auch als ASCII (add
wl,'0'), wenn ich damit zeigen will, dass ich den ASCII-Wert meine.
mit "add wl,48" oder "add wl,0x30" sieht man das erst auf dem
zweiten Blick. Binärschreibweise nehme ich für Bitmuster, z.B. bei
7-Segment-Anzeigen.

> Aber so hat
> jeder seine Gewohnheiten:
>
>  sub volt0,volt             ;1/256 vom Mittelwert
>  sbc volt,null              ;incl. Übertrag subtrahieren
>  add volt0,wl               ;1/256 des eingelesenen Wertes
>  adc volt,null              ;mit Übertrag addieren
>
> Ich kann keine '0' entdecken.

Dann hast du nicht das ganze Programm gesehen. Bei mir (und etlichen
anderen ASM-Programmirern) gibt es inzwischen immer ein unteres
Register mit dem Namen 'null' und dem Inhalt 0. Das braucht man
nämlich immer wieder, zum Beispiel zum Addieren/Subtrahieren mit Carry
bei 16(32)-Bit-Arithmetik oder zum Löschen von I/O-Registern. Ohne
dieses Register wäre z.B. die von dir zitierte Mittelwertbildung nicht
so effizient (in der ISR im Vorbeigehen) realisierbar. - Oder???

Aber das ist alles relativ. In der Codesammlung gibt es genug ASM-Code
von hochkarätigen Programmierern, den auch ich nicht so ohne Weiteres
verstehe.

...

von Hannes L. (hannes)


Lesenswert?

Na??

Stolpert keiner über "add wl,'0'"??? - Datt gibbet nämlich nitt...
Muss dann "subi wl,-'0'" heißen...

;-)

...

von Läubi (Gast)


Lesenswert?

Ich glaub im Freerunning wird nur einmal (nach der ersten Wandlung) ein
Interrupt ausgeführt.
Danach muß man dann immer wieder den Interrupt aktivieren, oder
periodisch abfragen.
(Zumindest hab ichs bisher so gemacht)

von Hannes L. (hannes)


Lesenswert?

Bei vielen AVRs braucht man den ADC garnicht starten (ADSC), es genügt,
ihn einzuschalten (ADEN, ADIE). Der ADC startet dann selbsttätig, wenn
er in den Sleep geschickt wird. Bei einigen AVRs funktioniert das nur
im Sleep-Mode ADC-Noisereduction, bei anderen sogar im Idle-Mode.

Einfach mal im Datenblatt unter Sleep nachschaun und ausprobieren.

...

von johnny.m (Gast)


Lesenswert?

@Läubi:
Natürlich wird der Interrupt nach jeder Wandlung ausgelöst (auch im
Free Running Mode), wenn das Interrupt Flag vorher gelöscht war (was
beim Einspringen in die ISR automatisch geschieht). Alles Andere wäre
ziemlicher Unfug.

Im Free Running Mode muss man afaik das ADSC zum Start der ersten
Wandlung einmal setzen. Den Rest macht der µC selber.

Gruß

Johnny

von Sepp -. (sepp_o)


Lesenswert?

@HanneS

>>Erkläre uns mal bitte, wie du mit $CF in ADCSR den Free-Run-Mode
>>aktivierst? (ADATE???)
Du hast recht, ich  habe vergessen den Wert zurückzustellen.
Es hat aber auch nicht mit 0xEF funktioniert.
Mit 0xFF wurde die Wandlung einmal durchgeführt, weil dadurch der
Interrupt-Flag manuell gesetzt wurde.


Das 0x00 habe ich vom Programieren mit höheren Programiersprachen
(C/C++,...) übernommen.

Wenn ich Konstanten verwende, verwende ich immer nur Hexzahlen.
Klar könnte man auch 0 anstatt 0x00 verwenden, aber mann sieht dadurch
sofort dass es sich um eine 1-Byte große Konstante für die Verwendung
bei (unsigned) char-Variablen handelt.

So kommt man nicht mit den Variablentypen bzw. der Bitbreite
durcheinander.

Ach übrigens
>>"subi wl,-'0'"
funktioniert nur wenn man wie du ein Workregister low deffiniert hat.

Die Initialiesierung der ADC-Register habe ich übrigens dierekt von
einem C-Programm übernommen dass ich mit CodeVision AVR geschrieben
habe.
Da hat der free-running Modus einwandfrei funktioniert.
Auch beim ATmega8 hat der free-running Modus nie Probleme gemacht.

Ich habe bis jetzt den free-running Modus und den Interrupt verwendet,
weil man da den ADC nur einmal einschalten muß und sich dann nicht mehr
um die Wandlung kümmern muß.
Man schreibt einfach den neuen ADC-Wert in der Interruptroutine in ein
eigenes Register und hat somit jederzeit einen gültigen ADC-Wert.

Man verschwendet auch keine Prozessor-Zeit durch warten auf das Ende
der ADC-Wandlung.

Außerdem hat man beim free-running Modus mit Interrupt anstatt einen
Timer zu benötigen einen weiteren gewonnen.


Laut Datenblatt wird die ADC-Wandlunng gestartet sobald der IDLE-Modus
gestartet wird.
(Das Gleiche steht beim ADC-Noisereduction.)
Desswegen habe ich die ADC-Initialisierung gleich unter die
Stack-Initialisierung gepackt.

Das hat aber auch nicht funktioniert.

Den ADC-Noisereduction Modus möchte ich eigentlich vermeiden, dann im
free-running Modus nichts anderes gemacht wird als Analogwerte zu
digitalisieren.
Und außerdem muß der ADC-Wert in den Anwendungen die ich gerade vor
habe nicht sehr genau sein.
(Überwachung der Versorgungsspannung.)


@Bernhard Schulz
Da ich eigentlich grundsätzlich mit PDF-Datenblättern und dem
Windows-Rechner im wissenschaftlichem Modus arbeite, erspare ich mir
durch deine Methode eigentlich keine Zeit.

Ich arbeite bei der Resetroutine lieber mit den Zahlen dierekt, da
diese im Quellcode herausleuchten und dadurch schneller zu finden
sind.
Normalerweise schreibe ich die Hexzahlen in den Komentar binär
aufgeschlüsselt mit deren Bedeutung.

Beim Zusammenkürzen des Codes dürfte ich versehentlich ein paar
Kometarzeilen gelöscht haben.

@Alle
Was habe ich in diesem Test-Programm falsch gemacht?

Mit:
  ldi  R30,0xEF
  out  ADCSR,R30
bzw:
  ldi  R30,0xFF
  out  ADCSR,R30

klappt's auch nicht.

mfg Sepp

von johnny.m (Gast)


Lesenswert?

Mir schwant da grade Fürchterliches, nachdem ich das erste Posting noch
mal gelesen habe: Hast Du das ganze bisher nur im Simulator
ausprobiert? Darauf deutet jedenfalls der Hinweis hin, Du hättest den
Interrupt manuell gesetzt, was m.W. nur in der Simulation geht.

Ich hatte mal ein ähnliches Problem mit nem Mega16, das mich zu der
Annahme geführt hat, dass der AVR-Simulator mit ADC Auto Trigger (und
dazu gehört auch der Free Running Mode) generell nix anfangen kann. Auf
meine Anfrage

http://www.mikrocontroller.net/forum/read-2-312911.html

hat damals leider niemand was zum Besten gegeben. Aber es passt
zusammen, vorausgesetzt meine Vermutung stimmt, dass Du das bisher nur
im Simulator getestet hast. In meinem Fall hat es in der Hardware
tadellos funktioniert, nur eben im Simulator nicht. Wenn die
Möglichkeit besteht, dann teste es doch mal in der Hardware. Es würde
mich nicht wundern, wenns klappt. In der Init finde ich jedenfalls auf
den ersten Blick keine Fehler.

Gruß und frohe Ostern

Johnny

von Sebastian M. (izaseba)


Lesenswert?

Hast Du den JTAG in den Fuse-Bits deaktiviert ?
Ich hab deswegen schon ein paar Nächte um die Ohren gaschlagen.

Gruß Sebastian

von Sepp -. (sepp_o)


Lesenswert?

@johnny.m

Es funktioniert weder Simulieren noch die Hardware.

Im Register ADCSR gibt's doch ein ADC Interrupt Flag(Bit 4) dass
anzeigt ob ein ADC-Interrupt aufgetreten ist.

Wenn man dieses Bit aktiviert wird die Interruptroutine genau einmal
ausgeführt.
(Beim Simulieren und beim µC)

Ich verwende übrigens eine ältere Version von AVR-Studio.
(Version 3.irgendwas. Ich weis die Versionsnummer gerade nicht weil ich
den Programierrechner gerade heruntergefahren habe.)

Da habe ich bis jetzt eigentlich keine Probleme mit dem Simulieren
gehabt.

Ich vermute dass das Problem mit dem ATmega32 zusammenhängt.
Beim ATmega 8 hatte ich nämlich mit fast dem selben Code keine
Probleme.


@Sebastian Mazur

An den Fusebit's habe ich eigentlich nichts gemacht außer den Internen
Resonator für einen kleinen Test auf 8MHz zu stellen und danach wieder
auf 1MZ zurückzustellen.

Vom Rest der Fusebit's habe ich die Finger gelassen.

mfg Sepp

von Sebastian M. (izaseba)


Lesenswert?

Dann würde ich mal den JTAG deaktivieren, er ist standardmäßig
aktiviert, Du wärst nicht der erste, der darauf reingefallen wär.

Probieren kostet ja nichts, wenn's hilft gut, wenn nicht liegt es wohl
an was anderem...

Gruß Sebastian

von johnny.m (Gast)


Lesenswert?

Normalerweise kann man die Interrupt Flags nicht manuell setzen, sondern
nur löschen (indem man eine 1 hineinschreibt). Oder ist das beim Mega32
anders? In den meisten mir bekannten Da6tenblättern steht da immer
'Writing a logical 0 to the Bit has no effect' oder so ähnlich. Ich
würd mir aber schnellstens die neueste Version von AVRStudio
runterladen, v.a. dann wenn man mit einem der neueren AVRs arbeitet.
Die vom JTAG-Interface genutzten Pins benutzt Du anscheinend nicht, so
dass von da her kein Fehler zu erwarten ist.

von Sepp -. (sepp_o)


Lesenswert?

Salve

Ich hab jetzt das Testprogramm in C mit Code Vision AVR geschrieben und
habe keine Probleme gehabt.

Also muß es am Programm liegen.

@johnny.m
Kann sein dass man die Flags so nicht setzen kann.
Aber aus irgend einem Grund verhält sich der µC so als ob es
funktioniert.

mfg Sepp

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Hallo Sepp,

ich habe Dir mal ein Assenbler-Beispiel für den ATmega8 beigefügt.
(Free-Running & Interrupt)

Einfach die inc-Datei und die Interrupt-Vektoren auf Deinen µC
anpassen.

Anschließend testen ==> sich daran erfreuen und uns anschließend
erklären, warum es bei Deiner Variante nicht funktionierte.


>Da ich eigentlich grundsätzlich mit PDF-Datenblättern und dem
>Windows-Rechner im wissenschaftlichem Modus arbeite, erspare ich mir
>durch deine Methode eigentlich keine Zeit.

Aber uns hättest Du viel Zeit erspart ;)




Bernhard

von Hagen R. (hagen)


Lesenswert?

ldi temp, 0<<REFS1 | 0<<REFS0

ich mache das genauso, und gerade auch wenn man 0 als Konstente
reinschiebt und temp dann 0 wäre.

Denn exakt das enthält die meisten Informationen für den Programmierer.
Kurzer Source ist kein Indiz für einen guten Source und sollte niemals
als Optimierung herhalten.

Die zusätzliche Information ist nämlich

Welche Bitkonstanten könnte der Programmierer benutzen ?
Welche Bitkonstanten wurden tatsächlich benutzt ?

Man sieht also erstmal die lesbaren Konstantennamen, und zweitens
braucht man nicht ständig im Datenblatt nachschlagen welche
Bitkonstanten nun für das entsprechende Register möglich sind.

Ich halte das für einen sehr guten Programmierstil eines
vorrauschauendend, planmäßig und diszipliniertem Programmierer.

Auch das Weglassen der Klammersetzung sagt mir das der Programmierer
die Operatorenprioritäten der Boolschen Algebra kappiert hat und nicht
mit unnötig vielen Klamerungen alles unleserlich macht.


Gruß Hagen

von Sepp -. (sepp_o)


Angehängte Dateien:

Lesenswert?

@Hagen Re (Hagen) und Bernhard Schulz
Ihr habt ja recht.

Aber als einer der sich das Programieren mit diversen
Programiersprachen durch Beispielquellcode und herumprobieren
beigebracht hat, kann ich solche Programiertricks nicht wissen.

@ Bernhard

Ich habe deinen Quellcode etwas verändert (siehe Anhang) damit er auf
dem ATmega32 läuft.

Aber es will weder beim Simulieren noch auf dem µC funktionieren.

Merkwürdigerweise springt das Programm durch den Aufruf von 'rjmp
loop' in die Mitte der Reset-Funktion. Genauergesagt in die
Einstellung des Startwertes von PortD mit: 'out PORTD, temp'.

Was ist da los?
Solche Probleme hatte ich beim ATmerga8 nie.

mfg Sepp

von Hannes L. (hannes)


Lesenswert?

Deine Interrupt-Vektoren stimmen nicht. AVRs ab 16KB Flash haben
aufgrund des größeren Adressraums zwei Adressen (4 Bytes) pro Vektor
reserviert, damit der Befehl 'JMP' verwendet werden kann.

Ich mach es so:
1
;----------------------- Interrupt-Sprungtabelle --------------------
2
.cseg       ;Code-Segment (Flash, Programmspeicher)
3
.org 0      ;Interrupt-Sprungtabelle ATmega32
4
 jmp RESET          ;Reset Handler
5
 jmp nix;EXT_INT0       ;IRQ0 Handler
6
 jmp nix;EXT_INT1       ;IRQ1 Handler
7
 jmp nix;EXT_INT2       ;IRQ2 Handler
8
 jmp nix;TIM2_COMP      ;Timer2 Compare Handler
9
 jmp nix;TIM2_OVF       ;Timer2 Overflow Handler
10
 jmp nix;TIM1_CAPT      ;Timer1 Capture Handler
11
 jmp TIM1_COMPA     ;Timer1 CompareA Handler
12
 jmp TIM1_COMPB     ;Timer1 CompareB Handler
13
 jmp nix;TIM1_OVF       ;Timer1 Overflow Handler
14
 jmp nix;TIM0_COMP      ;Timer0 Compare Handler
15
 jmp nix;TIM0_OVF       ;Timer0 Overflow Handler
16
 jmp nix;SPI_STC        ;SPI Transfer Complete Handler
17
 jmp nix;USART_RXC      ;USART RX Complete Handler
18
 jmp nix;USART_UDRE     ;UDR Empty Handler
19
 jmp nix;USART_TXC      ;USART TX Complete Handler
20
 jmp nix;ADCC           ;ADC Conversion Complete Handler
21
 jmp nix;EE_RDY         ;EEPROM Ready Handler
22
 jmp nix;ANA_COMP       ;Analog Comparator Handler
23
 jmp nix;TWI            ;Two-wire Serial Interface Handler
24
 jmp nix;SPM_RDY        ;Store Program Memory Ready Handler
25
nix: reti

Wobei während der Programmierphase die Routine 'nix' Code zum
Debuggen enthält.

...

von Sepp -. (sepp_o)


Lesenswert?

Genau dass war's!

Vielen vielen Dank für eure Hilfe.

Ganz besonders dir HanneS.

@johnny.m
Jepp, auch beim Simulieren mit dem älteren AVR-Studio(Version 3.56)
wird der ADC-Interrupt nicht ausgelöst.

Auf dem Mikrokontroller läuft's aber hervorragend.

Frohe Ostern euch allen.

mfg Sepp

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.