Forum: Mikrocontroller und Digitale Elektronik Fehler im Datenblatt der SAM D5x/E5x Familie?


von Mike (linne78)


Lesenswert?

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?

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.