Forum: Mikrocontroller und Digitale Elektronik AVR128DB48 - TCB 32Bit Counter


von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo,

hat schon jemand den kaskadierten 32Bit Timer ausprobiert und zum laufen 
gebracht? Bei mir zählt der MSB entweder gar nicht oder er läuft durch. 
Es wird nichts ins CCMP kopiert. Eigentlich soll TCB1 übers Eventsystem 
nur die Overflows von TCB0 zählen.

Was gar nicht funktioniert ist, wenn ich LSB (TCB0) statt in TCB0.CTRLB 
= TCB_CNTMODE_PW_gc in TCB_CNTMODE_CAPT_gc konfiguriere, laut Manual 
wäre das zwar richtig, aber dann zählt gar nichts mehr. Laut meiner 
Logik muss TCB0 in TCB_CNTMODE_PW_gc konfiguriert sein, ansonsten misst 
der nicht die gewünschte Pulsweite.

Ich frage mich auch wofür die CASCADE Einstellung gut ist, wenn man 
übers Eventsystem den Timer sagt das er die Overflows von TCB0 zählen 
soll, er bleibt ja ein 16Bit Zähler.

Der Interrupt von TCB0 reagiert immer auf die fallende Flanke vom Puls.
Der Interrupt von TCB1 reagiert immer auf die steigende Flanke vom Puls.

Laut meiner Logik müßten beide auf die fallende Flanke reagieren, weil 
dann übers Eventsystem der Capture Interrupt ausgelöst wird und beide 
Timer ihren Zählerstand in ihr CCMP Register kopieren. Beim TCB1 klappt 
das nicht.

