Forum: Mikrocontroller und Digitale Elektronik Invalid opcode 0xffff at address 0x000f00


von Christopher C. (Gast)


Lesenswert?

Hi,

ich bräuchte dringend Hilfe. Derzeit arbeite ich an einem Programm für 
meinen AtMega8, dass mein Fahrzeug steuert, also zwei Motoren. Das 
Programm wäre soweit fertig, es müssen nur noch die Fehler raus ;). 
Allerdings komme ich nun nicht mehr weiter. Ich habe das Problem, dass 
sich mein Programm aus unbekannten Gründen immer wieder neu startet. Das 
kann ich über mein Serial Terminal Programm sehen, ich debugge über die 
UART. Vorhin gings noch ohne Problem, bevor ich einen Bug aus meiner 
Timer Komponente entfernte. Wenn ich den Simulator vom AVR Studio 4 
drüber laufen lasse, bekomme ich immer wieder die Nachricht "AVR 
Simulator: Invalid opcode 0xffff at address 0x000f00", was das bedeutet 
habe ich bereits heraus gefunden, mein Programm springt komischerweise 
immer wieder zur Addresse 0x000f00, wo aber nichts ist, nur warum 
springt es ins leere?? Ich verwende in meiner Timer Komponente nur 
einmal ein Array von Funktionszeigern, ansonsten werden keine eigenen 
Funktionssprünge von mir vorgenommen, außer von C. Das Programm ist 
recht groß geworden, weshalb ich vorerst nur die Timer Komponente zeigen 
werde.

Timer.h
1
#ifndef TIMER_H_
2
#define TIMER_H_
3
4
typedef enum Prescaler
5
{
6
  prescaler_1 = 0x01, prescaler_8 = 0x02, prescaler_64 = 0x03,
7
  prescaler_256 = 0x04, prescaler_1024 = 0x05
8
} Prescaler;
9
10
typedef void (*TimerHandler) (void);
11
12
void timerInit(Prescaler prescaler, bool ctcMode, uint8_t ctcValue);
13
void timerAddHandler(TimerHandler handler);
14
15
#endif /* TIMER_H_ */

Timer.c
1
#include "General.h"
2
#include <avr/interrupt.h>
3
#include "Timer.h"
4
5
TimerHandler timerHandlerArray[5];
6
uint8_t timerHandlerCount = 0;
7
8
void timerInit(Prescaler prescaler, bool ctcMode, uint8_t ctcValue)
9
{
10
  cli();
11
  timerHandlerCount = 0;
12
  TCCR0 = (prescaler << CS00); /* Set prescaler */
13
  if (ctcMode)
14
  {
15
    TCCR0 |= (1 << WGM01); /* Set ctc mode */
16
    OCR0 = ctcValue; /* Set ctc value */
17
  }
18
  TIMSK |= (1 << OCIE0); /* Allow TIMER0_COMPARE interrupt */
19
  sei();
20
}
21
22
void timerAddHandler(TimerHandler handler)
23
{
24
  if (timerHandlerCount > 4)
25
    error(errorToMuchTimerHandler);
26
  timerHandlerArray[timerHandlerCount] = handler;
27
  timerHandlerCount++;
28
}
29
30
/* TIMER0_COMPARE interrupt */
31
ISR(TIMER0_COMP_vect)
32
{
33
  int i;
34
  for (i=0;i<timerHandlerCount;i++)
35
  {
36
    timerHandlerArray[i](); /* Execute timerhandler */
37
  }
38
}

Ich habe leider überhaupt keine Ahnung, warum das passiert. Er startet 
solange neu bis das Array überläuft und es zum Fehler kommt, was 
ebenfalls schon merkwürdig ist, da bei Neustart timerHandlerCount immer 
wieder zurück gesetzt wird. Wenn das zuwenig werde ich den ganzen Code 
zeigen, aber die Initialisierung müsste Fehler frei sein.

Vielen Dank für die Hilfe

mfg

von Stefan E. (sternst)


Lesenswert?

Christopher C. schrieb:
> Wenn ich den Simulator vom AVR Studio 4
> drüber laufen lasse, bekomme ich immer wieder die Nachricht "AVR
> Simulator: Invalid opcode 0xffff at address 0x000f00"

Bist du sicher, dass du den richtigen Controller im Simulator ausgewählt 
hast?

von meckerziege (Gast)


Lesenswert?

Irgendwelche undefinierten Interrupts aktiviert ohne passende ISR?

von Christopher C. (Gast)


Lesenswert?

Der Controller ist richtig eingestellt. Ich lasse mir jetzt jedes mal, 
wenn die timerInit() Funktion aufgerufen wird, eine Nachricht schicken. 
Nun läuft das Array nicht mehr über, allerdings startet er immer noch 
wieder neu. Habe den Simulator wieder drüber laufen lassen. Jetzt 
bekomme ich die Nachricht "Stack pointer below start of RAM", das 
bedeutet doch das RAM voll ist O.o vom Stack, oder? Das wäre eine 
Erklärung für das Phänomen oder?

von Christopher C. (Gast)


Lesenswert?

> Irgendwelche undefinierten Interrupts aktiviert ohne passende ISR?

