Hallo zusammen,
wie der Titel schon sagt, geht es um einen Encoder (1024 P/R).
Dieser wird zur Bestimmung der Rotorposition eines BLDC Motors
verwendet.
A und B des Quadrature Encoder ist an einen Timer eines STM32F4
angeschlossen.
1
GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_TIM1);// A
2
GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_TIM1);// B
Es soll zusätzlich die Z Phase ausgewertet werden, um ein Driften zu
vermeiden.
Ich habe den Z Ausgang an einen Pin angeschlossen und eine IRQ für
diesen Pin implementiert. Dort setze ich den Timer einfach wieder auf
Null.
So habe ich keinen Drift.
Problem: Die ganze IRQ ist zu langsam und wenn der Timer zurückgesetzt
wird, hat der Motor schon zu weit gedreht.
So läuft der Motor bei höheren Geschwindigkeiten nicht konstant da vom
Encoder mal mehr, mal weniger zeitverschobener Positionswinkel ankommt.
Gibt es eine Möglichkeit, den Timer so zu konfigurieren, dass er per
Hardware, ähnlich wie die A und B Eingänge, zurückgesetzt wird?
Habe dazu nichts gefunden. Sogar im Datenblatt wird es einfach
empfohlen, die Z Auswertung 'billig' in eine IRQ zu werfen.
EDIT: Z Ausgang bei meinem Encoder ist negativaktiv und liefert an
Position NULL einen Nadelimpuls.
Gruß
Andreas
Hallo Andreas,
theoretisch sollte man den TImer über einne exteren Puls zurücksetzen
können. Schau mal im Ref Manual in der Timerbeschreibung unter "Timers
and external trigger synchronization", hier gibt es den Reset mode.
Ob der allerdings im Encodermode funktioniert kann ich dir nicht sagen.
Gruß
Rainer
Willst Du wirklich den Zähler bedingungslos bei jeder Umdrehung
zurücksetzen? Ich würde eher den "Z-Impuls" als Capture Signal verwenden
und den Zählerstand beim Z-Impuls in ein Capture Register einlesen. Erst
wenn der Capture Wert inkonsistent ist, also micht um 1024 vom letzten
Impuls abweicht, erst dann hast Du ein Problem und soltest es behandeln.
Ich würde über den Index Puls ein Capture Event auslösen inkl. ISR.
In der ISR kannst du dann die Differenz zwischen aktuellem Zählerstand
und Capture wert berechnen und setzt den Timer auf diesen Wert (und
nicht auf 0)
Ich verstehe nicht, warum Du bei jeder Umdrehung Fehler erwartest und
daher den Encoderstand zuruecksetzten willst! Waere es nicht sinnvoller,
Fehler im Encoder, die doch hoffentlich selten passieren, zu erkennen
und komplexer zu reagieren?
Anderenfalls kannst Du den mit dem mit Z-Impuls erfassten Capturewert
eine Korrektur fuer Deinen Encoder berechen. Fuer ein Zuruecksetzten
synchron zum Z-Impuls hat bisher keiner eine Idee. Wenn Du den Wert in
der Capture SR korrigierst, wie von Chris vorgeschlagen, ist der Motor
natuerlich moeglicherweise wieder weitergelaufen wie mit dem Ruecksetzen
in der ISR.
Ich hätte vielleicht dazu schreiben müssen, dass ich den Timer nur bis
2047 (1024+1024, A, B) zählen lasse. Sprich, der muss pro Umdrehung
sowieso ein mal wieder auf Null kehren.
Chris schrieb:> In der ISR kannst du dann die Differenz zwischen aktuellem Zählerstand> und Capture wert berechnen und setzt den Timer auf diesen WertUwe Bonnes schrieb:> ist der Motor> natuerlich moeglicherweise wieder weitergelaufen wie mit dem Ruecksetzen> in der ISR
Ich denke auch, dass es leider genauso zu den oben genannten Performance
Problemen führt. (Motor schon weitergelaufen)
Schade, dass ARM, bzw ST sich hier nichts besseres einfallen hat lassen,
außer ISR zu verwenden.
Ich hätte noch eine allg. Frage zu den Encodern. Ich verwende diesen
hier:
https://www.sparkfun.com/products/11102
Der Z Ausgang ist auf deutsch gesagt die ganze Zeit HIGH und macht an
einer bestimmten Wellenposition jede Umdrehung einen Spike nach LOW. Auf
diesen Spike kann ich aber nicht einmal mein Scope triggern lassen, auch
nicht bei niedrigen Drehzahlen.
(Tektronix DSO)
Die ISR des stm32 Timers auf dem Z Pin dagegen reagiert auf diesen Spike
bei niedrigen Drehzahlen wunderbar.
Wenn ich in der ISR beispielsweise einen anderen Pin toggle, kann ich
mein Scope auf diesen anderen Pin triggern.
Aber wie gesagt, nur bei niedrigen Drehzahlen, wenns schneller wird,
werden auch hier Umdrehungen verpasst.
Mit Schnell meine ich aber auch nur 1000rpm an der Welle, was ja für die
ISR und den Z Pin ja eig. ein Witz ist.
Dieses Verhalten scheint mir nicht normal zu sein nicht wahr?
Vielleicht ist es weniger ein Performance Problem wie ein Fehler in
meinem Encoder?
Auf dem "Datenblatt" Seite 5 sieht Z auch nicht wie ein Nadelimpuls aus.
Gruß
Andreas
Andreas True schrieb:> Ich denke auch, dass es leider genauso zu den oben genannten Performance> Problemen führt. (Motor schon weitergelaufen)> Schade, dass ARM, bzw ST sich hier nichts besseres einfallen hat lassen,> außer ISR zu verwenden.
Also das wundert mich nun doch. Bei 1000 rpm und einen 1024 bit Encoder
kommt das Encoder Signal mit etwa 35 kHz, das sollte doch mehr als genug
Zeit für einen STM32 sein um da zwischen zwei Flanken über ein Interrupt
einen Counter zurückzusetzen.
Wobei auch mir das Konzept den Counter des Encoders bei jeder Umdrehung
zurückzusetzen etwas seltsam erscheint. Warum macht man das?
Es sieht für mich logisch aus, wenn der Counter pro Umdrehung um 2048
erhöht wird, diesen einfach an der Nullposition (Z Durchgang) wieder auf
Null zu setzen und nur bis 2048 zählen zu lassen. So kann ich zu jeder
Zeit direkt die absolute Rotorposition ablesen.
Natürlich würde es über verUNDen genau so funktionieren, den Timer
einfach weiter laufen zu lassen und trotzdem die Position zu bekommen.
Aber ich sehe da keinen Grund dafür.
Ist diese Vorgehensweise unüblich?
Andreas True schrieb:> Es sieht für mich logisch aus, wenn der Counter pro Umdrehung um 2048> erhöht wird, diesen einfach an der Nullposition (Z Durchgang) wieder auf> Null zu setzen und nur bis 2048 zählen zu lassen. So kann ich zu jeder> Zeit direkt die absolute Rotorposition ablesen...
Fuer mich ist das nicht logisch. Nach 8 Umdrehungen hast Du doch das
Ruecksetzen automatisch, jedenfalls bei den STM32 16-bit Zaehlern.
Und die absolute Position innerhalb einer Umdrehung hast Du auch ohne
das Zuruecksetzen wenn Du mit 0x3fff verundest.
Jap, habe ich oben auch dazugeschrieben. Wenn ich aber per Z Durchgang
auf 0 setze, habe ich immer an der selben physischen Position den selben
Timer Counter Wert.
Aber findest du von mir oben beschrieben Verhalten nicht auch seltsam?
Andreas True schrieb:> https://www.sparkfun.com/products/11102>> Der Z Ausgang ist auf deutsch gesagt die ganze Zeit HIGH und macht an> einer bestimmten Wellenposition jede Umdrehung einen Spike nach LOW. Auf> diesen Spike kann ich aber nicht einmal mein Scope triggern lassen, auch> nicht bei niedrigen Drehzahlen.> (Tektronix DSO)> Die ISR des stm32 Timers auf dem Z Pin dagegen reagiert auf diesen Spike> bei niedrigen Drehzahlen wunderbar.> Wenn ich in der ISR beispielsweise einen anderen Pin toggle, kann ich> mein Scope auf diesen anderen Pin triggern.> Aber wie gesagt, nur bei niedrigen Drehzahlen, wenns schneller wird,> werden auch hier Umdrehungen verpasst.
Andreas True schrieb:> Aber findest du von mir oben beschrieben Verhalten nicht auch seltsam?
Ja, das Teil ist wohl kaputt. Du hast ja selbst schon erkannt, dass Z
sich nicht so verhält wie er es nach Datenblatt sollte.
Moin,
Das Problem ist nicht der Ausgang sondern dessen Beschaltung!!
Datenblatt des Sensors Seite 5. Meine Zeichendeutung ist nicht gut, aber
der Schaltplan für den Z-Pin deutet für mich darauf hin das der PIN
deinen Pullup nicht treiben kann. Prüfe das mal bitte ob deine Externe
Beschaltung des Encoders richtig ist.
Hi,
Auf Seite 5 habe ich den A6B2-CWZ3E Encoder.
Es steht zwar irgendwo dass die Ausgänge open collector sind, aber die
Schaltung auf Seite 5 deutet ja darauf hin, dass der PullUp schon
integriert ist, weil ja noch ein Rahmen rundum ist.
Oder sehe ich das falsch?
Ich habe aktuell keinen PullUp, sondern sogar einen Spannungsteiler
gegen GND, um 5Volt->3Volt zu wandeln.
Meine Beschaltung siehe Anhang.
Aber der Wurm scheint trotzdem hier vergraben zu sein.
Wenn ich mein Scope vor dem Spannungsteiler direkt an den Z Ausgang
ansetze, kann das Oszi triggern und messen, hinter dem Spannungsteiler
aber nicht mehr.
Es ist sogar so, dass auch bei niedrigen Drehzahlen die ISR nicht
ausgeführt/getriggert wird, sobald ich den Tastkopf nach dem
Spannungsteiler, also auf der uC Seite ansetze.
Mein Spannungsteiler hat insgesamt irgendwas um die 10k.
Wenn ich vor dem Spg-Teiler messen kann und dahinter nicht, bedeutet es
doch dass ich einen kleineren Gesamtwiderstand für den Spg-Teiler wählen
muss?
EDIT: ok, das ist Schwachsinn, ich kann vor und nach dem Spannungsteiler
mit dem Scope problemlos messen, bei hohen und bei niedrigen Drehzahlen.
Hatte die TriggerlevelSpannung am Scope ungünstig eingestellt :D
Heißt ja aber, dass der Encoder Ausgang die Beschaltung und den uC Pin
treiben kann nicht wahr?
Jetzt bleibt noch die frage, ob man einen PullUp braucht.
Gruß
Andreas
Habe jetzt noch einiges auprobiert: Der Encoder ist nicht defekt.
Mein uC überspringt auch keine Index (Z) Signale, die ISR wird jedes mal
betreten.
Das Problem scheint wirklich die Performance zu sein.
Wenn ich in der ISR den Timer bei höheren Drehzahlen nicht auf 0 sondern
zB auf 10 setze, läuft der Motor wesentlich besser und konstanter, die
Stromaufnahme geht auch zurück.
Bedeutet am Schluss, dass wenn der Motor mit 1500rpm läuft und am
Nullpunkt vorbeifährt, die ISR aufgerufen wird um den Timer
zurückzusetzen (sprich zu synchronisieren), ist der Motor schon 10
Encoderschritte weitergelaufen.
Das wirkt sich natürlich stark auf den Motorlauf aus, da 7 elektrische
Rototationen einer Wellenrotation entsprechent bei meinem Motor.
Es scheint wohl keine Hardwarelösung für den Z Input zu geben :(
Wenn du den oben verlinkten Encoder hast (also in der verlinkten
Ausführung), dann hat der Push-Pull Ausgänge. Da die (meisten) Eingänge
des STM32F4 5V tolerant sind, kannst du direkt auf den Eingang gehen.
Meine Spannungsteiler sehen übrigens anders aus...
anon schrieb:> Meine Spannungsteiler sehen übrigens anders aus...
Meine Beschriftung ist hier vielleicht etwas irreführend:
ENCODER_A, ENCODER_B, ENCODER_Z gehen an den uC
und die Rechtecke stellen die Anschlussleiste für die Encoderausgänge
dar.
"uC" ist falsch plaziert.
Tec Nologic schrieb:> Naja die HW-Lösung ist Capture Compare wie bereits angedeutet. dann ist> die Laufzeit der Isr irrelevant
Ich denke jetzt habe ich verstanden, was Chris und Uwe mir weiter oben
sagen wollten:
Wenn A und B an Channel 1 und 2 hängen, soll ich Z auf Channel 3 legen
und diesen auf Capture konfigurieren. Immer wenn es auf CH3 einen Event
gibt, wird der aktuelle Timer Zählerstand weggespeichert. Diesen kann
ich dann mit
1
TIM_GetCapture3(TIMx)
abholen und habe alle Zeit der Welt den Zählerstand zu korrigieren.
Hoffentlich jetzt richtig verstanden D:
Könntet ihr bitte über meinen Code drüberschauen, ich habe den Timer wie
beschrieben eingestellt, es wird auch brav durch den Encoder
hochgezählt, nur der TIM8_CC_IRQHandler wird nicht betreten.
Ich habe genau das gleiche Problem wie der Thread-Starter und habe, ohne
diesen Thread zu kennen, den Inputcapture als Ausweichlösung in Betracht
gezogen. Im Moment fehlt mir noch eine Softwarelösung. Schade, dass der
Thread sang- und klanglos versackt ist.
Servus,
Andreas T. schrieb:> TIM_TimeBaseStructure.TIM_Period = 0x07ff;Andreas T. schrieb:> NVIC_InitStructure.NVIC_IRQChannel = TIM8_CC_IRQn;> NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;> NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;> NVIC_InitStructure.NVIC_IRQChannel = ENABLE;> NVIC_Init(&NVIC_InitStructure);
IRQChannelPreemptionPriority lieber auf 0 setzen, dann kann diese ISR
nicht unterbrochen werden oder mit:__disable_irq(), __enanble_irq()
arbeiten.
Bei zu langen Leitung müsste man sich die Quadratursignale am Scope mal
anschauen. Könnte deshalb schlechte Flanken ergeben. Pullup würde ich so
je nach länge der Leitung zwischen 1,5k bei 5V und max 6000rmp. Man kann
natürlich bei ganz langen Leitung auf 24V plus Spannungsteiler hingehen.
Aber auch hier nicht zu hochomig, sodas zwischen 3-5mA Strom fließt.