www.mikrocontroller.net

Forum: Compiler & IDEs Atmega8 löst Timerinterrupt nicht aus


Autor: Lorenz Hopfmüller (lolo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich habe die vergangenen Stunden damit verbracht, im Internet und diesem 
Forum nach einer Lösung für dieses Problem zu suchen:
Ich habe ein myAVR-Board v1.52 mit einem ATMega8. An Port D hängt eine 
LED. Folgendes Programm sollte eigentlich alle 710ms die LED an bzw 
ausschalten. Es tut sich aber nichts, die LED brennt dauernd. Woran kann 
das liegen?
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 3686400 
#include <util/delay.h>
volatile uint8_t counter;
int main() {
    DDRD = 0xFF;
    TIMSK |= (1 << TOIE0);            // Timer Overflow Interrupt freischalten  
    TCCR0 |= (1 << CS02) | (1<<CS00);  // Vorteiler 1024 -> Timerfrequenz 3,6 kHz -> 71ms Überlaufperiode
// Interrupts freigeben
    sei();
// Endlose Hauptschleife
    PORTD = 0xFF;
    while(1) {
        if (counter >= 10) { // Neuer Timerzyklus ?
            counter = 0;
 
            // hier steht jetzt in Normalfall ein grosser Programmblock ;-) 
            PORTD ^= 0xff;    // LED toggeln
        }
    }
}
// Timer0 overflow Interrupt
// hier wird der Hauptschleife ein neuer Timerinterrupt signalisiert
ISR(TIMER0_OVF_vect) {
    counter += 1;
}
Ich kompiliere den Code mit
avr-gcc -Os -mmcu=atmega8 timer3.c
 (Compilerversion ist 4.3.0) und brenne ihn mit
avrdude -p m8 -c sp12 -U flash:w:a.out:r -v -E noreset,vcc

Danke,
Lorenz

Autor: Wolfgang Horn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, Lorenz,

Im Programmkode erkenne ich keinen Fehler.

Anamnese:
1. Läuft der Oszillator?
2. Verhält sich ein anderer Chip genauso?
3. Stromlauf ohne Fehler?

Ciao
Wolfgang Horn

Autor: Lorenz Hopfmüller (lolo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
der Oszillator läuft. Folgender Code lässt die LED - wie erwartet - 
schnell blinken:
#include <avr/io.h>
#define F_CPU 3686400 
#include <avr/interrupt.h>
#include <util/delay.h>
volatile uint8_t counter;
int main() {
    DDRD = 0xFF;
    TIMSK |= (1 << TOIE0);            // Timer Overflow Interrupt freischalten  
    TCCR0 |= (1 << CS02) | (1<<CS00);  // Vorteiler 1024 -> Timerfrequenz 3,6 kHz -> 71ms Überlaufperiode
// Interrupts freigeben
//    sei();
    PORTD = 0xFF;
    while(1) {
  if (TIFR & (1 << TOV0)) {  //Wenn Overflow-Bit gesetzt
            PORTD ^= 0xff;    // LED toggeln
      TIFR |= (1 << TOV0);  // Overflow-Bit löschen -> Auf logisch 1 Stellen
  }
    }
}
Sobald ich aber sei() nicht mehr auskommentiert habe, bleibt die LED an. 
Verhängt sich mein ATMega8 auf der Suche nach einer Interruptfunktion?

Ich habe nur diesen eine Controller, evtl tut mir jemand, der auch im 
Besitz eines ATMega8 ist, den Gefallen, das mal auszuprobieren?

Was du mit Stromfluss meinst, kann ich nicht nachvollziehen. Aber ein 
allzu schwerer Fehler kann nicht vorliegen, denn alle meine Programme, 
die keine Interrupts verwenden, laufen anstandslos. Oder?

Danke für die Mühe,
Lorenz

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lorenz Hopfmüller wrote:

> Sobald ich aber sei() nicht mehr auskommentiert habe, bleibt die LED an.
> Verhängt sich mein ATMega8 auf der Suche nach einer Interruptfunktion?

Richtige Vermutung. Die ISR für den Timer0 Overflow fehlt.

#include <avr/io.h>
#define F_CPU 3686400 
#include <avr/interrupt.h>
#include <util/delay.h>

volatile uint8_t counter;

int main(void) 
{
    DDRD = 0xFF;

    // Timer Overflow Interrupt freischalten  
    TIMSK |= (1 << TOIE0);  
    // Vorteiler 1024 -> Timerfrequenz 3,6 kHz -> 71ms Überlaufperiode
    TCCR0 |= (1 << CS02) | (1<<CS00);  
    // Interrupts freigeben
    sei();

    PORTD = 0xFF;
    
    while(1) 
    {
      // für immer...
    }
}

ISR(TIMER0_OVF_vect)
{
    PORTD ^= 0xff;    // LED toggeln
}


Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit dem counter funktioniert das im Simulator:

#include <avr/io.h>
#define F_CPU 3686400 
#include <avr/interrupt.h>
#include <util/delay.h>

volatile uint8_t counter;

int main(void) 
{
    DDRD = 0xFF;

    // Timer Overflow Interrupt freischalten  
    TIMSK |= (1 << TOIE0);  
    // Vorteiler 1024 -> Timerfrequenz 3,6 kHz -> 71ms Überlaufperiode
    TCCR0 |= (1 << CS02) | (1<<CS00);  
    // Interrupts freigeben
    sei();

    PORTD = 0xFF;
    
    while(1) 
    {
        if (counter >= 10)
        {
            counter = 0;
            PORTD ^= 0xff;    // LED toggeln
        }
    }
}

ISR(TIMER0_OVF_vect)
{
    counter++;
}


Testen könnte ich es auf einem Atmega8, allerdings mit 12 MHz. Hilft dir 
das?

Autor: Lorenz Hopfmüller (lolo)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

dein Code bringt leider auch nichts, die LED bleibt in beiden Fällen an.
Ich habe aber heute Morgen nochmal das Datenblatt gewälzt, und bin dabei 
auf folgendes gestoßen:

Mit meinen Fuse-Bits, die noch auf Werkseinstellung sind, ergibt sich 
laut dem Datenblatt 
http://atmel.com/dyn/resources/prod_documents/doc2486.pdf , Tabelle 19, 
für die Interrupt-Vektor-Startadresse 0x001. Ich habe folgendes 
Minimalbeispiel mit "avr-gcc -mmcu=atmega8 miniinterrupt.c" kompiliert 
und den Disassembler avrdisas 
(http://www.johannes-bauer.com/avruc/index.php) drüberlaufen lassen. Der 
Output ist angehängt, der Code kommt hier:
#include <avr/interrupt.h>
int main() { }
ISR(INT0_vect) { }
ISR(INT1_vect) { }
Die Interrupt-Vektoren, zu erkennen an der langen Reihe von rjmps, von 
denen der 2. und der 3., also INT0 und INT1 (-> Datenblatt S.47) auf 
"eigene" Funktionen zeigen, sind nicht etwa an 0x01, sondern an 0x54! 
Kein Wunder, dass der ATMega8 beim Sprung dahin, wo er die Vektoren 
vermutet, in einen undefinierten Zustand übergeht.
Ich habe das natürlich auch mit "vernünftigen" Code ausprobiert, mit dem 
Beispiel aus meinem ersten Posting sind die Vektoren an 0x74.

Entweder habe also ich etwas mit den Interrupt-Vektoren-Adressen 
gründlich missverstanden, oder mein avr-gcc schert sich keinen Deut 
darum, dass diese Vektoren an einer bestimmten Adresse stehen müssen, 
und nicht einfach irgendwo im Speicher. Wie kann ich dem gcc in dieser 
Hinsicht Manieren beibringen? Ist vielleicht meine avr-libc-Version eine 
verkorkste?

Ich wäre dir, Stefan, sehr dankbar, wenn du das mal auf deinem ATMega8 
testen könntest. Toll wäre es auch, wenn du die Binary hier mal posten 
könntest, dann kann ich das mal mit einer anderen gcc-Version testen.

Danke für die Mühe,
Lorenz

Autor: Stefan B. (stefan) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Lorenz Hopfmüller wrote:

> Ich wäre dir, Stefan, sehr dankbar, wenn du das mal auf deinem ATMega8
> testen könntest. Toll wäre es auch, wenn du die Binary hier mal posten
> könntest, dann kann ich das mal mit einer anderen gcc-Version testen.

Binary zu diesem Quellcode im Anhang:
(AVR-Studio 4.12 SP2, WinAVR 20071221)

Ich habe nur eine LED an PD5 auf dem [[Pollin 
Funk-AVR-Evaluationsboard]] zur Anzeige benutzt.

// MCU = atmega8
// F_CPU 1000000 in AVR Studio oder Makefile eingestellt

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t counter;

int main(void) 
{
    DDRD = (1<<PD5);

    // Timer Overflow Interrupt freischalten  
    TIMSK |= (1 << TOIE0);  
    // Vorteiler 1024 -> Timerfrequenz 3,6 kHz -> 71ms Überlaufperiode
    TCCR0 |= (1 << CS02) | (1<<CS00);  
    // Interrupts freigeben
    sei();

    PORTD = (1<<PD5);
    
    while(1) 
    {
        if (counter >= 10)
        {
            counter = 0;
            PORTD ^= (1<<PD5);    // LED toggeln
        }
    }
}

ISR(TIMER0_OVF_vect)
{
    counter++;
}


Die LED blinkt fröhlich vor sich hin. Etwas hektisch, da das Board 12 
MHz hat. Ändere ich den Vergleich im if auf >= 10*12, ist es ein 
schönes, langsames Blinken Pi*Daumen im 1s/1s Takt.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Lorenz Hopfmüller:

Das a.out ist kein reines BIN-File (das müsste man daraus erst noch 
extrahieren). Sieht so aus, also würde dein Disassembler damit nicht 
klar kommen. Er versucht wohl, die Zusatzinhalte in der Datei ebenfalls 
zu disassemblieren.

Autor: Lorenz Hopfmüller (lolo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

@Stefan B.: Blinkt auch bei mir, danke!
@Stefan Ernst: Uups, das hatte ich nicht gewusst. Ich hatte bisher immer 
die a.out auf den ATMega8 gebrannt, kein Wunder, dass das nicht ging. 
Ein wenig peinlich...
Ich kompiliere jetzt mit
avr-gcc -Os -mmcu=atmega8 $1.c
avr-objcopy -O ihex a.out a.hex
 und brenne mit
avrdude -p m8 -c sp12 -U flash:w:a.hex -v -E noreset,vcc

Danke für die Fehlersuche, das Problem befand sich etwa 40cm vom 
Bildschirm entfernt. Was mich noch wundert: Wieso funktionierten alle 
Programme, die keine Interrupts benutzen?

Danke,
Lorenz

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lorenz Hopfmüller wrote:

> Was mich noch wundert: Wieso funktionierten alle
> Programme, die keine Interrupts benutzen?

Zufall. Der Prozessor "wurschtelt" sich anscheinend irgendwie durch den 
Müll am Anfang (was macht ein AVR eigentlich bei einem ungültigen 
Opcode?). Der eigentliche Code enthält nur relative Sprünge, so dass es 
unproblematisch weitergeht, wenn er diesen erstmal erreicht hat. 
Initialisierte globale Variablen gibt es auch nicht (die würden nämlich 
mit falschen Werten initialisiert werden). Stört also eigentlich "nur", 
dass die Interruptvektortabelle nicht an der richtigen Stelle sitzt. ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.