Ich werde aus der Beschreibung im Manual nicht schlau.
Könnte bitte jemand Hinweise geben?
Irgendwas muss in der Timer- und/oder Eventkonfiguration falsch sein.
1
/* 
2
  Arduino IDE 1.8.13
3
  AVR128DB48 Curiosity Nano Board
4
  https://github.com/SpenceKonde/DxCore
5
  32Bit Counter
6
  Takteingang Pin PA4
7
  Interruptmesspin für Oszi PB3 und PC3
8
*/
9
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
#include <util/atomic.h>
13
14
volatile unsigned long countTimerTCB0;
15
volatile unsigned long countTimerTCB1;
16
volatile unsigned long countTimerCCMP_LSB;
17
volatile unsigned long countTimerCCMP_MSB;
18
volatile unsigned long countTimerTotal;
19
bool finishTCB0 = false;
20
bool finishTCB1 = false;
21
22
const byte pinLedTCB0Int = 11;    // PB3 onboardLed
23
const byte pinLedTCB1Int = 17;    // PC3
24
25
void setup (void)
26
{
27
  Serial1.begin(115200);        // Package Pin 10/11 bzw. PC0/PC1, Tx/Rx
28
  Serial1.println("\nSTART");
29
  initPins();
30
  initEventSystem();
31
  initTCB();
32
}
33
34
void loop (void)
35
{
36
  if (finishTCB0 & finishTCB1)
37
  {
38
    Serial1.print("TCB0 "); Serial1.println(countTimerTCB0);
39
    Serial1.print("TCB1 "); Serial1.println(countTimerTCB1);
40
    Serial1.print("LSB  "); Serial1.println(countTimerCCMP_LSB);
41
    Serial1.print("MSB  "); Serial1.println(countTimerCCMP_MSB);
42
    countTimerTotal = (unsigned long) (countTimerCCMP_MSB << 16) | countTimerCCMP_LSB;
43
    Serial1.print("Total "); Serial1.println(countTimerTotal);
44
    Serial1.print(62.5 * countTimerTotal / 1000000UL); Serial1.print(" ms");
45
    Serial1.println();
46
    Serial1.flush();       // warten bis serieller Buffer geleert ist
47
    finishTCB0 = false;
48
    finishTCB1 = false;
49
  }
50
}
51
52
void initPins (void)
53
{
54
  pinMode(pinLedTCB0Int, OUTPUT);
55
  pinMode(pinLedTCB1Int, OUTPUT);
56
}
57
58
void initEventSystem (void)
59
{
60
  EVSYS.CHANNEL0 = EVSYS_CHANNEL0_PORTA_PIN4_gc;    // set Pin PA4 as input event
61
  EVSYS.USERTCB0CAPT = EVSYS_USER_CHANNEL0_gc;      // Connect user to event channel 0
62
  EVSYS.USERTCB1CAPT = EVSYS_USER_CHANNEL0_gc;      // 
63
64
  EVSYS.CHANNEL1 = EVSYS_CHANNEL1_TCB0_OVF_gc;      //
65
  EVSYS.USERTCB1COUNT = EVSYS_USER_CHANNEL1_gc;
66
}
67
68
void initTCB (void)
69
{
70
  // *** LSB *** //
71
  TCB0.CTRLA = TCB_CLKSEL_DIV1_gc;                  // CLK_PER divider
72
  TCB0.CTRLB = TCB_CNTMODE_PW_gc;                   // Capture Mode
73
  TCB0.EVCTRL = TCB_CAPTEI_bm;                      // Enable Event Input and Event Edge
74
  TCB0.INTCTRL = TCB_CAPT_bm | TCB_OVF_bm;          // Enable Capture interrupt
75
76
  // *** MSB *** //
77
  TCB1.CTRLA = TCB_CASCADE_bm | TCB_CLKSEL_EVENT_gc;  // 32Bit and select Event
78
  TCB1.CTRLB = TCB_CNTMODE_CAPT_gc;                 // Capture Event
79
  TCB1.EVCTRL = TCB_CAPTEI_bm;                      // Enable Event Input and Event Edge
80
  TCB1.INTCTRL = TCB_CAPT_bm;                       // Enable Capture interrupt
81
82
  // beide einschalten
83
  TCB0.CTRLA = TCB0.CTRLA | TCB_ENABLE_bm;          // Enable TCB0
84
  TCB1.CTRLA = TCB1.CTRLA | TCB_ENABLE_bm;          // Enable TCB1
85
}
86
87
ISR(TCB0_INT_vect)
88
{
89
  if (TCB0.INTFLAGS & TCB_CAPT_bm)
90
  {
91
    countTimerTCB0 = TCB0.CNT;              // Zählerstand sichern
92
    countTimerCCMP_LSB = TCB0.CCMP;         // Zählerstand sichern
93
    finishTCB0 = true;
94
    VPORTB.IN = VPORTB.IN | 0x08;           // toggle PB3
95
    TCB0.INTFLAGS = TCB_CAPT_bm;
96
  }
97
98
  if (TCB0.INTFLAGS & TCB_OVF_bm)
99
  {
100
    TCB0.INTFLAGS = TCB_OVF_bm;             // Clear the interrupt flag
101
  }
102
}
103
104
ISR(TCB1_INT_vect)
105
{
106
  countTimerTCB1 = TCB1.CNT;                // Zählerstand sichern
107
  countTimerCCMP_MSB = TCB1.CCMP;           // Zählerstand sichern
108
  finishTCB1 = true;
109
  VPORTC.IN = VPORTC.IN | 0x08;             // toggle PC3
110
  TCB1.INTFLAGS = TCB_CAPT_bm;              // Clear the interrupt flag
111
}

: Bearbeitet durch User
von S. Landolt (Gast)


Angehängte Dateien:

Lesenswert?

Für den Augenblick ist mir das alles zu umfangreich, vielleicht setze 
ich mich später in Ruhe dran; vorab nur: ich hatte das mal für den 
AVR128DA28 gemacht, die Initialisierung finden Sie in der Anlage 
(Assembler, natürlich, können Sie ja aber lesen&verstehen), so ad hoc 
sehe ich keinen Unterschied zu Ihrer. Unklar ist mir, weshalb Sie zwei 
ISR verwenden, ich habe nur eine, in welcher die 2*2 Bytes ausgelesen 
werden.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich hatte am Anfang auch nur eine ISR vom TCB0. Weil das zu keinem 
Ergebnis führte, habe ich eine ISR für TCB1 eingebaut, mit dem Ziel das 
beim Capture Event der Zählerstand zum richtigen Zeitpunkt ins CCMP 
kopiert und ausgelesen werden kann. Ich schau mir deinen Code an. Danke 
vorab. Wird eine Weile dauern.

Edit:
dein Code sieht sehr übersichtlich aus, könnte doch schneller gehen ...

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Tja, auch der zweite Blick bringt keine Erleuchtung, außer vielleicht, 
dass ich nur eine einzige Interruptquelle habe, nämlich TCB0-Capture, 
Sie hingegen sogar drei.
  Ich werde nachher mal mein Programm auf den AVR128DB48 bringen, das 
