Forum: Mikrocontroller und Digitale Elektronik Problem mit Timer Interrupt LPC1769


von Heiko1989 (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

vielen Dank für eure Hilfe im voraus. Ich arbeite momentan mit einem 
LPC1769 Mikrocontroller und der Entwicklungsumgebung LPCXpresso v6.0.4. 
Der Mikrocontroller hat die Hauptaufgabe die Schrittvorgaben für einen 
Schrittmotor zu berechnen, was auch schon gut funktioniert. Die 
Schrittfrequenz kann ich vergrößern bzw. verkleinern, indem ich das 
MR0-Register von Timer0 verändere. Der Timer0_IRQHandler gibt die 
entsprechende Schrittfrequenz für jeden Strang per GPIOs aus. Da ich in 
naher Zukunft die Schrittfrequenz von ca. 50Hz bis hin zu 8kHz 
hochfahren (Rampe) möchte, habe ich etwas mit dem MR0-Register 
herumgespielt. Dabei habe ich den Wert von MR0 stetig verringt und dabei 
jeweils die Schrittfrequenz mit einem Frequenzzähler gemessen. Die 
Messwerte sind im Folgenden zu sehen:

MR0      Freq in Hz
10000       6,25
7000        9
6000       11,1
5000       12,5
3000       22,22
2000       31,15
1500       41,6
1000       64,51
500       125
100       625
50       1250
25       2500
12       5000

An dieser Tabelle fiel mir sofort auf, dass die Auflösung im unteren 
Frequenzbereich recht gut ist und im oberen Frequenzbereich immer 
schlechter wird. Beispielsweise stehen für die Frequenzen zwischen 
6,25Hz und 9Hz 3000 MR0-Werte zur Verfügung, während zwischen 2500Hz und 
5000Hz nur 23 MR0-Werte zur Verfügung stehen. Wie kann ich die Auflösung 
im oberen Frequnenzbereich erhöhen?? Ich möchte gern Schrittfrequenzen 
von 50 bis 8kHz mit einer Auflösung von min. 1Hz in allen Bereichen 
erzeugen.

Die Timer-Einstellungen sind auf dem Bild im Anhang zu sehen.

Ich hoffe Ihr könnt mir helfen.  Danke

von Jim M. (turboj)


Lesenswert?

Heiko1989 schrieb:
> Die Timer-Einstellungen sind auf dem Bild im Anhang zu sehen.

Hänge bitte das nächste mal die .c Datei an, das ist bedeutend einfacher 
und besser als ein Bild. Hier fehlt unter anderem ein interessanter Teil 
des IRQHandlers.

> Der Timer0_IRQHandler gibt die entsprechende Schrittfrequenz für jeden
> Strang per GPIOs aus.

Das ist für hohe Frequenzen nicht optimal, denn da geht die meist 
variable Interrupt Lateniz mit ein. Der LPC176x hat eine extra PWM 
Einheit verbaut, die das möglicherweise ohne Interrupt hinbekommen 
würde. Außerdem gibt es noch die MCPWM. Siehe UM10360.pdf, Kapitel 24 
und 25.

Heiko1989 schrieb:
> An dieser Tabelle fiel mir sofort auf, dass die Auflösung im unteren
> Frequenzbereich recht gut ist und im oberen Frequenzbereich immer
> schlechter wird.

Das ist bei allen Timern so, denn da wird einfach eine Frequenz (PCLK) 
erst mit dem Prescaler und dann mit dem Match Register geteilt - und 
zwar in ganzzahligen Schritten.

Bei Deinen Angaben komme ich allerdings auf eine PCLK von nur 1,2 MHz; 
Da muss der IRQHandler noch weiter teilen.

Heiko1989 schrieb:
> bis 8kHz mit einer Auflösung von min. 1Hz

8000 Hz * 8000 Schritte ergibt 64 MHz Timer Basis Frequenz (PCLK). Das 
ist grade noch so eben im Bereich des Möglichen - aber nicht mehr mit 
Unterteilung in Software.

: Bearbeitet durch User
von old man (Gast)


Lesenswert?

Der LPC1769 kann max. 120MHz. Wenn du alle Vorteiler und Prescaler 
entfernst, brauchst du für 8000Hz einen Teiler von 15000. Der Schritt 
auf 15001 würde 7999.47Hz ergeben. Glatte 1Hz wirst du mit dieser 
einfachen Methode nicht hinkriegen. Da die Timer 32bit sind, reichen die 
auch bei 50Hz noch locker.
Deine Werte sind aber nicht plausibel. CLKSEL mit 0x03 bedeutet durch 8 
nicht durch 4 teilen. Bei einem Prescaler von 10 und MR0 mit 10000 
sollte 125Hz rauskommen und nicht 6.25. Mit welcher Frequenz läuft denn 
dein MC?

von Heiko1989 (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank erstmal für eure schnellen Kommentare :-)
Im Anhang befindet sich nun die komplette c-Datei, sodass ihr das 
Problem leichter nachvollziehen könnt.

> Mit welcher Frequenz läuft denn dein MC?

Der MC läuft mit 100Mhz.

> Bei einem Prescaler von 10 und MR0 mit 10000
> sollte 125Hz rauskommen und nicht 6.25.

Die niedrige Frequenz von 6,25Hz ergibt sich aus den 19 Case-Blöcken im 
IRQ-Handler. (siehe Anhang)

Kann man das oben beschriebene Problem also in den Griff bekommen, indem 
man die Vorteiler entfernt??

von Jim M. (turboj)


Lesenswert?

Heiko1989 schrieb:
> Kann man das oben beschriebene Problem also in den Griff bekommen, indem
> man die Vorteiler entfernt??

Nicht ohne weiteres, denn Du musst auch die Laufzeit des Interrupts 
beachten, d.h MR0 darf nicht zu klein werden.

Der Interrupt Handler liesse sich signifikant kürzen, wenn man die 
Portzuweisungen zusammenfasst:
1
case 0 :
2
3
    LPC_GPIO2->FIOCLR = (1<<1) |(1<<2) |(1<<4);      
4
    LPC_GPIO2->FIOSET = (1<<3)| (1<<5)|(1<<6);  
5
6
    LPC_GPIO0->FIOCLR = (1<<2)| (1<<21);
7
    LPC_GPIO0->FIOSET = (1<<3)|(1<<22);

Die Verwendung von "|=" ist bei FIOSET und FIOCLR unnötig da nur die "1" 
Bits die Aktion auslösen. Durch Weglassen spart man jeweils den 
Lesezyklus.

von Marc P. (marcvonwindscooting)


Lesenswert?

Das interrupt-Flag killt man ebenfalls ohne |= sondern mit = . Das |= 
ist strenggenommen sogar falsch, sobald irgend eine andere Sache auch 
noch mit dem Timer gemacht werden soll.
Im Manual genau lesen, wie die Register funktionieren, anstatt solche 
'Angst/Unwissenheits-Konstrukte' zu verwenden.

Die ISR ist ein bissl arg 'ueppig' gschrieben, willst Du das nicht mal 
mit einer Tabelle fuer die Sets/Clrs umsetzen?

Wenn das mit der Aufloesung wirklich schoen werden soll, dass musst Du 
Dir mal Software-DDS anschauen. Dann darfst Du naemlich deinen Timer 
ziemlich schnell laufen lassen (und damit die ISR = Abtastrate) aber die 
Drehung davon unabhaengig berechnen. Gerade bei hohen Drehzahlen willst 
Du ja keine grossen (relativen) Geschwindigkeitsspruenge.

: Bearbeitet durch User
von Heiko1989 (Gast)


Lesenswert?

Ich werde die ISR entsprechend eurer Ratschläge optimieren...

Könnt ihr mir gute Literatur bezüglich ARM-Mikrocontroller 
Programmierung empfehlen? Ich bin nämlich in einigen Dingen noch 
unsicher...

> Wenn das mit der Aufloesung wirklich schoen werden soll, dass musst Du
> Dir mal Software-DDS anschauen.

Das hört sich gut an :-)  DDS habe ich schon öfter im Zusammenhang mit 
Funktionsgeneratoren gehört, aber leider noch nie damit gearbeitet.

