Forum: Mikrocontroller und Digitale Elektronik PIC24 Timer1


von Max H. (hartl192)


Lesenswert?

Ich habe ein kleines Problem mit dem Timer1 des PIC24. Ich will alle 
500ms ein Interrupt haben und habe dazu den Prescaler auf 1:256 gesetzt:
16MHz/256=62500Hz
0.5s*62500Hz=31250
Also habe ich das Period Register auf 31250 gesetzt. Im Simulator 
bekomme ich alle 8.000.255 Zyklen einen Interrupt. Wenn ich das PR1 auf 
31249 setze sind es 7.999.999 Zyklen. Die 255 lassen vermuten, dass das 
irgendetwas mit dem 1:256 Prescaler zu tun hat. Gibt es einen Trick um 
genau auf die 0.5 Sekunden (8.000.000Zyklen) zu kommen?

Vielen Dank und Grüße
Max

von Helmut S. (helmuts)


Lesenswert?

Wie misst du diese Zyklen?
In dem du misst, wenn die erste Zeile in der Interrupt-Routine 
ausgeführt wird?
Bedenke, dass der Interrupt erst ausgeführt wird, nachdem der gerade 
bearbeitete Befehl abgearbeitet wurde.

von mknoelke (Gast)


Lesenswert?

Der Prescaler legt Deine kleinste Zeiteinheit fest die der Timer dann 
nur noch abzählt.
Ich hab jetzt wenig Lust mich wieder in die 24F timer einzulesen, aber 
wie wärs wenn Du eine kleinere Zeiteinheit nimmst die sich besser 
darstellen läßt und in der IRQ den Kram zusammenbastelst.

Wenns geht verschachtel zwei 16bit Timer zu einem 32bit und löse das 
Problem durch brachiale Recourcenverschwendung.

von Max H. (hartl192)


Lesenswert?

Helmut S. schrieb:
> Wie misst du diese Zyklen?
MPLAB SIM, STOP WATCH
Setzt in der ISR einen Breakpoint starte die Simulation, setzt beim 
Break die Stop Watch auf null und Simuliere bis zum nächsten Breakpoint.

Helmut S. schrieb:
> Bedenke, dass der Interrupt erst ausgeführt wird, nachdem der gerade
> bearbeitete Befehl abgearbeitet wurde.
Der Fehler ist aber konstant und fällt weg, wenn ich relativ von einem 
Break zum anderen messe. An den Zahlen ändert sich auch nichts, wenn ich 
den Breakpoint ans Ende der ISR setze.

von Helmut S. (helmuts)


Lesenswert?

> Helmut S. schrieb:
>> Bedenke, dass der Interrupt erst ausgeführt wird, nachdem der gerade
>> bearbeitete Befehl abgearbeitet wurde.
> Der Fehler ist aber konstant und fällt weg, wenn ich relativ von einem
> Break zum anderen messe. An den Zahlen ändert sich auch nichts, wenn ich
> den Breakpoint ans Ende der ISR setze.

In der ISR hast du immer die Unsicherheit, dass ein Befehl im 
übergeordneten Programm mal einen bis mehrere Takte länger dauert und du 
deshalb den Breakpoint in der Interrupt-Routine mal scheinbar früher 
oder später erreichst. Nur im Mittel über viele Durchläufe erhältst du 
dann die 8000000.

von Max H. (hartl192)


Lesenswert?

Helmut S. schrieb:
> Nur im Mittel über viele Durchläufe erhältst du
> dann die 8000000.

Nach 40 Interrupts erreiche ich 319.999.960(PR1=31249) / 
320.010.200(PR1=31250) Zyklen:
319.999.960/40=7.999.999
320.010.200/40=8.000.255

mknoelke schrieb:
> Der Prescaler legt Deine kleinste Zeiteinheit fest die der Timer dann
> nur noch abzählt.
Daher kommen die 256 Zyklen stufen, nur den Offset von einem Zyklus 
verstehe ich nicht.

: Bearbeitet durch User
von Anja (Gast)


Lesenswert?

Max H. schrieb:
> Die 255 lassen vermuten, dass das
> irgendetwas mit dem 1:256 Prescaler zu tun hat.

Schau mal im Datenblatt unter welchen Bedingungen der Prescaler gelöscht 
wird. Möglicherweise beschreibst Du im Interrupt eines der kritischen 
Register.

Gruß Anja

von Jens M. (Gast)


Lesenswert?

Max H. schrieb:
> Gibt es einen Trick um
> genau auf die 0.5 Sekunden (8.000.000Zyklen) zu kommen?

Ja, du musst warten bis die 0,5s abgelaufen sind.

Dafür springst du kurz vor Ablauf in die Routine und wartest bis das 
Timer Flag triggert.

von Max H. (hartl192)


Lesenswert?

Anja schrieb:
> Schau mal im Datenblatt unter welchen Bedingungen der Prescaler gelöscht
> wird.
Zitat "PIC24F Family Reference Manual, Sect. 14 Timers":
>The prescaler counter is cleared when any of the following occurs:
>• A write to the TMRx register
>• Clearing TON (TxCON<15>) to ‘0’
>• Any device Reset