kann aber, nun bei mir, eine Weile dauern.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

das drängelt nicht. Das Problem wird gefunden, da bin ich mir sicher, 
auch wenn es am Ende an den Interrupts liegt.  :-)

von S. Landolt (Gast)


Lesenswert?

Ging schneller als gedacht, läuft unverändert auch auf dem AVR128DB48.
> Das Problem wird gefunden
Genau, "kriegen wir hin, kriegen wir alles hin".

von S. Landolt (Gast)


Lesenswert?

Wo steht in Ihrem Programm eigentlich das Pendant zu sei?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

> Wo steht in Ihrem Programm eigentlich das Pendant zu sei?
Das ist bei Arduino standardmäßig im Hintergrund eingeschalten. Da muss 
ich immer daran denken wenn ich in AS programmiere, wie letztens.

Bei mir läuft es leider noch nicht. Der TCB0 Interrupt kommt jetzt bei 
steigender Messflanke statt bei fallender. Und beide Timer laufen durch, 
es wird kein Zählerstand ins CCMP kopiert. Habe mal den Code aufgeräumt.
Habe auch schon alle Timer Register vorher genullt, falls Arduino 
Timervoreinstellungen dazwischen funken, wobei laut Beschreibung Timer 
TCB0 und TCB 1 sowieso frei sein sollten. Falls dir hier nichts 
auffällt, dann muss ich alles erst ins Atmel Studio "schieben" ohne 
Arduino Komfortzone.

(Eingangspin auf PA7 geändert)
1
/*
2
  Arduino IDE 1.8.13
3
  AVR128DB48 Curiosity Nano Board
4
  https://github.com/SpenceKonde/DxCore
5
  32Bit Counter
6
  Takteingang Pin PA7
7
  Interruptmesspin für Oszi PB3
8
*/
9
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
#include <util/atomic.h>
13
14
volatile unsigned long countTimerTCB0;
15
volatile unsigned long countTimerTCB1;
16
volatile unsigned long countTimerCCMP_LSB;
17
volatile unsigned long countTimerCCMP_MSB;
18
volatile unsigned long countTimerTotal;
19
bool finishTCB0 = false;
20
21
const byte pinLedTCB0Int = 11;    // PB3 onboardLed
22
23
void setup (void)
24
{
25
  Serial1.begin(115200);        // Package Pin 10/11 bzw. PC0/PC1, Tx/Rx
26
  Serial1.println("\nSTART");
27
  initPins();
28
  initEventSystem();
29
  initTCB();
30
}
31
32
void loop (void)
33
{
34
  if (finishTCB0)
35
  {
36
    Serial1.print("TCB0 "); Serial1.println(countTimerTCB0);
37
    Serial1.print("TCB1 "); Serial1.println(countTimerTCB1);
38
    Serial1.print("LSB  "); Serial1.println(countTimerCCMP_LSB);
39
    Serial1.print("MSB  "); Serial1.println(countTimerCCMP_MSB);
40
    countTimerTotal = (unsigned long) (countTimerCCMP_MSB << 16) | countTimerCCMP_LSB;
41
    Serial1.print("Total "); Serial1.println(countTimerTotal);
42
    Serial1.print(62.5 * countTimerTotal / 1000000UL); Serial1.print(" ms");
43
    Serial1.println();
44
    Serial1.flush();       // warten bis serieller Buffer geleert ist
45
    finishTCB0 = false;
46
  }
47
}
48
49
void initPins (void)
50
{
51
  pinMode(pinLedTCB0Int, OUTPUT);
52
}
53
54
void initEventSystem (void)
55
{
56
  EVSYS.CHANNEL0 = EVSYS_CHANNEL0_PORTA_PIN7_gc;  // 0x47, set Pin PA7 as input event
57
  EVSYS.USERTCB0CAPT = 0x01;                      // Connect user to event channel 0
58
  EVSYS.USERTCB1CAPT = 0x01;                      // Connect user to event channel 0
59
  EVSYS.CHANNEL1 = 0xA1;                          // TCB0 OVF Counter Overflow to Channel 1
60
  EVSYS.USERTCB1COUNT = 0x02;                     // Connect user to event channel 1
61
}
62
63
void initTCB (void)
64
{  
65
  TCB0.EVCTRL = 0b00000001;      // Bit 0 – CAPTEI Capture Event Input Enable
66
  TCB1.EVCTRL = 0b00000001;      // Bit 0 – CAPTEI Capture Event Input Enable
67
68
  TCB0.CTRLA = 0b00000001;       // Bits 3:1 – CLKSEL[2:0]: 0x0 DIV1 CLK_PER
69
  TCB0.CTRLB = 0x02;             // CAPT Input Capture on Event mode
70
  TCB1.CTRLA = 0b00101111;       // Cascade; Bits 3:1 – CLKSEL[2:0]: 0x07 EVENT Positive edge on event input
71
  TCB1.CTRLB = 0x02;             // CAPT Input Capture on Event mode
72
73
  TCB0.INTCTRL = 0b00000001;     // Bit 0 – CAPT Capture Interrupt Enable
74
}
75
76
ISR(TCB0_INT_vect)
77
{
78
  countTimerTCB0 = TCB0.CNT;              // Zählerstand sichern
79
  countTimerCCMP_LSB = TCB0.CCMP;         // Zählerstand sichern
80
  countTimerTCB1 = TCB1.CNT;              // Zählerstand sichern
81
  countTimerCCMP_MSB = TCB1.CCMP;         // Zählerstand sichern
82
  finishTCB0 = true;
83
  VPORTB.IN = VPORTB.IN | 0x08;           // toggle PB3
84
  TCB0.INTFLAGS = TCB_CAPT_bm;
85
}

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Ich sehe keinen Fehler, es scheint meinem Programm zu entsprechen; ich 
kann nur vorschlagen, erstmal auf die Arduino-Umgebung zu verzichten 
(wusste gar nicht, dass die schon mit der AVR-Dx-Serie arbeiten kann).

