Forum: Mikrocontroller und Digitale Elektronik XMega und QDec


von Helmut R. (heru01)


Lesenswert?

Hallo Forum,
ich versuche den Quadraturdecoder am XMega in Betrieb zu nehmen. Die 
Doku: etwas dürftig - oder stelle ich mich nur an?
Zu Testzwecken habe ich einen Drehgeber mit 32 Positionen Auflösung an 
Port E eines XMega128A1 angeschlossen. Die Initialisierung ist:
1
lineCount = 32;
2
QDEC_Total_Setup(&PORTE,                    /*PORT_t * qPort*/
3
                   0,                         /*uint8_t qPin*/
4
                   false,                     /*bool invIO*/
5
                   0,                         /*uint8_t qEvMux*/
6
                   EVSYS_CHMUX_PORTE_PIN0_gc, /*EVSYS_CHMUX_t qPinInput*/
7
                   false,                     /*bool useIndex*/
8
                   EVSYS_QDIRM_00_gc,         /*EVSYS_QDIRM_t qIndexState*/
9
                   &TCC0,                     /*TC0_t * qTimer*/
10
                   TC_EVSEL_CH0_gc,           /*TC_EVSEL_t qEventChannel*/
11
                   lineCount);                /*uint8_t lineCount*/
12
13
// Auslesen mit 
14
iCountVal = GetCaptureValue(TCC0);

Also Ausgeben funktioniert - aber korrekt einlesen? Bis jetzt nicht.

Hat das jemand schonmal gemacht oder eine Idee?
Danke
Gruß
Helmut

von Joe (Gast)


Lesenswert?

hast du dir die app note mit beispielcode angeschaut? dürfte eigentlich 
alles erklären...

von ala42 (Gast)


Lesenswert?

Der aktuelle Wert steht im Counter Register, also
iCountVal = TCC0.CNT;

von Helmut R. (heru01)


Lesenswert?

Danke ala42! Ich habe nun mal alles herausfgeführt (RS232) was nicht 
niet- und nagelfest ist - und siehe da: ein Registerle zählt bereits 
munter vor sich hin. Allerdings etwas anders als erwartet (Startwert 
100)
Nun kann ich mich vorwärts hangeln bis das Ding tut. Die verwendete Fkt. 
GetCaptureValue des Atmel Beispiels hilft mir nicht, da es auf TCx->CCA 
zeigt und nicht auf TCx->CNT.

@Joe: Du bist bei Atmel, oder? Die Antwort dort ist - auch wenn etwas 
nachweislich nicht funktioniert - schau im Handbuch nach. Diese Info ist
* nicht immer angebracht
* wenig hilfreich
Hast Du denn mal in der Praxis Qdec getestet bevor Du wild postest?

Gruß
Helmut

von Helmut R. (heru01)


Lesenswert?

Hallo Forum,
als 16Bit Qdec: ja. Läuft. Hat schon jemand das als  32 bittige Version 
in Angriff genommen? :-)
Sollte(!) / muss durch Event funktionieren. Hmmm.
Der zählt bei mir nur aufwärts, obwohl ich die Richtung umkehre und das 
in
QDEC_Get_Direction feststellbar ist.
Hat da jemand Erfahrung?
Und nochmal @Joe: Tippen ist Blech - Schweigen ist Gold.

Gruß
Helmut

von ala42 (Gast)


Lesenswert?

Ich mach das per Software mit zwei Compareirqs, die ~$4000 links und 
rechts vom Start CNT Wert liegen. Wenn einer von beiden erreicht wird 
drehe ich das System um $4000, passe einen 32Bit Offset Wert 
entsprechend an und stell den CNT auf 0. Das allerdings nur virtuell, 
indem ich eine 16 Bit Variable auf den getroffenen Comparewert stelle, 
sonst könnten Ticks verloren gehen.
Den aktuellen 32bit Wert bekommt man dann mit
QDec32 = 32bit Offset + (signed int)(CNT - 16Bit Offset)
Der hintere Ausdruck muss ein Vorzeichen haben, sonst klappt das nicht.

Damit umgehe ich das potentielle Jitterproblem beim $FFFF-0 Übergang 
(Interrupts ohne Ende bei prellendem Encoder) und den 0,1 Overflow Bug 
beim Overflow Interrupt. Beim Vorwärtszählen macht der QDEC bei 0 und 
bei 1 einen Overflow Interrupt, beim Rückwärtszählen gibt es nur einen.

von Helmut R. (heru01)


Lesenswert?

Hallo ala42,
mich würden 2 Dinge interessieren:

* bis zu welcher Eingangsfrequenz kommst Du damit? Ich wollte halt die 
Einkanalzählerauswertung, sowie Zweikanalzählerauswertung ohne weitere 
Prozessorlast (Irq) laufen lassen. (Einkanalig 32Bit läuft, Zweikanalig 
32 Bit läuft nicht.)

* könntest Du mir die Codeschnipsel für Initialisierung und Auslesen 
bitte posten?
Ich komme mit 32Bit auch erst mal auf keinen grünen Zweig, seufz.
(wie sagt Werner: nach 32 Bit kann er alles... ;-) )

Vielen  Dank,

Gruß
Helmut

von ala42 (Gast)


Lesenswert?

Alle $4000 Encoder Ticks mal ein Interrupt, den man auch noch knapp 
$4000 Ticks verpennen darf, stört nicht besonders, auch wenn der QDEC 
viermal schneller läuft als die Eingangsfrequenz auf einer Spur.