Anja schrieb:
> Möglicherweise beschreibst Du im Interrupt eines der kritischen
> Register.
Meine ISR sieht so aus:
1
  .global __T1Interrupt
2
  __T1Interrupt:
3
  bclr IFS0,#T1IF ; clear the interrupt flag
4
  com.b LATB+1
5
  retfie

Jens Martin schrieb:
> Dafür springst du kurz vor Ablauf in die Routine und wartest bis das
> Timer Flag triggert.
Ich habe dabei nur das Problem, dass das Interrupt Flag nach 
8.000.255/7.999.999 Zyklen gesetzt wird.

Der MicroE Timer Calculator schlägt diese Einstellungen vor:
1
void InitTimer1(){
2
  T1CON = 0x8030;  //1:256 Prescaler
3
  T1IE_bit= 1;
4
  T1IF_bit = 0;
5
  IPC0 = IPC0 | 0x1000;
6
  PR1 = 31250; 
7
}
Wenn ich diese Einstellungen in mein ASM Programm einbaue erhalte ich 
aber 8.000.255 Zyklen zwischen den Interrupts.

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

Helmut S. schrieb:
> In der ISR hast du immer die Unsicherheit, dass ein Befehl im
> übergeordneten Programm mal einen bis mehrere Takte länger dauert
Ich habe gerade gelesen, dass die Interrupt Latenzzeit bei Two-Cycle und 
Single-Cycle Instructions die gleiche ist.

Das Problem sollte man nur haben, wenn man den DISI Befehl benutzt, 
mache ich aber nicht.

: Bearbeitet durch User
von Anja (Gast)


Lesenswert?

Max H. schrieb:
> Wenn ich diese Einstellungen in mein ASM Programm einbaue erhalte ich
> aber 8.000.255 Zyklen zwischen den Interrupts.

Nur im Simulator oder auch im real life?

Gruß Anja

von Max H. (hartl192)


Lesenswert?

Anja schrieb:
> Nur im Simulator oder auch im real life?
Das kann ich dir nicht sagen. Ich kann die 0.5s nicht mit einer 
Auflösung von <15.938µs Messen.

Edit:
Wenn ich das PR1 Register aber auf 10 setze sind es sowohl im Sumulator 
als auch im real life 175.9375µs (2815 Zyklen 10*256+255=2815)

: Bearbeitet durch User
von Anja (Gast)


Lesenswert?

Max H. schrieb:
> A write to the TMRx register

Dann wird wohl das Löschen des Timer-Registers beim Erreichen des 
Endwertes als Schreibzugriff gewertet und 1 Taktzyklus geht dabei 
verloren.
(normalerweise wird durch PR1+1 geteilt).

Vielleicht hilft ja ein 6.5536 MHz Quarz (Prescaler 64 und PR1 = 0xFFFF)

Gruß Anja

von Max H. (hartl192)


Lesenswert?

Anja schrieb:
> (normalerweise wird durch PR1+1 geteilt).
Das habe ich mittlerweile begriffen. Wenn man darüber nachdenkt ist das 
auch logisch.

Noch ein Test:
PS=1:8
PR1=1
Zeit:
-MPLAB SIM: 937.5ns (15 Zyklen)
-Real live: 996ns (vllt. auch 1µs: Kein high ein Oszi)

Über 22 Timer überlauf Zyklen messe ich 22µs und Simuliere 20.625µs

Dieses Mal passen die errechneten Werte mit den Gemessenen zusammen. 
Dann könnte das mit dem fehlenden Zyklus ein Fehler in der SIM-Software 
sein.

von Anja (Gast)


Lesenswert?

Der ultimative Test wäre einen 2. Timer als PWM ohne prescaler laufen zu 
lassen.
Die Frequenz ist dann entsprechend Prescaler höher.

Wenn beide Kanäle phasenstarr bleiben dann ist die Simulation falsch.
Wenn der eine Kanal "durchläuft" wird der Prescaler gelöscht.

Gruß Anja

von Max H. (hartl192)


Lesenswert?

Anja schrieb:
> Der ultimative Test wäre einen 2. Timer als PWM ohne prescaler
> laufen zu
> lassen.
> Die Frequenz ist dann entsprechend Prescaler höher.
>
> Wenn beide Kanäle phasenstarr bleiben dann ist die Simulation falsch.
> Wenn der eine Kanal "durchläuft" wird der Prescaler gelöscht.
So weit bin ich noch nicht. Ich werde aber mit da PWM Modul im DB 
anschauen und versuchen es zu programmieren. Wenn ich es geschafft habe, 
melde ich mich...

von Max H. (hartl192)


Lesenswert?

Gar nicht so komplizier das PWM Modul.
Ich habe das PWM/TMR2 Modul so eingestellt:
PR2=51199
PS=1:1

TMR1:
PR1=199
PS=1:256

Die Phase bleibt jetzt schon seit 3min. gleich. Also ist das mit dem 
fehlendem wirklich ein Fehler im Simulator. Damit ist mein Problem jetzt 
gelöst und ich habe gelernt, wie ich das PWM Modul verwende...

Vielen Dank für die Hilfe! :-)

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.