C Grundlagen Bootloader

Hallo Jan,

ich hatte leider noch nicht so richtig die Zeit, mir den Sourcecode genauer anzusehen.

Ich habe so ein bisschen den Interrupt vom UART in Verdacht. Wenn der Bootloader wieder zur Applikation springt, schaltest du zwar die Interrupts global ab, aber eventuell ist noch ein Interruptflag gesetzt. Wenn du im Hauptprogramm Interrupt global aktivierst, wird dann sofort die Interrupt-Vektor-Tabelle angesprungen.

Falls es am Speicher liegt, schau dir mal deine beiden .hex Files von der Applikation und vom Bootloader an. Du kannst hierfür meinen AVR-Hex Viewer verwenden. Du siehst hier, wie der Speicher des AVR ausgenutzt ist und kannst kontrollieren, ob der Bootloader richtig positioniert ist.

Mehr Ideen habe ich im Moment leider nicht, ich könnte aber am Wochenende noch einmal genauer reinschauen.

Dirk :ciao:
 
Hallo Jan,

Ich habe so ein bisschen den Interrupt vom UART in Verdacht. Wenn der Bootloader wieder zur Applikation springt, schaltest du zwar die Interrupts global ab, aber eventuell ist noch ein Interruptflag gesetzt. Wenn du im Hauptprogramm Interrupt global aktivierst, wird dann sofort die Interrupt-Vektor-Tabelle angesprungen.
Dirk :ciao:

Wenn dem so sei, erklärt es aber nicht, wieso Zeichen ausgegeben werden die es überhaupt nicht sein sollten.
 
Habe dein Tool mal ausprobiert mit meiner Boot.hex
An Adresse 0x3800 steht wohl nichts oder wie kann ich das verstehen?
 

Anhänge

  • inspec_hex.jpg
    inspec_hex.jpg
    586,9 KB · Aufrufe: 4
Ich habe so ein bisschen den Interrupt vom UART in Verdacht. Wenn der Bootloader wieder zur Applikation springt, schaltest du zwar die Interrupts global ab, aber eventuell ist noch ein Interruptflag gesetzt. Wenn du im Hauptprogramm Interrupt global aktivierst, wird dann sofort die Interrupt-Vektor-Tabelle angesprungen.

UCSRA / B / C habe ich jeweils auf '0' gesetzt. Das hatte auch nichts gebracht.
 
UCSRA / B / C habe ich jeweils auf '0' gesetzt. Das hatte auch nichts gebracht.

Die Interruptanforderungsflags löscht man in der Regel mit setzen des Bits, nicht mit löschen.
Also eine 0 in das Register bringt hier nichts.
Setze die wichtigen Bits explizit (nach sei() und vor Verbiegen der IVT) bevor du in die Applikation springst.

Ob das mit den Interruptflags was bringt bzw. die Ursache ist, kann ich nicht sagen, aber verkehrt ist es nicht und schnell zu machen ist es auch.

Wegen der Bootloaderadresse:
0x3800 ist eine Wordadresse. Das Tool zeigt die Byteadresse an. Also 0x3800 x 2 nehmen.
Unten siehst du grafisch die Position des Bootloaders, das sieht schon mal recht gut aus.

Dirk :ciao:
 
Die Interruptanforderungsflags löscht man in der Regel mit setzen des Bits, nicht mit löschen.
Also eine 0 in das Register bringt hier nichts.
Setze die wichtigen Bits explizit (nach sei() und vor Verbiegen der IVT) bevor du in die Applikation springst.

upload_2017-9-15_6-35-31.png

Hier ist es doch anders?
 
RXC wird gelöscht, wenn der Receiver deaktiviert ist.
TXC ist eventuell ein Problem.

Möglicherweise macht das Probleme in der Appliation. Kannst es ja mal manuell löschen.

Ansonsten, was sagt die Speicherbelegung, wieviel Platz nimmt die Anwendung ein? Lade einfach mal beide Hexfiles nacheinander.
 
Hier ist es doch anders?
Welches der drei IRQ-Flags meinst Du denn konkret?
RXC und UDRE sind, wie man sehen kann "readonly", und sollten immer mit "0" beschrieben werden. Sollten, weil das Bit beim schreiben keine Relevanz hat. Es passiert einfach nichts.
TXC hingegen ist beschreibbar - schreibt man eine "0" passiert nix, schreibt man eine"1" wird das Flag gelöscht. Genau wie Dirk es sagte.

