PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : AtMega16 Timer1 Overflow Zeitberechnung



cbg
11.05.2009, 00:25
Hallo!
So, für die Uni muss ich auf 4 verschiedene Arten ein PWM Signal (50us high, 25us low) generieren.
Timer1 mit Prescaler von 8 wird verwendet (F_CPU = 16M).
Bei der Timeroverflow Methode weicht leider mein berechneter Wert für High- und Lowtime vom gemessenen ab. Bei dieser Methode sollen wir nur die berechneten Preload Werte einsetzten ohne Fehlerkorrektur also soll der Wert nicht genau stimmen (25us, 50us).

Der Assemblercode der ISR ist im Anhang (mit Debuginfos von C Datei).
Hier die Ergebnisse von 4 Messungen:

+---------+-----------+----------+---------+
| Messung | High Time | Low Time | Periode |
+---------+-----------+----------+---------+
| 1 | 52.04us | 26.46us | 78.50us |
+---------+-----------+----------+---------+
| 2 | 52.00us | 26.49us | 78.50us |
+---------+-----------+----------+---------+
| 3 | 52.05us | 26.45us | 78.50us |
+---------+-----------+----------+---------+
| 4 | 52.09us | 26.40us | 78.50us |
+---------+-----------+----------+---------+
Da ich in der Main ständig in den Idle Sleep Modus gehe, dauert es mMn
4+4+3 Taktzyklen bis ich den ISR Code erreicht habe (4 cycles PC push, 3 cycles JMP @ Vector Adresse, 4 cycles weil Sleep).
Wakeup-Time hab ich beim Idle Sleep nicht gefunden im Datasheet, sondern nur bei Powerdown und noch einem anderen "tiefen" Modus.

Bis der Pin auf HIGH gesetzt wird, vergehen also:
4+4+3
2+1+1 (lds, and, brne=false)
2 (sbi)
--------
17 cycles

Bis der neue Preload eingetragen ist:
17
1+1+2 (ldi, ldi, rjmp)
1+1 (out, out)
-------
23 cycles

Innerhalb dieser 23 cycles hat der Timer floor(23/8) = 2 increments ausgeführt.


Jetzt läuft der Timer wieder normal weiter, bis der Pin auf LOW geht vergehen folgende cycles:
4+4+3
2+1+2 (lds, and, brne=true)
2 (cbi)
--------
18 cycles

Bis der neue Preload eingetragen ist:
18
1+1 (ldi, ldi)
1+1 (out, out)
--------
22 cycles

Hier ebenfalls 2 increments beim Timer.

Da der Wechsel von HIGH auf LOW und umgekehrt ca gleich schnell erfolgt (nach 17 bzw 18 cycles) und der Preloadwert noch vor dem 24ten cycle eingetragen wird, sollte mMn eine Verzögerung von 2 Timeriterationen (16 cycles) bei HIGH und LOW sein.
Ist es aber nicht, wie man den gemessenen Werten entnehmen kann.

Ich bräuchte nun Hilfe, ich bin mit meinem Latein am Ende. Bei der busywait Variante war alles noch so schön leicht :)

oberallgeier
11.05.2009, 08:37
Hallo cbg,

kannst Du mal den Code posten? Aber bitte in "in üblicher Weise" , also genauso wie Du Deine Messergebnisse gepostet hast? Bei Deiner txt-Datei müsste man ja erst ne halbe Stunde die Buchstaben ordnen :(. Und ich meine den originalen Code.

Vielleicht reicht es aber auch, wenn Du Dir in der Atmeldoc zum M16 den Abschnitt Clear Ti mer on Compare Match (CTC) Mode durchliest und (z.B.) den OC1A direkt vom Controller schalten läßt. Schau doch mal im Doc das Timingdiagramm auf Abb. 45 an. (Doc in der Version 2466P–AvR–08/07).


... So, für die Uni muss ich ...Was ist denn das für eine Uni? Gibts dort keine Assistenten die Du fragen kannst? Es gibt nämlich Unis, da haben die Assistenten entweder "open door" oder wenigstens Sprechstunden. Und bist Du der einzige Student? Es soll ja Unis geben, wo man den/die Kommilitonen fragen kann. Nicht dass Dir hier nicht geholfen werden soll, ich wundere mich nur.

cbg
11.05.2009, 14:19
Ja werd den Code nochmal posten. Ich glaub du meinst mit "halbe Stunde die Buchstaben ordnen", dass es kein CR gibt sondern nur LF (vom Linux). Werd nur den Assemberteil rauskopieren.
CTC Mode darf ich für dieses Teilbeispiel eben NICHT verwenden. Das PWM Signal soll auf 4 Arten erzeugt werden.
1) Busywait (funktionniert so wies soll)
2) Overflow (geht eben ned so gut)
3) CTC (funktionniert so wies soll)
4) FastPWM (funktionniert so wies soll)