Eigentlich nicht, nur die Timer und UART Komponente rühren andere 
Register als die Input/Output an.

von Noname (Gast)


Lesenswert?

Das erste Problem ist, ersteinmal darüber klar zu sein, was denn den 
Jump/Gosub an diese Stelle versursachen kann.

Das kann mindestens zwei Ursachen habe:
1. Es werden mehr RETs ausgeführt als zuvor Gosubs ausgeführt wurden.
Bei einem C Programm unwahrscheinlicher als bei einem Assemblerprogramm.
2. Eine Variable respektive ein Array wird jenseits seiner Grösse 
geschrieben.
Das scheint mir hier wahrscheinlicher zu sein.

Deine timerAddHandler ist vermutlich so ein Kandidat, denn sie schreibt 
in das Array auch wenn der maximale Index längst erreicht ist.
Ich schreibe "vermutlich", da es möglich ist, das Deine error-Funktion 
den Return-Stack manipuliert um eben dieses Problem zu vermeiden. 
Schreib mal was dazu bzw. zeige uns die error-Funktion.

Ein anderer Angriffspunkt ist mal im Memory-Map File zu gucken was denn 
unmittelbar vor dem Stack als Variable deklieriert ist. Die Funktionen 
welche dieses Variable manipulieren solltest Du Dir mal anschauen.

von Stefan E. (sternst)


Lesenswert?

Christopher C. schrieb:
> Jetzt
> bekomme ich die Nachricht "Stack pointer below start of RAM", das
> bedeutet doch das RAM voll ist O.o vom Stack, oder?

Oder dass du doch den falschen Controller eingestellt hast, entweder im 
Simulator oder beim Compilieren (das sind zwei separate Einstellungen).

von Christopher C. (Gast)


Lesenswert?

Danke schon mal für die ganzen Antworten.
Ich hab noch mal geschaut, der Controller ist in den 
Projekteigenschaften sowie in "Select Platform and Device" richtig 
eingestellt. Ich verwende den ATMega8515 hab nur fälschlicherweise den 
ATMega8 angegeben, ist aber in den Einstellungen richtig.

Das ist die Error Funktion
1
void error(const uint8_t errorCode)
2
{
3
  char tmpStr[5];
4
  utoa(errorCode, tmpStr, 10);
5
  uartSendSyncMessage("ERROR: ");
6
  uartSendSyncMessage(tmpStr);
7
  while (1) {} /* Endlosschleife */
8
}
Eigentlich nichts verdächtiges, oder?

Wo kann ich die Memory-Map File finden?

von Noname (Gast)


Lesenswert?

>Wo kann ich die Memory-Map File finden?
Da wo es die Dokumentation sagt. ;-)

Jedenfalls wird nicht weiter in dieses Array geschrieben. OK.

Ein anderer Aspekt, der sich möglicherweise aber nicht auf Dein Problem 
bezieht, ist, was denn die uartSendSyncMessage-Funktion macht. 
Verwendest Du den UASRT per Interrupt oder per Polling? Zeig mal die 
Funktion bitte.

von Christopher C. (Gast)


Lesenswert?

1
void uartSendSyncChar(const char ch)
2
{
3
  while ( !(UCSRA & (1<<UDRE)) )
4
            {}
5
  UDR = ch;
6
}
7
8
void uartSendSyncMessage(char *msg)
9
{
10
  while (*msg)
11
  {
12
  while ( !(UCSRA & (1<<UDRE)) )
13
            {}
14
    UDR = *msg;
15
    msg++;
16
  }
17
  uartSendSyncChar(13);/* CR */
18
}

Ich such mal nach der Memory-Map File :).

von Stefan E. (sternst)


Lesenswert?

Christopher C. schrieb:
> Ich hab noch mal geschaut, der Controller ist in den
> Projekteigenschaften sowie in "Select Platform and Device" richtig
> eingestellt.

Dann sehe ich 3 Möglichkeiten (Reihenfolge nach Wahrscheinlichkeit):

1) Du legst selber irgendwo reichlich Daten auf den Stack (zeige 
zumindest mal main()).

2) Du hast irgendwo selbst geschriebenen fehlerhaften ASM-Code.

3) Bug im Compiler.

von Christopher C. (Gast)


Angehängte Dateien:

Lesenswert?

Also ein paar Daten lege ich schon auf den Stack, aber ganze 512 Bytes? 
Da es sehr umfachreich ist poste ich mal den ganzen Code.
ASM Code benutze ich nicht, reines C.

von Dietrich L. (dietrichl)


Lesenswert?

Christopher C. schrieb:
> uint8_t timerHandlerCount = 0;

Muss da nicht "volatile" hin wegen:

> ISR(TIMER0_COMP_vect)
> {
>   int i;
>   for (i=0;i<timerHandlerCount;i++)

Gruß Dietrich

von Christopher C. (Gast)


Lesenswert?

Oh stimmt, danke! Es ändert aber leider nicht das Problem.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

> TCCR0 |= (1 << WGM01);
> OCR0 = ctcValue;
> TIMSK |= (1 << OCIE0);

ATmega8 hat weder OCRO, TIMSK.OCIE0 noch TCCR0.WGMxx

Zudem ist das Setzen von timerHandlerArray nicht atomar.

von Christopher C. (Gast)


Lesenswert?

> ATmega8 hat weder OCRO, TIMSK.OCIE0 noch TCCR0.WGMxx
Das mag sein, aber ein ATMega8515 :).

