Hi Leute,
Ich bin gerade dabei, einen SPI-zu-ServoPWM-Wandler mit 6 Kanälen auf
Basis des Attiny4313 zu programmieren. Hab auch schon den Teil mit der
PWM - Erzeugung fast geschafft - außer, dass der Chip per se nicht auf
den Clock Prescaler reagiert. Der Zugriff erfolgt wie im Datenblatt:
erst 0x80, dann die gewünschte Bitkonstellation schreiben (hier: 0x02)
1
TIMSK|=(1<<OCIE0A)|(1<<TOIE0);// Enable interrupts on compare and overflow
Das Problem ist, der Timer schert sich nicht drum und macht munter ohne
sich zu verlangsamen weiter. Leider kann ich die Frequenz des Clocks
nicht messen, der Oszi macht bei den Frequenzen nicht mehr mit.
Der (mittlererweile bis zu Löchern im HDD studierte) Datenblatt sagt
nichts, außer dass es eigentlich funktionieren sollte - Prescaler hängt
vor der CLK(I/O) und der Timer0 bezieht den Clock daraus mit einem
Prescaler von 8
1
sei();// #Interrupts
2
TCCR0B|=(1<<CS01);// Set clock input prescaler of 8, starting the timer (2 Mhz freq.)
Den gesamten Code könnte ich auf Anfrage posten, will ich aber wenn
möglich vermeiden, da ISR's etwas hässlich geworden sind und die
Variablennamen nur Leuten etwas sagen, die schon ein paar Nächten mit
dem Projekt verbracht haben. Also, hätte jemand einen Ansatz?
MfG
Was sagt das disasembly von dem Code , wird ser Presacler in weniger als
4 Takten gesetzt ? Kann dir in Inerupt da schon da zwischen Funken ?
Oder kommt das Sei() erst danach ?
Gruß JackFrost
Viktor B. schrieb:> TIMSK |= (1<<OCIE0A)|(1<<TOIE0); // Enable interrupts on> compare and overflow> CLKPR = 0x80; // Set clock div
Das Ding um CLKPR benötigt eine sog. timed sequence, d.h. innerhalb 4
Taktzyklen ab Setzen von CLKPCE muss der neue Prescalerwert geschrieben
sein. Das kann von Interrupts gestört werden. Auch wenn der Code nicht
optimiert wird, -O0, sollten immer noch die 4 Clocks einhaltbar sein,
man könnte trotzdem mal -Os versuchen.
Hallo,
es muß wohl an dieser Stelle etwas nicht stimmen.
"To avoid unintentional changes of clock frequency, a special write
procedure must be followed to change the CLKPS bits:
1.Write the Clock Prescaler Change Enable (CLKPCE) bit to one and all
other bits in CLKPR to zero.
2.Within four cycles, write the desired value to CLKPS while writing a
zero to CLKPCE.
Interrupts must be disabled when changing prescaler setting to make sure
the write procedure is not interrupted. The Application software must
ensure that a sufficient division factor is chosen if the selected clock
source has a higher frequency than the maximum frequency of the device
at the present operating conditions. The device is shipped with the
CKDIV8 fuse programmed."
MfG
Hubert G. schrieb:> Was glaubst du was passiert wenn du in das Register erst 0x80 und dann> 0x02 schreibst. Was wird dann im Register stehen?
Gut erkannt :-)
Hubert G. schrieb:> Was glaubst du was passiert wenn du in das Register erst 0x80 und> dann> 0x02 schreibst. Was wird dann im Register stehen?
W arum liest Du Dir den betreffenden Teil im DB nicht vor Deinem Post
durch?
The CLKPCE bit must be written to logic one to enable change of the
CLKPS bits. The CLKPCE
bit is only updated when the other bits in CLKPR are simultaneously
written to zero.
Ich hätte das so interpretiert das ich zuerst CLKPS setzen muss und dann
CLKPCE. Also genau umgekehrt wie im ersten Post geschrieben.
Lasse mich aber gerne belehren.
Um zu kontrollieren, wie schnell der Controller vor und nach der
Umstellung von CLKPR läuft, braucht man doch kein Oszilloskop, da reicht
eine LED.
Und wenn das Low Fuse Byte im Auslieferungszustand ist, dann bewirkt
> CLKPR = 0x02;
kein
> verlangsamen
sondern ein Beschleunigen, deshalb meine Frage.
Hubert G. schrieb:> The CLKPCE bit must be written to logic one to enable change of> the CLKPS bits. The CLKPCE> bit is only updated when the other bits in CLKPR are simultaneously> written to zero.> Ich hätte das so interpretiert das ich zuerst CLKPS setzen muss und dann> CLKPCE. Also genau umgekehrt wie im ersten Post geschrieben.> Lasse mich aber gerne belehren.
Übers.: "Das CLKPCE-Bit muss auf logisch 1 gesetzt werden, um die
Änderung der CLKPS-Bits zu erlauben. Das CLCPCE-Bit wird nur geändert,
wenn die anderen Bits in CLKPR gleichzeitig auf 0 gesetzt werden."
Wie würdest Du das interpretieren?
Hubert G. schrieb:> Ich hätte das so interpretiert das ich zuerst CLKPS setzen muss und dann> CLKPCE. Also genau umgekehrt wie im ersten Post geschrieben.
Ne, du musst immer zuerst das CLKPCE (das steht für CLocK Prescaler
Change Enable, d.h. ist es nicht gesetzt lässt sich der Prescaler auch
nicht ändern) setzen und dabei muss, lt. Datenblatt, alle anderen Bits
gleichzeitig 0 werden. da kommen die 0x80 her, das setzt nämlich nur das
CLKPCE auf 1 und alle anderen zu 0. Dann hat man vier Zyklen Zeit den
gewünschten Prescaler zu setzen.
Viktor B. schrieb:> Leider kann ich die Frequenz des Clocks> nicht messen, der Oszi macht bei den Frequenzen nicht mehr mit.
Woher weißt du dann, dass das mit dem Clock setzen nicht klappt? Tipp:
Mache erstmal ein simples Beispiel bei dem du mittels CLKPCE usw. den
Clock änderst sodass du es sehen kannst.
Tipp von mir: Timer Overflow Interrupt einstellen und darin eine
Variable hoch zählen lassen. Wenn die Variable einem Wert entspricht,
der eine Sekunde darstellt, dann lässt du einen Pin umschalten, an dem
du eine LED hast. Wenn das funktioniert versuchst du mit dem CLKPCE den
Systemtakt mindestens zu halbieren. Am Blinken der LED siehst du dann,
ob das wirklich geklappt hat.
Die Lower Fuse steht auf "DC": Kein Runterteilen, Externer Quarz mit
8Mhz, kein Clock auf D2.
Die Methode der Frequenzmessung mit einer LED ist mir nicht bekannt, wie
soll das gehen - ohne (software-)Timer?
Disassembly sieht so aus:
Ich verstehe beim besten Willen nicht, was die zwei LDIs vor LDI r24,
0x02 sollen.
Und es können keine Interrupts dazwischen kommen, da das Ganze sich in
dem Setup-Teil befindet, der zwischen cli(); und sei(); steht.
M. K. schrieb:> Woher weißt du dann, dass das mit dem Clock setzen nicht klappt?
Weil der Timer von der Clock abhängen soll(te). Und da sich der Timer
nicht regt, vermute ich, die Clock ist unverändert geblieben.
Viktor B. schrieb:> M. K. schrieb:>> Woher weißt du dann, dass das mit dem Clock setzen nicht klappt?>> Weil der Timer von der Clock abhängen soll(te). Und da sich der Timer> nicht regt, vermute ich, die Clock ist unverändert geblieben.
Wenn der Timer sich nicht regt (woher weißt du das?) dann heißt das
eigentlich, dass sich der Clock auch nicht regt.
Viktor B. schrieb:> Die Methode der Frequenzmessung mit einer LED ist mir nicht bekannt, wie> soll das gehen - ohne (software-)Timer?
Beispiel
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
volatileuint8_tmyCounter=0;
4
intmain(void){
5
// Timer1 einstellen
6
TIMSK0|=(1<<TOIE0);
7
// Timer1 Prescaler auf 1024 einstellen (passt das mit den Registern? Prüfen)
8
TCCR0B|=(1<<CS02)|(1<<CS00);
9
// Pin mit der LED einstellen als Ausgang
10
DDRB|=(1<<PB1);
11
// Interrupts einschalten
12
sei();
13
for(;;){
14
}
15
return0;
16
}
17
ISR(TIMER0_OVF_vect){
18
myCounter++;
19
if(myCounter>3){
20
// Pin toggeln
21
PORTB^=(1<<PB1);
22
muCounter=0;
23
}
24
}
Ich weiß jetzt nicht ob das so auf dem Attiny4313 liefe, hab die
Registernamen nicht geprüft. Bei einem AVR in
Standardeinstellung/Werkseinstellung ist dieser üblich auf den 8 MHz RC
Oszilator eingestellt mit einem Prescaler von 8, läuft also auf 1 MHz.
Beim Timer0, hier gehe ich von einem 8 bit Timer aus, stelle ich den
Overflow Interrupt ein und gebe ihn einen Prescaler von 1024, d.h. er
läuft mit ca. 1 kHz. Der Rest sollte eigentlich klar sein. Die LED
sollte mit ca. 1 Hz blinken. Jetzt ändert man nur den System-Prescaler
mit dem CLKPCE, dann sollte die LED entsprechend schneller oder
langsamer blinken. Das sieht man optisch prima und weiß dann, dass
zumindest das funktioniert.
Hi
Viktor B. schrieb:> Disassembly sieht so aus: CLKPR = 0x80; // Set clock> div> 35e: e6 e4 ldi r30, 0x46 ; 70> 360: f0 e0 ldi r31, 0x00 ; 0> 362: 80 e8 ldi r24, 0x80 ; 128> 364: 80 83 st Z, r24
Bis Hier ganz toll, aber:
> CLKPR = 0x02; // clock div/4: 8Mhz int.osz. / 4> presc. = 2Mhz eff. freq.> 366: e6 e4 ldi r30, 0x46 ; 70> 368: f0 e0 ldi r31, 0x00 ; 0> 36a: 82 e0 ldi r24, 0x02 ; 2> 36c: 80 83 st Z, r24
braucht 'geringfügig' mehr Takte als erlaubt (die 4 Takte), bis der neue
Wert in die Speicherstelle 0x46 geschrieben wird.
Wenn dort r30 und r31 nicht erneut gesetzt würden, sollte Das klappen
(sofern die Werte passen und 0x46 der Ort des passenden Register ist -
denke aber, daß dort der Compiler weiß, was Er tut)
Warum der Compiler hier Z mit dem bereits enthaltenen Wert neu lädt,
kann Dir nur der Compiler selber beantworten.
MfG
M. K. schrieb:> Wenn der Timer sich nicht regt (woher weißt du das?) dann heißt das> eigentlich, dass sich der Clock auch nicht regt.
Ich habe es mit dem Oszi nachgemessen. Und ich hab ja auch gesagt, dass
sich weder der Timer noch die Clock verändert haben. Die Unterscheidung
zwischen Timer und Clock hab ich nur gemacht, damit man nicht
Überraschungen wie beim STM8 bekommt - "Ach der Timer, der hat ja 'ne
ganz eigene Clock, die muss man auch noch aktivieren!"
M. K. schrieb:> Beim Timer0, hier gehe ich von einem 8 bit Timer aus, stelle ich den> Overflow Interrupt ein
Hier wurde der Timer 0 auch so eingestellt, nur halt dass da etwas mehr
Code und eine verschachtelte FSM dahinter sind. Im Beispiel würde der
Prescaler also auch keinen Einfluss auf den Timer nehmen.
Ich suche gerade nach einer Möglichkeit, die Disassembly-Datei zu
editieren. Vielleicht sind die 4 Instruktionen doch zu viel.
Patrick J. schrieb:
> Bis Hier ganz toll
Das ist jetzt aber schon keine Ironie mehr, sondern beißender Sarkasmus.
In Assembler schrieben wir beide doch
> Ich suche gerade nach einer Möglichkeit,> die Disassembly-Datei zu editieren.
Warum, funktioniert der Tipp von Thomas E. nicht?
> Vielleicht sind die 4 Instruktionen doch zu viel.
Sieht so aus, 5 Takte sind mehr als die 4 erlaubten.
S. Landolt schrieb:> Das ist jetzt aber schon keine Ironie mehr, sondern beißender Sarkasmus.> In Assembler schrieben wir beide doch
Aha. Und etwas weiter oben schrieb ich
>Viktor B. schrieb:> Disassembly sieht so aus:
- D.h. ich hab es in C geschrieben und dem Compiler gegeben. Der hat
dann den ASM-Code erzeugt. Wieso er mich boykottiert? Gute Frage
MWS schrieb:> Übers.: "Das CLKPCE-Bit muss auf logisch 1 gesetzt werden, um die> Änderung der CLKPS-Bits zu erlauben. Das CLCPCE-Bit wird nur geändert,> wenn die anderen Bits in CLKPR gleichzeitig auf 0 gesetzt werden.">> Wie würdest Du das interpretieren?
Da gibt es doch nichts zu "interpretieren". Es steht da so, wie du das
übersetzt hast.
So, mit der Funktion aus der power.h klappt jetzt alles. Damit
funktionieren schon mal die PWMs. SPI funktioniert zwar immer noch
nicht, aber das ist eine ganz andere Geschichte (c)
Viktor B. schrieb:> Im Beispiel würde der> Prescaler also auch keinen Einfluss auf den Timer nehmen.
Öhm, doch. Der Prescaler gibt immerhin die Geschwindigkeit vor, wie
schnell der Timer zählt. Machst du den Prescaler größer sinkt die
Taktrate und der Timer zählt langsamer, machst du den Prescaler kleiner
steigt die Taktrate und der Timer zählt schneller.
Viktor B. schrieb:> Ich habe es mit dem Oszi nachgemessen.
Du hast geschrieben, dass dein Oszi bei diesen Frequenzen nicht mehr mit
macht. Von daher bin ich davon ausgegangen, dass du mit dem Oszi in
diesem Fall nichts messen kannst.
Viktor B. schrieb:> So, mit der Funktion aus der power.h klappt jetzt alles.
Du könntest auch versuchen
1
...
2
asm("ldi r24, 0x80""\n\t"
3
"out CLKPR""\n\t"
4
"ldi r24, 0x20""\n\t"
5
"out CLKPR");
6
...
zu schreiben, das spart noch etwas Code bei dir (bei mir macht der
AVR-GCC aus dem C-Code übrigens genau das Obige bei Optimierungslevel
-Os). Du brauchst ja eigentlich die power.h nicht wirklich.
Viktor B. schrieb:> - D.h. ich hab es in C geschrieben und dem Compiler gegeben. Der hat> dann den ASM-Code erzeugt. Wieso er mich boykottiert? Gute Frage
Vielleicht wirst du unterdrückt :-)
Viktor B. schrieb:> Disassembly sieht so aus:
So sieht es aus, wenn man dem Compiler das Optimieren verbietet (-O0).
Mit -Os paßt es dann mit den 4 Zyklen.
Man sollte aber die Funktion aus der power.h bevorzugen.