Ein großes Array in C18 führt zum Zurücksetzen des Geräts

7

Ich verwende den PIC18F13K22 und den C18-Compiler von Microchip in MPLABX. Der PIC wurde immer wieder zurückgesetzt, als er in die Interrupt-Serviceroutine (ISR) springen wollte. Ich konnte das Problem bis zur Deklaration eines Arrays zurückverfolgen:

UINT16 rom periods[] = {64000,59412,55438,51962, ...} // 1024 Values

Wenn ich die Größe des Arrays auf wenige Elemente verkleinere, wird der PIC ausgeführt, ohne kontinuierlich zurückgesetzt zu werden.

Jetzt frage ich mich, warum das große Array einen Reset verursacht. Und noch interessanter für mich: Kann ich irgendwie einen Datensatz deklarieren, der diese 1024 Werte enthält?


Die angeforderten Abschnittsinformationen:

              Section       Type    Address   Location Size(Bytes)
            ---------  ---------  ---------  ---------  ---------
           _entry_scn       code   0x000000    program   0x000006
               .cinit    romdata   0x000006    program   0x000002
      .romdata_Main.o    romdata   0x000008    program   0x000800
         .code_Main.o       code   0x000808    program   0x000124
           _cinit_scn       code   0x00092c    program   0x00009e
        .code_Debug.o       code   0x0009ca    program   0x000080
       .code_Signal.o       code   0x000a4a    program   0x000040
                 PROG       code   0x000a8a    program   0x00003c
       .code_t0open.o       code   0x000ac6    program   0x000038
          .code_ADC.o       code   0x000afe    program   0x000032
         .stringtable    romdata   0x000b30    program   0x000026
                .code       code   0x000b56    program   0x000020
         _startup_scn       code   0x000b76    program   0x00001c
       .code___init.o       code   0x000b92    program   0x000002
    .romdata_t0open.o    romdata   0x000b94    program   0x000000
    .idata___init.o_i    romdata   0x000b94    program   0x000000
    .idata_t0open.o_i    romdata   0x000b94    program   0x000000
     .romdata_Debug.o    romdata   0x000b94    program   0x000000
     .idata_Debug.o_i    romdata   0x000b94    program   0x000000
    .romdata___init.o    romdata   0x000b94    program   0x000000
    .romdata_Signal.o    romdata   0x000b94    program   0x000000
    .idata_Signal.o_i    romdata   0x000b94    program   0x000000
      .idata_Main.o_i    romdata   0x000b94    program   0x000000
       .romdata_ADC.o    romdata   0x000b94    program   0x000000
       .idata_ADC.o_i    romdata   0x000b94    program   0x000000
        .code_c018i.o       code   0x000b94    program   0x000000
     .romdata_c018i.o    romdata   0x000b94    program   0x000000
     .idata_c018i.o_i    romdata   0x000b94    program   0x000000
.config_300001_Main.o    romdata   0x300001    program   0x000001
.config_300002_Main.o    romdata   0x300002    program   0x000001
.config_300003_Main.o    romdata   0x300003    program   0x000001
.config_300005_Main.o    romdata   0x300005    program   0x000001
.config_300006_Main.o    romdata   0x300006    program   0x000001
            MATH_DATA      udata   0x000000       data   0x000014
             .tmpdata      udata   0x000014       data   0x000000
               .stack      udata   0x000060       data   0x000050
       .udata_c018i.o      udata   0x0000b0       data   0x00000a
      .udata_Signal.o      udata   0x0000ba       data   0x000002
       .idata_c018i.o      idata   0x0000bc       data   0x000000
         .udata_ADC.o      udata   0x0000bc       data   0x000000
         .idata_ADC.o      idata   0x0000bc       data   0x000000
        .udata_Main.o      udata   0x0000bc       data   0x000000
        .idata_Main.o      idata   0x0000bc       data   0x000000
      .idata_Signal.o      idata   0x0000bc       data   0x000000
       .udata_Debug.o      udata   0x0000bc       data   0x000000
       .idata_Debug.o      idata   0x0000bc       data   0x000000
      .udata_t0open.o      udata   0x0000bc       data   0x000000
      .idata_t0open.o      idata   0x0000bc       data   0x000000
      .udata___init.o      udata   0x0000bc       data   0x000000
      .idata___init.o      idata   0x0000bc       data   0x000000
        SFR_UNBANKED0      udata   0x000f68       data   0x000098
PetPaulsen
quelle

Antworten:

8

Es gibt keinen inhärenten Grund, warum dieses Array einen Reset verursachen sollte. Sie deklarieren anscheinend 2 kByte Konstanten im Programmspeicher. Dieser PIC hat 8 kByte Programmspeicher, das sollte also in Ordnung sein.

Wahrscheinlicher ist, dass es anderswo einen Fehler gibt. Dieses Array ist wahrscheinlich das größte Element, das der Linker platzieren muss, sodass sich der gesamte Code, der sich nicht an bestimmten festen Adressen befindet, wahrscheinlich ändert, wenn die Array-Größe geändert wird, wodurch einige Fehler auftreten und verschwinden können.

Es kann nützlich sein, den Teil "Abschnittsinfo" der Linker-MAP-Datei anzuzeigen, damit wir sehen können, was wo gelandet ist. Versuchen Sie auch, dies mit dem Simulator durchzugehen, und prüfen Sie, ob Sie am Ende unbeabsichtigte Speicherorte oder ähnliches ausführen.

Hinzugefügt:

Mit dem Schlüsselwort "rom" wollten Sie offensichtlich, dass sich dieses Array im Programmspeicher befindet. Stellen Sie sicher, dass der C-Compiler dies richtig verstanden hat. Ich benutze C18 selten und erinnere mich nicht an die richtigen Beschwörungsformeln, um Konstanten im Programmspeicher zu definieren. Wenn der Compiler es nicht dort ablegt, können alle möglichen seltsamen Dinge passieren. Auch hier würde die Linker-Map-Datei dies aufklären.

Hinzugefügt 2:

Jetzt, wo wir eine Linker-Map-Datei haben, können wir das Problem sehen. 1024 Wörter mit jeweils 16 Bits sind 2048 Bytes, was 800 Stunden entspricht. Es gibt nur einen Abschnitt in der Nähe dieser Größe, und er hat genau 800 Stunden Byte. Der Compiler hat also verstanden, ihn in den Programmspeicher zu stellen. Beachten Sie jedoch, dass es an Adresse 8 platziert ist. Dies ist die Interrupt-Vektoradresse mit einfacher oder hoher Priorität. Dieses Array überlappt auch die Interrupt-Adresse mit niedriger Priorität bei 16, sodass Interrupts in beiden Fällen nicht dort verwendet werden können, wo dieses Array platziert wurde.

Die Tatsache, dass der Linker das Array dort platziert hat, wo es war, bedeutet, dass nichts anderes die feste Adresse eines der Interruptvektoren beansprucht. Ich verwende C nicht für Interrupt-Routinen, aber dies sagt mir, dass der C-Compiler nicht versteht, dass Ihre Interrupt-Routine tatsächlich eine Interrupt-Routine ist oder nicht in der Verknüpfung enthalten war.

Ich weiß nicht, wie Sie das Interrupt-Routinemodul genannt haben, aber ist es überhaupt in der Link-Map aufgeführt? Wenn ja, haben Sie vergessen, die richtige Beschwörung zu murmeln, damit der Compiler weiß, dass es sich um eine Interrupt-Routine handelt, und sie dadurch an eine bestimmte Adresse erzwingen. Wenn nicht, wird es irgendwie nicht in den Link aufgenommen. Dies kann passieren, wenn Sie alle Objektdateien in einer Bibliothek ablegen, damit der Linker auswählen kann, was er möchte, und keine externen Elemente des Interrupt-Moduls fehlen. Dies kann bei einem Interrupt-Modul passieren, da es niemals explizit aufgerufen wird. In diesem Fall muss die Interrupt-Modul-Objektdatei explizit an den Linker übergeben werden.

Olin Lathrop
quelle
Ich habe die Abschnittsinfo hinzugefügt. '.romdata_Main.o' 2024 Bytes werden an die Adresse 0x0008 gestellt. Ist das nicht die Interrupt-Vektoradresse? Das würde erklären, warum es zurückgesetzt wird, wenn ein Interrupt
ausgelöst
Ich danke dir sehr! Jetzt kann ich dieses Problem zumindest umgehen .
PetPaulsen
0

Aufgrund von Olins Antwort konnte ich das Problem beseitigen.

Wie Olin geschrieben hat, platziert der Linker das Array unter der Adresse 0x08. Dies ist die Interrupt-Vektoradresse.

Eine "Problemumgehung" besteht nun darin, Code explizit an der Adresse 0x08 zu platzieren, die zum ISR springt. (Inspiriert von der C18-Bedienungsanleitung Seite 29):

void isr(void);

#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
  _asm GOTO isr _endasm
}
#pragma code
#pragma interrupt isr
void isr (void)
{
  /* ... */
}

oder noch einfacher:

#pragma code high_vector=0x08
#pragma interrupt isr
void isr()
{
  /* ... */
}
PetPaulsen
quelle
1
Es ist der Linker , der das Array auf 8 setzt, nicht der Compiler. Wie gesagt, ich verwende keinen Compiler für Interrupt-Code, aber ich bin überrascht, dass der Compiler die Routine oder zumindest einen Stub nicht für Sie auf den festen Interrupt-Vektor setzt. Wenn Sie den Asm-Stub jedoch auf 8 setzen können, warum können Sie dann die Interrupt-Routine selbst nicht auf 8 setzen, anstatt denselben Mechanismus zu verwenden? Auf diese Weise sollten Sie überhaupt keinen Stummel brauchen.
Olin Lathrop
@Olin Lathrop - Du hast recht ... Ich kann die isr auf 0x08 setzen. Keine Notwendigkeit für einen Stummel. Aber immer noch seltsam, dass ich dem Linker sagen muss, dass ich nicht möchte, dass der Interrupt-Vektor von einigen Daten überschrieben wird.
PetPaulsen
Sie sagen dem Linker nicht wirklich, dass Sie den Interrupt-Vektor nicht überschreiben möchten, sondern in diesem Fall, dass Sie diesen Code an einer bestimmten Adresse haben möchten. Wenn Sie das nicht sagen, kann der Linker die Dinge überall platzieren, was in diesem Fall dazu führte, dass Ihr Array bei 8 lag. Es hätte genauso gut etwas anderes geben können. Dieses Problem hatte nichts mit Ihrem Array zu tun, aber Sie haben nicht genau festgelegt, wohin die Interrupt-Routine gehen muss.
Olin Lathrop