Guten Abend Zusammen Ich wundere mich gerade über die Wandlungszeit des ADC von meinem AVR32. Ich habe ihn im Freeruning mode und die ADC Frequenz ist auf 125kHz. Laut Datenblatt braucht der ADC 13 Cycles für eine Wandlung. Jedes mal wenn der Interrupt vom ADC kommt, übertrage ich das Resultat seriell. Die Zeitdifferenz zwischen den einzelnen Startbits variiert aber ganz anständig (Sollwert 0,104 ms) und ist nur selten einigermassen konstant --> siehe Plot (Zeitdifferenz zwischen den Startbits auf der y-achse). Warum ist das so? sollte die nicht ungefähr konstant sein? Dann habe ich noch eine Frage zu meinem Code weiter unten... Geht das decodieren eines Integer in Zeile 7 irgendwie schneller bzw. die serielle Übertragung ist noch nicht wirklich das Gelbe vom Ei, gibts da prinzipiell bessere Varianten? ISR(ADC_vect) { PORTD |= (1<<4); //set high, start bit ADCold = ADC; for(int i=0; i<10; i++) //10bit int { datasave[i] = ((ADCold >> i) & 1); //decode int } for(int i=0; i<10; i++) //send ADC value { if(datasave[i] == 1) PORTD |= (1 << 4); //set high else PORTD &= ~(1<<4); //set low _delay_us(5); //pause } PORTD &= ~(1<<4); //set low } Vielen Dank für jegliche Hinweise! Gruss bastler
bastler schrieb: > Geht das decodieren eines Integer in Zeile 7 irgendwie schneller bzw. > die serielle Übertragung ist noch nicht wirklich das Gelbe vom Ei, gibts > da prinzipiell bessere Varianten? ja. 1. macht keine langsamen Sachen in der ISR ( _delay_us!!!! ) 2. variabel Bitshift ist auf einem Atmel langsam. Warum erst alles in ein Array machen wenn es auch direkt geht?
1 | int adcvalue = 1234; |
2 | |
3 | for(int i=0; i<10; i++) { |
4 | if ( adcvalue & 1 ) { |
5 | PORTD |= (1 << 4); //set high |
6 | } else { |
7 | PORTD &= ~(1<<4); //set low |
8 | }
|
9 | adcvalue = advalue >> 1; |
10 | _delay_us(5); //pause |
11 | |
12 | }
|
13 | PORTD &= ~(1<<4); //set low |
Peter II schrieb: > Warum erst alles in ein Array machen wenn es auch direkt geht? der avr macht nichts anderes sonst, desshalb denke ich ist es egal wenn die isr ein bischen länger ist... die decodierung in binaries geschieht zuerst separat, damit der adc während der nächsten conversion nicht durch schaltende pins gestört wird. Aber die bits in das array schaufeln dauert ca. 25 us, was ein bischen zu lang ist so 15us wären ok... die pause zwischen dem setzen des startbits und den folgenden bits ist also gewollt fällt so aber zu lange aus. Ausserdem sind dann die zeitabstände zwischen den relevanten bits immer etwa gleich, da nicht noch gerechnet werden muss sondern nur das array ausgelsesen und ein pin gesetzt wird. Die Übertragung funktioniert so ganz gut aber das startbit ist zu lange bzw die Berechnungen dazwischen, um höhere samplingfrequenzen zu fahren als die 9.6kHz welche sich aus denn 125kHz des adcs ergeben. Das setzen des startbits erfolgt als Erstes damit der Zeitpunkt der Wandlung eruiert werden kann (-13 cycles). jetzt ist aber dieser zeitabstand nicht konstant (siehe plot) und ich weis nicht an was es liegen könnte... Vielen dank für die Mühe und weitere Gedanken! Gruss
Mit welcher Frequenz läuft der µC , und welche Baudrate soll das ergeben ? Es könnte durchaus sein, dass einfach die Übertragung zu lange dauert: So wie es aussieht 25 µs für das einsortieren ins Array, 50 µs für die 10 expliziten delays. Da sind nur noch 30 µs über. Der alternative Code ist schneller, selbst wenn man das Startbis explizit einfügt. Das Delay muss man ggf. minimal anpassen. In beiden Fällen hängt die Laufzeit ggf. minimal davon ab welcher Zweig beim IF .. Else genommen wird. Wenn man es schon mit dem Array macht, dann gleich die Werte rein die man ausgeben will (0 oder (1<<4)), so dass man da kein IF mehr braucht. Sonst wäre auch noch zu überlegen über der Fehler ggf. bei der Messung der Zeiten liegt. Der free running ADC interrupt kommt gleichmäßig alle 13 Zyklen des ADC Taktes. Den kann man sogar für Software UART nutzen und gibt bei z.B. 8 MHz Takt auch gleich die Standard-Baudraten.
Rudolph schrieb: > Eher AVR 8-Bit, eine ATMega32? Ja genau den, entschuldigt die ungenauigkeit. Ulrich H. schrieb: > Mit welcher Frequenz läuft der µC , und welche Baudrate soll das ergeben > ? 16 MHz mit prescaler 128 gibt dann die 125 kHz adcfreq und mit den 13 Zyklen gibts 9.6kHz also 104us zwischen den startbits. Mit den 5 us delay gibt das etwa 200 kHz . die if schlaufe kann ich ja weglassen, was die sache aber nur unwesentlich beeinflusst (danke für den Hinweis ) aber eigentlich sollten da noch um die 25us reserve sein. Im plot sieht man ja auch wie es ein paar samples lang funktioniert und dann wieder nicht. Werde mal kontrollieren ob der interrupt pünktlich kommt ohne Übertragung, dann kann es ja fast nur sein das die 25us reserve aufgebraucht werden, was ich aber auch komisch fände Gruss
Interrupt benötigen einige Taktzyklen bis zur Ausführung. Der aktuell ausgeführte Befehl wird niemals unterbrochen. Unter Umständen wird sogar noch ein Befehl mehr ausgeführt. Erst danach findet der Sprung zur ISR statt. Ich hab' die genauen Zahlen nicht im Kopf, glaube jedoch, dass bis zu 10 Takte Verzögerung vorkommen. Auf jeden Fall ist die Verzögerung unregelmäßig.
Die Verzögerung hängt von den Befehlen ab, die ausgeführt werden. Am langsamsten sind Aufrufe von Unterprogrammen (dürften bis 6 Zyklen sein). Damit hat man eine Unsicherheit bis etwa 5 Taktzyklen. Mit Atomaren Blöcken per CLI SEI kann es noch länger dauern, aber das sollte man vermeiden. Wenn das Hauptprogramm nichts tut, wird da aber keine Unterprogrammaufruf drin sei. Sondern nur ein einfacher Rücksprung damit hätte man dann nur 1-2 Zyklen Unsicherheit. Mit dem Aufwachen aus dem Idel-Modus kann man sogar ein definierte Reaktionszeit erreichen. Das Problem dürfte die zu lange Laufzeit sein.
Ulrich H. schrieb: > Der free running ADC interrupt kommt gleichmäßig alle 13 Zyklen des ADC > Taktes. Ja, das tut er :) Ulrich H. schrieb: > Wenn das Hauptprogramm nichts tut, wird da aber keine > Unterprogrammaufruf drin sei. Sondern nur ein einfacher Rücksprung damit > hätte man dann nur 1-2 Zyklen Unsicherheit. Bei 50000 Samples war der maximale Zeitunterschied der Startbits im Bereich 2e-7 s (siehe Plot), was etwa 3 Zyklen Unsicherheitspannweite bedeutet. Ich rechne jetzt mal mit +-2 Zyklen. Vielen Dank für diesen Hinweis! Ulrich H. schrieb: > Der alternative Code ist schneller, selbst wenn man das Startbis > explizit einfügt. Ja das ist er definitiv und jetzt ist auch noch ein bischen Luft nach oben :) Vielen Dank an Peter II an dieser Stelle!! Ulrich H. schrieb: > Sonst wäre auch noch zu überlegen über der Fehler ggf. bei der Messung > der Zeiten liegt. Ist mir jetzt ein bischen peinlich aber dies war schlussendlich das Problem... Mein erster Code hätte auch schon funktioniert aber jetzt habe ich ja eine schnellere Lösung. Einmal mehr wäre eine kritischere Haltung dem eigenen Code gegenüber angebracht gewesen. Ich denke ich kann das Thema abhacken. Vielen Dank für die rasche und kompetente Hilfe!! Gruess bastler
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.