Hallo, ich versuche gerade mit einem XMC 2Go Board einen
Inkrementalgeber mit 5000 Inkrementen mittels diesen Codes auszuwerten:
https://www.mikrocontroller.net/articles/Drehgeber
Durch die hohe Auflösung des Inkrementalgebers und der zu erwartenden
Drehzahl von 300 UpM wollte ich den Timer mit 500kHz takten lassen.
Der Timer löst alle 2us einen Interrupt aus. Wenn ich nur das Pintoggeln
in die ISR packe messe ich mit dem Oszi die gewünschten 2us, sobald
jedoch der Auswertecode für den Inkrementalgeber dazu kommt wächst die
gemessene Zeit auf 9.5us an. Der Mikrocontroller taktet mit 32MHz, ich
dachte das sollte reichen um diesen kleinen Code in den 2us
auszuführen...
R. H. schrieb:> ich> dachte das sollte reichen um diesen kleinen Code in den 2us> auszuführen...
In 2us macht der Controller mit 32MHz 64 Takte, das ist nicht viel...
Allerdings scheinen mir 304 Takte (9,5µs) auch etwas viel für diesen
Popelkram. Zeig mal das ASM listing.
> int8_t neu, diff;
Versuch mal uint32_t, das geht schneller.
Das Ändern der Variablen in uint32_t brachte keine Besserung. Ich habe
aber jetzt anstatt der von der DAVE IDE bereitgestellten Funktionen zum
Pinauslesen nun den Code so umgeschrieben das ich die Register direkt
auslese mit:
1
(((XMC_GPIO_PORT0->IN)>>8U)&0x1U)
vorher:
1
DIGITAL_IO_GetInput(&Spur_A)
jetzt komme ich auf 3.3us, nahe dran aber immer noch zu langsam...
was mich verwundert: wenn ich keine Interrupts habe und in der
Hauptschleife nur den Pin toggeln lasse komme ich auf nur 500ns. Ist
doch etwas zu langsam bei 32Mhz Systemtakt oder?
R. H. schrieb:> neu = 0;> if ( PHASE_A_Enc )> neu = 3;> if ( PHASE_B_Enc )> neu ^= 1;
Das ist doch recht umständlich. Wie wäre es mit:
1
if ( PHASE_A_Enc )
2
{
3
if ( PHASE_B_Enc )
4
neu = (3 ^ 1);
5
else
6
neu = 3;
7
}
8
else
9
{
10
if ( PHASE_B_Enc )
11
neu = (0 ^ 1);
12
else
13
neu = 0;
14
}
Die xor-Ausdrücke für die Nachvollziehbarkeit; da es konstante Ausdrücke
sind, wird der Compiler die ohnehin schon zur Compilezeit auswerten, so
daß sie keine Rechenzeit kosten.
Hast Du Dir schon mal den "Encoder interface mode" der Timer angeschaut?
Damit brauchst Du keinen einzigen CPU-cycle.
B.d.w.: welchen Optimierungslevel hast Du bei Deinem Compiler (welcher?)
eingestellt?
Gruß, Stefan
@ Tec Nologic, Stefan K.
danke für den Einwand, ist mir beim Datenblattüberfliegen nicht
aufgefallen das der Controller anscheinend Encoder in Hardware auslesen
kann. Das ist ntürlich die wesentlich angenehmere Methode. Dann werde
ich mich mal ans Studieren der Unterlagen machen...
Moin,
sieh die die Appnote an die ich gepostet habe, falls der Link nicht geht
such mal nach XMC CCU40 dann findest das Dokument auch. Da ist die CCU40
beschrieben. Unter anderem auch wie man sie zum Impulse Zählen verwenden
kann. Das richtige POSIF haben nur die XMC1300 und XMC1400 und die
XMC4xxx aber das ist nur ein Fortend für die Timer der CCU40 oder CCU80.
EDIT: OK nur mit der CCU40 wird das schwierig. Die kann zwar zählen aber
die Drehrichtung müsstest du mit einer externen Logik machen. Ohne POSIF
geht hier leider nix voll automatisch. Da habe ich mich getäuscht.
Gruß
Tec
R. H. schrieb:> Hallo, ich versuche gerade mit einem XMC 2Go Board einen> Inkrementalgeber mit 5000 Inkrementen mittels diesen Codes auszuwerten:> Durch die hohe Auflösung des Inkrementalgebers und der zu erwartenden> Drehzahl von 300 UpM wollte ich den Timer mit 500kHz takten lassen.
Brauchst du einen Absolutwert Position?
Dann erweitere den 16bit timer mithilfe einer 32bit var. Hier muss man
aber ein wenig Gehirmschmalz investieren. Dazu müsste man den update
flag (überlauf) nehmen. Dann pollst du jede ms und speicherst die neue
Position.
Anders wird es nicht ohne Zählfahler gehen. Oder dein µC ist nur damit
beschäftigt. Bei 300 rmp musst du, 1/(5* 5000*4)s das sind 10µs +
Nyquist das sind dann 5µs (160 Takte), eine Änderung des Encoders um 1
zu garantieren.
aSma>> schrieb:> Dann erweitere den 16bit timer mithilfe einer 32bit var. Hier muss man> aber ein wenig Gehirmschmalz investieren. Dazu müsste man den update> flag (überlauf) nehmen. Dann pollst du jede ms und speicherst die neue> Position.
Ok, das verstehe ich jetzt nicht ganz. Die frage ist ja wie ich mittels
der Counter die Drehrichtung erkennen kann. Ich denke hier bleibt doch
nur die anfangs erwähnte Softwarelösung. Der Mikrocontroller soll als
SPI-Slave arbeiten und bis auf das Zählen nichts weiter machen.
R. H. schrieb:> Der Mikrocontroller soll als SPI-Slave arbeiten und bis auf das Zählen> nichts weiter machen.
Was hast du denn als Master? Nimm doch für den Master einen
Mikrocontroller der Encoder in Hardware nebenher auswerten kann; viele
STM32 können das zB.
Nein, der Master kann das auch nicht, ist ein MSP430 von TI. Vielleicht
wäre noch eine Möglichkeit ein Quadratur Decoder IC, hat da jemand nen
Tipp für mich?
Wenn du nicht auf das XMC2Go festgelegt bist nimm doch einen größeren
Controller con Infineon den XMC1300 oder so. Oder einen STM32 vllt auch
dort nicht unbedingt den kleinsten M0. Dann geht das auch.
Oder du machst die 2 XOR in Hardware und hast ein Zählimpuls und eine
Drehrichtung dann kann das auch der XMC1100 auf dem XMC2Go.
Da ich für den vorgesehenen Einsatzzweck etwas kompaktes benötige mit
wenig Batelarbeit habe ich mich für dieses kleine Board entschieden.
Also ich sehe jetzt nur noch zwei Möglichkeiten: langsamer Samplen
(200Khz sollte klappen) oder ein Decoder IC verwenden...
R. H. schrieb:> (((XMC_GPIO_PORT0->IN) >> 8U) & 0x1U)
Habe mir mal das XMC1100 Manual angesehen und wie es aussieht hat der
keine Bit-adressierbaren Ports. Bei anderen M0 wie z.B. LPC800 ginge das
direkt:
(P0_8) bzw. LDRB bitval, [PORT0BASE, #8]
Und wie gesagt:
Ingo Less schrieb:> Zeig mal das ASM listing
Wahrscheinlich werden da mehrere unnötige type casts durchgeführt.
Abgesehen davon wäre ein M3 statt M0 auch nicht teurer und hätte
bedingte Codeausführung, was alles deutlich schneller macht.
R. H. schrieb:> Da ich für den vorgesehenen Einsatzzweck etwas kompaktes benötige mit> wenig Batelarbeit habe ich mich für dieses kleine Board entschieden.> Also ich sehe jetzt nur noch zwei Möglichkeiten: langsamer Samplen> (200Khz sollte klappen) oder ein Decoder IC verwenden...
Du suchst nach etwas kompakten, aber zwei IC´s erhöhen nur die
Fehlerwahrscheinlichkeit. Das ist einfach der falsche Weg.
Wenn dir die Pins vom XMC2Go reichen, dann nehme den 16bit timer + 32bit
hilfsvariable. Das kostet keine Rechenleistung!
Die Drehrichtung zu bestimmen ist voll low bob:
aSma>> schrieb:> Du suchst nach etwas kompakten, aber zwei IC´s erhöhen nur die> Fehlerwahrscheinlichkeit.
Ostern ist weit weg - Angsthasen gibt es zu jeder Jahreszeit.
Konsequenterweise darf man max. auch nur einen Abblockkondensator
verwenden?
Ein separater, autonom arbeitender µC reduziert m.E. die
Fehlerwahrscheinlichkeit.
Ob nun ein einzelner Dekoder, oder gleich fünf oder zehn davon - alles
kein Problem.
@m.n.
Ein sinnfreier Beitrag von dir mit einer sinnfreien Rhetorik. Die
Fehlerwahrscheinlichkeit kann auch durch die Software kommen...
Man kann hier alles mit nur einen µC lösen. Aber es gibt viele Wege nach
Moskau.
aSma>> schrieb:> Fehlerwahrscheinlichkeit kann auch durch die Software kommen...
... und noch viel schlimmer, wenn die Versorgungsspannung ausfällt.
Daher immer zwei Stromversorgungen vorsehen.
Diese blöde Schwarzmalerei geht mir schlicht auf den Keks!
aSma>> schrieb:> Wenn dir die Pins vom XMC2Go reichen, dann nehme den 16bit timer + 32bit> hilfsvariable. Das kostet keine Rechenleistung!>> Die Drehrichtung zu bestimmen ist voll low bob:> if(new_abs_pos >= old_abs_pos)> dir = NORMAL;> else> dir = REVERSE;>> Aber du musst zum Schluß entscheiden.
@ aSma
Ich kann dir nicht ganz folgen, wie soll ich deinen Vorschlag jetzt
verstehen? In Hardware zählen mit den Countereingängen? Die Frage ist
doch wie ich aus der A und B Spur des Encoders mit den Countereingängen
die absolute Position erhalten kann???
Wenn das ein echter Quadrature-Zähler ist, dann wertet der
automatisch(hardwaremäßig) A und B aus. Damit muss man nur z. B. alle
100us den 16bit Timer auslesen um die aktuelle Position jede 100us zu
bekommen. Benötigt man einen 32bit Quadrature-Zähler, dann muss man die
Überläufe des 16bit Zählers softwaremaßig zur 32bit Variable
addieren/subtrahieren. Diese Behandlung der Überläufe macht man in der
100us Interrupt-Routine.
Wenn du nur jede 1ms die Zahlen benötigst, dann halt jede 1ms einen
Interrupt auslösen.
Der XMC1100 hat nur normale Counter, im Datasheet steht nichts von
Quadratur-Eingängen. Also bleibt doch nur das softwaremäßige Polling mit
der Hoffnung das die 200kHz Abtastung reichen...
Helmut S. schrieb:> Nimm einen ARM Cortex Mx der das kann.
Da würde ich doch eher einen popeligen 8-Pin ATtiny ergänzen als den
Hauptprozessor zu wechseln.
Noch einmal gerechnet: 5 Umdrehungen/s mit 5000 Impulsen/Drehung und
4-fach-Auswertung erfordert eine minimale Abtastfrequenz von 100 kHz.
Der oben verlinkte ATtiny25 taktet mit 350 kHz und hat damit hinreichend
Reserve für diesen Geber.
Lothar schrieb:> Habe mir mal das XMC1100 Manual angesehen und wie es aussieht hat der> keine Bit-adressierbaren Ports. Bei anderen M0 wie z.B. LPC800 ginge das> direkt:>> (P0_8) bzw. LDRB bitval, [PORT0BASE, #8]>> Und wie gesagt:>> Ingo Less schrieb:>> Zeig mal das ASM listing>> Wahrscheinlich werden da mehrere unnötige type casts durchgeführt.> Abgesehen davon wäre ein M3 statt M0 auch nicht teurer und hätte> bedingte Codeausführung, was alles deutlich schneller macht.
@Lothar, Ingo Less
Ich hab hier nochmal das Asm Listing aus dem Debugger Disassembly-View
kopiert: