Forum: Mikrocontroller und Digitale Elektronik Mit Timer2 von AVR in FW einen 16bit Timer realisieren


von avr_timer2 (Gast)


Lesenswert?

Hallo Zusammen,

ich brauch basierend auf den Timer 2 eine Zeitbasis die aber 16bit groß 
sein muss.

Irgendwie läuft aber bei mir etwas schief so bekomme ich manchmal 
falsche Werte wie z.B. hier.
1. Wert: 0xB700
2. Wert: 0xB807
1 Tick ist 244us zw. Wert 1 und Wert 2 sind aber nur ca. 2ms vergangen 
(Oszi) => 1. Wert sollte 0xB7FF heißen (vermute ich jetzt mal g)

Das Problem tritt leider nicht sehr häufig auf ...

Timer2 macht beim Überlauf (ca. 62,5ms) einen Interrupt die Routine 
sieht so aus:
1
ISR(TIMER2_OVF_vect)
2
{
3
g_nOverflow_cnt++;
4
 while(ASSR & _BV(TCR2BUB));
5
6
  TCCR2B = TCCR2B;
7
}
Auslesen vom Timer2 16bit Wert sieht so aus:
1
uint16_t RTC_GetTickStamp(void)
2
{
3
  uint8_t tickstamp = 0;
4
  uint16_t retval = 0;
5
  do
6
  {
7
    retval = 0;
8
    tickstamp = TCNT2;
9
    retval = (g_nOverflow_cnt << 8);
10
  }
11
  while((tickstamp != TCNT2));
12
  retval |= tickstamp;
13
  return retval;
14
}

Während des Schreibens meines Beitrages ist mir das Problem aufgefallen, 
RTC_GetTickStamp wird in einer ISR aufgerufen, wenn nun aber der Timer2 
Interrupt auftritt wird natürlich g_nOverflow_cnt nicht erhöht.

So ich hab nun eine "safe" routine entschieden welche in interrupts 
aufgerufen wird (ich brauch das leider das ich mir den Zeitstempel merke 
wenn z.B. ein GPIO INterrupt auftritt. Nur funktioniert das auch nicht. 
Bin etwas ratlos, vlt. hat wer einen Tipp für mich? Danke!
1
uint16_t RTC_GetTickStamp_safe(void)
2
{
3
  uint8_t tickstamp = 0;
4
  uint16_t retval = 0;
5
  uint8_t overflow_cnt = g_nOverflow_cnt;
6
  uint8_t irq_happend = 0;
7
  /*needed for short wake up */
8
  OCR2A = OCR2A; //dummy write neccassary if awake time is less then 30us.
9
  while(ASSR & (_BV(OCR2AUB)));
10
  do
11
  {
12
    retval = 0;
13
    tickstamp = TCNT2;
14
    retval = (g_nOverflow_cnt);
15
    if(TIFR2 & _BV(TOV2))
16
    {
17
      irq_happend = 1;
18
    }
19
  }
20
  while((tickstamp != TCNT2) || (retval != g_nOverflow_cnt));
21
  retval = ((retval+irq_happend) << 8);
22
  retval |= tickstamp;
23
  return retval;
24
}

Danke!

von Peter D. (peda)


Lesenswert?

Codesammlung: "AVR Timer mit 32 Bit"


Peter

von avr_timer2 (Gast)


Lesenswert?

Hallo,

danke für deinen Tipp - löst aber nicht das Problem. Im Endeffekt hab 
ich es so wie schon diskutiert mit etwas Jitter und mehr Code gelöst 
gehabt. Deine Version ist eleganter keien Frage. Dennoch hab ich noch 
das Problem dass z.B. bei 2ms Delay 65ms Berechnet werden:
g_n_dbg_duration:0x0107
g_n_begin_tick:0x2700
g_n_end_tick:0x2807

das ist der Tickstamp, also der 16bit Timerwert. ich sag mal das ist 
hier ein schönes beispiel ich glaub das g_n_begin_tick 0x2800 sein 
sollte.

Hier mal mein Codeteil von dir übernommen:
1
uint16_t RTC_GetTickStamp(void)
2
{
3
  uint8_t tmp_sreg;
4
  uint16_t retval = 0;
5
  uint8_t irq_happend = 0;
6
  tmp_sreg = SREG;
7
  cli();
8
  retval = g_nOverflow_cnt + TCNT2;
9
  irq_happend = TIFR2;
10
  SREG = tmp_sreg;
11
12
  if((irq_happend & _BV(TOV2)) && !(retval&0x80))
13
  {
14
    retval += 256;
15
  }
16
17
  return retval;
18
}

So hab ich es jetzt cli/sreg hab ich etwas umgeschrieben weil es bei mir 
vorkommen kann das das GIE Flag gelöscht ist.

Also ich hab auch in meinem Codeteil keinen Fehler gefunden und deiner 
scheint auch sehr schlüßig zu sein, die Frage ist nun für mich warum 
funktioniert es bei mir trotzdem nicht?

Etwas mehr Hintergrundinfos von meinem Projekt:
Ich lege den Controller auch immer Schlafen fast immer in PWR_SAVE und 
manchmal IDLE. Könnte es event. damit zu tun haben?
1
void sch_go_into_sleep_mode(void)
2
{
3
  // sleep
4
  RTC_Wait();
5
  set_sleep_mode(_sleep_mode);
6
  cli();
7
  sleep_enable();
8
  sei();
9
  sleep_cpu();
10
  sleep_disable();
11
}
12
13
void RTC_Wait(void)
14
{
15
  OCR2A = OCR2A; //dummy write neccassary if awake time is less then 30us.
16
  while(ASSR & (_BV(OCR2AUB)));
17
}

_sleep_mode ist entweder PWR_SAVE oder  IDLE je nach Betriebszustand von 
mir (UART aktiv IDLE, ansonsten PWR_SAVE). Ich mess aber dzt. zu 99% nur 
im PWR_SAVE zustand.

Hast du vielleicht eine Idee woran es sonst liegen könnte bzw. Tipp?

Danke!

von avr_timer2 (Gast)


Lesenswert?

So ich glaub ich hab das Problem gefunden, hab das wie folgt abgeändert:
1
uint16_t RTC_GetTickStamp(void)
2
{
3
  uint8_t tmp_sreg;
4
  uint16_t retval = 0;
5
  uint8_t irq_happened = 0;
6
  tmp_sreg = SREG;
7
  cli();
8
  retval = g_nOverflow_cnt + TCNT2;
9
  TCCR2B = TCCR2B;
10
  while(ASSR & (1 << TCR2BUB))
11
  irq_happened = TIFR2;
12
  SREG = tmp_sreg;
13
14
  if((irq_happened & _BV(TOV2)) && !(retval&0x80))
15
  {
16
    retval += 256;
17
  }
18
19
  return retval;
20
}

Übrigens ist bei peda ein kleines typo im code drin es müsste für den 
Teimer 2 TIFR2 heißen - im Codeschnippel ist TIFR. aber das nur am Rande 
bemerkt.

Danke nochmal an peda für den input der eleganten Version!

Falls es doch nicht die LÖsung war melde ich mich wieder - versprochen 
;)

von spess53 (Gast)


Lesenswert?

Hi

>Übrigens ist bei peda ein kleines typo im code drin es müsste für den
>Teimer 2 TIFR2 heißen - im Codeschnippel ist TIFR. aber das nur am Rande
>bemerkt.

Es gibt AVRs, die für alle Timer nur ein TIF-Register haben. Und das 
heisst dann auch nur TIFR.

MfG Spess

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.