Forum: Mikrocontroller und Digitale Elektronik ATXMega ADC rührt sich nicht


von F. K. (superpcfan)


Angehängte Dateien:

Lesenswert?

Hallo

Ich habe ein Problem, das mich schon seit mehreren Tagen beschäftigt. 
Ich möchte den ADC meines ATXMega32A4 auf mehreren Pins verwenden. ADC A 
soll Werte von Pin0 bis Pin11 liefern und die Werte per DMA in den RAM 
schreiben.

Ich habe zu dem Thema schon hier im Forum geschaut und die Atmel AppNote 
1300 gelesen.

Das Symptom ist, dass der "Conversion Complete Interrupt" nicht 
ausgelöst wird. Ich lasse zu testzwecken jedes mal einen Ton ausgeben, 
wenn die ISR aufgerufen wird, aber es kommt kein Ton und keine 
Messwerte.

Die Interrupts sind global eingeschaltet und alle Interrupt Level sind 
aktiviert (andere Interrupts lösen korrekt aus). Der Aufruf der ADC A 
ISR ist an der richtigen Stelle in der Interrupt Vector Tabelle 
platziert. Die Initialisierung des ADC sieht für mich gemäß Datenblatt 
und AppNote auch schlüssig aus und die Pins sind auf Eingang 
konfiguriert.

Die Frage ist, ob der Interrupt nicht auslöst, die ISR nicht gefunden 
wird oder der ADC überhaupt nicht anläuft.

Ob der ADC genau arbeitet ist erstmal uninteressant. Die Kalibrierung 
schreibe ich später. Das Ding soll erstmal nur Werte ausspucken.

Ich hoffe, einer von euch hat eine zündende Idee. Mir gehen die nämlich 
langsam aus....oder ich seh den Wald vor lauter Bäumen nicht.

Um besser durch das Programm zu steigen, noch als Hinweis:
- Das Programm ist in Assembler geschrieben
- auf SPI C hängen 2 Portexpander und ein LCD (funzt)
- SPI D ist noch unbeschaltet
- USARTE0 ist noch unbeschaltet
- TCD1 ist ein Quadraturdecoder für einen Drehgeber (funzt)
- TCC1 arbeitet als Frequenzgenerator für einen Pieper (funzt)
- TCC0 erzeugt  8 und 16 Hz Interrupts für periodische Berechnungen 
(funzt)
- Der "dreckige" Code in der Hauptschleife "main" dient nur zum Testen 
des ADC

Falls ich irgendeine Info vergessen habe, liefer ich die natürlich gerne 
nach.

Danke schonmal im vorraus.

Gruß
SuperPCFan

von Stefan F. (sfrings)


Lesenswert?

Für Außenstehende ist es sehr mühsam, so viel Code zu überprüfen. 
Reduziere das Programm auf die problematische Stelle, dann schaue ich 
gerne rein.

- Initialisierung des ADC
- Starten der Messung
- Schalte eine LED im Interrupt-Handler an, und lesen den Messwert aus. 
Mehr Code sollte dort vorerst nicht drin stehen.

von F. K. (superpcfan)


Lesenswert?

Ein "gestückelter" Code ist genauso schwierig zu verstehen.

Die Initialisierung und der Start der ersten Messung finden in der 
"MainInit.asm" im Bereich "Konfiguration ADC A" statt.

Ich habe alle Interrupts bis auf den des ADC auskommentiert und in 
diesem eine LED geschaltet. Das Ergebnis ist das Selbe wie meine oben 
beschriebene "Ton-version".

Die ISR wird nicht aufgerufen.

von F. K. (superpcfan)


Lesenswert?

Der "Freerun" Modus erzeugt ebenfalls keinen Interrupt.

von unl34shed (Gast)


Angehängte Dateien:

Lesenswert?

vergleich mal, was meine Init macht.

funktionieren tut sie, einfach oben die Parameter einstellen.

DMA ist aber noch nicht drin.

von F. K. (superpcfan)


Lesenswert?

Ich hab gerade in der Pause mal fix die Init durchgeschaut und mir 
schwant übles.

Ich fürchte der ADC wird den Dienst versagen, wenn das Kalibrierregister 
null ist.

Ich habe die Kalibrierung ja erstmal außen vor gelassen, da im 
Datenblatt/Manual nur sinngemäß steht: "Der Kalibrierwert muss aus dem 
Signature-Bereich geladen werden, wenn der ADC genau messen soll"

Heute Nachmittag werde ich das mal testen.

Danke für den Hinweis

von unl34shed (Gast)


Lesenswert?

an der Kalibrierung wird es nicht liegen, da sind dann die Werte halt 
falsch. Aber klar reinmachen sollte man das schon.

Hatte heut früh keine Zeit genauer drüber zu schauen, aber ich denk es 
liegt daran, das du sofort den ADC einschaltest (Enable).
Mach das erst ganz am ende der ADC-Init.

