Forum: Mikrocontroller und Digitale Elektronik Ausführungsgeschwindigkeit ARM M0


von R. H. (breezer)


Lesenswert?

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...

1
void TimerISR (void)
2
{
3
4
  XMC_GPIO_PORT0->OMR = 0x10001U << 0U;
5
6
7
    int8_t neu, diff;
8
9
10
    neu = 0;
11
    if ( PHASE_A_Enc )
12
      neu = 3;
13
    if ( PHASE_B_Enc )
14
      neu ^= 1;                   // convert gray to binary
15
    diff = last - neu;                // difference last - new
16
    if ( diff & 1 ) {             // bit 0 = value (1)
17
      last = neu;                 // store new as next last
18
      enc_delta += (diff & 2) - 1;        // bit 1 = direction (+/-)
19
    }
20
21
22
}

von Ingo Less (Gast)


Lesenswert?

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...

von Ingo Less (Gast)


Lesenswert?

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.

von R. H. (breezer)


Lesenswert?

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...

von R. H. (breezer)


Lesenswert?

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?

von Ingo L. (corrtexx)


Lesenswert?

R. H. schrieb:
> auf nur 500ns
Das sind dann 16 Takte. Zeig mal das Programm zum "nur toggeln".

: Bearbeitet durch User
von Alex E. (tecnologic) Benutzerseite


Lesenswert?

Hallo Zusammen,

was soll dieser Spielkram? Warum nimmst du nicht die CCU40 und lässt die 
deine Impulse zählen. Dann sind auch 2MHz Pulstakt kein Problem. Wenn 
der Controller die Peripherie hat nutze sie.

Siehe: 
http://www.infineon.com/dgdl/Infineon-CCU4-XMC1000_XMC4000-AP32287-AN-v01_01-EN.pdf?fileId=5546d4624e765da5014ed8dd0f4614c0

Gruß

Tec

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

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.

von Stefan K. (stefan64)


Lesenswert?

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

von R. H. (breezer)


Lesenswert?

@ 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...

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

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

: Bearbeitet durch User
von aSma>> (Gast)


Lesenswert?

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.

von R. H. (breezer)


Lesenswert?

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.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

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.

von R. H. (breezer)


Lesenswert?

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?

von Alex E. (tecnologic) Benutzerseite


Lesenswert?

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.

von R. H. (breezer)


Lesenswert?

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...

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?


von Lothar (Gast)


Lesenswert?

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.

von aSma>> (Gast)


Lesenswert?

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:
1
if(new_abs_pos >= old_abs_pos)
2
  dir = NORMAL;
3
else
4
  dir = REVERSE;

Aber du musst zum Schluß entscheiden.

von m.n. (Gast)


Lesenswert?

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.

von aSma>> (Gast)


Lesenswert?

@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.

von m.n. (Gast)


Lesenswert?

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!

von R. H. (breezer)


Lesenswert?

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???

: Bearbeitet durch User
von Helmut S. (helmuts)


Lesenswert?

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.

von R. H. (breezer)


Lesenswert?

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...

von Helmut S. (helmuts)


Lesenswert?

Wenn der XMC1100 das nicht kann, dann gibt es nur eine Lösung - weg 
damit. Nimm einen ARM Cortex Mx der das kann.

von m.n. (Gast)


Lesenswert?

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.

von R. H. (breezer)


Lesenswert?

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:
1
43            XMC_GPIO_PORT0->OMR = 0x10001U << 0U;
2
10001976:   ldr r3, [pc, #8]        ; (0x10001980 <main+36>)
3
10001978:   ldr r2, [pc, #8]        ; (0x10001984 <main+40>)
4
1000197a:   str r2, [r3, #4]
5
44          }
6
1000197c:   b.n 0x10001976 <main+26>    }

hier der C-Code dazu...
1
  while(1U)
2
  {
3
    XMC_GPIO_PORT0->OMR = 0x10001U << 0U;
4
  }

Viel steckt nicht drin, benötigt er dafür tatsächlich 16 Taktzyklen?

: 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.