Hallo!
Ich beschäftige mich gerade mit der HighRes extension des Timers in
einem Xmega128A3.
Der soll eine einfache (single-slope) PWM mit 10bit an PORTD:0-3
erzeugen - und das möglichst flink. Dazu habe ich die HighRes extension
eingeschaltet und die Clocks so configuriert, dass Fper4 auf 128MHz
läuft und die CPU auf 32MHz.
Auf dem Oszi sehe ich schön meine PWM mit 125kHz. Im Datenblatt steht,
dass Werte kleiner als 4 keinen Output erzeugen, das leuchtet mir im
anbetracht der allgemeinen Funktionsweise des HighRes Moduls ein. Ich
kann das Verhalten auch am Oszi sehen.
Was ich aber ebenfalls sehe, ist dass die Werte 4,5,6,7 allesamt die
selbe Wellenform erzeugen, ebenso die Werte 8,9,10,11 usw.
De facto ist der Output also in nur 4er Schritten einstellbar. Warum?!
Dann hätte ich ja gleich meine PWM Auflösung um 2bit verringern und den
Timer ohne HighRes Extension betreiben können.
Hier kommt mein Code.
Dein Code sieht soweit OK aus
Hier solltest du das nur für den Timer einschalten, den du auch benutzt.
1
HIRESD.CTRLA=HIRES_HREN_BOTH_gc;
Der Fehler liegt also wahrscheinlich in deinem anderem Code.
Es gibt auch eine Atmel Appnote zu Hires/Awex mit Beispiel, im Zweifel
kannst du damit anfangen.
Hi Thomas,
ist es relevant, ob ich tatsächlich beide Timer verwende?
später soll auch der andere Timer hinzukommen, daher habe ich das Bit
schon gesetzt, auch wenn der Timer noch nicht läuft. Du hast Recht,
vielleicht spinnt die HiRes Extension, wenn einer der beiden Timer nicht
läuft.
Wenn ich zuhause bin, probiere ich nochmal, ob es geht, wenn ich den
Hires nur für den einen Timer einschalte.
Die Appnote habe ich gelesen, nur die macht einfach genau das selbe wie
ich (abgesehen von dem Fehler, den du beschrieben hast)
Ich frage mich allerdings, wie die Ports betrieben werden. Die haben ja
auch irgendeine Art von Taktung. Wenn die Ports nur mit 32MHz geupdatet
werden, dann würde mein Ergebnis nicht verwundern. Aber dann wäre eben
auch die ganze HiRes Extension sinnlos.
Das Timer-Bit sollte egal sein, aber wenns nicht funktioniert, würde ich
es erstmal auschalten.
Ich habe Hires(+Awex) bereits verwendet und es funktioniert, wie es soll
(auch nachgemessen) (mit xmegaA4U)
sonst:
-Clockeinstellungen Ok?
-xmega A3 oder A3U?, die U-Serie hat weniger Bugs
Es ist die A3 serie. Ich schau mal auf der Atmel Seite, obs irgendwo
known bugs gibt. EDIT: Es gibt ja einen haufen Errata, aber leider steht
nix zum HiRes drin. Die A3U serie scheint ja weitestgehend Bugfrei zu
sein.
Hier ist der Code, mit dem ich die Clocks initialisiere. Ich finde
keinen Fehler darin.
1
staticvoidclock_init(void)
2
{
3
// configure external 16MHz crystal, low power mode on 32kHz external crystal,
Hi Thomas,
ich habe jetzt den HiRes nur für TC0 aktiviert und das Problem bleibt
bestehen.
Interessanterweise erhalte ich neuerdings ziemlich starken Jitter, der
aber besteht, egal ob ich HiRes für einen oder für beide Timer
einschalte. Anbei ein Foto.
Evtl. muss ich mich mal direkt an Atmel wenden? Die Appnote macht, wie
gesagt, das selbe wie ich. Vielleicht sollte ich das mal
sicherheitshalber kompillieren und schauen, was passiert...
Ich habe gerade nochmal das Beispiel aus der Appnote getestet. Es
funktionierte auf Anhieb. Allerdings lief die CPU da auf 8MHz und die
Timer auf 32MHz. Also habe ich meinen Clock-initialisierungs Code
eingefügt. Es ging immer noch.
Jetzt habe ich allerding etwas eigenartiges bemerkt und würde mich
freuen, wenn jemand es nachprüfen kann. Folgenden Code verwende ich:
// Prescaler C: factor 1/2 => cpu and periphery runs at 32MHz
62
CLK.PSCTRL=CLK_PSADIV_1_gc|CLK_PSBCDIV_2_2_gc;
63
64
// protect during clock source change
65
CCP=CCP_IOREG_gc;
66
// switch clock source to PLL
67
CLK.CTRL=CLK_SCLKSEL_PLL_gc;
68
69
// Turn off int. RC osc.
70
OSC.CTRL&=~OSC_RC2MEN_bm;
71
}
Nun setzt man in der main() am Ende verschiedene Werte ein und
beobachtet die zwei Ausgänge am Oszi.
Variante 1 (siehe Bild 1)
1
TCD0.CCABUF=4;// hier verschiedene Werte einsetzen!!
2
TCD0.CCBBUF=0;
Alles okay.
Variante 2 (siehe Bild 2)
1
TCD0.CCABUF=5;// hier verschiedene Werte einsetzen!!
2
TCD0.CCBBUF=0;
Alles okay. HiRes offensichtlich aktiv.
Variante 3 (siehe Bild 3)
1
TCD0.CCABUF=4;// hier verschiedene Werte einsetzen!!
2
TCD0.CCBBUF=4;
Alles okay.
Variante 4 (siehe Bild 4)
1
TCD0.CCABUF=5;// hier verschiedene Werte einsetzen!!
2
TCD0.CCBBUF=5;
Alles okay. HiRes offensichtlich aktiv.
Variante 5 (siehe Bild 5)
1
TCD0.CCABUF=4;// hier verschiedene Werte einsetzen!!
2
TCD0.CCBBUF=5;
MOMENT! Was ist mit Channel 2 passiert? Der ist auch auf 4 runter
gegangen!
Das riecht mir doch stark nach einen Bug.
Kann das jemand bestätigen?
PS: Das erklärt auch den (verdächtig in 4er Schritten quantisierten)
Jitter in meiner vorherigen Messung: Ich habe Channel 2 gemessen (TCCB).
Auf TCCA lief parallel eine Rampenfunktion, welche in jedem zyklus den
Wert in Compare register um eins erhöht hat und damit alle Werte
durch-scannt. Immer, wenn Channel 1 also die Werte 4,5,6,7 angenommen
hat, ging channel 2 mit. Daher der Jitter. War das verständlich erklärt?
Ich hab deinen Code mal laufen lassen.
xmegaA3, PORTF
Ich würde mal sagen, das funktioniert.
Edit: Du hast auf jeden Fall ein Problem mit der Signalqualität (anderer
Code?, Port kaputt?) (vllt. liegt 'bessere' Darstellung am Oszi)
Danke dir für's Ausprobieren. Schon mal gut zu wissen, dass es
prinzipiell funktioniert.
Ich werde nochmal den selben Code für andere Ports probieren. Vielleicht
gehts ja aus irgendeinem komischen Grund nur bei PortD nicht.
Hmm. Problem mit der Signalqualität? Für mich sieht das eher nach einem
hochauflösenderen Oszi aus. Meins kann 100MHz (analoge Bandbreite). Wie
siehts bei deinem aus? Vielleicht bekommen wir deswegen andere
Signalverläufe. Die Flankensteilheit spricht jedenfalls dafür.
> Hmm. Problem mit der Signalqualität? Für mich sieht das eher nach einem> hochauflösenderen Oszi aus. Meins kann 100MHz (analoge Bandbreite).
Das wird wohl stimmen.
> Wie> siehts bei deinem aus?
Abtastrate entspricht Hires-Frequenz, sodass man immerhin die
Unterschiede noch sehen kann.
Ich habe noch ein wenig weiter untersucht.
Meines Wissens funktioniert die HiRes Extension so: Der Timer schaltet
die Pins wie bei einer normalen PWM und zählt dabei in 4er Schritten
aufwärts. Die HiRes Extension springt dann ein, wenn der Timer den Pin
low schalten würde und verlängert die High-Phase noch ein wenig, sodass
die feine Abstufung entsteht. Bei einem CC-Wert von z.B. 9 würde der
Timer selbst bei Schritt 8 den Pin abschalten, die HiRes Extension hält
den Pin dann aber noch einen weiteren Schritt high.
Soweit ich das überblicke, scheint die grobe Einstellung durch den Timer
selbst zu funktionieren. Die feine Abstufung in 4er Schritten, die die
HiRes Extension vornimmt, scheint aber für alle Kanäle synchronisiert zu
sein - was ja nicht dem Sinn der Sache entspricht.
Grundsätzlich bedeutet das, dass Channel B die gleiche Anzahl an feinen
HiRes Stufen erhält, wie Channel A.
Hier nochmal einige Beispiele:
1 - HiRes-Schritte von Chan B zu Chan A synchronisiert
14
2 - gleiche Anzahl an HiRes Schritten, daher kein Problem
15
3 - gleiche Anzahl an HiRes Schritten, daher kein Problem
16
4,5 - HiRes-Schritte von Chan B zu Chan A synchronisiert
Das Problem tritt bei mir an mehreren Ports auf.
EDIT: Bei dir auf einem A3 läuft es. Ich verwende den A3U. Vielleicht
könnte nochmal jemand mit einem A3U meinen Code von oben testen?
EDIT2: Haha, das quality inquiry Formular auf atmel.com ist offline mit
einen 404 error. Prima.
Mir ist gerade aufgefallen, dass ich im makefile die ganze Zeit den
atxmega128a3 angegeben habe, aber den atxmega128a3_U_ verwende. Jetzt
habe ich nach langem Suchen endlich Pakete der avr-libc gefunden, die
den atxmega128a3_U_ beinhalten. Allerdings sagt dann avrdude, er kenne
kein Bauteil mit diesem Namen. Ich verwende eine veraltete Version von
avrdude (5.11) weil alle neueren Versionen meinen LUFA-basierten
PDI-Programmer nicht mehr unterstützen. MANN. deadlock.
Bevor ich jetzt einen neuen Programmer kaufe, damit ich eine neuere
Version von avrdude verwenden kann, wollte ich erstmal sichergehen, ob
es überhaupt einen Unterschied macht, ob ich für die U version übersetze
oder für die nicht-U version.
Die includefiles (iox128a3.h bzw. iox128a3u.h) scheinen jedenfalls kaum
Unterschiede zu haben.
PS: habe jetzt die datei /etc/avrdude.conf manuell editiert und dem
avrdude die U version beigebracht. Die Device ID ist bei beiden gleich,
also musste einfach nur der Absatz des 128A3 kopiert werden. Jetzt
konnte ich meine Firmware endlich für den 128a3_u_ übersetzen und auf
den chip brennen. Es hat sich aber an meinem problem dadurch nichts
geändert.
Benutzt du die aktuelle Atmel-Toolchain? (die Atmel Studio benutzt)
Falls nicht, würde ich das damit noch mal testen. Optimierung -Os oder
-O1.
Wenn man sich sicher ist, es ist ein Device-Bug, ist es dann dann oft
doch "nur" ein Compilerbug.
Ich habe hier gerade den AtXmega128a1u verlötet und die HiRes-Extension
funktioniert anstandslos. Es scheint also ein spezifisches Problem des
xmega128a3u zu sein.
@Johannes: vielen Dank für die Erklärung mit dem Rest, den die HIRES
übernimmt.
Ich habe den ATXMega32A4U und beobachte das gleiche Problem: die
HIRES-Extension funktioniert nur auf Kanal A. Ich benutze Kanal A und
Kanal B des Timers TC0 für eine H-Brücke, wobei Kanal A die Linke Hälfte
(positive Welle) und Kanal B die rechte Hälfte (negative Welle)
übernehmen (jeweils immer nur ein Kanal an).
Folgender einfacher code (wird alle Paar ms aufgerufen):
1
if(vset<vact){
2
if(TCC0_CCB){
3
TCC0_CCBBUF--;
4
}else{
5
if(TCC0_CCA<MAX_VREG_TERM)TCC0_CCABUF++;
6
}
7
}elseif(vset>vact){
8
if(TCC0_CCA){
9
TCC0_CCABUF--;
10
}else{
11
if(TCC0_CCB<MAX_VREG_TERM){
12
TCC0_CCBBUF++;
13
}
14
}
15
}
Auf dem Scope ist die Linke Welle glatt und geschmeidig und die rechte
gestuft.
Dank deiner Erklärung habe ich für meine Anwendung einen Workaround
gebastelt: ich schreibe in Kanal A die unteren zwei Bits des Kanals B,
wenn Kanal B benutzt wird (dann ist in meinem Fall Kanal A ungenutzt und
eh immer 0).