Forum: Mikrocontroller und Digitale Elektronik SAMD21: 8bit timer problem


von timer4 (Gast)


Lesenswert?

Hallo,
ich bin gerade etwas am verzeifeln:

TC4 im SAMD21J18 soll einfach nur zählen und bei erreichen eines 
Endwertes soll es auf ZERO springen und das Interrupt-flag dazu setzen.
Klingt nicht schwer ..

Bei meinem eingestellten TC4 wird die Prüfbedingung nie wahr, der TC4 
setzt immer das interruptflag OVF, statt CM1 oder CM0.
Lasse ich eine LED toggeln erhalte ich ein Rechteck mit einer periode 
von 16,48ms

Also für mich sieht es so aus, als würde der TC4 sogar mit 16bit laufen 
statt 8bit.

1
void timer4_init() {
2
  /*
3
    NFRQ:  PER = TOP
4
  */
5
  
6
  #define TC4_WAIT_SYNC  while(REG_TC4_STATUS & 1<<7)
7
  
8
  #define TC_PRES_DIV1  0 << 8
9
  #define TC_NFRQ      0 << 5
10
  #define TC_MFRQ      1 << 5
11
  #define TC_MODE_COUNT8  1 << 2
12
  #define TC_ENABLE    1 << 1
13
  #define TC_RESET    1 << 0
14
  REG_TC4_CTRLA = TC_RESET;
15
  TC4_WAIT_SYNC;
16
  
17
  REG_TC4_CTRLA = TC_PRES_DIV1 | TC_MFRQ | TC_MODE_COUNT8;
18
  TC4_WAIT_SYNC;
19
  
20
  #define TC_CTRLB_RETRIGGER 1 << 6
21
  #define ONESHOT        1 << 2
22
  REG_TC4_CTRLBSET = TC_CTRLB_RETRIGGER;
23
  TC4_WAIT_SYNC;
24
  
25
  
26
  #define TC__CTRLC_CPTEN1 1 << 5
27
  #define TC__CTRLC_CPTEN0 1 << 4
28
  REG_TC4_CTRLC = TC__CTRLC_CPTEN1|TC__CTRLC_CPTEN0;
29
  TC4_WAIT_SYNC;
30
  
31
  
32
  //#define TC_INTEN_CM1  1<<5
33
  #define MC0  1<<4
34
  #define MC1  1<<5
35
  #define OVF  1
36
  #define ERR 2
37
  REG_TC4_INTENSET = MC0|MC1|OVF|ERR;
38
  TC4_WAIT_SYNC;
39
  
40
  REG_TC4_COUNT8_COUNT = 125;
41
  TC4_WAIT_SYNC;
42
  REG_TC4_COUNT8_CC0 = 100;
43
  TC4_WAIT_SYNC;
44
  REG_TC4_COUNT8_CC1 = 25;
45
  TC4_WAIT_SYNC;
46
  REG_TC4_COUNT8_PER = 150;
47
  TC4_WAIT_SYNC;
48
  
49
  REG_TC4_CTRLA = TC_ENABLE;
50
  TC4_WAIT_SYNC;
51
}
52
53
ui8 check_tc4() {  
54
  if(REG_TC4_INTFLAG & MC0) {
55
    REG_TC4_INTFLAG =  MC0;
56
    return 1;
57
  }
58
  
59
  if(REG_TC4_INTFLAG & MC1) {
60
    REG_TC4_INTFLAG =  MC1;
61
    return 2;
62
  }
63
64
  if(REG_TC4_INTFLAG & OVF) {
65
    return 3;
66
  }
67
  
68
  if(REG_TC4_INTFLAG & ERR) {
69
    REG_TC4_INTFLAG =  ERR;
70
    return 4;
71
  }
72
73
  return 0;
74
}

von timer4 (Gast)


Lesenswert?

N A C H T R A G:

Wenn ich dann in meiner main schleife check_tc4() ab-polle dann erhalte 
ich immer den Wert 3 -> OVF-bit war gesetzt.

von Jim M. (turboj)


Lesenswert?

>   #define TC_PRES_DIV1  0 << 8