von Veit D. (devil-elec)


Lesenswert?

Hallo,

Danke fürs prüfen. Dann mach ich das erstmal in Atmel Studio startklar.

In der Arduino IDE läuft das nur, weil User 'SpenceKonde' so fleißig war 
und eine Boarderweiterung geschrieben hat. Genauso wie MCUdude für die 
megaAVR0 Serie. Ich spreche an der Stelle beiden meinen herzlichsten 
Dank aus.
https://github.com/MCUdude/MegaCoreX
https://github.com/SpenceKonde/DxCore
Sind ähnlich in der Handhabung, aber doch ein klein wenig verschieden.
Bei SpenceKonde kann man noch nicht über USB wie gewohnt flashen. Da bin 
ich den Weg übers .hex File per Drag and Drop kopieren aufs Board 
Laufwerk gegangen.

Ich melde mich wieder ...

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Könnten Sie mal ein paar Zeilen der Ausgabe zeigen?
  Also ich versteh's nicht, wenn die ISR mit Capture Interrupt 
angesprungen wird, dann muss doch etwas in den ..CCMP.. stehen.

von S. Landolt (Gast)


Lesenswert?

Und eine wohl typische Frage eines Assembler-Programmierers: weshalb 
steht überall volatile, nur nicht bei finishTCB0?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

volatile, ja stimmt finishTCB0 muss auch volatile sein. Mit Daten muss 
ich dich vertrösten, war gerade am Tisch "aufräumen" und habe wohl mein 
Board zerstört. Da muss ich dich auf morgen verdrösten. Leider. Ärgere 
mich selbst, gerade jetzt wo es spannend wird. Ich kann das Board zwar 
mittlerweile wieder flashen, aber es tut sich nichts mehr.

von S. Landolt (Gast)


Lesenswert?

Die drei anderen schon verkauft? - Prima.

Wie lässt doch Spoerl den Pfeiffer imitieren: "Ech ben ein alter Mann 
und gähe leber fröh ins Bette". Also Gute Nacht.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

noch sind keine verkauft zum Glück. :-)  Wären die verkauft hätte ich 
noch 2 in Reserve gehabt. Morgen nochmal ganz in Ruhe von vorn. Für 
heute ist erstmal genug.  :-)   Danke soweit fürs mitmachen.

von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo,

kurze Rückmeldung, habs mir nicht nehmen lassen heute früh nochmal zu 
testen. Kurzfassung ist, Pin PA7 habe ich wahrscheinlich irgendwie 
abgeschossen. Teste ich irgendwann nochmal genauer. Nehme ich wieder PA4 
funktioniert erstmal technisch alles. Soweit so gut.

Einen Unterschied gibts zwischen unseren Timereinstellungen. Mein TCB0 
steht auf CTRLB Countermode Pulsweitenmessung. Aber das wusstest du ja 
bestimmt schon.