Das ist eine Laborübung aber ich hab mir das Laborkit ausgeborgt um auch zuhause arbeiten zu können. Ich kann durch andere Kurse bedingt nicht imma hinschaun. Dort sind ausserdem auch nur Tutoren, da weiß der eine mal ein bisschen mehr, der andere weniger. Ich glaube aber auch, dass die Frage gar nicht so genau beantwortet gehört ("How long is the signal really high and low in each of these methods and why? How do you
compute the actual high- and low-times? Verify your calculations with the oscilloscope.") aber ich möchte es persönlich wissen.

Code (mit C-Code Kommentaren):

ISR_SIG_OVERFLOW1:
;__attribute__((naked)) SIGNAL(SIG_OVERFLOW1) {
; static uint8_t delay_select = 0;
; if(delay_select == 0) {
lds r18, 0x0060 ; # +2 cycles
and r18, r18 ; # +1 cycle
brne .+8 ; zu cbi # +2/1 cycles
; P_PORT |= (1<<P_NR);
sbi 0x12, 5 ; 18 # +2 cycles
; TCNT1 = PRELOAD_50US;
ldi r24, 0x9C ; 156 # +1 cycle
ldi r25, 0xFF ; 255 # +1 cycle
rjmp .+6 ; zum ersten out # +2 cycles
; } else {
; P_PORT &= ~(1<<P_NR);
cbi 0x12, 5 ; 18 ; # +2 cycles
; TCNT1 = PRELOAD_25US;
ldi r24, 0xCE ; 206 # +1
ldi r25, 0xFF ; 255 # +1
out 0x2d, r25 ; 45 # +1
out 0x2c, r24 ; 44 # +1
; }
; /* toggle delay_select */
; delay_select = 1 - delay_select;
ldi r24, 0x01
sub r24, r18
sts 0x0060, r24
; asm volatile("reti \n\t" ::);
reti
;}

MAIN:
;void main() {
; /* Pin P_NR as output, initially 0 */
; P_DDR |= (1<<P_NR);
; /* enable Idle sleep mode */
; MCUCR |= (1<<SE);
; /* turn off AC to reduce power consumption */
; ACSR |= (1<<ACD);
; /* Timer1 in Normal Mode
; * default, so nothing to do */
; /* Enable Timer1 overflow interrupt */
; TIMSK |= (1<<TOIE1);
; /* Preload Timer1 to get Interrupt after 25us */
; TCNT1 = PRELOAD_25US;
; /* Start TIMER1 clock F_CPU/8 */
; TCCR1B |= (1<<CS11);
; /* enable interrupts */
; sei();
ldi r28, 0x5F ; 95
ldi r29, 0x04 ; 4
out 0x3e, r29 ; 62
out 0x3d, r28 ; 61
sbi 0x11, 5 ; 17
in r24, 0x35 ; 53
ori r24, 0x40 ; 64
out 0x35, r24 ; 53
sbi 0x08, 7 ; 8
in r24, 0x39 ; 57
ori r24, 0x04 ; 4
out 0x39, r24 ; 57
ldi r24, 0xCE ; 206
ldi r25, 0xFF ; 255
out 0x2d, r25 ; 45
out 0x2c, r24 ; 44
in r24, 0x2e ; 46
ori r24, 0x02 ; 2
out 0x2e, r24 ; 46
sei

; while(1)
; asm volatile("sleep \n\t");
sleep
rjmp .-4 ; zu sleep
;}

Code (ohne C-Code Kommentare):

ISR_SIG_OVERFLOW1:
; if togglevariable == 0
lds r18, 0x0060 ; # +2 cycles
and r18, r18 ; # +1 cycle
brne .+8 ; zu cbi # +2/1 cycles

; LED setzen
sbi 0x12, 5 ; # +2 cycles
; preload 50us;
ldi r24, 0x9C ; 156 # +1 cycle
ldi r25, 0xFF ; 255 # +1 cycle
rjmp .+6 ; zum ersten out # +2 cycles

; LED löschen
cbi 0x12, 5 ; # +2 cycles
; preload 25us
ldi r24, 0xCE ; 206 # +1
ldi r25, 0xFF ; 255 # +1

; preloadwert schreiben
out 0x2d, r25 ; 45 # +1
out 0x2c, r24 ; 44 # +1

; toggle variable neu setzen
ldi r24, 0x01
sub r24, r18
sts 0x0060, r24
reti

MAIN:
ldi r28, 0x5F ; 95
ldi r29, 0x04 ; 4
out 0x3e, r29 ; 62
out 0x3d, r28 ; 61
sbi 0x11, 5 ; 17
in r24, 0x35 ; 53
ori r24, 0x40 ; 64
out 0x35, r24 ; 53
sbi 0x08, 7 ; 8
in r24, 0x39 ; 57
ori r24, 0x04 ; 4
out 0x39, r24 ; 57
ldi r24, 0xCE ; 206
ldi r25, 0xFF ; 255
out 0x2d, r25 ; 45
out 0x2c, r24 ; 44
in r24, 0x2e ; 46
ori r24, 0x02 ; 2
out 0x2e, r24 ; 46
sei

sleep
rjmp .-4 ; zu sleep

Besserwessi
11.05.2009, 21:59
Der Simulator von AVRStudio ist zwar nicht perfekt, aber hier sollte er ausreichen. Einfach mal im Simulator schritt für schritt laufen lassen da sollte man sehen wo etwas falsch läuft.