Wie kann man denn DDS im Rahmen meines Projektes anwenden? Kannst du mir 
das bitte etwas genauer erläutern? Danke

von Marc P. (marcvonwindscooting)


Lesenswert?

Zum Prinzip:

http://www.mikrocontroller.net/articles/DDS

In deinem speziellen Fall - falls ich das richtig verstanden hab - 
gehts um 20 diskrete Schritte (Signalwechsel) statt eines Sinus. Ist 
aber nicht schlimm, deine Lookup-Tabelle ist dann halt nicht der Sinus, 
sondern deine digitalen Signale fuer die Halbbruecken. DDS sampled ja 
irgendeine Funktion. Als Nachteil bekommst nur ein bisschen 'jitter' auf 
die Signale.

Hilfreich w"are, wenn Du 16 oder 32 Schritte definieren wuerdest. Denn 
irgendwo musst Du einen Abschnitt des Phasenakku als Index in der 
Lookuptabelle verwenden.

Statt Tabelle, darfst Du weiterhin ein grosses switch() verwenden, 
wenn's unbedingt sein muss.

In der ISR (konstante, hohe Wiederholrate Fs) addierst du immer einen 
einstellbaren Wert (tuning word) tw auf den Phasenakku a (Integer mit 
vielen Bits, z.B. 32).
von dem Phasenakku nimmst Du z.B. die hoechsten n=4 bits (28..31) und 
die sind der Index der Tabelle oder der Wert im switch().
Wenn tw = 2^32/Fs, dann kommt gerade f = 1Zyklus/Sekunde zustande. tw 
doppelt so gross => doppelt so schnell. tw halb so gross => halb so 
schnell. Kurz f ~ tw. Und das genau ist das coole daran. Direkt 
proportional. Und tw hat bei guter Wahl der Konstanten viele Bits (hohe 
Genauigkeit).
Du musst in deinem Fall aber garantieren, dass keine Zwischenschritte 
fehlen, d.h. Fs > f * 2^n