Anbei noch die Ausgaben von hterm mit meinen und deinen Einstellungen. 
Einmal bleibt TCB0/LSB konstant und beim anderen nicht. Konstant wäre 
ok. Das begründe ich erstmal mit der CTRLB Einstellung. TCB1/MSB zählt 
immer munter hoch, bekommt demnach kein Capture Event mitgeteilt, laut 
meiner Überlegung.

Heute Abend mach ich mich an die Atmel Studio Umsetzung ran.

von S. Landolt (Gast)


Lesenswert?

> zählt immer munter hoch
Logisch, was sonst bei Capture?

> Konstant wäre ok
Dafür müssen Sie etwas tun, nämlich die Differenz der Capture-Werte 
zwischen zwei Ereignissen berechnen.

Mir scheint, da liegt ein grundlegendes Missverständnis vor; vermutlich 
eine Verwechslung mit dem Modus 'Pulsweitenmessung'.

von Veit D. (devil-elec)



Lesenswert?

Hallo,

eigentlich möchte ich nichts extra berechnen, weil der Pulsweiten 
Messmodus das alles selbst erledigt. Er reagiert selbstständig auf die 
Flanke (je nach Edge Einstellung) und kopiert den Zählerstand in sein 
CCMP Register. Bei der nächster Start-Flanke wird der Timercounter 
genullt und wieder gezählt. So funktionierte das schon einwandfrei mit 
einem TCB.

32Bit Counter:
Dann kam mir noch eine Idee, weil der TCB1 irgendwie falsch reagiert. 
Kurzerhand TCB1 auch in den "Input Capture Pulse-Width Measurement mode" 
gesetzt und ... funktioniert.   :-)

So eine ganz schlüssige Erklärung von hinten aufgezäunt habe ich noch 
nicht. Ich weiß laut Manual nur das ...

EVCTRL:
Input Capture on Event mode: löst Interrupt an rissing edge aus
Input Capture Pulse-Width Measurement mode: nullt Counter bei rissing 
edge und löst Interrupt bei falling edge aus oder umgekehrt je nach Edge 
Einstellung

INTFLAGS:
Im CAPT Interrupt wird bei beiden Modi der Zählerstand ins CCMP kopiert.

Im Nachgang betrachtet hat er schon immer die Zählerstände ins CCMP 
kopiert. Das durchlaufen des Zählers hatte mich irretiert.

Jetzt bleibt nur die Frage offen, warum TCB1 jetzt richtig zählt und 
nicht intern die Pulsweite vom OVF Signal vermisst? Hängt scheinbar mit 
dem Event System zusammen. Auf der einen Seite freut es mich das es 
funktioniert. Auf der anderen Seite fehlt mir noch die endgültige Logik 
dafür warum es so funktioniert wie es funktioniert.

1Hz, 3/4 DutyCycle.
1
TCB0 7410  TCB1 183
2
LSB  7392  MSB  183
3
Total 12000480
4
750.03 ms
5
TCB0 7412  TCB1 183
6
LSB  7392  MSB  183
7
Total 12000480
8
750.03 ms
9
TCB0 7411  TCB1 183
10
LSB  7392  MSB  183
11
Total 12000480
12
750.03 ms
13
TCB0 7410  TCB1 183
14
LSB  7392  MSB  183
15
Total 12000480
16
750.03 ms
17
TCB0 7410  TCB1 183
18
LSB  7392  MSB  183
19
Total 12000480
20
750.03 ms

von S. Landolt (Gast)


Lesenswert?

> der Pulsweiten Messmodus das alles selbst erledigt
Schon, aber nicht mit 32 bit.

> und ... funktioniert.   :-)
"With a few stupid exceptions, of course" - extrem selten, aber 
trotzdem; aus dem Datenblatt:
24.5.1 Control A
Bit 5 – CASCADE Cascade Two Timer/Counters ...
... delayed by one peripheral clock cycle. This compensates ...

von S. Landolt (Gast)


Lesenswert?

PS:
Zumindest kann ich nicht aus dem Datenblatt herauslesen, dass dieses 
CASCADE auch im PW-Modus funktioniert.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

