Hallo, ich habe ein kleines Problem mit F_CPU. Beim ATMega2560 z.B.kann ich zwar einen 14,7456 MHz Quarz anschließen, der endgültige CPU-Takt hängt aber vom Taktteiler ab. Da z.B. der ATMega2560V nur bis 8MHz spezifiziert ist, muss der Quarz-Takt halbiert werden. Deswegen mache ich in meiner 'cpu.h' eine Abfrage auf den Controllertyp und setze F_CPU entsprechend. Zur Laufzeit wird dann in 'cpu.c' der Takteiler entsprechend gesetzt. Deswegen gibt es bei mir noch ein F_XTAL um den Quarztakt zu spezifizieren. Das GCC-Modul 'delay.h' verwendet aber F_CPU um die Delayzeiten zu berechnen. Umschiffen kann ich das, indem man 'cpu.h' vor 'delay.h' einbindet (und der Compiler meckert dann, dass F_CPU 'redefined' ist, aber egal). Welche Module verwenden denn noch F_CPU ? Daniel
Da F_CPU der CPU-Takt und nicht der Quarztakt ist, warum setzt du das nicht auf halbe Quarzfrequenz und fertig? Wie diese CPU-Frequenz zustande kommt, ob halbiert oder nicht, ist ja egal.
Dann habe ich mich nicht klar ausgedrückt: Wenn ich zur Laufzeit (bzw. beim 'booten') den Takteiler ändere, ändert sich auch meine CPU-Frequenz. Dann stimmen die Ergebnisse aus z.B. 'delay.h' nicht mehr, weil diese zur Compilezeit errechnet wurden. Deswegen prüfe ich zur Compilezeit den CPU-Typ und definiere den Taktteiler und F_CPU neu. Leider wird aber F_CPU ja auch schon von der Entwicklungsumgebung (Eclipse+WinAVR) definiert, und diese Definition ist unter Umständen falsch, wenn ich F_CPU nicht vorher umdefiniere. Deswegen meine Frage von oben.
A. K. schrieb: > Da F_CPU der CPU-Takt und nicht der Quarztakt ist, warum setzt du das > nicht auf halbe Quarzfrequenz und fertig? Wie diese CPU-Frequenz > zustande kommt, ob halbiert oder nicht, ist ja egal. Weil ich auf ein und dem gleichen Board einmal ATMEGA2560 und einmal ATMEGA2560V bestücken kann. Der Quarz bleibt der gleiche.
Das wird so nicht funktionieren. Delay.h ist (im wesentlichen) nichts anderes als ein Sammlung von Makros welche ein konstantes F_CPU erwarten welche vom Compiler/Preprozessor ausgewertet werden. Wenn du F_CPU zu einer Variablen machst stimmen die Delays generell nicht mehr. Abgesehen davon wird immer die Floating Point Bibliothek benötigt.
Gast
#1684516
Daniel V. schrieb: > Leider wird aber F_CPU ja auch schon von der Entwicklungsumgebung > (Eclipse+WinAVR) definiert, und diese Definition ist unter Umständen > falsch, wenn ich F_CPU nicht vorher umdefiniere. Eclipse definiert gar nichts, wenn du das nicht möchtest. Es gibt für alles in den settings eine Einstellung, die man anpassen kann. Daniel V. schrieb: > Umschiffen kann ich das, indem man 'cpu.h' vor 'delay.h' > einbindet (und der Compiler meckert dann, dass F_CPU 'redefined' ist, > aber egal). Deine Lösung ist völlig in Ordnung, und wenn du Eclispe richtig einstellst, meckert auch der Compiler nicht mehr. F_CPU wird überhaupt nicht vom Compiler versendet, nur von der avrlibc. Dort nutzt es IMHO ausser delay.h nur noch setbaud.h. Oliver
Gast
#1684517
versendet -> verwendet ;-)
Das ist ja auch mein Problem. Um das ganze variabel zu machen, wäre es ja vorstellbar, dass zur Laufzeit (beim Aufrufen von delay_ms() z.B.) geschaut wird, welche Frequenz der Quarz hat (das gibt man z.B. über F_XTAL an) und wie der Takteiler eingestellt ist. Daraus errechnet sich dann die Wartezeit. Das wäre doch mal ein kleines Projekt....ausserdem könnte man die CPU runtertakten und die Delay-Zeiten stimmen immer noch :-)
Oliver schrieb: > Eclipse definiert gar nichts, wenn du das nicht möchtest. Es gibt für > alles in den settings eine Einstellung, die man anpassen kann. > Oliver Tja, leider kann ich Eclipse nicht dazu bewegen F_CPU nicht zu definieren.
Gast
#1684550
Daniel V. schrieb: > Tja, leider kann ich Eclipse nicht dazu bewegen F_CPU nicht zu > definieren. project properties->C/C++-Build->settings dort unter AVR Compiler/Symbols (welche Überraschung ;-) gibt es eine Checkbox "Omit F_CPU". Anklicken, weg ist das F_CPU. Olver
Oliver schrieb: > Daniel V. schrieb: >> Tja, leider kann ich Eclipse nicht dazu bewegen F_CPU nicht zu >> definieren. > > project properties->C/C++-Build->settings > > dort unter AVR Compiler/Symbols (welche Überraschung ;-) gibt es eine > Checkbox "Omit F_CPU". > Anklicken, weg ist das F_CPU. > > Olver Das muss man aber auch erstmal finden, ich bin unter project properties->C/C++-Build->environment rumgeeiert
Nimm einen Timer für die Delay-Generierung, und bau die Funktionen so, dass sie sich an die CPU-Frequenz anpassen können. Je nach Timer kannst du die unterschiedlichen CPU-Frequenzen sogar durch den Vorteiler ausgleichen. Oder betreibe einfach gleich beide Setups mit dem halben Takt...
Daniel V. schrieb: > Um das ganze variabel zu machen, wäre es ja vorstellbar, dass zur > Laufzeit (beim Aufrufen von delay_ms() z.B.) geschaut wird, welche > Frequenz der Quarz hat (das gibt man z.B. über F_XTAL an) und wie der > Takteiler eingestellt ist. Das geht nicht. Ein Macro muß zur Compilezeit definiert sein und kann auch nur zur Compilezeit ausgewertet werden. Zur Laufzeit geht das garnicht. Du mußt für den ATMega2560 und den ATMega2560V verschiedene Programmversionen compilieren. Einmal mit F_CPU = 14,7456MHz und einmal mit 7,3728MHz. Fertig ist die Laube. Peter
Gast
#1685141
Mir leuchtet noch nicht ein, warum man ein und dasselbe Programm einmal mit 14,7456MHz und einmal mit 7,3728MHz laufen lassen muß. Entweder reicht der niedrige Takt, dann aber auch auf beiden CPUs, da es ja das selbe Programm ist, oder es reicht nicht, dann ist der V sowieso nicht geeignet.
Jörg Wunsch schrieb: > Nimm einen Timer für die Delay-Generierung, und bau die Funktionen > so, dass sie sich an die CPU-Frequenz anpassen können. Je nach > Timer kannst du die unterschiedlichen CPU-Frequenzen sogar durch > den Vorteiler ausgleichen. > > Oder betreibe einfach gleich beide Setups mit dem halben Takt... ja, aber dann hätte ich immer noch das Problem, dass der GCC eventuell das falsche F_CPU verwendet (auch wennes jetzt nur in delay.h und setup.h vorkommt, aber das könnte sich ja in Zukunft ändern)
Peter Dannegger schrieb: > Das geht nicht. > Ein Macro muß zur Compilezeit definiert sein und kann auch nur zur > Compilezeit ausgewertet werden. > Zur Laufzeit geht das garnicht. > > Peter Hab ja nicht gesagt, dass ein Macro das machen muss...
Rolf Magnus schrieb: > Mir leuchtet noch nicht ein, warum man ein und dasselbe Programm einmal > mit 14,7456MHz und einmal mit 7,3728MHz laufen lassen muß. Entweder > reicht der niedrige Takt, dann aber auch auf beiden CPUs, da es ja das > selbe Programm ist, oder es reicht nicht, dann ist der V sowieso nicht > geeignet. Das ist ein berechtigter Einwand. Vielleicht liegt es einfach an mir, dass ich mich zunächst noch nicht festlegen möchte. Aber ich sollte wohl mal eine Grundsatzentscheidung treffen, da hast du Recht!
Daniel V. schrieb: > ja, aber dann hätte ich immer noch das Problem, dass der GCC eventuell > das falsche F_CPU verwendet Wenn du weder <util/delay.h> noch <util/setbaud.h> einbindest, musst du auch kein F_CPU definieren. Du hast ja schon festgestellt, dass das sonst niemand braucht. Der Rest der Bibliothek (und der Compiler erst recht) interessiert sich einen feuchten Kehrricht dafür, mit welcher Frequenz deine CPU läuft. Am ehesten würdest du diese Konstante noch in deiner eigenen Applikation benötigen, um das ganze Timer-Setup zu berechnen, aber dafür verbietet dir ja 1.) niemand, einen anderen Namen als F_CPU zu benutzen und zweitens kannst du dort prima mit einem #ifdef arbeiten.
Daniel V. schrieb: > ja, aber dann hätte ich immer noch das Problem, dass der GCC eventuell > das falsche F_CPU verwendet Dann bist Du aber selbst dran schuld. Das F_CPU darf man nur an einer einzigen Stelle definieren für alle Module gleich. Also entweder im Make auf der GCC-Kommandozeile. Oder z.B. in einem "hardware.h", welches alle includieren. Sicherheitshalber sollte man auch vor der Definition testen, ob schon ein F_CPU existiert und dann knallhart mit einem #error abbrechen. Peter
Peter Dannegger schrieb: > Daniel V. schrieb: >> ja, aber dann hätte ich immer noch das Problem, dass der GCC eventuell >> das falsche F_CPU verwendet > > Dann bist Du aber selbst dran schuld. Deswegen wollte ich ja wissen, welche Module F_CPU verwenden. Aber woher weiß ich denn, dass zukünftige Module das nicht auch verwenden, z.B. wenn der Ordner utils weitere Headers bekommt. Jaaa, vielleicht denk ich da zu weit vorraus. Selber schuld. > Das F_CPU darf man nur an einer einzigen Stelle definieren für alle > Module gleich. Das ist mir völlig klar. Ich wollte in diesem Thread eigentlich nur darauf hinweisen, dass die Definition von F_CPU völlig ausblendet, dass der AVR das Feature eines Taktteilers hat. Und der kann nunmal zur Laufzeit geändert werden. Also darf ich z.B. delay_ms() nicht verwenden, wenn ich am Taktteiler rumspiele.
Daniel V. schrieb: > Ich wollte in diesem Thread eigentlich nur darauf hinweisen, dass die > Definition von F_CPU völlig ausblendet, dass der AVR das Feature eines > Taktteilers hat. Und der kann nunmal zur Laufzeit geändert werden. Die AVR-GCC Entwickler gehen wohl davon aus, daß man nur einmal in der Initialisierung den Teiler einstellt und dann kann man den Teiler gleich in F_CPU hineinrechnen. Inwieweit es sinnvoll ist, den Teiler mitten im Programm umzustellen, muß jeder für sich entscheiden. Daß dann neben dem Delay auch Timer, UART, CAN, ADC, I2C, SPI-Takte nach dem Mond gehen, dürfte klar sein. Peter
Gast
#1685397
Peter Dannegger schrieb: > Die AVR-GCC Entwickler gehen wohl davon aus, daß man nur einmal in der > Initialisierung den Teiler einstellt So wie ich das bisher verstanden hab, macht Daniel V. genau das. Oder? Daniel V. schrieb: > Wenn ich zur Laufzeit (bzw. beim 'booten') den Takteiler ändere, ändert > sich auch meine CPU-Frequenz.
Peter Dannegger schrieb: > Inwieweit es sinnvoll ist, den Teiler mitten im Programm umzustellen, > muß jeder für sich entscheiden. > Daß dann neben dem Delay auch Timer, UART, CAN, ADC, I2C, SPI-Takte nach > dem Mond gehen, dürfte klar sein. > > > Peter Ja, das zieht dann einen ganzen Rattenschwanz hinter sich her....und die Taktberechnungen müssten in den Init-Routinen über eine Variable erfolgen (nicht über F_CPU).
Daniel V. schrieb: > und die > Taktberechnungen müssten in den Init-Routinen über eine Variable > erfolgen (nicht über F_CPU). ...was zusätzlichen Laufzeitaufwand bedeutet, obwohl du eigentlich in der Applikation am Ende mit genau einer CPU-Frequenz arbeitest.
Dieter schrieb: > Peter Dannegger schrieb: >> Die AVR-GCC Entwickler gehen wohl davon aus, daß man nur einmal in der >> Initialisierung den Teiler einstellt > > So wie ich das bisher verstanden hab, macht Daniel V. genau das. Oder? > > Daniel V. schrieb: >> Wenn ich zur Laufzeit (bzw. beim 'booten') den Takteiler ändere, ändert >> sich auch meine CPU-Frequenz. Jepp, beim booten stelle ich alles ein. Mitten im Programm ändere ich nichts. Aber das wäre ja auch mal interessant...
Dieter schrieb: > Peter Dannegger schrieb: >> Die AVR-GCC Entwickler gehen wohl davon aus, daß man nur einmal in der >> Initialisierung den Teiler einstellt > > So wie ich das bisher verstanden hab, macht Daniel V. genau das. Oder? Ja, aber in Abhängigkeit von der CPU-Variante, auf der der Code gerade läuft, d.h. die endgültige Teilereinstellung ist zur Compilezeit nicht bekannt. Eine Lösung könnte noch sein, die Delay-Funktionen in ein Makro zu packen, das den übergebenen Wert bei Bedarf halbiert, um bei halber Frequenz wieder auf die gleiche Zeit zu kommen:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
Das verdoppelt halt den Platzbedarf für jede Verwendung von Delay.
Mir dünkt, du diskutierst hier Stunden über ein Problem, das gar keins ist: entweder läuft deine Applikation mit 7 MHz, dann kannst du sie auch auf den nicht-V-AVRs damit laufen lassen, oder sie läuft damit nicht, dann kannst du die Vs einfach in die Ecke legen. Hat denn jemand schon vor der Fertigstellung des Prototyps schachtel- weise beide CPU-Varianten gekauft?
Jörg Wunsch schrieb: > Mir dünkt, du diskutierst hier Stunden über ein Problem, das gar keins > ist: [...] Klar mag es in diesem konkreten Fall bessere Lösungen geben, aber warum die Frage nicht zum Anlaß nehmen, sich mal Gedanken zu machen, wie Delays mit einer laufzeitabhängigen Takfrequenz unter einen Hut gebracht werden können?
Gast
#1685476
R. Max schrieb: > Klar mag es in diesem konkreten Fall bessere Lösungen geben, aber warum > die Frage nicht zum Anlaß nehmen, sich mal Gedanken zu machen, wie > Delays mit einer laufzeitabhängigen Takfrequenz unter einen Hut gebracht > werden können? Mit Timern! (!!!!) Denn dazu sind die schließlich da :)
Dieter schrieb: > Mit Timern! (!!!!) Denn dazu sind die schließlich da :) Kein Grund hier rumzuschreien, zumal Deine Antwort am Problem vorbei geht. Auch Timer sind von der Taktfrequenz abhängig (wenn man extern getaktete mal außen vor läßt). Man muß sich also auch bei Timern zusätzliche Gedanken machen, wenn die Taktfrequenz erst zur Laufzeit endgültig feststeht.
Gast
#1685586
Erstens habe ich nicht geschriehen, zweitens ist es bei Timern ja wohl überhaupt kein Problem, zur Laufzeit die den richtigen Wert zur Verzögerung auszurechnen. Denn ob man das vom Compiler oder zur Laufzeit machen lässt, ist quasi kein Unterschied. Nen problem hat man nur, wenn mans zuvor per Hand und Taschenrechner ausgerechnet hat. Und mein Beitrag war insofern durchaus ernst gemeint, weil es Hauptproblem beim verwenden der delay-Macros bei Timern nicht auftritt. Die delay-Macros kann man nämlich nicht mit variablen (=zur Laufzeit berechneten Werten) verwenden, ohne irgendwelche Krücken drumherum zu stricken.
Jörg Wunsch schrieb: > Mir dünkt, du diskutierst hier Stunden über ein Problem, das gar keins > ist: entweder läuft deine Applikation mit 7 MHz, dann kannst du sie > auch auf den nicht-V-AVRs damit laufen lassen, oder sie läuft damit > nicht, dann kannst du die Vs einfach in die Ecke legen. > > Hat denn jemand schon vor der Fertigstellung des Prototyps schachtel- > weise beide CPU-Varianten gekauft? Du musst dich ja nicht an der Diskussion beteiligen :-) Ich habe mit den nicht V-AVRs angefangen und festgestellt, dass es bei einem Spannungsverlust am Board (also wenns ausgeschaltet wird) vorteilhaft ist, wenn man einen V-AVR drin hat - der arbeitet auch noch bei 2,7V ;-).
R. Max schrieb: > Jörg Wunsch schrieb: >> Mir dünkt, du diskutierst hier Stunden über ein Problem, das gar keins >> ist: [...] > > Klar mag es in diesem konkreten Fall bessere Lösungen geben, aber warum > die Frage nicht zum Anlaß nehmen, sich mal Gedanken zu machen, wie > Delays mit einer laufzeitabhängigen Takfrequenz unter einen Hut gebracht > werden können? Du sprichst mir aus der Seele :-)
Dieter schrieb: > Denn ob man das vom Compiler oder zur Laufzeit > machen lässt, ist quasi kein Unterschied. Das ist schon ein gewaltiger Unterschied, ob man ne Konstante zuweist oder ob man erstmal die Math-Lib ackern läßt (in float, damits richtig reinhaut). > Nen problem hat man nur, wenn > mans zuvor per Hand und Taschenrechner ausgerechnet hat. Wer macht den sowas? Die Compiler rechnen Konstanten selber aus. Sie sind zu faul, unnötigen Code zu generieren. Ich schreib immer nur die Formel hin, Taschenrechner wäre mir zu umständlich und fehlerträchtig. Delay abhängig vom Vorteiler 1 oder 2 ist auch nicht aufwendig:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Peter Dannegger schrieb: > > Delay abhängig vom Vorteiler 1 oder 2 ist auch nicht aufwendig: >
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
Das ist mit Abstand die Beste Idee, die ich hier gelesen habe!
Daniel V. schrieb: > Das ist mit Abstand die Beste Idee, die ich hier gelesen habe! Geht aber auch nur im Millisekundenbereich, und da sind die delay- Makros eigentlich schon nur noch mal für'n schnellen Hack da, in einer fertigen Applikation sollte man es seiner CPU ersparen, sinnlose Kreise für solch eine Ewigkeit zu drehen. Für den Mikrosekundenbereich schlägt der Overhead bei dieser Lösung schon zu stark auf's Ergebnis durch. Daniel V. schrieb: > Ich habe mit den nicht V-AVRs angefangen und festgestellt, dass es bei > einem Spannungsverlust am Board (also wenns ausgeschaltet wird) > vorteilhaft ist, wenn man einen V-AVR drin hat Dann musst du doch aber ohnehin in der Lage sein, mit den 7 MHz auszukommen. Wenn du das andererseits nicht bist, dann war das mit den V-AVRs auch nicht sinnvoll, dann kannst du entweder normale Typen mit 14 MHz takten und hoffen, dass sie weit genug runter noch arbeiten, oder du könntest genauso gut die V-Type mit 14 MHz takten. Beides wird ziemlich gleichermaßen gut oder schlecht gehen, ist aber halt vom Hersteller nicht mehr garantiert.
Daniel V. schrieb: > Das ist mit Abstand die Beste Idee, die ich hier gelesen habe! Ja, recht kompakt, hat aber den Nachteil, daß die Auflösung mit 1ms deutlich schlechter ist als bei _delay_ms(). Hier noch eine Variante, mit dem gleichen Nachteil, die aber etwas kleiner sein dürfte, weil sie den Delay-Code nur einmal einbindet und etwas genauer, weil sie das Clock-Register nur einmal testet, statt in jedem Schleifendurchlauf. Allerdings halbiert sich die maximal mögliche Wartezeit.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
R. Max schrieb: > Hier noch eine Variante, mit dem gleichen Nachteil, die aber etwas > kleiner sein dürfte, weil sie den Delay-Code nur einmal einbindet und > etwas genauer, weil sie das Clock-Register nur einmal testet, statt in > jedem Schleifendurchlauf. Allerdings halbiert sich die maximal mögliche > Wartezeit. > >
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Ja mein ich doch, die Idee ist interessant und kann ausgebaut werden.
Jörg Wunsch schrieb: > Daniel V. schrieb: >> Das ist mit Abstand die Beste Idee, die ich hier gelesen habe! > > Geht aber auch nur im Millisekundenbereich, und da sind die delay- > Makros eigentlich schon nur noch mal für'n schnellen Hack da, in > einer fertigen Applikation sollte man es seiner CPU ersparen, > sinnlose Kreise für solch eine Ewigkeit zu drehen. > > Für den Mikrosekundenbereich schlägt der Overhead bei dieser Lösung > schon zu stark auf's Ergebnis durch. Bei den manchen Display-Routinen braucht man halt die Wartezeiten, weil die Displays so schnarchig sind. > > Daniel V. schrieb: >> Ich habe mit den nicht V-AVRs angefangen und festgestellt, dass es bei >> einem Spannungsverlust am Board (also wenns ausgeschaltet wird) >> vorteilhaft ist, wenn man einen V-AVR drin hat > > Dann musst du doch aber ohnehin in der Lage sein, mit den 7 MHz > auszukommen. Wenn du das andererseits nicht bist, dann war das > mit den V-AVRs auch nicht sinnvoll, dann kannst du entweder normale > Typen mit 14 MHz takten und hoffen, dass sie weit genug runter noch > arbeiten, oder du könntest genauso gut die V-Type mit 14 MHz takten. > Beides wird ziemlich gleichermaßen gut oder schlecht gehen, ist aber > halt vom Hersteller nicht mehr garantiert. Ja, da sollte ich mal ne Grundsatzentscheidung treffen und einfach nur einen Typ verbauen. Stimmt. btw: Wie zitiere ich denn mehrere verschiedene Beiträge in einem Post? Einfach kopieren scheint nicht zu funktionieren...
Daniel V. schrieb: > btw: Wie zitiere ich denn mehrere verschiedene Beiträge in einem Post? > Einfach kopieren scheint nicht zu funktionieren... Du kannst mehrmals nacheinander einen Beitrag oder einen Ausschnitt daraus markieren und dann auf "Markierten Text zitieren" klicken. Es wird dann im Eingabefeld jeweils ein neuer Zitatblock angehängt.
Daniel V. schrieb: > Bei den manchen Display-Routinen braucht man halt die Wartezeiten, weil > die Displays so schnarchig sind. Bei Millisekunden lohnt es sich aber eigentlich immer, einen Timer anzuwerfen und die CPU schlafen zu legen (*). Ich schrieb ja schon weiter oben, wenn du das mit dem Timer geschickt machst, brauchst du nur je nach CPU-Frequenz zwei verschiedene Vorteiler zu wählen (die sich um 2:1 unterscheiden), während die eigentliche Berechnung dann komplett unabhängig von der tatsächlichen CPU-Frequenz klappt. Beim ATmega2560 geht das auf diese Weise für den Timer 2, dessen Vorteiler komplett 2:1 gestaffelt sind. (*) Oder aber du legst die komplette Ausgabe in den Hintergrund, wenn das Display so schnarchlangsam ist, ähnlich wie man das für eine UART-Ausgabe ja auch machen würde.
Noch weniger Extra-Overhead, und ohne großen Auflösungsverlust:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
Das FP-Berechnung wird hier vom Compiler komplett wegoptimiert, so wie es auch bei _delay_ms() alleine der Fall ist. Andreas
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.