Hallo, ich sehe nen Effekt, den ich nicht verstehe, was zweifellos an meiner mangelnden Einsichtsfähigkeit liegt, aber Ihr könnt das besser: STM32F405 Olimex board, gcc. etc. pp., hat mit der hardware nix zum tun. Ich hole mir in der timergesteuerten ISR einen ADC-Wert (160ks/s) und werfe den ADC dann gleich wieder an, warte also nicht. Die Werte schreibe ich in einen Wechselbuffer: auf einem wird in der main() gerechnet, der andere wird in der ISR vollgeschrieben. In der main() rechne ich also auf dem fertigen Buffer und warte dann, bis der nächste buffer fertig ist. Wenn der fertig ist, fange ich von vorn an. Die Wartezeit macht eine langsame Sägezahnkurve, steigt linear an bis sie schlagartig wieder abfällt. Das verstehe ich nicht, eigentlich müsste die Wartezeit doch konstant sein!? Das Ganze würde ich wie so vieles Andere unverstanden lassen, wenn nicht meine berechneten Messerte auch mit derselben Periode von einem Signal überlagert wären. Kann sich jemand nen Reim drauf machen, Programmierfehler, irgendwas anderes oder ist der Sägezahn in dem plot schon angelegt? hm THX Cheers Detlef
@ Detlef _a (detlef_a) >STM32F405 Olimex board, gcc. etc. pp., hat mit der hardware nix zum tun. Wirklich? >Ich hole mir in der timergesteuerten ISR einen ADC-Wert (160ks/s) und 160 ks/s sind auch für einen 32 Bitter schon SEHR sportlich, wenn man jeden Meßwert einzeln per ISR abholt! >Die Wartezeit macht eine langsame Sägezahnkurve, steigt linear an bis >sie schlagartig wieder abfällt. Klingt danach, als ob deine CPU ISRs verschluckt. Dann kommt eine Schwebung raus, eben deine Sägezahnkurve.
Yo, das könntes' sein. Probier ich aus, indem ich die Rechenlast im Interrupt reduziere, vllt. is dann weg. Ausserdem mache ich mich kundig, wie man beim Cortex einen ISR Overrun entdecken kann :-/ Melde mich. Danke. Cheers Detlef
Hallo, ich habe immer noch das Problem: Die Wartezeit auf die interrupt service routine (idle_cnt, anghängte source) beschreibt eine Sägezahnkurve, meine Messwerte sind auch überlagert von dieser Kurve. Ich habe die ISR jetzt bis auf die Knochen abgemagert, da passiert nix langwieriges mehr, siehe angehängte source. Frage: Das 'TIM_ClearITPendingBit(TIM2, TIM_IT_Update);' ist so ok !? Die ganze Rechnerei passiert jetzt im main(), angehängt. Dort kriege ich mit, wenn ich die Rechenlast nicht mehr schaffe, das geht. Dort rufe ich auch meine Funktion lin_regress() auf, die macht fett (hardware, 32Bit) float-Rechnung. Ich benutze dort die lib-Funktionen acosf, sinf, cosf, atan2f, sqrtf, log10f neben float add, mult und div. Frage: Kann es sein, dass die lib-Routinen die interrupts stilllegen !? War da nicht irgendwas mit float Rechnung und interrupts !? Die float-Register wurden im interrupt nicht gesichert und durften deswegen im interrupt nicht benutzt werden (was ich nicht mehr tue), oder verwechsel ich da Prozessoren!? Wüßte auch nicht, wo ich in der Doku suchen sollte. Bin STM32 Anfänger, ich weiß. Danke für Eure Mühe. Cheers Detlef main: while(1){ lin_regress(&hbuf[buf_calc*(HBUFLEN/2)],HBUFLEN/2,0); val8= 1&((uint8_t)(buf_calc)^(uint8_t)(hbufp<HBUFLEN/2)); if(val8==1) statusword |= STATUS_OVERRUN; buf_calc = 1&(buf_calc+1); idle_cnt=0; while( 1&((uint8_t)(buf_calc)^(uint8_t)(hbufp<HBUFLEN/2))) idle_cnt++; } /******************************************************************/ void TIM2_IRQHandler() /******************************************************************/ { uint8_t ui; int16_t i1; uint16_t adcval; uint32_t ind; uint8_t c; TIM_ClearITPendingBit(TIM2, TIM_IT_Update); isrcnt ++; timercnt ++; adcval=ADC_GetConversionValue(ADC1); ADC_SoftwareStartConv(ADC1); hbuf[hbufp]=(adcval); hbufp++; if(hbufp==HBUFLEN) hbufp=0; }
1/160k sind 6,25 µs Zeit zwischen zwei Interrupts. Das ist schon eine sehr kurze Zeit. Eine andere Sache noch: Was passiert denn, wenn dein ADC beim Einteten des Timer-Interrupts noch nicht fertig mit der Konvertierung ist?
Warum machst du das überhaupt so kompliziert? Der STM32F4 hat einen DMA mit Double-Buffer-Modus, d.h. alles was deine ISR macht kann der komplett in Hardware. In der main() musst du also nur noch die Werte aus einem Array holen (welches, sagt dir ein DMA-Register).
Hallo, >>>>>>>>>>>>>>>> Was passiert denn, wenn dein ADC beim Einteten des Timer-Interrupts noch nicht fertig mit der Konvertierung ist? Ist er auf jeden Fall, hatte ich so aus dem Datenblatt gesehen. >>>Warum machst du das überhaupt so kompliziert? Ja, ich weiss der kann DMA. Aber erstens finde ich DAS komplizierter aufzusetzen als die ISR und ausserdem wollte ich fast alles gleich im interrupt rechnen. Aber wenn das so nix wird werde ich mich wohl durch die DMA beissen. Was ist denn mit float-Rechnung und interrupt, gibts' da was zu beachten was ich nicht weiss? Cheers Detlef
Der ADC wird aber nicht in einem Buffer geschrieben um einen Mittelwert zu errechnen ? Das waer dann schade und komplett unnuetz. Und float ... aaahhhhhhhh. Wozu braucht man float ? Um einen ADC Wert umzurechnen ? Sowas macht man sonst eigentlich nicht. Der ist als Integerwertt genauso nuetzlich.
Jetztnicht wieder die Standardeinlassung 'kein float'. Oh Doch, ich weiss genau was ich rechne. Geht denn jetzt interrupt zusammen mit float? Cheers Detlef
> Ja, ich weiss der kann DMA. Aber erstens finde ich DAS komplizierter > aufzusetzen als die ISR und ausserdem wollte ich fast alles gleich im > interrupt rechnen. Das hört sich nach > mangelnden Einsichtsfähigkeit an. Was ist da kompliziert? Ein paar Zeilen Code mehr. ILOIL. > Was ist denn mit float-Rechnung und interrupt, gibts' da was zu beachten > was ich nicht weiss? Nicht wenn du die FPU angemacht hast.
Detlef _. schrieb: > Geht denn jetzt interrupt zusammen mit float? Ja, du musst einschalten dass die Float-Register beim ISR-Betreten gesichert werden, sonst werden die float-Werte der main() oder unterbrochenen anderen ISR's überschrieben. Das geht zB über das Bit ASPEN im Register FPCCR. Dadurch werden die ISR's logischerweise nochmal langsamer. Für einen Mittelwert braucht man natürlich kein float, und es ist natürlich auch zu beachten dass bei floating-Point immer Präzision verloren gehen kann. Siehe S. 672 im ARMv7M Architecture Reference Manual.
Auch wenn man eine FPU hat rechnet man nie den Mittelwert, sondern den Tiefpass. Siehe zB auch http://www.ibrtses.com/embedded/exponential.html Den rechnet man auf den integer ADC Werten und kann den getiefpassten Wert dann skalieren wenn man dem skalieren verfallen ist. Der Vorteil vom Tiefpass : nach jedem Sample gibt's einen Wert mit minimalem aufwand.
Ohne mich mit dem Chip bzw. SDK schon einmal auseinandergesetzt zu haben: Erstens: Ich sehe keinerlei Synchronisationsmechanismus des Buffers zwischen ISR und Main. Wie soll das zuverlässig funktionieren? Zweitens: Was ist denn die maximale Abtastrate des ADC? Wenn die Funktion ADC_GetConversionValue(ADC1) blockierend ist bis die Wandlung fertig ist, ist das Verhalten doch kein Wunder. Die wartende ISR blockiert denn sogar noch den Prozessor. Das kann IMHO so nicht gewollt sein. Ist die Funktion nicht blockierend, werden aber auch merkwürdige Dinge passieren, denn dann liest du ungültige Werte, wenn die Wandlung zum Abfragezeitpunkt nicht fertig ist. Kommt es dir auf eine konstante Abtastfrequenz an, oder willst du so schnell wie möglich ADC-Werte erhalten? Hat der ADC keinen "Wandlung fertig" Interrupt? Beim Atmel würde man mit dem ADC-Interrupt lesen und will man eine bestimmte, konstante Abtastrate erreichen eine neue Wandlung mit einem Timer-Interrupt starten. Die Frequenz des Timer-Interrupts muss dabei niedriger sein als die maximale Abtastrate des ADC. Dann laufen beide Interrupts so kurz wie nötig. Auch die Main Routine muss mit einer Berechnung schneller fertig werden als die Werte angeliefert werden, ansonsten hast du trotzdem diesen Effekt weil die Main dann Abtastwerte unberechnet verschluckt. DMA hin DMA her, deine Beobachtung deutet darauf hin, dass Wandlung und/oder Berechnung zu langsam sind.
:
Bearbeitet durch User
Wolfgang K. schrieb: > DMA hin DMA her, deine Beobachtung deutet darauf hin, dass Wandlung > und/oder Berechnung zu langsam sind. Was nach Aussage des TO nicht sein kann, weil im Datenblatt steht, sein Code sei rechtzeitig fertig. (Ich wundere mich, wie aufwändig die Datenblätter heutzutage sind, dass sogar fremder Entwickler Code darin bedacht ist.) Detlef _. schrieb: >> Was passiert denn, wenn dein ADC beim Einteten >> des Timer-Interrupts noch nicht fertig mit der Konvertierung ist? > > Ist er auf jeden Fall, hatte ich so aus dem Datenblatt gesehen. Und was (Lib-) Funktionen wie die für Winkel anbelangt wäre ich bzgl. der Ausführungszeit vorsichtig. Die Standarddiskussion über float vs. int möchtest du ja nicht. Schnell geht jedenfalls anders und darüber gibt es dicke Pappen mit bedrucktem Papier dazwischen.
Detlef _. schrieb: > Geht denn jetzt interrupt zusammen mit float? Natürlich geht Interrupt mit Float. Hierbei gibt es aber verschiedene Szenarios: - Komplette FPU Register beim Interrupt entry sichern und beim return wieder herstellen. Kostet extrem viel zeit und ist meist völlig überflüssig. Denn: - Keine FPU benutzen im Interrupt. Dann muss nichts gesichert werden. Das ist bei deinem Beispielcode ja der Fall. - Oder Lazy Stacking verwenden. Hier wird die FPU erst gesichert, wenn sie tatsächlich im Interrupt verwendet wird. Damit ist man eigentlich auf der sicheren Seite, aber bitte nachschaun, wie und wo die register gesichert werden. Oh D. schrieb: > Und float ... aaahhhhhhhh. Wozu braucht man float ? Um einen ADC Wert > umzurechnen ? Sowas macht man sonst eigentlich nicht. Der ist als > Integerwertt genauso nuetzlich. Der Cortex M4 ist für Regel- und DSP-Aufgaben gemacht. Natürlich kann der Float berechnen, und das sogar sehr gut. Die Zeiten der alten PIC16 sind vorbei, "float ist böse" gilt also nicht mehr! Rolf Magnus schrieb: > 1/160k sind 6,25 µs Zeit zwischen zwei Interrupts. Das ist schon eine > sehr kurze Zeit. Ich nehme mal an, dass dein Prozessor mit 168MHz taktet. Dann hast du zwischen zwei Interrupts genau 1050 Taktzyklen. Das ist schon arg knapp, da hier auch noch der Context Switch mit abgedeckt werden muss.
Little B. schrieb: > Der Cortex M4 ist für Regel- und DSP-Aufgaben gemacht. Natürlich kann > der Float berechnen, und das sogar sehr gut. Die Zeiten der alten PIC16 > sind vorbei, "float ist böse" gilt also nicht mehr! Yep. Details hier: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439b/BEHJADED.html
Hallo, danke für die vielen Anregungen und Überlegungen. Zu den Zweifeln am Grundkonzept: ich setze nen Timerinterupt auf. Wenn der kommt lese ich den ADC aus und starte ihn gleich neu. Den gelesenen Wert speichere ich in einem Buffer. Der Bufferpointer macht mir Synchronisation im main(), da weiss ich wo der Sampler gerade ist. Wenn ich sicher bin, dass der ADC fertig ist wenn der nächste Interrupt kommt, funktioniert das so. >>>>>>>>>> - Keine FPU benutzen im Interrupt. Dann muss nichts gesichert werden. Das ist bei deinem Beispielcode ja der Fall. <<<<<<<<<< Ok, da bin ich erstmal beruhigt. >>>>>>>> Der Cortex M4 ist für Regel- und DSP-Aufgaben gemacht. Natürlich kann der Float berechnen, und das sogar sehr gut. <<<<<<<<< Ja, deswegen hab ich den ja genommen. >>>>>>>>>> Und was (Lib-) Funktionen wie die für Winkel anbelangt wäre ich bzgl. der Ausführungszeit vorsichtig. <<<<<<<<< Ja, die sind unübersichtlich und aufwendig. Ich werde mal probieren, was ohne diese Funktionen passiert. Den Effekt (Sägezahn bei der Wartezeit) sollte ich auch ohne korrekte Rechergebnisse sehen. Wenn das nix bringt setze ich den DMA auf. Sollte ich trotz meiner mangelnden Einsichtsfähigkeit schaffen, wird aber dauern. Und, nein, einen Mittelwert möchte ich nicht berechnen. Danke Cheers Detlef
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.