es wäre schon blöd wenn der 32Bit Counter nur im CAPT Mode funktionieren 
würde, zumindestens offiziell.  Habe ich ein Secret gefunden? :-)
Habe mal spassenshalber TCB0 nicht enabled. Der Interrupt von TCB1 
reagiert immer noch. Aber alle Counterwerte bleiben 0. TCB1 reagiert 
demnach auf den Eingangstakt bedingt durch den PW Mode, kann aber keine 
OVF Events zählen, weil vom TCB0 nichts kommt. Wäre erstmal logisch 
gesehen korrekt.

Würde mir das derzeit so erklären, dass der CountMode (EVCTRL) nur den 
Zähler beeinflusst, wann er startet/stoppt und wann er genullt wird. Was 
er zählt wird von Clock Select vorgegeben. Das ist auf Event eingestellt 
und reagiert laut Beschreibung nur auf die steigende Flanke. Das ist 
mittels Event System mit dem TCB0 Overflow Ausgang verbunden. Vielleicht 
klappt das dadurch, weil er hier nicht auf die fallende Flanke reagiert. 
Am Ende sagt das Capture Eventsystem zusammen mit dem Interrupts beiden 
Timern, dass bei abgeschlossener Pulsweitenerkennung jetzt die 
Zählerstände kopiert und die Zähler bei der nächsten Flanke genullt 
werden.
Sollte an einer plausiblen Erklärung zumindestens nah dran sein.  :-)

von S. Landolt (Gast)


Lesenswert?

> es wäre schon blöd ...
Dem stimme ich zu; und nach erneutem Durchlesen der Datenblattstellen 
neige ich auch zu der Ansicht, dass es in den 'Measurement modes' 
funktionieren sollte.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

das stimmt mich zuversichtlich. Danke soweit fürs mitmachen und 
mitdenken usw. du weißt schon.  :-)

von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo,

32Bit Counter - Pulsweite messen - die Zweite.  :-)

Nachdem die Kaskadierung erfolgreich abgeschlossen war wollte ich es 
ohne Kaskadierung wissen. Also Overflows zählen und ggf. Ergebnis 
korrigieren. Sprich das hier anwenden 
Beitrag "Timer Overflow Counter - Wie richtig berücksichtigen?" Warum überhaupt? Damit 
man alle TCBn Timer frei hat bzw. hätte.

Problem dabei war, dass im Interrupt der eigentliche Timercounter 
ungleich dem Capture Count ist. Denn der Timer läuft bis zur nächsten zu 
vermessenden Signal-Startflanke weiter. Erst dabei wird er genullt. 
Zudem gibt es keine getrennten Interrupt Vectoren. Man muss also den 
ausgelösten Timer Interrupt ermitteln. Ob das jetzt ein Vorteil oder 
Nachteil ist wage ich mich nicht zu beurteilen. Beim Overflow filtern 
war ich gezwungen andere Wege zu gehen.

Ich musste vom Signaleingang zusätzlich einen Interrupt anlegen um den 
Overflow Zähler sicher zu nullen und einen noch alten anstehenden OVF zu 
löschen. Damit die nächste Zählung stimmt. Danach galt es die Overflow 
Addition im Timer Interrupt zu unterdrücken, wenn ein Capture Interrupt 
aktiv und zeitgleich der ausgelesene Capture Zähler im Endbereich liegt. 
Also kurz vorm eigenen Überlauf steht.
Hat mich eine Woche Nerven "gekostet".  :-)
Bis dahin hatte ich, wenn die Capture Zählung auf Überlauf Kippe stand, 
alles dabei. Von Ergebnis 0 bis 131071, obwohl es entweder 65535/65536 
sein muss. 1 Takt Restungenauigkeit.

Taktquelle/Signalquelle ist ein ATmega328PB mit 16MHz Quarz, der 
glücklicherweise einen Hauch langsamer läuft, sodass ich mit einem CTC 
Timer mit Prescaler 1 und im Bereich 65528 - 65531 meinen OVF Kipp-Punkt 
provozierbar testen konnte. Wer Verbesserungen am Code sieht ... immer 
raus damit. Ich weiß nicht ob man die Bedingung für die Overflow 
Addition noch besser schreiben kann. Wenn es jemand testen könnte wäre 
ich auch dankbar.

