PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATMega8: Interrupts im Bootloader



Jaecko
25.11.2009, 10:56
Moin.

Ich versuche gerade, einen Bootloader mit einem Timer-Interrupt auszustatten, um die Möglichkeit eines Timeouts zu haben (falls die Kommunikation abreisst etc.)

Das Problem ist aber jetzt: Statt des Interrupts löst der Mega8 einen Reset aus.

Das erste was ja getan werden muss, ist ja die ISR-Tabelle in den Bootbereich zu legen. Das hab ich erst mit C versucht:


GICR |= (1 << IVCE); // Move interrupt table to boot section
GICR |= (1 << IVSEL);


aber auch mal direkt mit ASM, um wirklich die beiden Bits so eng wie möglich nacheinander zu setzen (muss ja innerhalb von 4 Zyklen passiert sein):


asm volatile (
"PUSH R24" "\n\t" // Save R24
"PUSH R25" "\n\t" // Save R25
"IN R24,0x3B" "\n\t" // GICR => R24
"IN R25,0x3B" "\n\t" // GICR => R25
"ORI R24, 0x01" "\n\t" // "GICR |= (1 << IVCE)"
"ORI R25, 0x03" "\n\t" // "GICR |= (1 << IVCE) | (1 << IVSEL)"
"OUT 0x3B, R24" "\n\t" // R24 => GICR
"OUT 0x3B, R25" "\n\t" // R25 => GICR
"PUSH R25" "\n\t" // Restore R25
"PUSH R24" "\n\t" // Restore R24
::);


Nächstes war der Verdacht, dass evtl. an der Timereinstellung was falsch ist.
Deshalb auch 2 Versuche; einmal als "normaler Timer":


TCCR1A = 0; // Standard timer (No Counting, No PWM)
TCCR1B = 0 | (1<<CS12); // Prescaler = 256
TCNT1 = 0xFFFF - 31250; // Preload value
TIMSK |= (1<<TOIE1);
sei();


und einmal als CTC:


TCNT1 = 0;
TCCR1B = (1<<WGM12); // CTC-Mode
TCCR1B |= (1<<CS12); // Prescaler 256 (normal operation)
OCR1A = 31250; // Counting value: // 8 MHz / Prescaler 256 = 31250
TIMSK |= (1<<OCIE1A); // Enable timer
sei();



Die ISRs sind natürlich beide definiert:



SIGNAL(SIG_OUTPUT_COMPARE1A) // = TIMER1_COMPA_vect
{
LED_Toggle(BLUE);
}

ISR (SIG_OVERFLOW1)
{
LED_Toggle(GREEN);
}


Beide LEDs machen jedoch nichts; es wird stattdessen ein Reset durchgeführt. Lt. Simulator im AVR-Studio wird die jeweilige ISR aber korrekt angesprungen. Verfracht ich das ganze in die normale App.-Section (also als normales Programm), dann klappt das ganze wunderbar.
Ohne Interrupts funktioniert auch der Bootloader problemlos.

aktivierte Fuses: SPIEN, EESAVE, BOOTSZ: 1024 Words (0x0C00), BOOTRST
Linker-Kommando: -Wl,--section-start=.text=0x1800

Hab ich für die Interrupts im Bootloader noch irgendwas übersehen?

mfG

sternst
25.11.2009, 11:34
Du hast im Datenblatt eine Kleinigkeit übersehen:

2. Within four cycles, write the desired value to IVSEL while writing a zero to IVCE

Ich würde es so machen:

uint8_t tmpGICR = GICR;
GICR = tmpGICR | (1 << IVCE);
GICR = tmpGICR | (1 << IVSEL);

Resultierender Code mit -Os ist dann:

uint8_t tmpGICR = GICR;
38: 8b b7 in r24, 0x3b ; 59
GICR = tmpGICR | (1 << IVCE);
3a: 98 2f mov r25, r24
3c: 91 60 ori r25, 0x01 ; 1
3e: 9b bf out 0x3b, r25 ; 59
GICR = tmpGICR | (1 << IVSEL);
40: 82 60 ori r24, 0x02 ; 2
42: 8b bf out 0x3b, r24 ; 59Das "four cycle"-Timing wird also eingehalten.

Jaecko
25.11.2009, 11:40
Arghl... stimmt. Das wars. Thx.
Jetzt läufts.