SAMD21: 8bit timer problem

Gast #6666147
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
}
Gast #6666242
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
}
Gast #6666244
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
}
Gast #6666300
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
Gast #6666443
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?
Gast #6666607
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.
Gast #6666914
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren