Hallo liebe Community,
ich hab ein Projekt im Bereich ATmega übernommen. Übersichtlicher
Quelltext, aber dennoch gibt es ein paar Ungereimtheiten.
Mikrocontrollerprogrammierung ist mir nicht fremd. Ich habe vorher
einiges auf der STM32-Plattform gemacht. Deswegen ist mir AVR und ATmega
etwas fremd.
Es handelt sich um den ATmega48PA. Was der Quelltext macht ist für mich
kein Problem, es hängt aber etwas an den ATmega-spezifischen
Einstellungen die man vornehmen muss.
Im Quelltext befindet sich folgende Textzeile:
1
#define F_CPU 1000000UL
Das ist auch soweit klar. Damit kann ich die Taktfrequenz einstellen.
Nun wird der uC aber mit folgender Fuse programmiert:
INTRCOSC_128KHZ_6CK_14CK_65MS
Laut Datenblatt ist das interne 128 kHZ Oszillator. Beim STM32 kann man
ebenfalls einen niedrigeren Takt einstellen und diesen dann schnließend
hochteilen. Geht das hier durch den clock prescaler auch? Entsprechende
Codezeilen habe ich nicht gefunden.
Meine Frage ist nun: mit welcher Taktfrequenz arbeitet denn nun der uC?
Vielen Dank :)
Sheriff Silver schrieb:> Damit kann ich die Taktfrequenz einstellen.
Damit gibt man lediglich die Frequenz an, damit sie im Code in
Berechnungen von Delayzeiten etc. benutzt werden kann. Den uC
interessiert das nicht, der richtet sich nach den Fuse-Einstellungen.
Tom schrieb:> Damit gibt man lediglich die Frequenz an, damit sie im Code in> Berechnungen von Delayzeiten etc. benutzt werden kann. Den uC> interessiert das nicht, der richtet sich nach den Fuse-Einstellungen.
Ich habe gerade auch noch folgendes gefunden:
1
// Der MCU-Takt. Wird gebraucht, um Timer1 mit den richtigen
2
// Werten zu initialisieren. Voreinstellung ist 1MHz.
3
// (Werkseinstellung für AVRs mit internem Oszillator).
4
// Das Define wird nur gemacht, wenn F_CPU noch nicht definiert wurde.
5
// F_CPU kann man so auch per Kommandozeile definieren, z.B. für 8MHz:
6
// avr-gcc ... -DF_CPU=8000000
7
//
8
// ! Der Wert von F_CPU hat rein informativen Character für
9
// ! die korrekte Codeerzeugung im Programm!
10
// ! Um die Taktrate zu ändern müssen die Fuses des Controllers
11
// ! und/oder Quarz/Resonator/RC-Glied/Oszillator
12
// ! angepasst werden!
13
#ifndef F_CPU
14
#define F_CPU 1000000
15
#endif
Das bedeutet er arbeitet mit 128 kHz.
Okay. Vielen Dank :)
Sheriff Silver schrieb:> Ich habe gerade auch noch folgendes gefunden:
An der 1000000 sollte immer ein UL stehen nicht dass der Compiler
versucht zu optimieren, da kann es ggf. zu Fehlern sonst kommen.
Sheriff Silver schrieb:> Das bedeutet er arbeitet mit 128 kHz.
Ja, in deinem obigen Post schon (sofern der Prescaler auf 1 ist), wie
schon gesagt wurde, es zählt was gefused wurde.
Sheriff Silver schrieb:> Ich habe gerade auch noch folgendes gefunden:> ...
Das sollte man besser löschen.
Ansonsten sucht man sich nen Wolf, wo der Fehler ist, wenn man die
Einstellung im make vergißt.
M. K. schrieb:> es zählt was gefused wurde.
und was angeschlossen ist und F_CPU sollte nun passend gesetzt werden
aber natürlich nur wenn es nicht schon an anderer Stelle
deklariert/definiert wurde.
Ich denke das hier wäre dann sinnvoll!
Sheriff Silver schrieb:> as bedeutet er arbeitet mit 128 kHz.Sheriff Silver schrieb:> #ifndef F_CPU> #define F_CPU 128000> #endif
folgendes nur für den ersten Lauf vor der Fuse Änderung mit intern 8MHz
und div 8
Sheriff Silver schrieb:> #ifndef F_CPU> #define F_CPU 1000000> #endif
Joachim B. schrieb:> und was angeschlossen ist und F_CPU sollte nun passend gesetzt werden> aber natürlich nur wenn es nicht schon an anderer Stelle> deklariert/definiert wurde.
was aber sehr schlecht ist. Wenn es schon an anderer Stelle ist das ein
Fehler der nicht ignoriert werden darf!
Also nur:
1
#define F_CPU 128000
was aber immer nicht schön ist, dann das define gehört eigentlich in die
Projekteinstellungen und nicht in den Quellcode.
Peter II schrieb:> Wenn es schon an anderer Stelle ist das ein> Fehler der nicht ignoriert werden darf!
deswegen ja:
#ifndef F_CPU
oder wer weiss was er tut
#ifndef F_CPU
#undef F_CPU
und dann
#define F_CPU
Peter II schrieb:> was aber immer nicht schön ist, dann das define gehört eigentlich in die> Projekteinstellungen und nicht in den Quellcode.Draco schrieb:> Also wenn dann so:>> #ifdef F_CPU> #undef F_CPU> #define F_CPU 128000> #endif
Eher nicht. Siehe das post von Peter II. ifndef F_CPU <bla bla blubb>
macht meiner Meinung nach viel mehr Sinn.
Grüsse,
René
Rene H. schrieb:> Eher nicht. Siehe das post von Peter II. ifndef F_CPU <bla bla blubb>> macht meiner Meinung nach viel mehr Sinn.>> Grüsse,> René
Gruß Namensveter :D
Ich sagte ja "Wenn schon, dann..." - das dieses Define einmal reindarf
steht außer Frage, das es sinnvoller ist es in die Porjekteinstellungen
zu legen.
Aaaaber, ich trösel das mal auf, F_CPU ist im folgenden Fall schon
definiert:
1
#ifdef F_CPU //schauen ob F_CPU schon definiert wurde
2
#undef F_CPU //F_CPU "löschen" / "undefinieren"
3
#define F_CPU 128000 //F_CPU neu setzen
4
#endif //Ende Schleife
Joachim B. schrieb:> #ifndef F_CPU> #undef F_CPU>> und dann>> #define F_CPU
Das macht nunmal kein Sinn -> mit #ifndef (IF NOT DEFINED) prüfen ob
F_CPU NICHT gesetzt wurde um dann mit #undef das nicht gesetzte #define
zu löschen?! Das macht garkein Sinn.
Draco schrieb:> Also wenn dann so:>> #ifdef F_CPU> #undef F_CPU> #define F_CPU 128000> #endif
Sorry, das ist suboptimal.
Der einzig sinnvolle Weg ist:
1
#ifndef F_CPU
2
#error F_CPU not defined.
3
#endif
Und dann im Projekt/Makefile F_CPU für alle Sources angeben. Jede IDE
für AVRs untertützt das. So werden widersprüchliche Angaben in C-Sources
innerhalb eines Projekts von vornherein vermieden.
Frank M. schrieb:> Sorry, das ist suboptimal.>> Der einzig sinnvolle Weg ist:#ifndef F_CPU> #error F_CPU not defined.> #endif>> Und dann im Projekt/Makefile F_CPU für alle Sources angeben. Jede IDE> für AVRs untertützt das. So werden widersprüchliche Angaben in C-Sources> innerhalb eines Projekts von vornherein vermieden.
Da stimme ich dir vollkommen zu! Ohne Frage! Aber darum ging es oben ja
nicht.
Draco schrieb:> Das macht nunmal kein Sinn -> mit #ifndef (IF NOT DEFINED) prüfen ob> F_CPU NICHT gesetzt wurde um dann mit #undef das nicht gesetzte #define> zu löschen?! Das macht garkein Sinn.
hast du wohl falsch verstanden oder ich doof erklärt, ist aber egal es
wurde eigentlich alles deutlich gemacht, dem TO bleibt zu prüfen ob
F_CPU defined ist wie und wo überall!
Manchmal gibt es F_CPU auch nicht weil noch XTAL verwendet wurde!
Taktfrequenz sind die beschriebenen 128 kHz.
Der Timer ist ja so eingestellt, dass er mit 256 vorgeteilt wird.
128 kHz/256/256 = 1,95 Hz = 512 ms
Jetzt habe ich über den Port B die ganze Sache mal nachgemessen und
komme auf eine Frequenz von 1s. Sprich aller einer Sekunde wird die ISR
ausgelöst.
Ich erkläre mir das jetzt so, dass zu Beginn der ISR der volle Takt
aktiviert wird. Am Ende wird der Takt wieder auf 64 kHz gestellt.
Wenn ich das mit 64 kHz durchrechne, dann komme ich auch auf eine
Sekunde.
Ist mein Gedankengang richtig?
Sheriff Silver schrieb:> Jetzt habe ich über den Port B die ganze Sache mal nachgemessen und> komme auf eine Frequenz von 1s. Sprich aller einer Sekunde wird die ISR> ausgelöst.
Womit kommst du auf 1s? Misst du eine Frequenz von 1 Hz? Ist ja normal
wenn der Timer OVF auf 512 ms steht, dann ändert sich der Pegel an PB0
alle 512 ms und du musst zwei Pegeländerungen abwarten für eine Periode,
also 2*512 ms ;)
PS: Übrigens, die ISR ist recht schlecht. In einer ISR soll man so wenig
wie möglich machen. Du machst da anscheinend so viel wie geht. Ich würde
in einer ISR nie den ADC starten und auf das Wandlerergebnis da drin
warten, genau das scheinst du aber zu machen, das ist IMO grober Unfug.
Sheriff Silver schrieb:> Mikrocontrollerprogrammierung ist mir nicht fremd. Ich habe vorher> einiges auf der STM32-Plattform gemacht. Deswegen ist mir AVR und ATmega> etwas fremd.
Hallo René,
wenn der obige Text korrekt wäre, ist die Fragestellung doch reichlich
verstörend. Unrecht hat er da nicht. Nur die Tonart .....
Grüsse,
René
... vielleich hätte dem Threadersteller jemand sagen sollen, dass:
.. im Gegensatz zu STM32 der Prozessortakt nicht zur "Laufzeit" der MCU
per Programm (HSE, HSI und diverser Prescaler) eingestellt wird (und
meistens in einer SystemInit Datei erledigt wird), sondern der Takt, mit
dem der MCU läuft über sogenannte "Fuses" eingestellt wird, oder
anderst: Es werden Speicherstellen AUSSERHALB des C-Programms mit Werten
beschrieben, die den Takt der MCU einstellen: interner RC-Generator,
oder externer Takt (entweder als "fertiges" Taktsignal zugeführt oder
über einen Quarz/Resonator erzeugt).
Welche Fuses wie zu beschreiben sind kann hier ermittelt werden:
http://www.engbedded.com/fusecalc/
Beispiel für ATMega48PA:
Interner RC-Generator, 8 MHz Taktfrequenz (F_CPU=8000000ul)
Fuses Low: 0xD2 Fuses High: 0xDC Extended: 0x01
Interner RC-Generator, 1 MHz Taktfrequenz
Fuses Low: 0x52 Fuses High: 0xDC Extended: 0x01
Externer Quarz (Quarz hier >= 8 MHz), Taktfrequenz die des Quarzes
Fuses Low: 0xFE Fuses High: 0xDC Extended: 0x01
Um diese Fuses für externen Quarz (bspw. mit einem STK500v2) mittels
AVRDUDE zu schreiben, der an COM1 angeschlossen ist und mit einer
Baudrate von 115200 betrieben wird, muß folgendes eingegeben werden:
Unter Windows:
avrdude -c stk500v2 -p m48 -P com1 -b 115200 -B 20 -U lfuse:w:0xFE:m -U
hfuse:w:0xDC:m
Unter Linux (wenn der STK500 die Schnittstelle ttyACM0 besitzt):
avrdude -c stk500v2 -p m48 -P /dev/ttyACM0 -b 115200 -B 20 -U
lfuse:w:0xFE:m -U hfuse:w:0xDC:m
Legende:
-c stk500v2 ... -c benennt den verwendeten Programmer
-p m48 ... -p benennt den verwendeten MCU
-P /dev/ttyACM0 ... -P benennt den Anschlussport an den der Programmer
angeschlossen ist
-B 20 ... ISP Clock (20 ist hier langsam damit auch ein
fabrikneuer MCU geflasht wird)
-U ... -U wählt Speicher an (hier die Register der Fuses)
lfuse benennt die Low-Fuse
hfuse benennt die High-Fuse
:w bedeutet schreiben (write)
:m memory
Wird bspw. ein Programmer verwendet, der sein eigenes Interface über USB
mitbringt (bspw. USBasp) und nicht über einen echten oder virtuellen
Com-Port angesprochen wird, kann die Einstellung für Anschlussport und
Baudrate weggelassen werden:
avrdude -c usbasp -p m48 -B 20 -U lfuse:w:0xFE:m -U hfuse:w:0xDC:m