Edit: habs als Datei angehangen statt Text.

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich hatte noch bei Microchip nachgefragt bzw. hingewiesen. Das dauerte 
etwas mit hin und her. Ich wollte wissen ob die 32Bit Counter 
Funktionalität im "Input Capture Pulse-Width Measurement Mode" Zufall 
ist oder nur vergessen wurde im Manual zu erwähnen. Das wurde dann ans 
internal Team weitergeleitet. Die ernüchternde Antwort lautet nun. Geht 
nicht. Der 32 Bit Counter funktioniert nur im “Input Capture on Event" 
Mode.
Hmmm, ich hatte extra meinen Code mitgeliefert damit die das prüfen und 
nachvollziehen können. Jetzt stehe ich wieder am Anfang und weiß immer 
noch nicht ob es zufällig im PW Mode funktioniert oder nur im Manual 
vergessen wurde. An Zufälle glaube ich jedoch weniger.  :-)  Ich denke 
das wird die Zeit zeigen. Oder jemand anders testet das bei sich in Ruhe 
wenn er Muse hat.

von S. Landolt (Gast)


Lesenswert?

Meine Vermutung ist, dass es daran liegt:
Beitrag "Re: AVR128DB48 - TCB 32Bit Counter"

Mittlerweile nutze ich diese Funktionalität auch, aber nur für eine 
fortlaufende Anzeige, und wenn da alle Schaltjahre mal eine Fehlanzeige 
auftritt, bemerke ich das gar nicht.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

das verlinkte guck ich mir ab morgen nochmal genauer an.

von S. Landolt (Gast)


Lesenswert?

Hallo Veit Devil,

es ist so, ich kann das Problem jetzt erzeugen: wenn die zu messende 
Pulsbreite im Bereich 0000FFFF und 00010000 liegt, treten Fehler auf, 
gemessen wird 0001FFFF oder auch 00000001.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

aha, interessant. Ich programmiere mir einen Testcode zusammen ...

von S. Landolt (Gast)


Lesenswert?

Als Generator (Assembler, sollte aber selbsterklärend sein):
1
putiw   TCA0_SINGLE_CMP0,32766              ; 32766 -> $0000FFFD, 32767 -> $0001FFFF, 32768 -> $00000001, 32769 -> $00010003
2
puti    TCA0_SINGLE_CTRLA,0b0_000_001_1     ; DIV2, ENABLE
3
puti    TCA0_SINGLE_CTRLB,0b0_0_0_1_0_001   ; CMP0EN: WO0, FRQ Frequency
4
sbi     VPORTA_DIR,0                        ; WO0

Den Ausgang hiervon (WO0 bzw. A0) mit Ihrem Messeingang verbinden; 
vorausgesetzt, Ihre TCBn laufen mit dem Systemtakt, sonst eben anpassen.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

den TCA zu nutzen war auch meine Idee, wegen Syncronität.  :-)
Es kam gestern noch etwas dazwischen und danach konnte ich das Problem 
nicht nachvollziehen. Seltsamerweise kann ich es heute mit verschiedenen 
TCA Takteinstellungen auch nicht nachvollziehen. Der 32Bit TCB misst 
exakt das was er soll. Ich lasse mir mit 1MBaud LSB, MSB und Total 
seriell ausgeben, mit 4ms Pause bremst die nichts aus, sodass ich jede 
Pulsmessung angezeigt bekomme. Ich werde nochmal einen externen Takt 
anklemmen der dann bedingt immer leicht pendelt, vielleicht sehe ich da 
etwas ...

von S. Landolt (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen, Veit Devil,

ich vermute, dass ein externer Takt nur sehr selten den Fall zeigt; 
arbeitet man nicht phasenstarr, wird es schwer, diesen einen Systemtakt 
zu erwischen, in dem das Event-System das Carry weitergibt.
  Im Anhang finden Sie einen größeren Ausschnitt meines Testprogramms, 
vielleicht stellen Sie Ihres auch vor. Ich weiß aber nicht, ob ich vor 
dem Nachmittag noch dazu komme, mir es auf Unterschiede hin 
durchzusehen.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

wie oft tritt der Messfehler bei dir auf? Jede Sekunde? Aller paar 
Sekunden?
Mit externen Takt habe ich genau die Messschwelle zwischen 65535 und 
65536 getroffen. Das Ergebnis pendelt sehr oft zwischen 65535 und 65536 
ohne Ausreißer. Das kann ich Minutenlang beobachten.

Ich muss dann auch nochmal weg. Den vom debuggen bereinigten Code zeige 
ich selbstverständlich.

Und mach dir keinen Kopf wegen Antwortzeiten. Alles gut. Das Forum ist 
schließlich kein Chat.  :-)

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

