Ein großes Array in C18 verursacht einen Geräte-Reset

Ich verwende den PIC18F13K22 und den C18-Compiler von Microchip in MPLABX. Der PIC setzte sich immer wieder zurück, als er kurz davor war, in die Interrupt-Service-Routine (ISR) zu springen. Ich konnte das Problem auf die Deklaration eines Arrays zurückführen:

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

Wenn ich die Größe des Arrays auf wenige Elemente verkleinere, läuft der PIC ohne kontinuierliches Zurücksetzen.

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

Antworten (2)

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 an anderer Stelle einen Fehler gibt. Dieses Array ist wahrscheinlich das Größte, was der Linker platzieren muss, sodass sich der gesamte Code, der sich nicht an bestimmten festen Adressen befindet, wahrscheinlich bewegt, wenn die Arraygröße geändert wird, was dazu führen kann, dass einige Fehler auftreten und verschwinden.

Es könnte nützlich sein, den Teil "Section Info" der Linker-MAP-Datei anzuzeigen, damit wir sehen können, was wo gelandet ist. Versuchen Sie auch, dies mit dem Simulator zu durchlaufen, und sehen Sie, ob Sie am Ende unbeabsichtigte Orte oder ähnliches ausführen.

Hinzugefügt:

Aus dem Schlüsselwort "rom" geht hervor, dass Sie offensichtlich beabsichtigt haben, dass sich dieses Array im Programmspeicher befindet. Stellen Sie wirklich sicher, dass der C-Compiler dies richtig verstanden hat. Ich verwende C18 selten und erinnere mich nicht, was die richtigen Beschwörungsformeln sind, um Konstanten im Programmspeicher zu definieren. Wenn der Compiler es nicht dort abgelegt hat, könnten alle möglichen seltsamen Dinge passieren. Auch hier würde die Linker-Map-Datei dies klären.

2 hinzugefügt:

Jetzt, da wir eine Linker-Map-Datei haben, können wir das Problem erkennen. 1024 Worte zu je 16 Bit sind 2048 Byte, also 800 h. Es gibt nur einen Abschnitt in der Nähe dieser Größe, und es sind genau 800 h Bytes, also hat der Compiler es verstanden, ihn in den Programmspeicher zu legen. Beachten Sie jedoch, dass es an Adresse 8 platziert ist. Das ist die Interrupt-Vektoradresse mit einfacher oder hoher Priorität. Dieses Array überlappt auch die Interrupt-Adresse mit niedriger Priorität bei 16, so dass Interrupts so oder so nicht mit dem Ort verwendet werden können, an dem dieses Array platziert wurde.

Die Tatsache, dass der Linker das Array dort platziert hat, wo er es getan hat, bedeutet, dass nichts anderes die feste Adresse eines der beiden Interrupt-Vektoren beansprucht. Ich verwende C nicht für Interrupt-Routinen, aber das sagt mir, dass der C-Compiler nicht versteht, dass Ihre Interrupt-Routine tatsächlich eine Interrupt-Routine ist, oder dass sie nicht im Link enthalten war.

Ich weiß nicht, wie Sie das Interrupt-Routine-Modul genannt haben, aber ist es überhaupt in der Link-Map aufgeführt? Wenn ja, dann haben Sie vergessen, die richtige Beschwörung zu murmeln, damit der Compiler weiß, dass es sich um eine Interrupt-Routine handelt, und ihn dadurch zu einer bestimmten Adresse zwingt. Wenn nicht, dann ist es irgendwie nicht im Link enthalten. Dies kann passieren, wenn Sie alle Objektdateien in einer Bibliothek ablegen, damit der Linker auswählen kann, was er möchte, und es keine fehlenden Externals für das Interrupt-Modul gibt. Das kann bei einem Interrupt-Modul passieren, da es nie explizit aufgerufen wird. In diesem Fall muss die Objektdatei des Interrupt-Moduls explizit an den Linker übergeben werden.

Ich habe die Abschnittsinformationen hinzugefügt. '.romdata_Main.o' 2024 Bytes werden an Adresse 0x0008 platziert. Ist das nicht die Adresse des Interrupt-Vektors? Das würde erklären, warum es zurückgesetzt wird, wenn ein Interrupt ausgelöst wird ...
Ich danke dir sehr! Jetzt bin ich zumindest in der Lage, dieses Problem zu umgehen .

Durch Olins Antwort konnte ich das Problem beseitigen.

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

Ein 'Workaround' besteht nun darin, Code explizit an Adresse 0x08 zu platzieren, der zur 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()
{
  /* ... */
}
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 legt. Aber wenn Sie den asm-Stub auf 8 setzen können, warum können Sie dann nicht die Interrupt-Routine selbst auf 8 setzen, anstatt denselben Mechanismus zu verwenden? Auf diese Weise sollten Sie überhaupt keinen Stub benötigen.
@Olin Lathrop - Sie haben Recht ... Ich kann den ISR bei 0x08 platzieren. 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.
Sie sagen dem Linker nicht wirklich, dass Sie den Interrupt-Vektor nicht überschreiben möchten, sondern in diesem einen Fall, dass Sie diesen Code an einer bestimmten Adresse haben möchten. Wenn Sie das nicht sagen, steht es dem Linker frei, Dinge an beliebiger Stelle zu platzieren, was sich in diesem Fall zufällig mit Ihrem Array bei 8 ergab. Da hätte genauso gut etwas anderes sein können. Dieses Problem hatte nichts mit Ihrem Array zu tun, sondern damit, dass Sie nicht festgelegt haben, wohin die Interrupt-Routine gehen musste.