Hi,
ich nutze einen ATTiny85 um variable Frequenzen auszugeben. Dazu
verwende ich den TIMER0 im Compare-Mode:
1
// Initialisierung
2
TCCR0A=(1<<WGM01);// CTC Modus
3
OCR0A=1;
4
TCCR0B&=~0x07;// stop timer
5
TIMSK|=(1<<OCIE0A);
6
7
// Starte Timer, so bald er benötigt wird
8
TCCR0B|=0x04;
9
10
//Timer-ISR
11
ISR(TIMER0_COMPA_vect,ISR_NOBLOCK)
12
{
13
...
14
}
Die Frequenz erzeuge ich über eine Zählvariable, diese wird in der ISR
runtergezählt und ein Ausgangsbit immer dann geswitcht, wenn der Zähler
bei 0 angekommen ist. Mit 16,5 MHz Takt und dem gewählten Teiler
erreiche ich damit eine Maximalfrequenz von ca. 16 kHz. Parallel dazu
habe ich den V-USB laufen, um von außen Kommandos schicken zu können.
Dabei habe ich jetzt zwei Probleme:
1. Die Maximalfrequenz müsste bei ca 32. kHz liegen: 16,5 MHz durch
Teiler 256 durch 2 (Bit setzen und Bit löschen in separaten Aufrufen der
ISR) wären ca. 32226 Hz, nicht 16113 Hz. Für die Maximalfrequenz ist die
Zählvariable immer 0 und es wird das Ausgangsbit bei jedem Aufruf der
ISR getoggelt. Wo habe ich mich hier verrechnet?
2. Ich habe einen ziemlichen Jitter auf der ausgegebenen Frequenz. Der
entsteht durch den USB-Anschluß, wenn ich die CPU ohne USB laufen lasse,
ist der Jitter weg. Vermutlich funkt hier also irgend ein Interrupt von
den für V-USB verwendeten Eingängen dazwischen. Welche Möglichkeiten
habe ich hier, den Jitter zu verkleinern? Interruptprioritäten kann ich
ja nicht setzen, oder? Eine andere Hardware kann ich auch nicht
einsetzen, ich bin an den ATTiny85 gebunden.
Es ist jeder konstruktive Hinweis willkommen :-)
Danke!
Harstad schrieb:> 1. Die Maximalfrequenz müsste bei ca 32. kHz liegen: 16,5 MHz durch> Teiler 256 durch 2 (Bit setzen und Bit löschen in separaten Aufrufen der> ISR) wären ca. 32226 Hz, nicht 16113 Hz.
OCR0A=1;
Durch noch mal 2, weil der Timer 2 Zählzyklen braucht um bei 1 angelangt
zu sein.
> 2. Ich habe einen ziemlichen Jitter auf der ausgegebenen Frequenz. Der> entsteht durch den USB-Anschluß, wenn ich die CPU ohne USB laufen lasse,> ist der Jitter weg.
Nimm das NO_BLOCK aus der ISR Definition raus.
Du willst nicht haben, dass dir der USB Code deine ISR unterbrechen
kann.
Problem könnte natürlich sein, dass dann der USB Code auf die
kurzzeitigen Unterbrechungen durch deinen Timer allergisch reagiert.
Aber ein bischen Luft wird da hoffentlich schon drinnen sein.
Einen gewissen Grundjitter wirst du natürlich so immer haben, denn
während der USB Code in einer ISR hängt, muss dein ISR Aufruf warten.
Das kriegst du nur mehr dadurch weg, dass du einen PWM Modus nimmst, bei
dem die Timer-Hardware selber den Pin umschaltet. Das könnte allerdings
bei den längeren Zeiten etwas tricky werden, wenn du den Timer nicht
langsam genug einstellen kannst.
Fazit:
Wenn das ordentlich werden soll, kommst du nicht umhin dir ein Verfahren
auszudenken, wie du aus der gewünschten Frequenz für den Timer einen
geeigneten Vorteiler samt Compare und Top Wert bestimmen kannst, mit
denen du eine PWM im Modus 15 füttern kannst, so dass dir die Hardware
die Frequenz erzeugt.
Karl H. schrieb:> Nimm das NO_BLOCK aus der ISR Definition raus.> Du willst nicht haben, dass dir der USB Code deine ISR unterbrechen> kann.
Keine Chance, dann ist der USB-Anschluss sofort tot. Dann müsste ich die
Timer-Frequenz auf max 10 kHz begrenzen, damit mir die ISR das
USB-Timing nicht killt.
> Wenn das ordentlich werden soll, kommst du nicht umhin dir ein Verfahren> auszudenken, wie du aus der gewünschten Frequenz für den Timer einen> geeigneten Vorteiler samt Compare und Top Wert bestimmen kannst, mit> denen du eine PWM im Modus 15 füttern kannst, so dass dir die Hardware> die Frequenz erzeugt.
Den PWM habe ich bisher nicht genommen, weil ich auch Rampen können
muss. Sprich die Frequenz wird nicht einfach nur angeschaltet, sondern
mehr oder weniger langsam (=parametrisierbar) von 5 Hz bis auf die
Zielfrequenz erhöht bzw. von dort auf 5 Hz gesenkt. Und sowas ist mit
dem PWM-Modul ja nicht machbar!? Zumindest habe ich keinen Modus
gefunden, in dem ich die PWM-Frequenz langsam steigen/sinken lassen
kann...
Harstad schrieb:> Welche Möglichkeiten> habe ich hier, den Jitter zu verkleinern?
Einen PWM-Ausgang benutzen.
Der Interrupt bereitet ihn nur vor (setzen oder löschen) und mit dem
nächsten Compare wird der Pin umgeschaltet, unabhängig von der
Interruptlatenz.
Harstad schrieb:> Den PWM habe ich bisher nicht genommen, weil ich auch Rampen können> muss.
Das schliesst sich nicht automatisch aus.
Nur weil der Timer eine PWM erzeugt, bedeutet das nicht, dass er keine
Interrupts mehr erzeugt.
Ein wenig wirst du dich in der Frequenz einschränken müssen, aber ob die
Berechnung für den jweils folgenden PWM Zyklus ein paar Takte länger
dauert oder nicht, ist dann nicht mehr so tragisch (d.h. wenn der USB
Code nicht zuviel Takte abzieht). Du musst nur fertig sein, bis die
Hardware den Pin das nächste mal umschalten will.
Harstad schrieb:> Karl H. schrieb:>> Nimm das NO_BLOCK aus der ISR Definition raus.>> Du willst nicht haben, dass dir der USB Code deine ISR unterbrechen>> kann.>> Keine Chance, dann ist der USB-Anschluss sofort tot.
Dann nimm eine CPU, die USB kann.
> Den PWM habe ich bisher nicht genommen, weil ich auch Rampen können> muss.
Bei einem Timer mit PWM-Ausgabe kannst du eine Rampe erzeugen, indem du
regelmäßig den Vergleichswert änderst.
(Mit DMA (hat der ATTiny nicht) und einem zweiten Timer ginge das
vollautomatisch.)