Im Datenblatt des Mega32 findest Du auf Seite 14:
There are basically two types of interrupts. The first type is triggered by an event that sets the Interrupt Flag. For these interrupts, the Program Counter is vectored to the actual Interrupt Vector in order to execute the interrupt handling routine, and hardware clears the corresponding Interrupt Flag. Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s) to be cleared. If an interrupt condition occurs while the corresponding interrupt enable bit is cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the flag is cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt Enable bit is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the global interrupt enable bit is set, and will then be executed by order of priority. The second type of interrupts will trigger as long as the interrupt condition is present. These interrupts do not necessarily have Interrupt Flags. If the interrupt condition disappears before the interrupt is enabled, the interrupt will not be triggered.
Eine weitere Ausnahme ist zB das Interruptflag des TWI (TWINT). Das gehört zwar eigentlich zum ersten Typen, wird aber nicht automatisch durch eintreten des Interruptes (automatisches Pushen des Program Counter auf den Stack, beladen des Program Counters mit dem Interrupteinsprungpunkt - also für Euch Hochsprachler quasi ein automatischer Call der IVT-Adresse) gelöscht. Hintergrund ist, daß TWINT auch die SCL "strecht", also solange stoppt, bis Du im Interrupt gehandelt hast. ZB um zu entscheiden, ob mit einem ACK oder einem NACK reagiert werden soll...
 
Zuletzt bearbeitet:
Kannst du dir das mal bitte anschauen? Habe die beiden .hex Files mit hochgeladen.
Bin aber der Meinung das dass alles passen sollte (habe davon ja jetzt nicht viel Ahnung..)
 

Anhänge

  • Hex.zip
    14 KB · Aufrufe: 2


CodeBox C
while(boot_state!=BOOT_STATE_EXIT);
uart_puts("* ->Reset now!\n\r" );
uart_puts("***********************\n\r" );
[I]_delay_ms[/I](500);

cli();

UCSRA |= (1<<TXC); // Clear TXC Flag

/* Interrupt Vektoren wieder gerade biegen */

temp = GICR;
GICR = temp | (1<<IVCE);
GICR = temp & ~(1<<IVSEL);

/* Reset */

start();



return 0;


@Dirk, du meinst das sicherlich so ? Das ist jetzt nur mal der Ausschnitt der denke Ich relevant ist.
 
Ja, so meinte ich das.

(wenn das Flag in UCSRA ist)

Der Bootloader startet bei 0x3800 (Word Adresse) also bei 0x7000 (Byte Adresse).

Die Fusebits müssen zu der Startadresse passen, in das Datenblatt habe ich nicht geschaut.

Zwischen Applikation und Bootloader ist noch recht viel Platz.

Bootloader:
upload_2017-9-15_8-48-18.png


Applikation:
upload_2017-9-15_8-55-21.png
 
Okay.. Also es muss an dem Bootloader liegen! Habe gerade den Bootloader und meine Applikation drauf gespielt und siehe das alles spackt wieder rum... UART und GLCD zeigen nur Blödsinn an. Ohne Bootloader ist alles so wie es sein sollte. ALSO BOOTLOADER..

Was kann da schief gehen? Was geht da schief? Einen harten Reset kann man nicht machen via. Watchdog, dann springt er wieder in den Bootloader. Gibt es noch eine andere Möglichkeit? Irgendwelche Register zurück setzen?
 
Frag doch im Bootloader einfach ab was den Reset ausgelöst hat. Wenn es der Watchdog war dann direkt zur Anwendung springen, so wie Dirk es schon sagte. Oder du definierst ein Pin wo ein Taster dran sitzt. Ist der beim Power-On Low dann direkt in die Anwendung springen, wenn High dann den Bootloader weiter ausführen.
 
Kann es nicht auch sein, dass wenn der Bootloader in die Applikation springt, dass im RAM noch irgendein Müll steht?
Diese Zeichen die ausgegeben werden, obwohl sie es nicht sollten, sind ja im RAM abgelegt. Das würde doch darauf schließen oder liege ich falsch?
 