> Zudem ist das Setzen von timerHandlerArray nicht atomar.
Stimmt das könnte unter Umständen gefährlich werden, ein cli() und ein 
sei() in timerAddHandler() dürfte helfen, oder?

von Stefan E. (sternst)


Lesenswert?

Christopher C. schrieb:
>> Zudem ist das Setzen von timerHandlerArray nicht atomar.
> Stimmt das könnte unter Umständen gefährlich werden, ein cli() und ein
> sei() in timerAddHandler() dürfte helfen, oder?

Nicht wirklich nötig. Der Interrupt erfährt ja erst durch das Erhöhen 
von timerHandlerCount von dem neuen Eintrag, da muss das Eintragen 
selber nicht atomar sein.

von Christopher C. (Gast)


Lesenswert?

Ich glaube, dass ich eine interessante Entdeckung gemacht habe. Ich habe 
noch mal den Simulator laufen lassen, er meldet wieder "Stack pointer 
below start of RAM" und hält bei
1
 TIMSK |= (1 << OCIE0); /* Allow TIMER0_COMPARE interrupt */
. Ich weiß, dass ich damals diesen Befehl fälschlicherweise in der If 
Abfrage hatte. Nun habe ich mal die Parameter überprüft, der Parameter: 
bool ctcMode ist false, obwohl er eigentlich true sein müsste. Beim 
ersten Aufruf ist er auch true, d.h. irgentwas stimmt da gewalltig 
nicht. Läuft der Mikrocontroller amok? Aber warum sind die ganzen 
Nachrichten über die UART in der richtigen Reihenfolge? Füllt der Stack 
den ganzen Speicher aus. Was meint ihr?

von Noname (Gast)


Lesenswert?

>Was meint ihr?
Nicht raten. Untersuchen. :-)

von Christopher C. (Gast)


Angehängte Dateien:

Lesenswert?

Ich weiß zwar nicht ob das so aussehen soll, aber es sieht nicht gut 
aus.
Warum sind da Strings im SRAM? Kommen die nicht in den Programmspeicher?

von Stefan E. (sternst)


Lesenswert?

An dem ersten Bild kann man sehen, dass du die libm.a nicht mitlinkst 
(was den RAM-Verbrauch drastisch erhöht). Unter "Libraries" hinzufügen 
und nochmal probieren.

von Noname (Gast)


Lesenswert?

@ Stefan Ernst
>An dem ersten Bild kann man sehen, dass du die libm.a nicht mitlinkst

Magst Du bitte etwas mehr im Detail erklären, woran man das sieht? Würde 
mich interessieren.

von Christopher C. (Gast)


Lesenswert?

Wow tatsächlich, das drückt den Speicherverbrauch drastisch und nun 
funktionierts sogar. Endlich. Also lags am vollen Speicher. Was genau 
macht den diese libm.a?

Vielen Dank ;)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Christopher C. schrieb:
>> ATmega8 hat weder OCRO, TIMSK.OCIE0 noch TCCR0.WGMxx
> Das mag sein, aber ein ATmega8515 :).

Ober schreibst du explizit ATmega8.

von Stefan E. (sternst)


Lesenswert?

Noname schrieb:
> @ Stefan Ernst
>>An dem ersten Bild kann man sehen, dass du die libm.a nicht mitlinkst
>
> Magst Du bitte etwas mehr im Detail erklären, woran man das sieht? Würde
> mich interessieren.

An dem auffälligen Muster:
01 02 02 03 03 03 03 04 04 04 04 04 04 04 04 ...
Das ist eine Lookup-Tabelle, die vom generischen Math-Code benutzt wird.

von Stefan E. (sternst)


Lesenswert?

Christopher C. schrieb:
> Was genau
> macht den diese libm.a?

Darin sind die für den AVR optimierten mathematischen Funktionen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:

> 01 02 02 03 03 03 03 04 04 04 04 04 04 04 04 ...
> Das ist eine Lookup-Tabelle, die vom generischen Math-Code benutzt wird.

Was aber auch mit libm passieren kann, siehe

http://gcc.gnu.org/PR29524 (behoben in 4.7.0)

von Christopher C. (Gast)


Lesenswert?

Johann L. schrieb:
>>> ATmega8 hat weder OCRO, TIMSK.OCIE0 noch TCCR0.WGMxx
>> Das mag sein, aber ein ATmega8515 :).

> Ober schreibst du explizit ATmega8.

Ja war ein kleiner Denkfehler.

> Ich verwende den ATMega8515 hab nur fälschlicherweise den ATMega8   angegeben, 
ist aber in den Einstellungen richtig.

Also vielen Dank noch mal ;)

von Noname (Gast)


Lesenswert?

Stefan Ernst schrieb:
>An dem auffälligen Muster...

Dankeschön.

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.