Forum: Mikrocontroller und Digitale Elektronik Bootloader Interrupts "verbiegen"


von Mike (Gast)


Lesenswert?

Hi Leute,

ich versuche gerade ein kleines Programm funktiontauglich in den 
Bootloaderbereich zu bekommen. Es scheint aber dass ich irgendwie auf 
dem Schlauch stehe.

Ich benutze einen Atmega16 inc. AVR Studio

Folgendes Programm funktioniert ab Adresse 0x0000 so wie es soll.
PortA wechselt nach jedem empfangenen Byte über die UART seinen Zustand.

------------------------------------------------------------------------ 
-

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

volatile int debug = 0;

int main(void) {

  DDRA = 0xFF;
  SREG |= (1<<7);

  UCSRB |=  (1<<TXEN)  | (1<<RXEN);
  UCSRB |=  (1<<RXCIE);
  UBRRL= 26;  //Baud = 19200

  while(1) {
    if (debug%2)
      PORTA = 0x00;
    else
      PORTA = 0xFF;
  }
  return 0;
}

//****************************************

ISR ( USART_RXC_vect ) {
  while (!(UCSRA & (1<<RXC)));
  unsigned char dummy = UDR;
  debug++;
}
------------------------------------------------------------------------ 
-

Ok, nun will ich das Programm samt Vektortabelle verschieben.

Dafür habe ich das Linker Script um die Option -Ttext=0x3800 erweitert.
Wenn ich das Hex File auslese, steht der Code auch an der richtigen 
Stelle im Flash und nicht mehr an Adresse 0x0000.

Um die Vektoren mit zu verschieben habe ich den Code um die Zeilen
GICR = (1<<IVCE);
GICR = (1<<IVSEL);
direkt unter "int main(void) {" erweitert

In den Fuses
Häckchen bei BOOTRST
BootSZ = Boot Flash Size=1024 words start address=$1C00

Hoffe jemand kann mir einen Hinweis geben.

MFG
Mike

von ARM dran (Gast)


Lesenswert?

Mike schrieb:
> Wenn ich das Hex File auslese, steht der Code auch an der richtigen
> Stelle im Flash und nicht mehr an Adresse 0x0000.

Steht auch die ISR, bzw der Sprung in die ISR an der richtigen Stelle?

Mike schrieb:
> GICR = (1<<IVCE);
> GICR = (1<<IVSEL);


Mal den Compiler-Output (disassembler) kontrolliert?
IVSEL-Setzen erfordert eine "Timed Sequence", das kann dieses Codestück 
nicht garantieren.
Ggfs per Inline-ASM machen.

von Mike (Gast)


Lesenswert?

>Steht auch die ISR, bzw der Sprung in die ISR an der richtigen Stelle?
Wie kann ich im Hexfile explizit nach dem ISR Eintrag schauen?

>Mal den Compiler-Output (disassembler) kontrolliert?
>IVSEL-Setzen erfordert eine "Timed Sequence", das kann dieses Codestück
>nicht garantieren.
>Ggfs per Inline-ASM machen.
Das hatte ich auch schon gelesen. Da aber der C Code auch im Datenblatt 
steht und ich die Codeoptimierung auf O0 gestellt habe, ging ich davon 
aus dass das auch richtig funktionieren sollte.

Bin gerade dabei alles ohne Interrupts zu machen, brauche nicht 
unbedingt welche deswegen ist es wohl ohnehin besser.

Würde das aber dennoch gerne geklärt haben ...
mit ASM habe ich noch nie was gemacht. Auf die Schnelle habe ich mal 
folgendes versucht.

asm volatile (
   "ldi r16, (1<<IVCE)   \n\t"
   "out GICR, r16  \n\t"
   "ldi r16, (1<<IVSEL)  \n\t"
   "out GICR, r16  \n\t"
);

Bringt ne komische Fehlermeldung im AVR Studio
ccvbfsXd.s:43: Error: constant value required

Hier verstehe ich gar nichts mehr :)

von Thomas E. (thomase)


Lesenswert?

Mach's mal so:
                  //Application
    unsigned char nTemp = GICR;
    GICR = nTemp | (1<<IVCE);
    GICR = nTemp & ~(1<<IVSEL);
bzw.
                  //Boot
    unsigned char nTemp = GICR;
    GICR = nTemp | (1<<IVCE);
    GICR = nTemp | (1<<IVSEL);

das funktioniert.

Warum so und nicht wie es im Datenblatt steht?

Das, was im Datenblatt steht ist einfach falsch. Das haben die bei Atmel 
auch irgendwann auch einmal selber erkannt und schreiben es bei den 
neueren Controllern richtig rein.

Bei dieser (falschen) Variante
                  GICR = (1<<IVCE);
                  GICR = (1<<IVSEL);
wird das Bit direkt im SFR geändert. Das geht aber nicht direkt, da man 
im SFR nicht rechnen kann. Das bedeutet Byte lesen >> im Akku ändern >> 
Byte wieder zurückschreiben. Sowas nannt man auch Read-Modify-Write. 
Davon kriegt man auch im Debugger nichts mit, da der CPU-Core das ganz 
von selbst so macht, dauert aber einfach zu lange. Sodaß die Lizenz zum 
Ändern schon abgelaufen ist, wenn man das IVSEL auf gleiche Weise 
verändert.

Bei der Variante oben wird das Byte vor Setzen des IVCE in ein Register 
geladen (Rx) und dort verändert. Im Gegensatz zum SFR kann ein Register 
Rx aber selber rechnen. Das ist dann keine Read-Modify-Write Operation 
sondern passiert in einem statt in 3 Taktzyklen im Register selber. 
Somit wird das IVSEL innerhalb von 4 Taktzyklen geändert.

Ob man das nun in C oder Assembler programmiert ist völlig belanglos.

Mfg

von Mike (Gast)


Angehängte Dateien:

Lesenswert?

@Thomas,

danke für die verständliche Erklärung.
Leider funktionieren die Interrupts bei mir immer noch nicht :(

Ich habe das noch mal mit einem Timer Interrupt versucht. Hier verhält 
es sich genauso. PORTA wechselt jede Sekunde seinen Zustand wenn ich das 
Programm ab 0x000 in den Flash schreibe.
Das gleiche Programm ab 0x3800 funktioniert dann nicht mehr.

Unten nochmal mein Code, im Anhang die 2 Hex Files ... vielleicht kann 
sich das mal jemand anschauen oder bei sich testen.

MFG
Mike

-----------

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

volatile int cnt = 0;

int main(void) {

    unsigned char nTemp = GICR;
    GICR = nTemp | (1<<IVCE);
    GICR = nTemp | (1<<IVSEL);

  DDRA = 0xFF;

  SREG |= (1<<7);

  TIMSK |= (1<<TOIE0);
  TCCR0 |= (1<<CS01);

  while(1) {
    PORTA = 0x00;
    while(cnt<10000);
    cnt = 0;
    PORTA = 0xFF;
    while(cnt<10000);
    cnt = 0;
  }
}

//-------------------------------------------------------------

ISR ( TIMER0_OVF_vect ) {
  TCNT0 = 162;
  cnt++;
}

von Mike (Gast)


Angehängte Dateien:

Lesenswert?

Nun funktioniert es.
Ich habe die Optimerung von -O0 auf -Os eingestellt.

Kann mir vielleicht jemand erklären warum der Code optimiert läuft und 
unoptimiert nicht ??

Im Anhang nochmal das optimierte Hexfile.

MFG

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.