Wie mehrfach angedeutet, gibt es zwei Möglichkeiten, den Loader zu verlassen: entweder zu Begin des Loaders, oder an dessen Ende. Durch einen Reset verläßt Du den Loader zwar auch, aber dann startest Du ihn ja sofort wieder.
Kann es nicht auch sein, dass wenn der Bootloader in die Applikation springt, dass im RAM noch irgendein Müll steht?
Nein, Es steht genau das drin, was der Loader da hinterläßt. Grundsätzlich mußt Du beim Start des Controllers immer(!) davon ausgehen, daß der Inhalt des SRAM undefiniert ist.
Die I/O-Register hingegen werden bei jedem Reset in ihren (ggf Fuse-abhängigen) initialen Zustand versetzt. Grundsätzlich kannst Du den Loader nur (sinnig) mit einem Sprung verlassen. Dabei verbleiben auch die I/O-Register genau so, wie der Loader sie hinterläßt.
Dirk läßt deswegen, wenn der Loader an das Hauptprogramm abgeben soll über den Watchdog einen Reset auslösen. Beim Reset werden die I/Os auf default gesetzt, danach startet logischerweise wieder der Loader (BOOTRST-Fuse). Dirk läßt im Loader als erstes prüfen, ob der Watchdog die Reset-Ursache war, und springt dann sofort nach 0x0000, also ohne daß der Loader irgendwas in den I/Os rummachen kann.
 
Hallo zusammen,

also ich denke mal nicht, dass der Bootloader fehlerhaft ist, er ist vom mikrocontroller.net Thema oder Tutorial, das ist auch anscheinend schon etwas älter. Wenn da Fehler aufgetreten wären, hätten sich sicher schon Anwender gemeldet.

Da der Bootloader anscheinend nichts anderes macht, als auf Kommandos warten und Page flashen, hätte ich den UART einfach nur pollen lassen. Aber egal, das ist "Geschmacksache".

Ich vermute, dass irgendetwas anderes "faul" ist.

Fuse bits und Bootloaderstartadresse (Projekteinstellung) ... scheinen zu stimmen.
Projekt nutzt auch den richtigen Mikrocontroller, für Applikation und Bootloader?
Gibt es irgendetwas wichtiges zu beachten von der Migration des Projekts von mc.net zum ATmega32A?
Wie wird der Mikrocontroller programmiert? Chip Erase, Bootloader programmieren, Applikation programmieren?

Mehr Ideen habe ich im Moment nicht, ich kann mir aber am Wochenende die Software noch einmal genauer ansehen. :)

Dirk :ciao:
 
Also.. Ich habe mein Programm mal minimiert.


CodeBox C
int main(void)
{
   uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,16e6));
   sei();

   while (1)
   {       
       uart_puts("************************************\r\n");
       uart_puts("* J.H-Elec. - Booty\r\n");
       uart_puts("* reset AVR and hold \"p\" for flash\r\n");
       uart_puts("************************************\r\n");

       if (uart_getc() == 'p')
       {
           bootloader();
       }
       
       _delay_ms(1500);               
   }
}

/* live the CPU?*/
ISR(TIMER1_COMPA_vect)
{
}


Jetzt wird nicht mehr gemacht als UART Ausgaben. Und es ist immer noch da. Was kann jetzt an dem Programm falsch sein?
 
Auch wenn ich es mit einem Watchdog reset versuche..



