Hi, ich bin hier gerade auf ein komisches Problem mit dem ADSC Bit aus dem ADCSRA Register gestossen. Leider kann ich den Code nicht soweit runterstrippen das ich ihn öffentlich machen kann, also versuche ich das mal zu beschreiben. Ich benutze den ADC im One-Shot Modus mit IRQ, alles schick soweit, abwechselnd werden zwei Kanäle gelesen und im IRQ die nächste Wandlung angeschoben. Mein Mega88PA läuft an 5V mit 16 MHz und mit nem Prescaler von 128 komme ich auf etwa 105µs Zeit für eine Wandlung - um das zu messen habe ich im ADC-IRQ einen Pin wackeln lassen. Jetzt habe ich mir überlegt, weniger Wandlungen zu machen. Also starte ich im ADC-IRQ einfach keine neue Wandlung und werte in der Hauptschleife alle 400µs das ADSC Bit aus. Nur, ebenfalls per Pin-Wackler und Oszi nachgemessen wird ADSC erst so nach 2,8..3,2 ms zurückgesetzt. Obwohl die Wandlung nach 105 µs beendet ist. Benutze ich dagegen ein eigenes Flag das ich vor der Wandlung setze und im IRQ zurücksetze, dann komme ich auf saubere 400µs Abstände. Wieso braucht ADSC so ewig lange um nach der Wandlung auf Null zu gehen? Normalerweise sollte das doch synchron mit der Ausführung des ADC-IRQ passieren?
Hi >Leider kann ich den Code nicht soweit runterstrippen das ich ihn >öffentlich machen kann, also versuche ich das mal zu beschreiben. Bringt nichts. Das ist nur Rätselraten. >Jetzt habe ich mir überlegt, weniger Wandlungen zu machen. >Also starte ich im ADC-IRQ einfach keine neue Wandlung und werte in der >Hauptschleife alle 400µs das ADSC Bit aus. Schon mal etwas von Autotrigger gehört? MfG Spess
Rudolph Riedel schrieb: > und werte in der > Hauptschleife alle 400µs das ADSC Bit aus. Wie genau machst du das denn? Und warum überhaupt? Orientier dich doch an ADIF; dazu ist es doch da. Macht die ISR doch auch.
Lutz schrieb: > Orientier dich doch an ADIF Das kann man aber nicht mehr pollen, wenn man den Interrupt aktiviert hat. Prinzipiell denke ich, dass ein in der ISR gesetztes Flag der korrekte Weg ist, aber Pollen von ADSC muss genauso klappen. Vermutlich wird Rudolph die Ursache wie Schuppen aus den Haaren fallen, wenn er versucht, das Problem auf ein minimales Stück Code runterzubrechen, damit wir es hier nachvollziehen können. ;-)
Tja, Rätselraten, naja, dann habe ich halt ein Problem. :-) Danke trotzdem soweit, werde ich halt selbst drauf kommen müssen. Das in Worte zu fassen ist auch schonmal hilreich. :-) >Schon mal etwas von Autotrigger gehört? Ja, und bisher verworfen, weil man dafür ja einen Timer "opfern" muss, aber vielleicht habe ich den sogar über, danke für den Tipp. >> Hauptschleife alle 400µs das ADSC Bit aus. >Wie genau machst du das denn? Ich benutze einen einfachen "Scheduler" mit einem 100µs Timer-IRQ und im Moment 4 "Tasks" -> 400µs Umlauf. >Prinzipiell denke ich, dass ein in der ISR gesetztes Flag >der korrekte Weg ist, Naja, jetzt habe ich festgestellt, dass auf dem Weg die Wandlung nicht richtig funktioniert. Da man mit dem JTAG-ICE-MK3 den Mega88PA nicht debuggen kann (DebugWire ist sowieso nicht witzig), sehe ich das aber nur an der Reaktion auf das Ergebnis, nicht aber die Werte selbst. Die Pins für die serielle Schnittstelle habe ich natürlich auch anderweitig belegt... >aber Pollen von ADSC muss genauso klappen. Klappt ja auch, nur seltsamerweise wird ADSC erst 2,8 ms nach der Wandlung zurückgesetzt. Damit kann ich ja auch leben weil selbst das als Abtastrate etwas hoch ist, es ist nur das komische Gefühl, dass da was nicht stimmt. :-) >Vermutlich wird Rudolph die Ursache wie Schuppen aus den Haaren fallen, >wenn er versucht, das Problem auf ein minimales Stück Code >runterzubrechen, damit wir es hier nachvollziehen können. ;-) Argh ja, ich bekomme das nicht so minimal das ich es einerseits posten kann und es andererseits nachvollziehbar wird, persönliches Pech halt. Den ADC-IRQ rauszuwerfen und ADIF pollen wäre auch noch ne Option.
Rudolph Riedel schrieb: > Argh ja, ich bekomme das nicht so minimal das ich es einerseits posten > kann und es andererseits nachvollziehbar wird, persönliches Pech halt. Nö, das ist trivial. Du willst ja nur wissen, wie lange es dauert, bis ADSC == 0 ist. Den Init-Code für T1 und den ADC mußt Du noch hinzufügen.
1 | TCNT1 = 0; |
2 | TCCR1B |= 1<<CS10; // start T1 |
3 | ADCSRA |= 1<<ADSC; // start ADC |
4 | while( ADCSRA & 1<<ADSC ); // until ADSC == 0 |
5 | TCCR1B &= ~(1<<CS10); // stop T1 |
So und jetzt mußt Du nur noch TCNT1 ausgeben. Peter
Rudolph Riedel schrieb: > Ja, und bisher verworfen, weil man dafür ja einen Timer "opfern" muss, Der Timer ist nicht "geopfert", er kann durchaus noch andere Sachen machen. Aber Achtung! Autotrigger funktioniert nur, wenn das Timerinterruptflag immer wieder gelöscht wird! Peter
Hi >Argh ja, ich bekomme das nicht so minimal das ich es einerseits posten >kann und es andererseits nachvollziehbar wird, persönliches Pech halt. Was soll das nun? Das Verhalten von ADSC ist im Datenblatt, S.256, genau beschrieben. Und mir ist noch kein AVR untergekommen, bei dem das nicht so ist. Und davon solltest du auch ausgehen. Der Bug ist woanders. MfG Spess
>Was soll das nun? Was denn? Einfach nur die Ansage das mir klar ist, dass ich keine konkrete Hilfe erwarten kann, wenn ich keinen Code poste. >So und jetzt mußt Du nur noch TCNT1 ausgeben. Ich kann nur leider nichts ausgeben mit der Platine. Für die I/Os hätte vermutlich auch nen Tiny44 gereicht. >Der Timer ist nicht "geopfert", er kann durchaus >noch andere Sachen machen. Das sollte die '"' andeuten. :-) Die Verwendbarkeit für andere Sachen wird halt eingeschränkt. Okay, mal rein auf ADSC reduziert:
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | |
4 | ISR(ADC_vect) |
5 | {
|
6 | uint8_t scrap; |
7 | |
8 | PORTC |= (1<<PC3); |
9 | scrap = ADCH; |
10 | }
|
11 | |
12 | int main(void) |
13 | {
|
14 | |
15 | cli(); |
16 | DDRC = (1<<PC3); |
17 | ADCSRA = 0x00; |
18 | ADMUX = (1<<REFS0) | (1<<ADLAR); |
19 | ACSR = (1<<ACD); |
20 | ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); |
21 | sei(); |
22 | |
23 | while(1) |
24 | {
|
25 | if( (ADCSRA & (1<<ADSC)) == 0) // letzte Wandlung fertig? |
26 | {
|
27 | PORTC &= ~(1<<PC3); |
28 | ADCSRA |= (1<<ADSC); |
29 | }
|
30 | }
|
31 | }
|
Damit tritt das von mir oben beschriebene "Problem" nicht auf. Das Signal was ich am Oszi messe hat ca. 107µs Pulsbreite und ca. 112µs Periodendauer, genau was man so erwarten kann. Das Problem liegt also woanders. Vielen Dank fürs zuhören. :-)
Rudolph Riedel schrieb: > Ich kann nur leider nichts ausgeben mit der Platine. Ach komm, ein IO-Pin wird doch wohl benutzbar sein. Du brauchst nichtmal nen Pegelwandler, wenn Du die Bitbefehle vertauschst.
1 | void sputchar( uint8_t c ) |
2 | {
|
3 | c = ~c; |
4 | STX_PORT &= ~(1<<STX_BIT); // start bit |
5 | for( uint8_t i = 10; i; i-- ){ // 10 bits |
6 | _delay_us( 1e6 / BAUD ); // bit duration |
7 | if( c & 1 ) |
8 | STX_PORT &= ~(1<<STX_BIT); // data bit 0 |
9 | else
|
10 | STX_PORT |= 1<<STX_BIT; // data bit 1 or stop bit |
11 | c >>= 1; |
12 | }
|
13 | }
|
Rudolph Riedel schrieb: > Damit tritt das von mir oben beschriebene "Problem" nicht auf. Damit weißt Du immerhin, daß es kein AVR-Bug ist. Rudolph Riedel schrieb: > Das Problem liegt also woanders. Irgendein Codeteil wird einfach so lange dauern. Peter
Okay, laut Datenblatt kann man eine einzelne Konvertierung anschieben indem man entweder das PRADC Bit löscht oder das ADSC Bit setzt. Leider gibt es noch eine dritte Möglichkeit die ich überlesen habe, nämlich den µC in den IDle-Modus schlafen zu schicken. "If the ADC is enabled, a conversion starts automatically when this mode ist entered." Schöner Nebensatz in Kapitel 10.3 Das mache ich aber um alle 100µs den µC durch den Timer-IRQ wecken zu lassen - mitsamt Verriegelung falls der µC nicht durch den Timer-IRQ gewecket wurde. Dadurch wurden ständig neue Wandlungen angeschoben und durch den 10µs Versatz war der ADC alle xx Wandlungen mal zufällig gerade dann fertig als das ADSC Bit abgefragt wurde. Mit Sleep kann ich also vergessen den ADC seltener zu triggern wenn ich nicht auch meinen Timer-IRQ langsamer mache. Dann noch auf den ADC-IRQ verzichten, damit der nicht für zusätzliche Aufwach-Ereignisse sorgt. Wobei sich mir gerade noch die Frage stellt was eigentlich passiert, wenn man versucht eine neue Wandlung zu starten bevor die letzte abgeschlossen ist. Was macht der ADC wenn man in IDLE Mode geht oder schlicht ADSC setzt obwohl gerade eine Wandlung läuft?
Hi >Okay, laut Datenblatt kann man eine einzelne Konvertierung anschieben >indem man entweder das PRADC Bit löscht oder das ADSC Bit setzt. Nein. Datenblatt: A single conversion is started by disabling the Power Reduction ADC bit, PRADC, in ”Minimizing Power Consumption” on page 43 by writing a logical zero to it and writing a logical one to the ADC Start Conversion bit, ADSC. Also nur mit Setzen vin PRADC startet der ADC nicht. >Wobei sich mir gerade noch die Frage stellt was eigentlich passiert, >wenn man versucht eine neue Wandlung zu starten bevor die letzte >abgeschlossen ist. Was soll passieren? Mehr als 1 kann ADSC nicht werden. MfG Spess
Rudolph Riedel schrieb: > "If the ADC is enabled, a conversion starts automatically when this mode > ist entered." Das scheint ein Randeffekt davon zu sein, dass es einen "ADC Noise Reduction" sleep mode gibt, bei dem natürlich der Start des ADC beim Erreichen des Sleep gewünscht ist. Das sollte natürlich unter "Starting a Conversion" auf jeden Fall erwähnt werden. Dafür solltest du ein Ticket bei avr -at- atmel.com öffnen. > Wobei sich mir gerade noch die Frage stellt was eigentlich passiert, > wenn man versucht eine neue Wandlung zu starten bevor die letzte > abgeschlossen ist. Nichts. Solange ADEN noch gesetzt ist, läuft die alte Wandlung einfach zu Ende.
Jörg Wunsch schrieb: >> "If the ADC is enabled, a conversion starts automatically when this mode > >> ist entered." > > > Das scheint ein Randeffekt davon zu sein, dass es einen "ADC Noise > > Reduction" sleep mode gibt, bei dem natürlich der Start des ADC > > beim Erreichen des Sleep gewünscht ist. Ich habe jetzt meinen Timer auf 250µs gesetzt, den ADC-IRQ sowie das setzen des ADSC entfernt und ja, mein Pin wackelt jetzt alle 250µ, also jedesmal wenn ich in der Hauptschleife ADSC abfrage. > Das sollte natürlich unter "Starting a Conversion" auf jeden Fall > > erwähnt werden. Dafür solltest du ein Ticket bei avr -at- atmel.com > öffnen. Och nö, da habe ich ehrlich gesagt keinen Bock mehr drauf. Nach der vollautomatischen Antwort das das Ticket eingegangen ist habe ich bisher nie irgendeine Reaktion sonst erhalten. >> Wobei sich mir gerade noch die Frage stellt was eigentlich passiert, >> wenn man versucht eine neue Wandlung zu starten bevor die letzte >> abgeschlossen ist. > > Nichts. Solange ADEN noch gesetzt ist, läuft die alte Wandlung einfach > zu Ende. Ich will ja nur sagen, das steht auch nirgendwo. Oder vorsichtiger formuliert, ich habe dazu keine Aussage gefunden. :-) In dem Fall ist ja vor allem die Frage was passiert, wenn man den µC schlafen legt bevor eine Wandlung abgeschlossen ist. Ausprobieren ist bei sowas dann auch nur bedingt hilfreich.
> Moment 4 "Tasks" -> 400µs Umlauf.
Kommt dir diese Zeit auch bekannt vor ?
Dann ist der Task ADCS Pollen ja auch nur alle 400µS dran !
Das ganze steht auch noch unter: 23.6 ADC Noise Canceler Konnte natürlich keiner ahnen, daß Du den Idle-Mode benutzt. Meine Philisophie ist außerdem, daß die Sparmodi immer ganz am Schluß programmiert werden, nachdem die komplette Anwendung getestet ist und einwandfrei läuft. Das Vermengen des Stromsparens mit der Funktion führt unweigerlich zu Ärger. Das beobachtet man hier im Forum immer wieder. Teile (die Aufgaben) und herrsche. Bei Netzbetrieb hat es eh keinen merkbaren Effekt, da ist es schade um die zusätzliche Entwicklungszeit. Auch kann es durchaus mehr sparen, wenn man einfach versucht, mit weniger als 16MHz auszukommen. Eine CPU muß nicht unbedingt am Anschlag laufen. Peter
Uwe schrieb: >> Moment 4 "Tasks" -> 400µs Umlauf. > > Kommt dir diese Zeit auch bekannt vor ? > > Dann ist der Task ADCS Pollen ja auch nur alle 400µS dran ! Das ja okay, eigentlich wäre die Wandlung dann ja auch 290µs vorher fertig gewesen. Gesehen habe ich aber das die Wandlung vermeintlich etwa erst jedes 8. Mal fertig war als ich das Bit gelesen habe. @Peter Dannegger Der "Scheduler" ist eigentlich sowas wie Basis-Funktionalität in meinen Projekten, bisher habe nur nicht versucht den ADC seltener zu triggern, bin also auch nicht darüber gestolpert, dass IDLE den ADC startet. :-) Und ja, den Takt kann ich noch runterschrauben, und ja, das bringt einiges. Da bin ich aber noch nicht, erstmal muss ja die ganze Funktion da sein bevor man dafür sorgen kann dass sich der µC langsamer langweilt. :-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.