von F. K. (superpcfan)


Lesenswert?

Richtig, die Kalibrierung hatte auch keinen Effekt.
Ebenso ein "Above" Interrupt statt eines "Complete" Interrupt zeigt 
keine Wirkung.

Den ADC am Anfang oder am Ende zu initialisieren macht auch keinen 
Unterschied, funktioniert beides nicht.

Ich habe deine Init so wie sie ist in mein Programm übernommen, meine 
Init auskommentiert und folgende Parameter verändert:

- Vorteiler auf 256 (125kHz)
- Ch1 aus
- CH0 auf Complete interrupt
- CH0 interrupt level auf high
- Folgende beiden Zeilen habe ich auskommentiert, da ich kein 
"ADCA_SWEEP" habe.
1
// EVENTCTRL
2
  ldi R16, (ADCA_SWEEP << ADC_SWEEP_gp)
3
  sts ADC_EVCTRL_offset + ADCA_Port,R16

Leider auch ohne Erfolg.

Welchen Wert hat dein "ADCA_SWEEP"?

von unl34shed (Gast)


Lesenswert?

1
; Konfiguration ADC A
2
ldi    r16,0b00000001    ; enable ADC
3
sts    ADCA_CTRLA,r16
4
5
....


Die Zeilen hab ich mit "am Anfang" gemeint, die muss raus

von unl34shed (Gast)


Lesenswert?

Achso Sweep berechne ich so, hab ich vergessen zu kopieren.

.equ ADCA_SWEEP = (ADCA_Ch1_EN + ADCA_Ch2_EN + ADCA_Ch3_EN)

von F. K. (superpcfan)


Lesenswert?

Das meinte ich ja mit:

"Den ADC am Anfang oder am Ende zu initialisieren macht auch keinen
Unterschied, funktioniert beides nicht."

Streich "initialisieren" weg und schreib "starten" hin. :)

Ich hab jetzt mal das Interrupt Flag direkt überprüft.
Das ist erst null und wird dann irgendwann gesetzt.
Funktioniert also korrekt.

Die spannende Frage ist nun also, warum wird die ISR nicht auslöst.

Global Interrupts sind an, der Interupt Level High ist gesetzt und die 
ISR ist gemäß Datenblatt an Position 0x08E + 0 platziert.

von unl34shed (Gast)


Lesenswert?

hast du die Interrupts Enabled?

Gibt da jetzt ein Register für, das die einzelnen Level aktiviert.
"sei" reicht nicht mehr.
1
ldi R16, ((1 << PMIC_HILVLEN_bp) | (1 << PMIC_MEDLVLEN_bp) | (1 << PMIC_LOLVLEN_bp))
2
sts PMIC_CTRL, R16
3
sei

mehr dazu im "Xmega A Manual" ab Seite 122

von F. K. (superpcfan)


Lesenswert?

Jup, hab ich, die anderen Peripherie nutzt den Level "High" ja 
erfolgreich.

von unl34shed (Gast)


Lesenswert?

Mal getestet, ob der ADC überhaupt sampled?

also Werte am USART oder LCD ausgegeben?

weil wenn er die Flag setzt sollte das doch klappen.

Oder hängt dein Controller in einem anderen Interrupt noch drinne?
nur "ret" statt "reti" geschrieben? Und kommt deswegen nicht in die High 
lvl ISR. Die Flag mal wärend der Laufzeit überprüfen.

von F. K. (superpcfan)


Lesenswert?

Alle ISR' werden mit "reti" beendet.
Selbst wenn ich alle anderen ISR's auskommentiere, wird die ISR vom ADC 
nicht aufgerufen.

Ich habe jetzt mal die ADC ISR auf "ret" umgeschrieben, resette am Ende 
der ISR das Interrupt Flag und polle das Interrupt Flag in der "main" 
schleife.

Das klappt.
Wenn ich das Interrupt Flag zu Fuß auswerte, geht der ADC. Ich bekomme 
einigermaßen korrekte Messwerte von jedem Pin.

Nur der interrupt wird nicht generiert.

von F. K. (superpcfan)


Lesenswert?

Beim "zu Fuß" Auswerten des Interrupt-Flags ist mir der Gedanke 
gekommen, dass diese 16.000 Messungen (Complete Interrupts bei 125kHz) 
eigentlich noch viel zu viel sind. Langsamer darf der ADC ja nicht 
laufen.

Ich benötige nur ein paar Messungen pro Sekunde, sodass ich nun das 
Interrupt Flag in der SPI C ISR mit 50Hz polle.

Das machr bei 12 Pins 4 Messwerte pro Sekunde pro Pin.


Das erklärt zwar immernoch nicht, warum der dämliche Interrupt nicht 
will, aber ich kann den ADC nutzen.

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.