#define QDecCounterStep 0x4000;

int32_t QDecCounter0Base=0;
int16_t QDecCounter0Offset=0;

Init()
{
  ...
  QDEC_Total_Setup(..., counter, ...)
  counter->CNT = 0;
  counter->CCA = QDecCounterStep
  counter->CCB = -QDecCounterStep
  counter->INTCTRLB = (counter->INTCTRLB & ~TC0_CCAINTLVL_gm) | 
TC0_CCAINTLVL1_bm | TC0_CCBINTLVL1_bm;
}


long GetQDec0()
{
  AVR_ENTER_CRITICAL_REGION();

  int c = QDecCounter0.CNT-QDecCounter0Offset;
  long count = QDecCounter0Base + c;
  AVR_LEAVE_CRITICAL_REGION();

  return count;
}


ISR(QDecCounter0CCA)
{
  AVR_ENTER_CRITICAL_REGION();

  register int step = QDecCounterStep;
  QDecCounter0Base += step;
  QDecCounter0Offset += step;
  QDecCounter0.CCA += step;
  QDecCounter0.CCB += step;
  QDecCounter0.INTFLAGS = TC0_CCAIF_bm;

  AVR_LEAVE_CRITICAL_REGION();
}

ISR(QDecCounter0CCB)
{
  AVR_ENTER_CRITICAL_REGION();

  register int step = QDecCounterStep;
  QDecCounter0Base -= step;
  QDecCounter0Offset -= step;
  QDecCounter0.CCA -= step;
  QDecCounter0.CCB -= step;
  QDecCounter0.INTFLAGS = TC0_CCBIF_bm;

  AVR_LEAVE_CRITICAL_REGION();
}

von Helmut R. (heru01)


Lesenswert?

Hallo ala42,

jetzt hab ich das Ding wo ich es haben wollte:
ich habe die Atmel Treiber genommen - diese setzen linecount ein.
Wer seinen Zähler nicht mit uint8_t linecount nach max. 255*4 -1 
zurückgesetzt haben will, muss eingreifen: wenn ich nachträglich 
TCx->PER = 0xffff; hinter die Initialisierung setze, so kann ich zwei 
Events laufen lassen - das ganze als 32 Bit Zähler . Da wollte ich hin.

Trotzdem: vielen herzlichen Dank an Dich! Du hast mich auf die richtige 
Fährte gesetzt!

Gruß
Helmut

von Helmut R. (heru01)


Lesenswert?

Nachtrag:
so wie ala42 das macht ist es richtig. Danke nochmals an dieser Stelle. 
In HW gibt es ein Problem: die Zähler sind zwar verkettet und zählen 
munter vor sich hin, aber den Auf-abwärtswechsel bekommen diese nicht 
mit: bei 0xFFFF 0x0000 des Quadraturzählers Z_15_0 steht der höhere 
Zähler Z32_16 auf 0x0001. Das Aufwärtszählen funktioniert mit einfacher 
Verkettung richtig, beim Abwärtszählen wird Z32_16 nicht in der Richtung 
umgekehrt. Ich habe noch versucht den Richtungswechsel zu erfassen, etc, 
aber:
in SW ist das dann doch viel sauberer - Events hin oder her.
Der Sprung im Zählerwert mir ist schon eher aufgefallen; gesehen wo es 
klemmt habe ich, nachdem ich mir die Zählerwerte binär ausgegeben habe.
Schade. Viele Encoder wollen nicht nur bis 65535 zählen...
Und von der Geschwindigkeit ist das in SW auch vertretbar (die ISR bei 
mir:  alle 1,6 Sekunden)

von ala42 (Gast)


Lesenswert?

Schon erstaunlich, das die Eventlogik nur einmal zählt, obwohl das 
Overflowbit bei $FFFF->$0000 und $0000->$0001 gesetzt wird. Der 
Simulator 2 ist übrigens so gut, das er diesen Double Overflow Bug 
perfekt nachbildet.

von XMega Fan (Gast)


Lesenswert?

Hallo Leute,
wie ich sehe haben hier doch wohl ein paar User den XMega QDEC am 
laufen. Kann mal jemand das zugehörige Init als ASM hier posten? Das 
würde mir sehr weiterhelfen.
Danke

von Guest (Gast)


Lesenswert?

Hallo XMega Fan,
in den Atmel Appnotes gibt es die Datei QDec_Driver.* ;-) Die habe ich 
auch als Grundlage genommen. Da ist der C Code als Besipiel enthalten. 
Wenn Du nun eine Übersetzung in Asm vornimmst, heisst das lediglich die 
Register befüllen und Qdec läuft. Dann hast Du das ganze 16 bittig. 
Wichtig: Counterregister auslesen; das war mein 1. Fehler; der 2. war 
Linecount in der Headerdatei zu ignorieren.
Du hast nicht geschrieben in welcher Breite Du QDec benötigst. Die 
Dikussion hier ging um 32 Bit. Wenn Du die haben willst, kannst Du die 
Funktionen, die ala42 geschrieben hat in Asm übersetzen. Fix und fertig 
in Asm gibts das hier anscheinend nirgends.


Gruß
Helmut

von XMega Fan (Gast)


Lesenswert?

Hallo Helmut,

danke für die Info.

von heinje (Gast)


Lesenswert?

Hallo,


kann vielleicht mal jemand den linecount definieren?

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.