Ausführungsgeschwindigkeit ARM M0

OP #4721499
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
}
OP #4721529
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...
Gast #4721547
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.
OP #4721571
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...
Persönliche Seite #4721593
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
Gast #4721623
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.
OP #4721676
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.
OP #4721728
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...
Gast #4721897
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.
Gast #4722295
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.
Gast #4722607
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.
Gast #4722631
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.
OP #4723346
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???
#4723382
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.
Gast #4723602
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.
OP #4725758
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren