Atmega8L: Warum geht Timer0 Interrupt nicht?

OP #2513589
Lesenswert?

Hallo zusammen,

ich habe 2 Testprogramme für euch.
Das erste läuft wie erwartet. Hier wird TIMER0_OVF über TIFR abgefragt.
Beim zweiten wird in der ISR toggle=1 gesetzt, als Indikator für
eine ausgeführte ISR. Makefile ist in beiden Fällen gleich und setzt
atmega8 als uC.

Hardware Plattform STK500.
Meine Rechereche hat einen sehr ähnlichen Fall herausgebracht.
Beitrag "atmega8515 auf STK 500: Timer funtkionieren nicht"
Leider wurde dem Fragesteller dort nicht geholfen.

Alle Quellen nachfolgend gelistet.


Zuerst Makefile (Cygwin Umgebung)
1
gcc = avr-gcc
2
objcopy = avr-objcopy
3
inc = -I /cygdrive/c/WinAVR-20100110/avr/include
4
cflags = -Wall -O2 -Os
5
controller = atmega8
6

7
main: main.c
8
  $(gcc) -c main.c -mmcu=$(controller) $(inc) $(cflags)
9
  $(gcc) -o main.elf main.o
10
  $(objcopy) -j .text -j .data -I binary -O ihex main.elf main.hex
11
  
12
flash:
13
  avrdude -p atmega8 -P COM5 -c stk500v2 -e -U flash:w:main.hex:i
14

15
read:
16
  avrdude -p atmega8 -P COM5 -c stk500v2 -U flash:r:main_.hex:i
17

18
clean:
19
  rm -f main.o main.elf main.hex



Program ohne ISR
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
 
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7

8
void init_timer0(void) {
9
  TCNT0 = 0;
10
  TCCR0 = 0x05;    // 1024 prescaler of 8MHz
11
  TIFR = 1<<TOV0;    // clear pending interrupt
12
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
13
}
14

15
void init(void) {
16
  DDRB = 0x03;
17
  init_timer0();
18
}
19

20
int main(void) {
21
  uint8_t cnt=0;
22
  init();
23
  while(1) {
24
    PORTB = 0x03;
25
    while(1)
26
      if(TIFR & (1<<TOV0)) {
27
        TIFR = 1<<TOV0;
28
        TCNT0 = 0;
29
        break;
30
      }
31
    PORTB = 0x00;
32
    for(cnt=0; cnt<20; cnt++)
33
      while(1)
34
        if(TIFR & (1<<TOV0)) {
35
          TIFR = 1<<TOV0;
36
          TCNT0 = 0;
37
          break;
38
        }
39
  }
40
  return 0;
41
}


Mit ISR (nicht funktionierend = ISR nicht ausgeführt)
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
 
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7

8
volatile uint8_t toggle = 0;
9

10
ISR(TIMER0_OVF_vect) {
11
  TCNT0 = 0;
12
  toggle = 1;
13
}
14

15
void init_timer0(void) {
16
  cli();
17
  TCNT0 = 0;
18
  TCCR0 |= 0x05;    // 1024 prescaler of 8MHz
19
  TIFR = 1<<TOV0;    // clear pending interrupt
20
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
21
  sei();
22
}
23

24
void init(void) {
25
  DDRB = 0x03;
26
  init_timer0();
27
}
28

29
int main(void) {
30
  init();
31
  PORTB = 0x03;  // switch on
32
  while(1) {
33
    if(toggle)      // if interrupt occured
34
      PORTB = 0x00;  // switch off
35
  }
36
  return 0;
37
}
OP #2513623
Lesenswert?

Nachtrag:

$(objcopy) -j .text -j .data -I binary -O ihex main.elf main.hex

ist das so korrekt?


Was mich nocht etwas verwundert ist ...
1
$ avr-objdump.exe -j .data -d main.elf
2

3
main.elf:     file format elf32-avr

müsste nicht die volatile Variable toggle in der Sektion .data
abgelegt sein? Oder "löst" Compiler die volatile Anforderung damit,
dass er ihnen ein Register zuweist.
Gast #2513630
Lesenswert?

Wie erkennst du, ob was passiert? Zwischen PORTB=0x03 und PORTB=0x00 
vergehen nur 32.8ms. Und dann passiert laut Programmcode im 2. Beispiel 
nix mehr.

Wenn du zwei LEDs hast, schalte nur eine regelmä0ig und lass die andere 
immer an. Wenn die eine LED sehr schnell geschaltet wird (alle 32ms ist 
schnell!), sollte man wenigstens einen Helligkeitsunterschied sehen.
OP #2513807
Lesenswert?

Krapao schrieb:
> Wie erkennst du, ob was passiert?

vielleicht hätte ich das, was ich beobachte deutlicher zum Ausdruck 
bringen sollen

Vorbereitung => setze die 2 externen leds mit PORTB = 0x03; (sie 
leuchten)

Erwartung => ich erwarte, dass ISR toggle=1 setzt, sodass dann in main
if(toggle){PORTB=0x00;} die leds abschaltet.

Beobachtung => die externen leds werden nicht abgeschaltet. (sie 
leuchten)

Schlussfolgerung => ISR wird nicht ausgeführt.


---

toggle ist irreführend bezeichnet, ihr habt da recht.
Gast #2513830
Lesenswert?

Beim STK500 sind die LEDs active-low geschaltet. NAch dem Reset sind die 
LEDs aus, da der Pourt Eingang ist. Beim Datenrichtungssetzen sind die 
LEDs ein. Dein erstes Kommando schaltet die LEDs aus. Dann beim Timer 
IRQ schaltest du die LEDs ein. Weil zwischen den ersten Kommandos der 
AVR affenartig schnell ist, siehst du die einzelnen LED-Zustände nicht.
OP #2513832
Lesenswert?

spess53 schrieb:
> Kommt darauf an, wie die LEDs angeschlossen sind.
>
> MfG Spess

logo :)

masse --|<|-- PORTB1
masse --|<|-- PORTB2

kein Vorwiderstand, lasse den AVR die leds mit 20mA speisen :)

BTW: wieviel mA kann ein Port (in dem Fall zufälligerweise PORTB)
insgesamt treiben? Das ein Pin 20mA heisst, bedeutet ja noch
lange nicht, dass ein Port mit 8 Pins 160mA treiben kann.
Oder im Fall von AVR schon? Hab leider dazu vergeblich im Netz gesucht.
OP #2513907
Lesenswert?

um ein Paar zusätzliche Einsichten zu bekommen, habe ich mein Code
leicht erweitert.

als feedback, dass main normal abgearbeitet wird, habe ich
STK500 eigene leds mit in spiel reingebracht.
Das interessante ist, wenn ich sei() herauskommentiere!, dann
wechseln die STK500 leds ihren Zustand (0xAA -> 0x55 -> 0xAA ..)
Wenn sei() nicht herauskommentiert ist, verharren die STK500 leds
im 0x55 Zustand.

hmm, irgendwas stinkt da. Das ist nämlich exakt das, was im Thread
Beitrag "atmega8515 auf STK 500: Timer funtkionieren nicht"
beschrieben wird.

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
 
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7

8
volatile uint8_t toggle = 0;
9

10
ISR(TIMER0_OVF_vect) {
11
  TCNT0 = 0;
12
  toggle = 1;
13
}
14

15
void init_timer0(void) {
16
  cli();
17
  TCNT0 = 0;
18
  TCCR0 |= 0x05;    // 1024 prescaler of 8MHz
19
  TIFR = 1<<TOV0;    // clear pending interrupt
20
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
21
  sei();   // main hängt, wenn nicht auskommentiert!!!
22
}
23

24
void init(void) {
25
  DDRC = 0xFF;
26
  DDRB = 0x03;
27
  init_timer0();
28
}
29

30
int main(void) {
31
  init();
32
  PORTB = 0x03;  // switch on
33
  while(1) {
34
    if(toggle)      // if interrupt occured
35
      PORTB = 0x00;  // switch off
36
    PORTC = 0xAA;
37
    _delay_ms(100);
38
    PORTC = 0x55;
39
    _delay_ms(100);
40
  }
41
  return 0;
42
}
#2513928
Lesenswert?

Daniel -------- schrieb:
> jetzt habe ich Makefile abgeändert, aber keine Wirkung.

Dann mache doch mal
1
avr-objdump -d -h main.elf
und poste den Output.

Daniel -------- schrieb:
> Gehört -mmcu Option in jedem Fall dazu, wenn man aus .o die .elf Datei
> erzeugt?

Ja, zwingend.

Übrigens:
1
cflags = -Wall -O2 -Os
Was denn nun, 2 oder s?
(dürfte aber nicht die Ursache deines Problems sein)
OP #2513937
Lesenswert?

als Zusammenfassung meiner Erkenntnise


schleife in main läuft ab
1
void init_timer0(void) {
2
  cli();
3
  TCNT0 = 0;
4
  TCCR0 |= 0x00;    // timer0 stopped
5
  TIFR = 1<<TOV0;    // clear pending interrupt
6
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
7
  sei();
8
}


schleife in main hängt
1
void init_timer0(void) {
2
  cli();
3
  TCNT0 = 0;
4
  TCCR0 |= 0x05;    // 1024 prescaler of 8MHz
5
  TIFR = 1<<TOV0;    // clear pending interrupt
6
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
7
  sei();
8
}

schleife in main läuft, aber ISR wird nicht ausgeführt
1
void init_timer0(void) {
2
  cli();
3
  TCNT0 = 0;
4
  TCCR0 |= 0x05;    // 1024 prescaler of 8MHz
5
  TIFR = 1<<TOV0;    // clear pending interrupt
6
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
7
  //sei();
8
}
OP #2513944
Lesenswert?

Stefan Ernst schrieb:
>> hmm, irgendwas stinkt da. Das ist nämlich exakt das, was im Thread
>> Beitrag "atmega8515 auf STK 500: Timer funtkionieren nicht"
>> beschrieben wird.
>
> Und dort fehlt übrigens auch ein -mmcu.

Makefile ist nachgezogen, sieht jetzt so aus
1
gcc = avr-gcc
2
objcopy = avr-objcopy
3
inc = -I /cygdrive/c/WinAVR-20100110/avr/include
4
cflags = -Wall -O2
5
controller = atmega8
6

7
main: main.c
8
  $(gcc) -c main.c -mmcu=$(controller) $(inc) $(cflags)
9
  $(gcc) -o main.elf -mmcu=$(controller) main.o
10
  $(objcopy) -j .text -j .data -I binary -O ihex main.elf main.hex
11
  
12
flash:
13
  avrdude -p atmega8 -P COM5 -c stk500v2 -e -U flash:w:main.hex:i
14

15
read:
16
  avrdude -p atmega8 -P COM5 -c stk500v2 -U flash:r:main_.hex:i
17

18
clean:
19
  rm -f main.o main.elf main.hex
#2513958
Lesenswert?

Hallo zusammen!

Wie Daniel habe ich das Selbe Problem, allerdings mit Bascom (ich hoffe 
jemand kann nebst C auch Bascom lesen)

Bei mir will der Timer2 (übrigens das gleiche Problem auch mit Timer0) 
nicht hochzählen.
Am Besten ist es wenn ich den Code poste:

$regfile "m48def.dat"
$crystal = 10000000
$baud = 9600


Config Portb = Output
Dim A As Integer                                            'Winkel 
Alpha
Dim B As Integer                                            'Sin- Wert 
von Alpha
Dim C As Integer                                            'Ein- Zeit 
der PWM (indirekte Spannung)
Dim D As Integer                                            'Winkel
Dim E As Integer
Dim W As Byte

'PWM- Timer 
====================================================================
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Down , Compare B 
Pwm = Clear Up , Prescale = 256
Enable Timer1

'Interrupttimer 
================================================================
Config Timer2 = Timer , Prescale = 1

On Timer2 Tim2isr
Enable Interrupts
Enable Timer2

'======================================================================= 
========
Start Timer2

A = 0
B = 0
C = 1
D = 235 / 100

sbi portb,3
cbi portb,4
Pwm1a = C
Start Timer2

Do
W = Timer2
   If W > 2 Then
   sbi portb,5
   End If
Loop




Tim2isr: 
'interruptroutine f¸r timer0

A = A + D
'B = Sin(a)                                                  'B = 
Round(b)
'B = Rad2deg(b)

   If A => 179 Then
   A = 0
   Toggle Pinb.3
   Toggle Pinb.4
   Else
   End If

C = B * 254                                                 'Ein-Zeit = 
sinAlpha * Radius
Pwm1a = C

Return


End                                        'end program





Kann mir ja vielleicht jemand helfen, bzw, sagen was nicht richtig ist?

Danke und Gruss Andi
#2514025
Lesenswert?

Andi K. schrieb:
>> Wie Daniel habe ich das Selbe Problem, allerdings mit Bascom (ich hoffe
>> jemand kann nebst C auch Bascom lesen)

>Mach' Dir 'nen eigenen Thraed auf, statt einen zu kapern.

Naja ich habe gedacht es wäre leichter zwei Leuten in einem Thraed zu 
helfen, als in zwei Thraed's... Aber gut, mache ich hald einen neuen 
auf.
Gast #2514064
Lesenswert?

Daniel -------- schrieb:
> vielleicht kann jemand mal bei sich ausprobieren

Mit AVR-Studio4 und dem angehängten Makefile lässt sich das erst gar 
nicht compilieren.
> make: *** No rule to make target `main.c', needed by `main'.  Stop.

mit ordentlichem makefile compiliert der Code. Wobei der aber sinnlos 
ist, da "toggle" nicht zurückgesetzt wird.
Gast #2514101
Lesenswert?

Versuch's mal so, läuft im Simulator:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
 
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7

8
volatile uint8_t toggle = 0;
9

10
ISR(TIMER0_OVF_vect) {
11
  TCNT0 = 0;
12
  toggle = 1;
13
}
14

15
void init_timer0(void) {
16
  cli();
17
  TCNT0 = 0;
18
  TCCR0 |= 0x01;    // 1024 prescaler of 8MHz
19
  TIFR = 1<<TOV0;    // clear pending interrupt
20
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
21
  sei();
22
}
23

24
void init(void) {
25
  DDRB = 0x03;
26
  init_timer0();
27
}
28

29
int main(void) {
30
  init();
31
  while(1) {
32
    if(toggle)      // if interrupt occured
33
      PORTB ^= 0x03;  // switch off
34
      toggle = 0;
35
  }
36
  return 0;
37
}
Und benutze anhängendes makefile.
Angehängte Dateien:
OP #2514176
Lesenswert?

Danke an alle. Ich glaube ich hab das Problem lokalisiert.

vorher
1
$(objcopy) -j .text -j .data -I binary -O ihex main.elf main.hex

nacher
1
$(objcopy) -j .text -j .data -O ihex main.elf main.hex

löst das Rätsel. Das Eingabeformat ist wohl nicht "binary".

@MWS
ich bevorzuge selbstgeschriebene makefiles
die sind schmächtig und ich verstehe was sie tun.
Bis solche harten Nüsse hochkommen :)
Andererseits lernt man es an denen mit der Zeit.

peace
Gast #2514203
Lesenswert?

Daniel -------- schrieb:
> ich bevorzuge selbstgeschriebene makefiles
> die sind schmächtig und ich verstehe was sie tun.

Ob die nun schmächtig sind, wird wohl eher wurscht sein. Wichtig ist, 
dass es läuft und wenn ein automatisch generiertes makefile dafür sorgt, 
dass das selbst zusammengeschraubte schließlich funktioniert, umso 
besser.

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