Hallo,
ich will den Timer TCC0 vom ATSAME54P20A als Counter verwenden. Dabei
ist es mir wichtig, dass ich den Timer stoppen und wieder starten kann,
ohne dass der aktuelle Zählerstand zurückgesetzt wird. Laut
[Datenblatt](https://ww1.microchip.com/downloads/aemDocuments/documents/MCU32/ProductDocuments/DataSheets/SAM-D5x-E5x-Family-Data-Sheet-DS60001507.pdf)
kann man hierfür den ***Stop Command*** und den ***Re-Trigger
Command***. Im Kapitel 49.6.2.4 steht folgendes zum Stop Command:
>When a stop is detected while the counter is running, the counter will maintain
its current value.
Und folgendes zum Re-Trigger Command:
>If the re-trigger command is detected when the counter is stopped, the counter
will resume counting operation from the value in COUNT.
Theoretisch sollte also der Zählerstand nicht zurückgesetzt werden, wenn
man den Timer vom laufenden Zustand in den gestoppten oder umgekehrt
versetzt. Dieses scheint in der Praxis aber nicht so zu sein. Wenn der
Timer TCC0 läuf und ein C/C++-Programm folgende Codezeilen durchläuft,
wird der Zählerstand zurückgesetzt. Das Register TCC0.COUNT steht dann
auf 0:
1 | TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_STOP_Val;
|
2 | while (TCC0->SYNCBUSY.bit.CTRLB || !TCC0->STATUS.bit.STOP);
|
3 |
|
4 | TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_RETRIGGER_Val;
|
5 | while (TCC0->SYNCBUSY.bit.CTRLB || TCC0->STATUS.bit.STOP);
|
6 |
|
7 | TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;
|
8 | while (TCC0->SYNCBUSY.bit.CTRLB);
|
Aber der Zählerstand wird auch nur zurückgesetzt, wenn diese Codezeilen
im Release durchlaufen werden oder im Debug-Modus im Run-Betrieb
durchlaufen werden. Geht man im Debug-Modus mit einzelnen Steps durch
diese Codezeilen kommt es nicht zu einem Zurücksetzen des Zählerstand.
Ich habe herausbekommen, dass das Zurücksetzen beim Stoppen des Timers
auftritt. Weil wenn der Timer gestoppt ist, man einen Wert in TCC0.COUNT
schreibt und dann den Timer startet, dann startet dieser auch von dem
Wert den man vorher in TCC0.COUNT geschrieben hat.
Hier ist der vollständige Quellcode für eine main.cpp, mit der man das
Problem sehen kann. Durchläuft an den Code zwischen den beiden
Breakpoint-Kommentaren mit Steps kommt es nicht zu dem Rücksetzen,
ansonsten schon:
1 | #include "sam.h"
|
2 |
|
3 | int main(void)
|
4 | {
|
5 | OSCCTRL->XOSCCTRL[1].reg = OSCCTRL_XOSCCTRL_ENABLE | OSCCTRL_XOSCCTRL_IPTAT(0x03) | OSCCTRL_XOSCCTRL_IMULT(0x04) | OSCCTRL_XOSCCTRL_CFDPRESC(0x3);
|
6 |
|
7 | OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_XOSC1 | OSCCTRL_DPLLCTRLB_DIV(5);
|
8 |
|
9 | OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDR(119) | OSCCTRL_DPLLRATIO_LDRFRAC(0);
|
10 | while (OSCCTRL->Dpll[0].DPLLSYNCBUSY.bit.DPLLRATIO);
|
11 |
|
12 | OSCCTRL->Dpll[0].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE;
|
13 | while (OSCCTRL->Dpll[0].DPLLSYNCBUSY.bit.ENABLE | OSCCTRL->Dpll[0].DPLLSTATUS.bit.LOCK || OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY);
|
14 |
|
15 | GCLK->CTRLA.bit.SWRST = true;
|
16 | while (GCLK->SYNCBUSY.bit.SWRST);
|
17 |
|
18 | GCLK->GENCTRL[0].reg = GCLK_GENCTRL_SRC_DPLL0 | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(1);
|
19 | while (GCLK->SYNCBUSY.bit.GENCTRL0);
|
20 |
|
21 | GCLK->PCHCTRL[TCC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN;
|
22 | while (!GCLK->PCHCTRL[TCC0_GCLK_ID].bit.CHEN);
|
23 |
|
24 | MCLK->APBBMASK.bit.TCC0_ = true;
|
25 |
|
26 | TCC0->CTRLA.bit.ENABLE = false;
|
27 | while (TCC0->SYNCBUSY.bit.ENABLE);
|
28 |
|
29 | TCC0->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_MFRQ_Val;
|
30 | while (TCC0->SYNCBUSY.bit.WAVE);
|
31 |
|
32 | TCC0->CC[0].bit.CC = 0x7270e;
|
33 | while (TCC0->SYNCBUSY.bit.CC0);
|
34 |
|
35 | TCC0->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV256 | TCC_CTRLA_ENABLE;
|
36 | while (TCC0->SYNCBUSY.bit.ENABLE);
|
37 |
|
38 | uint32_t Count = 0;
|
39 |
|
40 | while (Count < 0x20000)
|
41 | {
|
42 | TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;
|
43 | while (TCC0->SYNCBUSY.bit.CTRLB);
|
44 |
|
45 | Count = TCC0->COUNT.bit.COUNT;;
|
46 | }
|
47 |
|
48 | if (!TCC0->STATUS.bit.STOP)
|
49 | {
|
50 | TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_STOP_Val; //Breakpoint
|
51 |
|
52 | while (TCC0->SYNCBUSY.bit.CTRLB || !TCC0->STATUS.bit.STOP);
|
53 | }
|
54 |
|
55 | if (TCC0->STATUS.bit.STOP) //Breakpoint
|
56 | {
|
57 | TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_RETRIGGER_Val;
|
58 |
|
59 | while (TCC0->SYNCBUSY.bit.CTRLB || TCC0->STATUS.bit.STOP);
|
60 | }
|
61 |
|
62 | while (true)
|
63 | {
|
64 | TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;
|
65 |
|
66 | while (TCC0->SYNCBUSY.bit.CTRLB);
|
67 |
|
68 | Count = TCC0->COUNT.bit.COUNT;
|
69 | }
|
70 | }
|
Als letzte Information noch, ich verwende als IDE Mircrochipstudio mit
der ARM GNU Toolchain 6.3.1. Und für das Beispiel habe ich den [SAM E54
CURIOSITY ULTRA DEVELOPMENT
BOARD](https://www.microchip.com/en-us/development-tool/dm320210)
verwendet.
Und jetzt die Frage. Könnt ihr bestätigen, dass es sich hierbei um einen
Fehler im Datenblatt handelt oder ggf. sagen, warum es bei mir zu einem
Zurücksetzen des Timers kommt, obwohl diese nicht sein soll? Habe ich
ggf. ein Flag nicht gesetzt, dass man unbedingt setzen muss?