Da würde ich immer  klammern:
1
 
2
#define TC_PRES_DIV1  (0 << 8)

Ansonsten kommt man bei C mit der Reihenfolge von Operatoren 
durcheinander, d.h. in REG_TC4_CTRLA landet nicht der erwartete Wert.

von Tretbrettfahrer (Gast)


Lesenswert?

timer4 schrieb:
> while (REG_TC4_STATUS & 1<<7)

Auch so was kann schwer missverstanden werden. Ich klammere
schon deswegen weil ich mir nie die Priorität dieser Operatoren
merken kann.

von timer4 (Gast)


Lesenswert?

die Schiebeoperatoren haben Vorrang. Aber der Übersichtlichkeit halber 
sind Klammern besser :)


1
void timer4_init() {
2
  /*
3
    NFRQ:  PER = TOP
4
  */
5
  
6
  #define TC4_WAIT_SYNC  while(REG_TC4_STATUS & (1<<7))
7
  
8
  #define TC_PRES_DIV1  (0 << 8)
9
  #define TC_NFRQ      (0 << 5)
10
  #define TC_MFRQ      (1 << 5)
11
  #define TC_MODE_COUNT8  (1 << 2)
12
  #define TC_ENABLE    (1 << 1)
13
  #define TC_RESET    (1 << 0)
14
  REG_TC4_CTRLA = TC_RESET;
15
  TC4_WAIT_SYNC;
16
  
17
  REG_TC4_CTRLA = TC_PRES_DIV1 | TC_NFRQ | TC_MODE_COUNT8;
18
  TC4_WAIT_SYNC;
19
  
20
  #define TC_CTRLB_RETRIGGER (1 << 6)
21
  #define ONESHOT        (1 << 2)
22
  REG_TC4_CTRLBSET = TC_CTRLB_RETRIGGER;
23
  TC4_WAIT_SYNC;
24
  
25
  
26
  #define TC__CTRLC_CPTEN1 (1 << 5)
27
  #define TC__CTRLC_CPTEN0 (1 << 4)
28
  REG_TC4_CTRLC = TC__CTRLC_CPTEN1|TC__CTRLC_CPTEN0;
29
  TC4_WAIT_SYNC;
30
  
31
  
32
  #define MC0  (1<<4)
33
  #define MC1  (1<<5)
34
  #define OVF  1
35
  #define ERR 2
36
  REG_TC4_INTENSET = MC0|MC1|OVF|ERR;
37
  TC4_WAIT_SYNC;
38
  
39
  /*
40
  REG_TC4_COUNT8_COUNT = 125;
41
  TC4_WAIT_SYNC;
42
  REG_TC4_COUNT8_CC0 = 100;
43
  TC4_WAIT_SYNC;
44
  REG_TC4_COUNT8_CC1 = 25;
45
  TC4_WAIT_SYNC;
46
  REG_TC4_COUNT8_PER = 150;
47
  TC4_WAIT_SYNC;
48
  */
49
  REG_TC4_COUNT8_PER = 50;
50
  TC4_WAIT_SYNC;
51
  
52
  REG_TC4_CTRLA = TC_ENABLE;
53
  TC4_WAIT_SYNC;
54
}
55
56
ui8 check_tc4() {  
57
  if(REG_TC4_INTFLAG & MC0) {
58
    REG_TC4_INTFLAG =  MC0;
59
    return 1;
60
  }
61
  
62
  if(REG_TC4_INTFLAG & MC1) {
63
    REG_TC4_INTFLAG =  MC1;
64
    return 2;
65
  }
66
67
  if(REG_TC4_INTFLAG & OVF) {
68
    return 3;
69
  }
70
  
71
  if(REG_TC4_INTFLAG & ERR) {
72
    REG_TC4_INTFLAG =  ERR;
73
    return 4;
74
  }
75
76
  return 0;
77
}

von timer4 (Gast)


Lesenswert?

