Hallo! Für ein Projekt an meiner Uni haben wir ein USBasp Board entworfen, dieses funktioniert soweit auch gut. Nun benötigen wir allerdings noch einen USB->RS232 Wandler, dieser Wandler soll allerdings auf dem gleichen Controller laufen! Ich habe mir das avr-cdc Projekt angesehen, dies läuft nach Anpassungen auch auf unserem Board. Doch wie bekomme ich nun beide Programme gleichzeitig auf den Controller? Eine Möglichkeit wäre ja meiner Meinung nach, ein Programm in den Bootloader zu packen, das andere vorne in den Flash. An den Anfang des "normalen" Programms kommt dann eine Jumper-Abfrage, entweder läuft das Programm normal weiter, oder aber es springt in den Bootloader und biegt die Interrupt Tabelle in den Bootloader. Wäre dies so möglich? Das Problem ist leider nun, dass avr-cdc ca. 2,5kB groß ist, die maximale Bootloadergröße im Atmega8 allerdings scheinbar nur 2kB ist?! Nun wird es etwas komplizierter: Ich habe mir überlegt ein kleines Bootloader-Programm zu schreiben, welches wiederum den "Programmauswahl-Jumper" abfragt und dann an die richtige Adresse zum ausgewählten Programm im Flash springt. (um das Programm an die richtige Stelle im Flash zu kriegen könnte ich doch ganz "unelegant" einfach hunderte "nop's" an den Anfang des Programms setzen oder? Die Interrupt Tabelle soll ja immer noch am Anfang stehen und auf die richtigen Adressen verweisen). Sollte nun das andere Programm ausgewählt werden, müsste ich an eine andere Stelle im Flash springen und vorher noch die Interrupt Tabelle anpassen, damit die Interrupts an die richtigen Stellen in eben diesem anderen Programm verweisen. Das Schreiben aus dem Bootloader heraus in die Interrupt Tabelle müsste doch möglich sein oder? Kann irgendjemand meine Idee nachvollziehen? ;) Wäre dies theoretisch möglich oder gibt es noch etwas was ich nicht berücksichtig habe? Viele Grüße Markus
Markus H. schrieb: > Für ein Projekt an meiner Uni haben wir ein USBasp Board entworfen, > dieses funktioniert soweit auch gut Und warum setzt ihr da so eine olle Atmega8-Gurke drauf? Mit einem pinkompatiblen Atmega328 und 4K Bootsektor wäre das alles einfacher. Markus H. schrieb: > unelegant" einfach hunderte "nop's" Dafür gibt es Sections. Damit kann man den Code da "hinschieben", wo man ihn haben will. Die Vektoren bleiben dabei vorne. "Attribute Section avr". Google das mal. mfg.
Hallo, danke für die Antwort. Leider ist es auch eine Kostenfrage welchen Controller wir einsetzen, da wir auch einige 100 Stück bestellt haben, und diese teilweise auch schon ausgegeben wurden. Daher wäre es schöner das ganze in Software anpassen zu können.. Ich habe mir mal ein paar Seiten zu "Section's" angesehen, allerdings finde ich nur Befehle wie --section-start=.text=0x1234, welche allerdings den gesamten Programmcode verschieben oder? Ich hätte ja gerne die Interrupt Tabelle noch am Anfang des Flashs, nur den "richtigen" Programmcode dann an einer anderen Stelle.
Markus H. schrieb: > finde ich nur Befehle wie --section-start=.text=0x1234, Das ist doch schon die halbe Miete. > welche allerdings den gesamten Programmcode verschieben oder? Gerade nicht. Erstmal ist das nur da und macht gar nichts. Im Makefile: ## Linker flags ... ... ... LDFLAGS += -Wl,-section-start=.blubb=0xe00 0xe00 ist eine BYTE-Adresse. entspicht der Word-Adresse 0x700. In AVR-Studio 4.x, Studio verweigere ich: >>Project >>Configuration Options >>Memory Settings <ADD> Memory Type: Flash Name: .blubb //Der Punkt ist wichtig Address: 0x700 //Hier wird die Wordadresse angegeben!!! >>OK >>OK Im Sourcecode: _attribute_ ((section (".blubb"))) void Delay(unsigned char nDelay) { for (unsigned char nInd = 0; nInd < nDelay; nInd++) _delay_ms(1); } Das __attribute.... muß vor jede Funktion geschrieben werden. im *.lss: _attribute_ ((section (".blubb"))) void Delay(unsigned char nDelay) { for (unsigned char nInd = 0; nInd < nDelay; nInd++) _delay_ms(1); e00: 90 e0 ldi r25, 0x00 ; 0 ^^^^ ohne __attri.... sieht das so aus: //__attribute__ ((section (".blubb"))) void Delay(unsigned char nDelay) { for (unsigned char nInd = 0; nInd < nDelay; nInd++) _delay_ms(1); 45c: 90 e0 ldi r25, 0x00 ; 0 ^^^^ Die Vektortabelle steht vorne, wo sie hingehört. mfg.
Also sind nur die Interrupts das Problem? Kann man per Software verzweigen mit ein paar inline-Assembler-Befehlen. Ein bisschen tricky, kostet auch etwas Zeit. Oder für alle doppelt benutzten Ints beide Programme in die ISR schreiben und direkt am Anfang Teil 1 oder 2 auswählen. Alternativ nach Programmstart und Jumperauswahl page0 mittels SPM passend beschreiben.
Thomas Eckmann schrieb: > In AVR-Studio 4.x, Studio verweigere ich: Das sollte Studio5 heissen. Ich kann das kaum schreiben. mfg.
Nun kommt beim Kompilieren eine Fehlermeldung: Error 2 section .prog loaded at [0000073e,000008c1] overlaps section .data loaded at [0000073e,0000073f] Wird die Position von .data schon durch irgendwas festgelegt? Oder wieso überschneidet sich das?
Sollte der USBasp nicht sowieso irgendwann mal auch einen USB-Seriell-Konverter beinhalten? Das lässt sich zumindest nach dem Schaltplan auf fischl vermuten... mfg mf
Warum meint eigentlich jeder Horst, in sein Projekt unbedingt einen USB-RS232 Konverter reinstopfen zu müssen? USB-RS232 Kabel gibts für 1-2 EUR auf eGay, also wozu das Theater? Oder schämen sich manche Leute, wenn ihre Superplatine einen DSUB Stecker anstatt einer USB Buchse hat?
Naja, leider ist "irgendwann" ein wenig zu spät für mich^^ In ca. 1 Monat muss das ganze laufen. Ich habe mal eine kleine Nachtschicht eingelegt und jetzt den USBasp, avr-cdc und den Bootloader zusammen im Flash. Ich habe einfach mit --section-start=.text=0x1100 den gesamten Programmcode des avr-cdc (incl. Interrupt-Table!) verschoben. Der USBasp liegt am Anfang des Flash, der Bootloader logischerweise ganz hinten. Im Bootloader wird nun ein Jumper abgefragt und dann entweder void (*start1)( void ) = 0x0000; oder void (*start2)( void ) = 0x0880; aufgerufen, der USBasp funktioniert auf diese Weise ohne Probleme, avr-cdc allerdings noch nicht, da ich die Interrupt-Tabelle am Anfang des Flash noch nicht modifiziere wenn ich den Programmteil des avr-cdc aufrufe. Eine Endlosschleife zum LED-Blinken am Anfang der main() des avr-cdc funktioniert aber. Die Modifikation der Interrupt-Table werde ich dann morgen noch versuchen. Die Schlüsselwörter dürften wohl "boot_page_write" und "boot_page_fill" sein oder? Oder ist es auch möglich nur einzelne Bytes zu schreiben, da ich (wenn ich es richtig überblickt habe) nur 2 Adressen verändern muss?
So, ich habe nun einmal versucht den Flash zu beschreiben, aber aus irgendeinem Grund schreibt er andere Daten hinein als ichs gerne hätte :( Das Programm lautet folgerndermaßen:
1 | unsigned char it1[] = { 0x3B,0xC0,0x39,0xC7,0x54,0xC0,0x53,0xC0,0x52,0xC0,0x51,0xC0,0x50,0xC0,0x4F,0xC0,0x4E,0xC0,0x4D,0xC0,0x4C,0xC0,0x4B,0xC0,0x4A,0xC0,0x49,0xC0,0x48,0xC0,0x47,0xC0,0x46,0xC0,0x45,0xC0,0x44,0xC0,0x04,0x03,0x09,0x04,0x1C,0x03,0x77,0x00,0x77,0x00,0x77,0x00,0x2E,0x00,0x66,0x00,0x69,0x00,0x73,0x00,0x63,0x00,0x68,0x00,0x6C,0x00}; |
2 | |
3 | void boot_program_page (uint32_t page, uint8_t *buf) { |
4 | uint8_t i; |
5 | uint8_t sreg; |
6 | |
7 | // Disable interrupts.
|
8 | sreg = SREG; |
9 | cli(); |
10 | eeprom_busy_wait (); |
11 | boot_page_erase (page); |
12 | boot_spm_busy_wait (); // Wait until the memory is erased. |
13 | |
14 | for (i=0; i<SPM_PAGESIZE; i+=2) { |
15 | // Set up little-endian word.
|
16 | uint16_t w = *buf++; |
17 | w += (*buf++) << 8; |
18 | boot_page_fill (page+i, w); |
19 | }
|
20 | |
21 | boot_page_write (page); // Store buffer in flash page. |
22 | boot_spm_busy_wait(); // Wait until the memory is written. |
23 | // Reenable RWW-section again. We need this if we want to jump back
|
24 | // to the application after bootloading.
|
25 | boot_rww_enable (); |
26 | // Re-enable interrupts (if they were ever enabled).
|
27 | SREG = sreg; |
28 | }
|
29 | |
30 | |
31 | |
32 | int main() |
33 | {
|
34 | void (*start1)( void ) = 0x0000; /* Funktionspointer auf 0x0000 */ |
35 | void (*start2)( void ) = 0x0880; /* Funktionspointer auf 0x0000 */ |
36 | |
37 | DDRC=(1<<PC1); |
38 | PORTC|=(1<<PC4); |
39 | _delay_ms(5); |
40 | |
41 | |
42 | boot_program_page(3200,it1); |
43 | while(1){} |
44 | start1(); |
45 | |
46 | return 0; |
47 | }
|
Die Daten die dann im Flash an Stelle 0x0C80 - 0x0CBF stehen sind: 118010C654401280000001000000054000804CC048804880004000000000054002C00140 44400400000004010000250000000E00420008002000210008002400 Dies passt doch nicht?! Erkennt jemand meinen Fehler oder etwas was ich nicht beachtet habe? Grüße Markus
Wenn ich dies:
1 | for (i=0; i<SPM_PAGESIZE; i+=2) { |
2 | // Set up little-endian word.
|
3 | uint16_t w = *buf++; |
4 | w += (*buf++) << 8; |
5 | |
6 | }
|
durch folgendes ersetze:
1 | for (i=0; i<SPM_PAGESIZE; i+=2) { |
2 | boot_page_fill (page+i, i+((i+1)<<8)); |
3 | }
|
steht das Richtige im Flash! Also funktioniert die Übergabe des Arrays nicht richtig?! Doch wo ist der Fehler?
Markus H. schrieb: > for (i=0; i<SPM_PAGESIZE; i+=2) { > // Set up little-endian word. > uint16_t w = *buf++; > w += (*buf++) << 8; > > } ich habe
1 | boot_page_fill (page+i, w); |
vergessen, dies steht natürlich auch noch in der For-Schleife...
@ Markus H. (Gast) >Leider ist es auch eine Kostenfrage welchen Controller wir einsetzen, da >wir auch einige 100 Stück bestellt haben, und diese teilweise auch schon >ausgegeben wurden. Daher wäre es schöner das ganze in Software anpassen >zu können.. Andere Leute bauen erstmal einen Prototypen, ehe sie tonnenweise Geld für eine (Klein)serie ausgeben.
Falk Brunner schrieb: > Andere Leute bauen erstmal einen Prototypen, ehe sie tonnenweise Geld > für eine (Klein)serie ausgeben. Das ganze war ja erst nur als Programmer gedacht, die Erweiterung mit dem RS232 Wandler kommt jetzt nachträglich dazu.
Markus H. schrieb: > Das ganze war ja erst nur als Programmer gedacht, die Erweiterung mit > dem RS232 Wandler kommt jetzt nachträglich dazu. Wie wäre es denn, wenn man die Sache so usbavrlab-mäßig aufzieht? Man könnte den usbasploader verwenden (Taster drücken beim Einstecken aktiviert ihn) und dann über avrdude die jeweilige gewünschte Firmware einspielen. Mache ich bei meinem usbasp so. Gruß Oliver
Es funktioniert! ;) War irgendwie n Krampf, ich weiß nich wieso er keine Lust auf meine Arrays hatte, ich habs jetzt einfach ganz unschön einfach mit 32 Befehlen hintereinander hart reingecodet, jetzt läufts aber ;) Solang keiner in den Sourcecode guckt :P Das funktioniert jetzt eigentlich wie ich oben beschrieben habe: Zuerst wird der Bootloader aufgerufen, dieser prüft per Jumper ob PC4 auf Masse gezogen ist oder nicht. Falls nicht, wird Page0 mit der Interrupt-Tabelle des USBasp beschrieben, dieser befindet sich "ganz normal" am Anfang des Flash, danach wird an Stelle 0 im Flash gesprungen und der USBasp startet. Sollte der Jumper PC4 auf Masse ziehen, wird Page0 mit einer modifizierten Interrupt Tabelle beschrieben, diese leitet alle Interrupts einfach auf die entsprechenden Einträge in der Interrupt-Tabelle des avr-cdc um, welcher ab Stelle 0c1100 im Flash steht. Dadurch habe ich 2 Sprünge für einen Interrupt, dies ist meiner Meinung nach aber besser, da ich so unabhängig den Sourcecode des avr-cdc anpassen kann und ich nicht die Sprünge vorne in der Tabelle anpassen muss weil sich evtl die Adressen der Interrupt Routinen des avr-cdc verändert haben. Falls jemand Interesse hat das Programm selber zu benutzen, habe ich mal die .hex-File angehängt.
Achso, vergessen zu erwähnen: Es müssen natürlich noch die passenden Fusebits eingestellt werden damit der Controller auch in den Bootloader geht. Bootloader Size ist 1kb, für den Atmega8 habe ich daher folgende Fusebits: hfuse: 0xCA lfuse: 0xFF
Markus H. schrieb: > Falls nicht, wird Page0 mit der Interrupt-Tabelle des USBasp > beschrieben, dieser befindet sich "ganz normal" am Anfang des Flash, > danach wird an Stelle 0 im Flash gesprungen und der USBasp startet. > Sollte der Jumper PC4 auf Masse ziehen, wird Page0 mit einer > modifizierten Interrupt Tabelle beschrieben, diese leitet alle > Interrupts einfach auf die entsprechenden Einträge in der > Interrupt-Tabelle des avr-cdc um, Schöner Ansatz. Man könnte noch vorher die bestehende und die zuschreibende Interrupt-Vector-Tabelle vergleichen und erst bei Ungleichheit eine neue schreiben. Das würde Schreibzyklen sparen. > Falls jemand Interesse hat das Programm selber zu benutzen, habe ich mal > die .hex-File angehängt Mir persönlich ist Quellcode lieber. Gruß Oliver
Oliver J. schrieb: > Schöner Ansatz. > Man könnte noch vorher die bestehende und die zuschreibende > Interrupt-Vector-Tabelle vergleichen und erst bei Ungleichheit eine neue > schreiben. Das würde Schreibzyklen sparen. Stimmt, gute Idee! Das könnte ich vielleicht auch noch einbauen. Meistens wird ja auch eh nich jedes mal gewechselt. Wobei der Atmega ja mindestens 10000 Schreibzyklen überlebt, das wäre bei einem täglichen 10fachen Wechsel immer noch ca. 3 Jahre, also würde auch reichen ;) Gut, dann werde ich mir mal pgm_read_byte() ansehen und gucken ob ichs hin kriege. Ich habe den Quellcode jetzt auch noch angehängt, solang ich nicht gleich von den Informatikern hingerichtet werde :D Ist äußerst unschön, wie gesagt gings mit dem Array irgendwie nich, selbst wenn ichs direkt in die "boot_program_page"-Funktion schreibe, ohne es als Parameter zu übergeben. Brauch jetzt so etwas mehr Platz, passt aber zum Glück noch alles rein. Beim Kompilieren drauf achten dass beim Linker die Startadresse 0xE00 (word) steht.
So, ich habs angepasst, jetzt wird nur noch bei Ungleichheit der Flash neu beschrieben. Habe außerdem noch eine Vereinfachung vorgenommen, da ich Adresse 0 (Sprung zu <__ctors_end>) ja auch mit der passenden Adresse überschreibe, brauche ich nicht mehr unterscheiden zu welcher Adresse ich zum Programmstart springen muss, ich starte einfach immer von Adresse 0, von dort wird dann an die richtige Stelle im Flash gesprungen. Falls jemand Lust hat den Code um 50 Bytes zu verkleinern, würde das ganze noch in einen Bootloader mit 512kB Größe passen ;) Irgendwie muss das mit dem Array ja doch funktionieren...
Und noch ein Update ;) Ich habs nochmal mit einem Array versucht, jetzt hats komischerweise geklappt. Bin jetzt auf 430 kB herunter gekommen, also Bootloader eine Stufe kleiner gemacht: hfuse: 0xCC lfuse: 0xFF
Wenn's nur der Code vom Bootloader ist, das Anbei compiliert bei mir zu 348 Bytes. In obigem Code sind für meinen Geschmack zu viel magische Zahlen drinne... Wenn ich mich recht erinnere gibt's im USBasp Ansätze für einen USB->UART Converter, die aber wohl nie komplett ausgeführt wurden. Die Basisfunktionalität zum USB-Handling gibt's im USBasp bereits, vielleicht ist es ja gar nicht sooo viel Arbeit, des Entsprechende Interface und Endpoints zu ergänzen. Am Protokoll selbst ändert sich doch nix, oder? Das zu erweitern wäre freilich kein Spaß, weil das Taktgenau in Assembler geschieht...
Vielen Dank für die Hilfe! Bei mir im AVR-Studio 5 kompiliert dein Code allerdings nicht, folgende Zeile ergibt den Fehler "Error 1 expected '=', ',', ';', 'asm' or '__attribute__' before 'uint8_t'" static const __flash uint8_t www_fischl[] = Und ich habe mal die lss vom Original USBasp mit den Werten verglichen die dein Bootloader dorthin schreibt, die stimmen allerdings nicht überein, damit dürfte das ganze doch nicht direkt so funktionieren oder? Page0 geht ja bis Adresse 0x40. Im Anhang ist die lss die beim Kompilieren des USBasp generiert wurde.
Markus H. schrieb: > Vielen Dank für die Hilfe! > > static const __flash uint8_t www_fischl[] = Ah, sorry für die Zeile. Für ältere Compilerversionen braucht du da PROGMEM + pgm_read. > Und ich habe mal die lss vom Original USBasp mit den Werten verglichen > die dein Bootloader dorthin schreibt, die stimmen allerdings nicht > überein, damit dürfte das ganze doch nicht direkt so funktionieren oder? Ich hatte mit Standardeinstllungen gelinkt, abgesehen von --defsym start=0 Wenn ich's recht sehe hat der Originalcode keine Daten in .progmem, der neue aber wohl. Hast du ein eigenes Linkerskript oder schubst Sections per Hand duch die Gegend, die .progmem nicht berücksichtigen? Ausserdem ist mein Code natütlich ungetestet und kann Tippfehler enthalten.
Johann L. schrieb: > Wenn ich's recht sehe hat der Originalcode keine Daten in .progmem, der > neue aber wohl. > > Hast du ein eigenes Linkerskript oder schubst Sections per Hand duch die > Gegend, die .progmem nicht berücksichtigen? Tut mir leid, ich versteh nich ganz was du meinst, ist das erste Projekt wo ich mich überhaupt mal mit dem Linker auseinander setze ;) Also ich habe einfach den Quellcode vom USBasp heruntergeladen und kompiliert (alles Standardeinstellungen) und mir dann die ersten 64 Byte des Hex-Files angesehen und die einfach mehr oder weniger in meinen Bootloader abgetippt (deshalb auch die undurchsichtigen Zahlenwerte), so dass dieser dann immer wieder den Originalcode wiederherstellen kann. Beim avr-cdc habe ich als Linker Option "-Wl,--section-start=.text=0x1100" angegeben, damit wird ja einfach der komplette Code an Stelle 0x1100 geschoben, incl. Interrupt Tabelle und allem. Diesen Wert habe ich einfach blind festgesetzt, ein paar Byte vorher ist ja der Code des USBasp zuende. Damit hatte ich dann USBasp und avr-cdc zusammen auf dem Controller, einfach hintereinander. Ansonsten habe ich nichts mit dem Linker gemacht, alles soweit Standardeinstellungen. Was mich an deinem Code jetzt gewundert hat, ist dass er ja scheinbar andere Werte an Page0 schreibt als ursprünglich vom USBasp dort drinstehen. Ich habe ja versucht 1:1 den Zustand wiederherzustellen, das einzige was sich beim avr-cdc Aufruf ändert sind die 2 Sprungbefehle vorne in der Interrupt Tabelle. Ich hoffe das war jetzt verständlich ;) Ich habe meinen Code ja jetzt mittlerweile auch <512 Byte, d.h. eine Verkleinerung bringt auch eh nix, solang man nicht unter die 256 Byte kommt um den Bootloader eine Stufe kleiner zu kriegen..
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.