Moin,
Auf einem atmega16 verwende ich den ADC zum samplen von 1 Kanal.
Samplingfrequenz ist 32kHz, CPU Takt 16MHz. Plan dahinter: Der ADC wird
regelmaessig vom Timer1 getriggert; wenn er fertig gewandelt hat, gibts
einen ADC interrupt und ich hol' mir das Sample ab.
Das funktioniert auch soweit prima. Zumindest zwischen ein paar Minuten
und mehreren Stunden lang. So wie's aussieht, kanns dann bei mir dazu
kommen, dass der ganze Apparat stehenbleibt. D.h. aus irgendeinem Grund
wird nicht mehr in den ADC-Interrupthandler gesprungen (derzeit solange,
bis ich einen Reset ausloese). Die "restliche" Software (nicht irq
gesteuert) laeuft weiter.
Vom Fehlerbild her riecht das fuer mich ganz stark nach irgendeiner
bloeden Racecondition, will sagen: Es koennte irgendwelche Zeitpunkte in
meiner SW geben, in der z.b. das Interrupt-Ack nicht funktioniert oder
sowas...Da fangen bei mir jetzt die Vermutungen an...bei mir gepaart mit
keinerlei Erfahrung auf AVR.
Hier n' paar codefragmente - den kompletten source gibts da im File
hb-0.1.0.zip:
Beitrag "Re: "LED-Spectrumanalyzer"software ohne Fouriertransformation"
Ich mach' hier mal einen separaten Thread auf, alldieweilen ich gesehen
hab', wie andere Threads unter Projekte & Code durch die dort
aufgetretenen Probleme doch ziemlich laenglich wurden.
Initialisierung:
1
...
2
ldi r29,0x01
3
ldi r28,0xf3
4
out 0x2b,r29
5
out 0x2a,r28; ocr1a = 499 -> 16MHz / 500 = 32kHz ADC sampling frequency
6
7
ldi r28,0x00
8
out 0x1f,r28; EEARH=0, the bar/dot lookuptable is just 256 bytes
9
out 0x2f,r28; tccr1a = 0
10
ldi r28,0x09
11
out 0x2e,r28; tccr1b = 9
12
ldi r28,0xed
13
out 0x06,r28; adcsra=0xed
14
ldi r28,0xe0
15
out 0x07,r28; admux=0xe0
16
17
in r28,0x30
18
andi r28,0x0f
19
ori r28,0xa0
20
out 0x30,r28; sfior upper nibble =0xa
21
...
Anfang irq-handler incl. irq-ack:
1
adc_irq:
2
in r6,0x3f ; save flag register
3
ldi r25,0x08 ;
4
out 0x38,r25 ; int ack
5
in r25,0x05 ; read adc
6
;--uncomment next line for testsignal sawtooth
7
;mov r25,r30
8
;--uncomment next line for testsignal silence
9
;ldi r25,0x80
10
;--end testsignal
11
subi r25,128 ; convert to signed 8 bit
12
;--uncomment next line for -6dB
13
;asr r25 ; -6dB
14
st z,r25 ; store in buffer
15
inc r30 ; increment buffer write pointer
16
mov r25,r30
17
andi r25,0x0f;
18
brne nodisplay
19
....
20
nodisplay:
21
out 0x3f,r6 ; restore flag register
22
reti
Ich denk' mal, regelmaessiges Samplen mit dem ADC ist nicht so exotisch,
als dass das noch nie jemand in Assembler gemacht haette, daher die
abschliessende Frage:
Was laeuft da manchmal schief?
Gruss
WK
Hallo,
was steht denn in Datenblatt in welchem Bereich sich der ADC-Takt
befinden muss (soll) ?
Ich würde hier erstmal nachbessern und warum programmiert man so etwas
nicht in C oder einer anderen Hochsprache ?
Noch nie etwas von Register namen gehört?
in r6,0x3f ; save flag register
out 0x38,r25 ; int ack
wer soll denn mit 0x3F oder 0x38 etwas anfangen können?
Moin,
Karl M. schrieb:> was steht denn in Datenblatt in welchem Bereich sich der ADC-Takt> befinden muss (soll) ?
Wenn ich das Datenblatt richtig interpretiere, steht da:
Zwischen 50kHz und 200kHz, wenn man 10bit haben will, und oberhalb von
200kHz, wenn einem 8bit reichen. Tut mir.
Also hoff' ich mal, dass ich den Vorteiler so eingestellt hab', dass
16MHz/32=500kHz rauskommen. Damit sollte der ADC pro Wandlung
500kHz/32kHz= 15.625 Zyklen Zeit haben. Damit sollte ich ueber den 13
Zyklen liegen, die der ADC nach Datenblatt braucht. Die Ergebnisse des
ADC sehen fuer mich auch OK aus, soweit ich's beurteilen kann. Haben
also durchaus was mit dem Eingangssignal zu tun.
> Ich würde hier erstmal nachbessern und warum programmiert man so etwas> nicht in C oder einer anderen Hochsprache ?
Das programmiert man deshalb nicht in C oder einer anderen Hochsprache,
weil man gesehen hat, was ein in C programmierter Interrupt-Handler so
an Ballast mit sich rumschleppt und weil man weiss, dass bei 32000
Interrupts/sec. jeder Zyklus zaehlt, weil man weiss, dass zwischen 2
Interrupts auch nur 500 Zyklen vergehen.
Karl M. schrieb:> in einer ISR muss man auch alle benutzen Register sichern, wenn man> nicht ausschließlich diese nur dort verwendet !
<Loriotmode>Ach</Loriotmode> Genau das ist einer der Gruende, warum ich
das in Assembler gemacht hab'. Wenn man nicht alle von ausserhalb
benutzten Register in einem IRQ Handler sichert und wiederherstellt, der
32k mal pro Sekunde aufgerufen wird, dann ist's auch eher
unwahrscheinlich dass das ueberhaupt ein paar Sekunden laueft. Bei mir
tuts das aber schon auch stundenlang.
Peter II schrieb:> Noch nie etwas von Register namen gehört?
Ja, schon. Nur eben der gcc nicht. Dessen asm output war vor Monaten mal
die Basis des ganzen.
Gruss
WK
Dergute W. schrieb:> out 0x2a,r28; ocr1a = 499 -> 16MHz / 500 = 32kHz ADC sampling> frequency
Ohne mich jetzt im Detail durchzurechnen:
1
out0x06,r28;adcsra=0xed
Das ist 16MHz / 32 = 500KHz = 2us * 13Cy = 26us = 38.4KHz.
Wird aber on Timer/Counter1 Compare Match B gestartet ?
TCCR1A = 0, das ist für mich Normal Mode, was da OCR1A zu suchen
hat, ist mir unklar.
Kurz, das ist so viel zu kompliziert, wenn du Hilfe erwartest, must
du schon deinen Teil dazu beitragen.
Also:
Ich hab Timer1 so eingestellt...
Und zwar hier...
ADC ist so eingestellt...
Und zwar hier...
Und nicht Link auf 17 zipped Files und dann um Hilfe bitten.
Dergute W. schrieb:> Das programmiert man deshalb nicht in C oder einer anderen Hochsprache,> weil man gesehen hat, was ein in C programmierter Interrupt-Handler so> an Ballast mit sich rumschleppt
Um genau dieses zu vermeiden, wurde das Attribut "nacked" erfunden.
(wenn ich mich nicht total irre)
Dergute W. schrieb:> <Loriotmode>Ach</Loriotmode>
Ja.
Peter II schrieb:> wer soll denn mit 0x3F oder 0x38 etwas anfangen können?Marc V. schrieb:> Kurz, das ist so viel zu kompliziert, wenn du Hilfe erwartest, must> du schon deinen Teil dazu beitragen.
Deswegen verwendet auch ATMEL Register und Bitnamen.
Moin,
Marc V. schrieb:> Kurz, das ist so viel zu kompliziert, wenn du Hilfe erwartest, must> du schon deinen Teil dazu beitragen.> Also:> Ich hab Timer1 so eingestellt...> Und zwar hier...> ADC ist so eingestellt...> Und zwar hier...
Ja, da ist natuerlich was dran, das ist in der Form, in der ich's
vorliegen hab', nicht so mundgerecht serviert, wie es sein koennte.
Pardong.
> Und nicht Link auf 17 zipped Files und dann um Hilfe bitten.
Tja, wie man's macht, isses verkehrt. Wenn da nur die .s Files und ein
Makefile drinnen ist, motzen wieder welche, weil sie nur die hex-Files
wollen; weil sie nicht wissen, wie's zum Inhalt des eeproms kommt, etc.
Daher hatte ich auch hier direkt signifikante Teile der sourcen in den
Post uebernommen.
Marc V. schrieb:> TCCR1A = 0, das ist für mich Normal Mode, was da OCR1A zu suchen> hat, ist mir unklar.
Mir momentan auch, wahrscheinlich war das in irgendeinem
C-Codeschnipsel, den ich ausm www gefischt hatte, vielleicht um
zusaetzlich einen Pin wackeln zu lassen.
Merci schonmal fuer die Anregung, ich werd' mir die Timerinitialisierung
noch paarmal angucken.
Aber mal unter uns: Wie wahrscheinlich ist es, dass ein Effekt, der
irgendwann mal nach Stunden auftritt und natuerlich nicht, wenn man
drauf wartet, mit einer falschen Initialisierung zusammenhaengt?
Ich mein - klar, wenn das Ding noch nie gelaufen waere, oder nach genau
1x ADC wandlung haengen wuerde - dann isses wohl was mit der
Initialisierung. Aber der Effekt tritt halt wirklich selten auf. Hab's,
waehrend ich programmiert hab', nicht bemerkt; wahrscheinlich, weil die
Software nie lang genug gelaufen ist.
U. F. schrieb:> Um genau dieses zu vermeiden, wurde das Attribut "nacked" erfunden.> (wenn ich mich nicht total irre)
OMG, "naggisch" als Attribut hab' ich noch nicht gekannt. OK,
wahrscheinlich kriegt man mit solchen Sauereien mit Gewalt irgendwelchen
Sourcecode zustande, der, wenn durch einen gcc gepruegelt wird,
irgendwie sowas aehnliches ergibt, wie das, was ich direkt in Assembler
haben wollte.
Aber ob das dann besser leserlich ist?
Marc V. schrieb:> ist doch ein Unterschied, oder ?
Ja klar - wie Tag und Nacht. Mit beiden kann ich ohne Datenblatt als pdf
fuer erleichterte Suche oder meinetwegen Headerfile gleich wenig
anfangen.
Gruss
WK
Dergute W. schrieb:> Marc V. schrieb:>> TCCR1A = 0, das ist für mich Normal Mode, was da OCR1A zu suchen>> hat, ist mir unklar.>> Mir momentan auch ...
?
Mit WGM12 (alias CTC1) in TCCR1B wird CTC auf OCR1A eingeschaltet, OCR1B
steht auf 0, löst also dort den ADC aus, stimmt doch alles. Der beste
Beweis ist ja auch, dass es im Prinzip läuft.
Ich vermute ein ungewolltes Überschreiben von Registern und/oder SRAM.
S. Landolt schrieb:> Mit WGM12 (alias CTC1) in TCCR1B wird CTC auf OCR1A eingeschaltet, OCR1B> steht auf 0, löst also dort den ADC aus, stimmt doch alles. Der beste> Beweis ist ja auch, dass es im Prinzip läuft.
Korrekt.
Aber auch wiederum der beste Beweis dafür, dass man es mit Bitnamen,
Registernamen und direkt hintereinander im Code machen soll... ;)
Man kann auch C und ASM Code mischen, wenn man tatsächlich ein Problem
mit einer ISR haben sollte. Und ob man hat, "erfühlt" man am besten
durch messen.
".s" bedeutet doch GNU-Toolchain, oder nicht?