EDIT: Fehler in der tw-Formel behoben.

: Bearbeitet durch User
von Heiko1989 (Gast)


Angehängte Dateien:

Lesenswert?

Ok, das DDS-Prinzip habe ich verstanden. Echt geniale Sache^^

Allerdings habe ich dabei noch ein kleines Problem:

> Hilfreich w"are, wenn Du 16 oder 32 Schritte definieren wuerdest. Denn
> irgendwo musst Du einen Abschnitt des Phasenakku als Index in der
> Lookuptabelle verwenden.

Wenn ich 16 Werte in der Lookuptabelle adressieren will, brauche ich 3 
MSB's von dem Phasenakku und wenn 32 Werte dann 4 Bits  usw...

In meinem Fall brauche ich genau 20 Werte, weil es sich um einen 
fünfsträngiggen Schrittmotor, welcher mit 5 H-Brücken angesteuert wird, 
handelt.

Die Ansteuertabelle habe ich angehängt. Das + steht für Strom in 
positiver Richtung und das - für Strom in negativer Richtung. Diese 
Tabelle ist in der ISR in der großen Case-Anweisung abgebildet.

Nun meine Frage:
Ist das DDS-Prinzip auch mit einer Lookuptabelle, welche 20 Werte 
enthält, möglich?  Oder habt Ihr/du noch eine andere Idee?
Danke

von Marc P. (marcvonwindscooting)


Lesenswert?

Heiko1989 schrieb:
> In meinem Fall brauche ich genau 20 Werte, weil es sich um einen
> fünfsträngiggen Schrittmotor, welcher mit 5 H-Brücken angesteuert wird,
> handelt.

Kopfkratz

Dann braucht's etwas Zusatzaufwand: oberste 5 bits fuer 32 moegliche 
Werte nehmen und bei jedem Durchlauf durch die ISR (Phasenakku-Update) 
diese 5 bits % 20 rechnen. Grob gesagt, musst Du den 'wrap-around' 
selber machen und darfst nicht den 32-bit Ueberlauf passieren lassen. 
Sonst bleibt alles gleich.

PS: einen coolen Motor hast Du da!

: Bearbeitet durch User
von Marc P. (marcvonwindscooting)


Lesenswert?

Marc P. schrieb:

> Dann braucht's etwas Zusatzaufwand: oberste 5 bits fuer 32 moegliche
> Werte nehmen und bei jedem Durchlauf durch die ISR (Phasenakku-Update)
> diese 5 bits % 20 rechnen.

Oder gleich einen Schritt weiter gehen: 8 bit oder mehr lookup, dann 
Sinus-Tabelle und den Motor mit 5 phasenverschobenen Sinus ansteuern. 
Dann wird's richtig cool (Mikroschritt). Dann wirst Du den Motor nicht 
mehr hoeren wenn er sich bewegt, Ehrenwort!

Eine 2x3-Phasen-Variante davon koennte ich Dir vielleicht ueberlassen. 
Ich hab das schon mehrfach getan, auch noch zufaellig auf 'nem LPC17 .-)

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.