N A C H T R A G:
in check_tc4 was das OVF bit nicht zurück gesetzt. Dennoch keine 
Änderung..
1
ui8 check_tc4() {  
2
  if(REG_TC4_INTFLAG & MC0) {
3
    REG_TC4_INTFLAG =  MC0;
4
    return 1;
5
  }
6
  
7
  if(REG_TC4_INTFLAG & MC1) {
8
    REG_TC4_INTFLAG =  MC1;
9
    return 2;
10
  }
11
12
  if(REG_TC4_INTFLAG & OVF) {
13
    REG_TC4_INTFLAG = OVF;
14
    return 3;
15
  }
16
  
17
  if(REG_TC4_INTFLAG & ERR) {
18
    REG_TC4_INTFLAG =  ERR;
19
    return 4;
20
  }
21
22
  return 0;
23
}

von timer4 (Gast)


Lesenswert?

Ich weis nicht woran es liegt aber ich habe den TCC0 gleich beim ersten 
mal zum laufen bekommen, obwohl dieser wesentlich umfangreicher ist.
Im forum avrfreaks habe ich mehrmals gelesen das man am besten die 
einfachen TC´s nicht nutzen sollte, wegen bugs. ich dachte immer bugs 
gibt nur im zusammenhang mit der API :D

von MaWin (Gast)


Lesenswert?

timer4 schrieb:
> der Übersichtlichkeit halber

Schreibt man irgendwelche #define nicht mitten im source code. Entweder 
sind sie Teil des Interface oder globale Schalter.

und 1 << 5 ist sowieso ein Atmel Krampf. Welche Bedeutung hat das 6te 
Bit in dem Register? Zum controller gehört doch ein header, oder?

von Elektrolurch (Gast)


Lesenswert?

Du hast CAPTENx gesetzt. Damit hast du den Capture-Mode eingestellt!
Der macht Counter-Stamps, wenn eine Triggerquelle vorhanden ist.
Du willst aber PWM und das ist der Compare-Mode. deshalb dürfen CAPTENx 
nicht gesetzt sein.
Und ja, in Atmel Studio etc. verwendet man tunlichst die vordefinierten 
Header. Ich habe mir diese PWM-Init-Routine geschrieben. Mit Rechtsclick 
und "Goto Implementation" siehst du wo und wie die definiert sind:

#include "sam.h"
void TcPwm8Init(Tc* const tctimer, const uint8_t clkdiv, const uint8_t 
channel, uint8_t effper, uint8_t pulse)
{
  if(!effper)
    return;
  // Timer Reset
  tctimer->COUNT8.CTRLA.bit.SWRST= 1;
  while(tctimer->COUNT8.CTRLA.bit.SWRST) ;
  // Enable the TC bus clock (CLK_TCx_APB)...
  TcTimerPowerUp(tctimer);
  tctimer->COUNT8.CTRLA.reg= TC_CTRLA_PRESCSYNC_RESYNC | 
(TC_CTRLA_PRESCALER_Msk & (clkdiv << TC_CTRLA_PRESCALER_Pos)) | 
TC_CTRLA_WAVEGEN_NPWM | TC_CTRLA_MODE_COUNT8;
  while(tctimer->COUNT8.STATUS.bit.SYNCBUSY) ;
  tctimer->COUNT8.PER.reg= effper - 1;
  while(tctimer->COUNT8.STATUS.bit.SYNCBUSY) ;
  tctimer->COUNT8.CC[channel].reg= pulse;
  while(tctimer->COUNT8.STATUS.bit.SYNCBUSY) ;
}

Ich hoffe, das hilft dir.

von timer4 (Gast)


Lesenswert?

Vielen Dank für deine Hilfe  Elektrolurch.
Ich stelle gerad enoch ein grundlegendes Problem fest. Mein Main-clock 
scheint nicht 8MHz zu sein, ich habe eher 800Khz.
1
#include "sam.h"
2
3
int main() {
4
  REG_SYSCTRL_OSC8M &= ~(3 << 8); // no prescaler
5
  
6
  REG_PORT_DIRSET1 = (1<<10);
7
  while(1) {
8
    REG_PORT_OUTTGL1 = (1<<10);
9
  }
10
}

Ich Messe 1,214µs zwischen jeden Flankenwechsel. Bei 8MHz würde ich aber 
125ns erwarten.

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.