Für ein MC-System brauche ich einen Systemcounter mit Microsekunden
Auflösung.
Ursprünglich wollte ich den ARM0 Systemcounter verwenden und diesen mit
den ASF-Treibern ansprechen:
Beitrag "ARM Cortex M0 system timer"
Nach einigen Ratschlägen bin ich zum Schluss gekommen, auf die ASF und
sonstige fertige Treiber zu verzichten, alles von Hand zu machen und
einen 32 Timer/Counter zu verwenden.
Hier gibt es ein Beispiel:
http://community.atmel.com/forum/timerscounters-0?skey=samd%20timer%20example
uint16_tPRESCSYNC:2;/*!< bit: 12..13 Prescaler and Counter Synchronization */
15
uint16_t:2;/*!< bit: 14..15 Reserved */
16
}bit;/*!< Structure used for bit access */
17
uint16_treg;/*!< Type used for register access */
18
}TC_CTRLA_TypeX;
19
20
voidInit_TC1(void)
21
{
22
// Turn on the digital interface clock
23
PM->APBCMASK.reg|=PM_APBCMASK_TC1;
24
25
// Turn on the analog interface clock and select GCLK
26
GCLK_CLKCTRL_Typeclkctrl=
27
{
28
.bit.WRTLOCK=false,
29
.bit.CLKEN=true,
30
.bit.ID=TC1_GCLK_ID,
31
.bit.GEN=0,
32
};
33
34
GCLK->CLKCTRL.reg=clkctrl.reg;
35
TC1->COUNT32.CTRLA.bit.SWRST=true;
36
37
// wait for synchronization to complete
38
while(TC1->COUNT32.STATUS.bit.SYNCBUSY==true);
39
40
// set the access mode for the timer
41
TC1->COUNT32.CTRLA.reg=TC_CTRLA_MODE_COUNT32;
42
43
TC_CTRLA_TypeXtc_ctrla=
44
{
45
.bit.PRESCSYNC=0,
46
.bit.RUNSTDBY=0,
47
.bit.PRESCALER=4,// TC_PRESCALER_DIV16
48
.bit.WAVEGEN=0,// Normal Frequency
49
.bit.MODE=2,// TC_MODE_COUNT32
50
.bit.ENABLETC=1,
51
};
52
53
TC1->COUNT32.CTRLA.reg=tc_ctrla.reg;
54
// wait for synchronization to complete
55
while(TC1->COUNT32.STATUS.bit.SYNCBUSY==true);
56
57
}
In Atmel Studio sieht man, dass die Register initialisiert werden, aber
der Zähler zählt einfach nicht.
Liegt es vielleicht am Input-Clock? Hat jemand eine Idee?
PMC Clock für die Timer aktiviert ? Auch für die PIO ?
1
pmc_enable_periph_clk(ID_PIOB);
Auch die PIO entsprechen Konfiguriert ?
1
pio_configure(PIOB,PIO_PERIPH_B,PIO_PB25,PIO_DEFAULT);// Port PIO_PB25 auf TIOA vom Timer TC0
2
3
pmc_enable_periph_clk(ID_TC0);
4
5
NVIC_DisableIRQ(TC0_IRQn);
6
7
NVIC_ClearPendingIRQ(TC0_IRQn);
8
9
NVIC_SetPriority(TC0_IRQn,5);
10
11
NVIC_EnableIRQ(TC0_IRQn);
12
13
tc_init(TC0,0,TC_CMR_TCCLKS_TIMER_CLOCK5|// set clock slow clock 32768HZ
14
TC_CMR_LDRA_FALLING|// load RA by falling edge
15
TC_CMR_ETRGEDG_RISING|// set TC zero by rising edge
16
TC_CMR_ABETRG|// trigger from TIOA
17
TC_CMR_CPCTRG// interrupt by RC compare
18
);)
19
20
// set RC on 1.1sec timeout
21
tc_write_rc(TC0,0,36045);
22
23
tc_enable_interrupt(TC0,0,TC_IER_CPCS|
24
TC_IER_LDRAS);
25
26
tc_start(TC0,0);// ab hier läuft er los ;)
Wenn Interrupts aktiv
1
voidTC0_Handler(void){
2
tc_get_status(TC0,0);// unbedingt auslesen damit das Flag zurückgesetzt wird
3
4
}
Eigentlich nicht schwer ;) welche Flags man setzen muss kann man aus dem
Referenz Manual entnehmen. Bitte den Code nicht per Copy übernehmen. Sie
sind für einen sam3x. Das ASF sollte aber ähnlich sein :)
>Auch die PIO entsprechen Konfiguriert ?
Danke für die Antwort. Die Ports brauche ich nicht. Ich brauche nur den
Zählerstand des Counters. Der Counter wird mit dem Systemclock
getacktet.
Also beim SAM3 kann man das Umstellen. Jeder Timerchannel hat seinen
eignen Teiler und man kann ihn auf den Slowclock stellen.
In der Referenz ist mit Sicherheit eine Übersicht voraus man die
Möglichkeiten entnehmen kann.
tc_start(TC0,0); Startet den Channel sonst läuft dieser nicht los.
Dieser gibt den Clock frei.
Bitte möglichst keine Hardware-Bitfields selbst definieren. Diese
sind normalerweise alle über "sam.h" bereits da. Wenn nicht, musst
du sehen, wie du sie ranbekommst.
Ich habe hier beispielsweise sowas für einen 1-Hz-Takt im TC3:
Marco H. schrieb:> Also beim SAM3 kann man das Umstellen.
SAMD und Konsorten sind in den Peripherals völlig anders (allerdings
meiner Meinung nach durchaus in vielen Dingen besser).
>Bitte möglichst keine Hardware-Bitfields selbst definieren.
Hallo Jörg,
ich weiß, ich weiß. Leider gab es in dem Atmel-Framwork einen Fehler in
"compile.h" weil dort ein
#define ENABLE 1
stand. Was mit der Defintion in "tc.h" kollidiert ist. Deshalb habe ich
die Struktur zum Test raus genommen und umbenannt.
Ich habe es gerade noch mal mit einer anderen Version der probiert, da
haben sie den Fehler wohl beseitigt.
Das liegt daran, dass die Jungs dort sich nicht an gängige
Konventionen halten: Makros schreibt man GROSS, andere Bezeichner
(wie bspw. in Bitfeldern) schreibt man klein oder camelCase.
Das gleiche passiert einem bei sowas:
1
PM->APBBMASK.bit.PORT=1;
Ist zum Glück nicht nötig, da der Takt für PORT standardmäßig im
PM aktiv ist. Wenn man die Zeile compilieren will, stolpert man
drüber, dass das Bitfield namens PORT mit einem gleichnamigen Makro
kollidiert.
>Ich habe hier beispielsweise sowas für einen 1-Hz-Takt im TC3:
Danke dafür. Jetzt bewegt sich der Counter endlich. Ich musste noch eine
kleine Änderung für den SAMD20 machen, weil es eine Definition anders
ist ( siehe Programmtext ).
Jetzt muss ich nur noch auf 32bit und 1us Tick umstellen.
Leider funktioniert genau die gleiche Konfiguration nur mit 32bit nicht.
Woran könnte das denn liegen? Laut Datenblatt müsste der Counter 32bit
können.
chris_ schrieb:> Leider funktioniert genau die gleiche Konfiguration nur mit 32bit nicht.
32-bit-TC braucht zwei unmittelbar aufeinanderfolgende TCs. Ist
ein bisschen tricky. Wenn ich mich recht erinnere, muss man dann
alles auf TC2 konfigurieren, und TC3 wird dabei implizit mit
herangezogen.
Lies diesbezüglich nochmal genau das Datenblatt. Hab' gerade keine
Zeit dafür.
Danke für den Hinweis. Ich denke, das ist einer der Punkte, bei denen
man lange suchen kann.
Ich kopiere mal die entsprechende Stelle aus dem Datenblatt und
versuche, daraus schlau zu werden:
Was mich wundert: Du hast TC3 als counter verwendet. Das scheinen einige
so zu tun. Die Frage ist: Warum nicht bei TC0 beginnen? Hat das auch
etwas mit den "Inhomogenitäten" dieser Peripherie zu tun?
Ich wollte es gerade hinschreiben ;) Im 32 bit Mode werden zwei TC
gepaart. Gezählt wird von TC0 -> gerade Master -> ungerade Slave. Der
Clock wird auch so im PM aktiviert. Du wolltest den TC 3 als Master
Konfigurieren das geht nicht im 32bit Mode.
Nicht unwichtig
The following registers need synchronization when read:
Control B Clear register (CTRLBCLR)
Control B Set register (CTRLBSET)
Control C register (CTRLC)
Count Value register (COUNT)
Period Value register (PERIOD)
Compare/Capture Value registers (CCx)
Read-synchronization is denoted by the Read-Synchronized property in the
register description.
chris_ schrieb:> Du hast TC3 als counter verwendet. Das scheinen einige so zu tun. Die> Frage ist: Warum nicht bei TC0 beginnen?
Hing in diesem Falle mit der IO-Zuordnung für die waveform generation
ab. Die Alternativfunktionen für die einzelnen IO-Pins sind ja nicht
beliebig frei wählbar.
chris_ schrieb:>> The following registers need synchronization when read:>> Das heißt dann für jedes dieser Register eine Zeile dieser Art:
Ja. Kann man auch in einem Makro schieben, dann sieht der Code
nicht ganz so „verwürgt“ aus.
Doch Vorsicht ! Bei mir schwingt der Generator 3 mit 8MHZ und dein
gewählter Wave Mode hat bei CC 0xffffffff im
TC_WAVE_GENERATION_NORMAL_FREQ keine Wirkung auf den WO[x]. Da der
Ausgang beim Match und Top getoggelt wird.
Wichtig man muss zwischen TC und TCC unterscheiden. Sind zwar alles
Timer aber mit unterschiedlichen Eigenschaften und Registern ! Beim
SAMD21 gibt es nur 3 Timer dieser Art TC3,TC4,TC5. Im 32Bit Mode werden
zwei gepaart. Gerade-> Ungerade. Das geht nur mit TC4 !