CodeBox C
    /* Intel-HEX Zieladresse */
   uint32_t        hex_addr = 0,
   /* Intel-HEX Zieladress-Offset */
   hex_addr_offset = 0,
   /* Zu schreibende Flash-Page */
   flash_page = 0;
   /* Empfangenes Zeichen + Statuscode */
   uint16_t        c = 0,
   /* Intel-HEX Checksumme zum Überprüfen des Daten */
   hex_check = 0,
   /* Positions zum Schreiben in der Datenpuffer */
   flash_cnt = 0;
   /* temporäre Variable */
   uint8_t         temp,
   /* Flag zum steuern des Programmiermodus */
   boot_state = BOOT_STATE_EXIT,
   /* Empfangszustandssteuerung */
   parser_state = PARSER_STATE_START,
   /* Flag zum ermitteln einer neuen Flash-Page */
   flash_page_flag = 1,
   /* Datenpuffer für die Hexdaten*/
   flash_data[SPM_PAGESIZE],
   /* Position zum Schreiben in den HEX-Puffer */
   hex_cnt = 0,
   /* Puffer für die Umwandlung der ASCII in Binärdaten */
   hex_buffer[5],
   /* Intel-HEX Datenlänge */
   hex_size = 0,
   /* Zähler für die empfangenen HEX-Daten einer Zeile */
   hex_data_cnt = 0,
   /* Intel-HEX Recordtype */
   hex_type = 0,
   /* empfangene HEX-Checksumme */
   hex_checksum=0;
   /* Funktionspointer auf 0x0000 */
   void (*start)( void ) = (void*)0x0000;   

   /* Füllen der Puffer mit definierten Werten */
   memset(hex_buffer, 0x00, sizeof(hex_buffer));
   memset(flash_data, 0xFF, sizeof(flash_data));

   /* Interrupt Vektoren verbiegen */
   temp = GICR;
   GICR = temp | (1<<IVCE);
   GICR = temp | (1<<IVSEL);
   
   /* Einstellen der Baudrate und aktivieren der Interrupts */
   uart_init( UART_BAUD_SELECT(BOOT_UART_BAUD_RATE,F_CPU) );
   sei();

   uart_puts("***********************\n\r"    );
   uart_puts("* J.H Elec-Booty\n\r"          );
   uart_puts("* press \"p\" for prog.\n\r"    );
   uart_puts("***********************\n\r"    );
   _delay_ms(500);
       
[COLOR=#ff0000][B]   if ((MCUCSR & (1<<WDRF)))[/B]
[B]   {[/B]
[B]       MCUCSR = 0x00;[/B]
[B]       uart_puts("Starting Application!\r\n");[/B]
[B]       _delay_ms(500);[/B]
[B]       start();[/B]
[B]   }[/B][/COLOR]




CodeBox C
    while(boot_state!=BOOT_STATE_EXIT);
   
   uart_puts("*  ->Reset now!\n\r"                );
   uart_puts("***********************\n\r"        );
   _delay_ms(500);
   
   /* Interrupt Vektoren wieder gerade biegen */
   temp = GICR;
   GICR = temp | (1<<IVCE);
   GICR = temp & ~(1<<IVSEL);
   
   /* Reset */
[COLOR=#ff0000][B]   wdt_enable(WDTO_15MS);[/B]
[B]   while(1){};[/B]
[B]   //start();[/B][/COLOR]
   
   return 0;
 
Hallo Jan,

was mir noch nicht ganz klar ist, nutzt der UART in der Applikation und im Bootloader überhaupt Interrupts oder werden die Flags gepollt?

Dies kann ich leider im Code nicht sehen. Ich vermute aber mal es wird gepollt?!

Falls nur gepollt wird, musst du im Bootloader die Interrupts erst gar nicht global aktivieren und die Interrupt-Vektor-Tabell muss nicht in den Bootloader gelegt werden. Es werden sonst ja keine Interrupts im Bootloader genutzt. Das wäre dann schon einfacher, man könnte den ganzen Bereich Interrupts als Fehlerquelle ausschließen, zumindest bezogen auf den Bootloader.

Also wenn gepollt wird folgendes entfernen bzw. auskommentieren ...



CodeBox C
sei()

temp = GICR;
GICR = temp | (1<<IVCE);
GICR = temp | (1<<IVSEL);

temp = GICR;
GICR = temp | (1<<IVCE);
GICR = temp & ~(1<<IVSEL);




Zu deinem Versuch mit dem Watchdog Reset:

Du springst zur Applikation mit global aktivierten Interrupts und auf den Bootloaderbereich verbogener Interrupt-Vektor-Tabelle und aktiviertem UART.

Prüfe mal vor memset() auf den Watchdog-Reset.

EDIT:
Du musst im Bootloader auch am Anfang den Watchdog deaktivieren, der läuft nämlich weiter und löst wieder ein Reset aus!
 
Zuletzt bearbeitet:
Hallo Dirk,

Leider laufen die Routinen alle mit Interrupt.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)