> wie oft tritt der Messfehler bei dir auf?
Permanent, so wie es im Kommentar zu TCA0_SINGLE_CMP0 steht.

von Veit D. (devil-elec)



Lesenswert?

Hallo,

okay. Ich glaube der Hauptunterschied zwischen unserem Code ist, dass 
ich den Interrupt beider Timer zum Zählerstand auslesen verwende. Wie 
stellst du fest das beide Timer einen zusammengehörigen neuen Wert 
haben? Ich habe nochmal mit 32767 und 32768 probiert. Alles stabil.

von S. Landolt (Gast)


Lesenswert?

Okay, ich hatte es eben schon vermutet, und Ihr Programm bestätigt es: 
der Unterschied ist das 'Input Capture Noise Cancellation Filter' im 
TCB0_EVCTRL; wenn ich das bei mir abschalte, sehe ich keine Fehler mehr.
  Ich bin aber nicht ganz sicher, ob damit das Problem vom Tisch ist.

von S. Landolt (Gast)


Lesenswert?

> Wie stellst du fest ...
Verstehe ich jetzt nicht - es gibt ein Capture-Event, und auf dieses 
frage ich TCB0_INTFLAGS ab, danach muss der komplette 32-bit-Wert 
verfügbar sein.
  Auf die Idee, zwei ISR dafür zu verwenden, kam ich gar nicht. Alles 
Weitere später.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

mit aktivierten Noise Filter kann ich den Messfehler nachvollziehen. Er 
ist dann auch immer vorhanden. Wegen dem TCB0_INTFLAGS, ja okay, 
funktioniert auch. Der Capture Event Input wirkt ja auf beide Timer. Ich 
habe da Netz und doppelten Boden.  :-)

Warum der Filter so eine seltsame Wirkung zeigt? Mal sehen ob man das 
aufklären kann.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich habs. Die 4 Takte Filter Verzögerung wird der Grund sein. Wenn man 
den Filter für beide Timer aktiviert, stimmt wieder alles.  :-)

von S. Landolt (Gast)


Lesenswert?

> Filter für beide Timer aktiviert ...
In der Tat, das hatte ich übersehen.
Dann scheint es wirklich so, als hätten Sie Recht, und es bleibt die 
Frage, weshalb Microchip eine gegenteilige Auskunft gibt.

Bleibt mir nur noch, Ihnen ein schönes Wochenende zu wünschen.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich habe daraufhin nochmal bei Microship nachgefragt was laut ihrer 
Meinung bzw. ihres Wissens das Problem ist wenn man einen anderen Modi 
verwendet. Welcher Fehler daraus resultieren würde. Bisher heißt es ja 
nur kurz "geht nicht". Ich werde berichten.

Wünsche ebenfalls schönes Wochenende.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich konnte es nicht lassen auch noch den Frequenz und 
Frequenz-Pulsweiten Modus zu testen. Du kennst die Antwort. 
Funktioniert.  :-)
Ich kann auch in der Theorie kein Problem erkennen. Man konfiguriert 
beide Timer mit gleichen Modus. Damit reagiert jeder Timer exakt gleich 
auf das Event. Demzufolge sichert jeder Timer seinen Zähler zum 
richtigen Zeitpunkt ins CCMP bzw. der CNT bleibt stehen. Was der MSB 
Timer eigentlich zählt kann ihm auch egal sein, der zählt das was man 
ihm übers Event System ankoppelt. Da kann gar nichts schiefen gehen. 
:-)  Bin gespannt was Microship antwortet.
Das als letzte Anmerkung zum Wochenende.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

habe eine positive Antwort erhalten.
1
"We have got confirmation from our design team. You are correct, the 32-bit Input Capture works for all 4 Input Capture modes. Thank you for bringing this to us and we shall update the datasheet accordingly to clarify in the future."

Hartnäckigkeit zahlt sich aus. :-)

von S. Landolt (Gast)


Lesenswert?

Glückwunsch, bzw: Congratulation!

"... there may be little you can do about it, but at least you can try. 
Squawk. Nag. Cajole. Remind. Phone. Write memos. Keep in mind that to 
get anything done in this world, you often must be willing to be a bit 
obnoxious."
Ediwn C. Bliss

von S. Landolt (Gast)


Lesenswert?

Pardon (noch kein Kaffee): 'Edwin' heißt der Mann mit Vornamen.

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.