//--- INTTERRUPT Vector in den Bootloader verschieben --------------------------
15
/* Enable change of Interrupt Vectors */
16
MCUCR=(1<<IVCE);
17
/* Move interrupts to Boot Flash section */
18
MCUCR=(1<<IVSEL);
19
sei();
20
21
while(1){/* "BOOT Programm" Schleife */
22
/* später erfolgt hier die Abbruchbedingung */
23
}
24
return0;
25
26
//--- INTTERRUPT Vector in den Mainbereich verschieben ------------------------
27
cli();
28
CLEAR_BIT(MCUCR,IVCE);// Disable change of interrupt vectors
29
CLEAR_BIT(MCUCR,IVSEL);// Move interrupts to main flash section
30
31
asmvolatile("jmp 0x0000");
32
}
Nun meine Frage, wie bekomme ich eine ISR Routine für meinen Timer2
Overflow programmiert?
Ich weiß das es eine eigene Routine sein muß, ein Versuch wie...
[c]
ISR(BOOT_TIMER2_OVF_vect)
{
TCNT2 = TCNT2-18; // Startwert laden
/* mach was */
}
{/c]
Führte aber nicht zum Erfolg, wie ist der richtige Weg?
Hier kam immer eine Fehlermeldung "redefiniert" logisch, ich nutze den
ja auch im Main Programm...
Ich sehe das er auf Adress 0x10 springt aber das ist mitten im
MAIN_BOOTLOADER Abschnitt.... :-(
Danke für eure Hilfe, Tobi...
hallo,
du kannst ganz normal im bootloader interrupts benutzen. soe wie immer.
verschieben tust du die interrupts ja schon in die BLS. wichtig ist dann
nur noch, das gesamte geschütz per -Wl,--section-start=.text=0xirgendwas
an den beginn der BLS zu verschieben.
das mit dem "refefined" ist für mich nicht logisch. da fehlt wohl noch
etwas input.
bye kosmo
Puhh wie macht man das denn?
Ich nutze AVR Studio die aktuelle Version und "WinAVR-20070525rc2".
Ich habe ja im Mainprogramm schoneinmal eine ISR für den Timer2Ovf
deklariert deshalb meckert er halt.
Also Main sieht so aus...
1
ISR(TIMER2_OVF_vect)
2
{
3
TCNT2=TCNT2-18;// Startwert für }
4
/* mach was im main mit dem timer */
5
}
6
7
intmain(void){
8
/* was man so macht also Port's initialisieren usw. */
9
}
Das funktioniert auch soweit das es ja mein "normales" Programm ist.
Nun der Bootloader...
Dazu habe ich mir im AVR Studio unter den GCC Optionen das Segment
".bootloader" angelegt und gesagt es ist Adress 0x7000.
Soweit so gut...
Nun springt er nach dem Start in der Tat im Quelltext auf den Eintrag
"BOOTLOADER_SECTION"
Und beginnt mit der Abarbeitung, soweit ist mir das nun klar.
Jetz wollte ich hier in der BOOTLOADER_SECTION meine ISR Routine ablegen
welche ja in den geschützten Bereich muß, aber das bekomme ich nich
gebacken.... da gibt es entweder die Meldung:
../C-HelloWorld.c:1496: error: redefinition of '__vector_11'
Das dürfte wohl mein Problem sein, das ich nicht weiß wie man dem
compiler nun bei bringt das er die im Bottsector geschribenen ISR
Routinen nehmen soll...
Ich stell mich wohl einfach zu blöd an :(
Gruß Tobi...
zugegeben, ich kenne mich mit avr studio und den optionen da nicht aus.
aber eine ISR kannst du nur einmal definieren (wie alles übrigens).
warum nimmst du nicht die aus deiner main raus? zwei mains gehen schon
gar nicht, auch wenn du da mit der main-bootloader etwas rumtrickst.
Ich hab zwar die vorangegangenen Posts nur überflogen geb aber trotzdem
schnell mal was in den Ideentopf.
ISR Aufrufe sind ja im Allgemeinen so realisiert, dass in einem
bestimmten Speicherbereich die Sprungadressen zu den ISRs stehen was
auch Interrupt Vector Table genannt wird. Meistens wird diese im
Bootloader initialisiert was du ja wohl auch machst.
Nun kann man die Interrupt Vektoren natürlich auch zur Laufzeit ändern
indem man einfach die Sprungadressen ändert.
@OP: Wieso willst du unbedingt_ Bootloader und Anwendung _gleichzeitig
erstellen? Es reicht doch den Bootloader einzeln zu compilieren, zu
flashen und anschließend die eigentliche Anwendung (die du man mit dem
bootloader flashen kannst ;) ) -- was btw. oben schon erwähnt wurde.
Alternativ geht auch, dass du die .hex-Dateien aneinander hängst (wurde
hier im Forum schon besprochen, da muss die letzte Zeile gelöscht werden
--_glaub ich_).
hth. Jörg
Hi,
also ich glaube meine Lösung ist folgende, vlt. kann mich da noch jemand
anschubbsen?
Also nach dem WERT
BOOTLOADER_SECTION
da muß eine Aufstellung hin wo die Adressen der einzelnen Routinen
gespeichert ist.
In Assembler wüste ich wie es geht...
.equ BOOTGO = FOURTHBOOTSTART
.equ reti
.equ reti
.equ reti
.equ BOOT_TIMER2_OVFL
.equ reti
...das Vergleichstück in C ist mir nicht bekannt. :-(
Also so in etwa...
BOOTLOADER_SECTION (0x7000)
BOOT_MAIN (zum BOOT_MAIN springen)
BOOT_NO_USE (nur zurück springen)
BOOT_NO_USE (nur zurück springen)
BOOT_NO_USE (nur zurück springen)
BOOT_NO_USE (nur zurück springen)
BOOT_NO_USE (nur zurück springen)
BOOT_NO_USE (nur zurück springen)
BOOT_NO_USE (nur zurück springen)
BOOT_NO_USE (nur zurück springen)
BOOT_NO_USE (nur zurück springen)
BOOT_TIMER2_OVFL (zur BOOT_TIMER2_OVFL springen)
BOOT_NO_USE (nur zurück springen)
dann sollte es klappen... wie definiert man sowas in C?
Gruß Tobi...
Hmm also zum einen wird ein einfaches reti nicht reichen. Du wirst für
alle Interrupts die du aktivierst eine routine schreiben müssen die
mindestens das Interrupt Flag zurücksetzt bevor du reti machst. Sonst
landest du in einer Endlosschleife weil der Interrupt ständig ausgelöst
wird.
Ansonsten sind die Speicheradressen der Interrupt Vektoren fest
definiert.
Wo die genau sind musst du im Hardware Manual deines Controllers
nachlesen.
Da wird eine Tabelle drin sein die so aussehen könnte:
8 ,0x00E ,TIMER3 ,COMPA Timer/Counter3 Compare Match A
Und an die angegebenen Adressen musst du dann die Funktionspointer
deiner ISRs schreiben.
Hinter den Adressen stecken übrigens meistens Register, müssen also bei
jedem Start auf die richtigen Werte gesetzt werden.
Von daher deine Idee mit .equ nicht schlecht aber leider falsch.
wirst etwas machen müssen wie
hallo,
>Hinter den Adressen stecken übrigens meistens Register, müssen also bei>jedem Start auf die richtigen Werte gesetzt werden.
das stimmt doch nicht. das sind inhalte im befehlsspeicher, und der ist
fest/non-volatile. da wird nichts geladen, da wird einfach ein befehl
samt operand ausgeführt.
wie im handbuch zu lesen, kann man den platz der interrupts auch für was
anderes benutzen, so man denn nicht interrupts benutzt. sind die
interrupts aber an, wird der befehl an der entsprechenden stelle
gelesen, interpretiert und ausgeführt. im normalfall ein jmp.
bye kosmo
Hi Kosmo,
ja das stimmt auch... ich habe mir das file mal angesehen im
Disassembler...
Bei normalen Betrieb erzeugt der compiler die Einsprungadressen wie
folgt...
+00000000: 940C0169 JMP 0x00000169 Jump
+00000002: 940C0186 JMP 0x00000186 Jump
+00000004: 940C0186 JMP 0x00000186 Jump
+00000006: 940C0186 JMP 0x00000186 Jump
+00000008: 940C0186 JMP 0x00000186 Jump
+0000000A: 940C0186 JMP 0x00000186 Jump
+0000000C: 940C0186 JMP 0x00000186 Jump
+0000000E: 940C0186 JMP 0x00000186 Jump
+00000010: 940C0186 JMP 0x00000186 Jump
+00000012: 940C0186 JMP 0x00000186 Jump
+00000014: 940C0186 JMP 0x00000186 Jump
+00000016: 940C046B JMP 0x0000046B Jump
Das ist soweit ok!
Nun brache ich irgenwie die Befehle um folgenes zu erreichen.
Beim BOOTLOADER ist ja nicht 0x0000 der Start sonder bei mir nun 0x7000
und da muß nun im Disasembler eine ähnklich eTabelle entstehen, tut's
aber nicht da kommt gleich mein Quellcode der im BOOT_MAIN geschrieben
ist... ach mano...
An Adresse +00007016 sollte stehen auf welche ISR Routine er springen
soll.
Alle anderen einfach zurück oder mit Dummy belegen weil der Abstand
eingehalten werden muß... hmm
Für heute reicht es... ich geh mal pennen, vielleicht hilft das
weiter... ;-)
MfG Tobi...
@ tobiTob:
Hast du mal in der AVR-GCC doku nach "avr/boot.h" geschaut? (Bei WinAVR
ist die Doku auf jeden Fall dabei, bei linux-Paketen wahrscheinlich
auch)
Außerdem kannst du dir mal den Bootloader von Peter Fleury anschauen
(unter jump.to/fleury) -- der ist zwar nicht soo aktuell, aber eben für
den gcc geschrieben.
hth. Jörg
kosmonaut pirx wrote:
> hallo,>>>Hinter den Adressen stecken übrigens meistens Register, müssen also bei>>jedem Start auf die richtigen Werte gesetzt werden.>> das stimmt doch nicht. das sind inhalte im befehlsspeicher, und der ist> fest/non-volatile. da wird nichts geladen, da wird einfach ein befehl> samt operand ausgeführt.
Da habe ich dann wohl zu groß gedacht. Ich hatte bei der Aussage etwas
größere Controller im Kopf, welche ein AIC oder Ähnliches haben. Diese
müssen nach jedem Reset neu initialisiert werden.
Also,
streiche: meistens
setze: manchmal
In der Hinsicht wäre es vielleicht hilfreich zu wissen welchen
Controller er einsetzt um diesbezüglich klare Aussagen treffen zu
können.
@all
Ich arbeite mit einem ATMEL ATmeag644 im Moment.
Tool's sind AVRStudio mit WinAVR.
Das ganze was ich machen möchte ist das der Gesamte Code wirklich in der
BOOT_SECTION, also nach 0x7000 geschrieben wird.
Es ist bei den ATMEL's so vorgesehen das nach der Adresse 0x0000 eben
alle VECTOREN definiert werden wo bei welchem Interrupt hinzuspringen
ist. In Assembler wüste ich es, könnte es auch posten.
Nun hat man die Möglichkeit bei den ATMEL die Vectoren umzuschalten, das
macht Sinn wenn man seinen Code komplett in der BOOT_SECTION speichern
möchte.
Dann erwartet der µC das man seine VECTOREN nach der Statradresse
definiert, also ab 0x7000 in meinem Fall. ;-)
Nun, in der BOOT_SECTION steht nun meine Funktion wie...
1
ISR(BOOT_TIMER2_OVF_vect)
2
{
3
TCNT2=TCNT2-18;// Startwert laden
4
5
/* mach was */
6
7
}
Diese muß nun auf den VECTOR 0x7000 + 10 angemeldet werden damit der µC
das richtig abarbeitet. An 0x7000 muß irgendwie was stehen das er meine
"BOOT_TIMER2_OVF_vect" anspricht.
Also ich denke das es geht nur der Weg zum Ziel ist das Rätsel.
@Jörg X.
Also angesehen habe ich es mir aber verstanden würde ich nicht sagen.
Es ist immer schwer andere Quelltexte fließend zu lesen doch ich habe
das Gefühl es läuft da anders, also nicht mit einem Bootbereich mit
Interrupts.
Die Datei boot.h habe ich mir auch angesehen, da find ich überhaut
nichts von Interrupts in der BOOT_SECTION... :-(
Hab ich das Prinzip nun verstanden oder nicht. :-D
Ich hoffe die Lösung ist nicht mehr weit weg.
Einen schönen Tag, Tobi...
kosmonaut pirx wrote:
> die lösung ist wie beschrieben ganz nahe: die .text-section nach 0x7000> verschieben. ende, aus maus.
Für AVR Studio nimmst du dafür entweder gleich ein externes Makefile,
oder du musst das -Wl,--section-start=.text=0x7000 irgendwie in die
Optionen reinpopeln, die er zum Linken nimmt.
@Jörg Wunsch
Hi Jörg, du siehst ich bin noh nicht weiter... ich denke aber das Du
genau der richtige bist da Du dich mit dem WinAVR Zeug's wohl bestens
auskennst.
Verstehst Du meine Ansätze?
Ich drehe mich nun schon einen Tag im Kreis.
Nun bin ich fast soweit den Bootloader aus meinen ASM Projekt in den
Chip zu pusten da ich es so nicht in den Griff bekomme.
Ich will es aber innerlich in C schaffen. ;-)
C finde ich einfach übersichtlicher zu schreiben, ich wollte deshalb
auch in C den Bootloader realisiseren doch es scheint das es da
Diferenzen gibt.
Im AVR Studio gibts ja die Möglichkeit über die Settings das .bootloader
Segment auf 0x7000 zu setzen, das klappt auch!
Er schreibt alles was nach dem Wort BOOTLOADER_SECTION an die Position
0x7000 was aber nicht berücksichtig wird sind die neuen
Interruptvectoren.
Wie ist das gedacht bei WinAVR wenn man im Bootloader Bereich eigene
Interruptvectoren verwenden möchte?
Wie sagt man in deinen Kreisen... 73 de Tobi... ;-)
tobiTob wrote:
> Im AVR Studio gibts ja die Möglichkeit über die Settings das .bootloader> Segment auf 0x7000 zu setzen, das klappt auch!Das ist aber genau der falsche Ansatz. Du sollst das bitteschön
nicht in eine .bootloader-Section packen, sondern ganz normal den
kompletten Bootloader als eigenständige Applikation betrachten, der
ganz normal .text, .data und .bss hat, und dessen .text-Section
du dann per Linkeroption auf 0x7000 schiebst. Nur so verschiebst
du alles einschließlich der Interruptvektoren.
Die eigentliche Applikation läuft dann völlig separat und weiß einfach
gar nichts davon, dass sie von einem Bootloader in den Flash gepumpt
worden ist. Die ist ein komplett separates Projekt.
Hallo,
brauchst Du überhaupt unbedingt Interrupts im Bootloader ?
(Ich schreibe mir in C gerade selber einen, und ich optimistisch,
keine Interrupts brauchen zu müssen)
Jogibär
Naja ob man sie bracht... geht bestimmt auch ohne... ;-)
Ich habe einen in ASM geschrieben der nimt den TIMER2 Overflow INT und
die gesamte UART Sache läuft auch mit den INT's.
Läuft eigendlich ohne Probleme, den wollte ich nun nach C portieren aber
das ist ein schwieriges Unterfangen.
Nun ich denke ich werde meine ASM Sache anpassen auf den 644 das
kopilieren. Wie ich es dann dauerhaft in mein C Project einbinde das das
fertige ASM Zeugs immer an Adresse 0x7000 angehangen werden soll weiß
ich nicht...
Ist doch noch einiges unklar...
Gruß Tobi
@tobiTob: Wo ist dein Problem? Willst du die Antwort nicht sehen?
Schreibe doch einfach zwei C-Programme. Einmal den Bootloader, und
einmal den Rest.
Das wurde hier doch schon oft genug gesagt.
tobiTob wrote:
> Nun ich denke ich werde meine ASM Sache anpassen auf den 644 das> kopilieren. Wie ich es dann dauerhaft in mein C Project einbinde das das> fertige ASM Zeugs immer an Adresse 0x7000 angehangen werden soll weiß> ich nicht...
Der Witz eines Bootloader ist ja, er wird nirgends nicht angehangen.
Er ist ein ganz normales Programm, was ganz für sich alleine in den AVR
geflasht wird und gut is.
Und dann lötest Du den Chip in Deine Schaltung ein und flashst die
Anwendung per Bootloader wie es sich gehört.
Interrupts braucht man im Bootloader nicht unbedingt, machen nur die
Anpassung an verschiedene AVRs schwieriger.
Peter
P.S.:
Einen sorgenfreien Bootloader (ATtiny13..ATmega644) findet man übrigens
in der Codesammlung.
Ich verstehe das Problem nicht ganz.
Um einen Bootloader zu erzeugen,musst Du nur 2 Dinge beachten:
* wie Jörg schon sagte:
die .text-Section per Linkeroption auf 0x7000 schieben, bzw.
auf die gewünschte Boot-Start-Adresse.
* die Fuse BOOTRST setzen und je nach Bedarf
die Fuses BOOTSZ0 bzw. BOOTSZ1.
Danach ist Dein Programm im Bootloader-Bereich, alles andere kannst Du
wie bei "normalen" Programmen auch machen.
Du kannst Interrupts extakt gleich wie in "normalen" Programmen
verwenden, das geht sogar so weit, dass Du z.B. ein File, das die
serielle Schnittstelle über den Interrupt anspricht, ohne eine Änderung
auch in Deinem Bootloader verwenden kannst.
Du kannst sogar WÄHREND dem Programmieren des Flashs Interrupts
zulassen. Dabei musst Du nur eine Sache beachten:
Die Befehle zum Beschreiben des Flashs sind Sequenzen aus 2
ASM-Befehlen, die innerhalb von 4 Clockzyklen erfolgen müssen (Schutz
gegen unbeabsichtigtes Beschreiben). Deshalb während diesen Sequenzen
die IRs abschalten (sonst kann es passieren, dass ein IR GENAU zwischen
beide Befehle hineintrifft).
Bei Verwendung der Befehle aus der AVR-LIBC:
Die Aufrufe zum Löschen und Beschreiben des Flash mit abgeschalteten IRs
geben, z.B.:
1
cli();
2
boot_page_write(...);
3
sei();
Da die Routinen zum Beschreiben des Flash den Flash-Programmiervorgang
nur anstossen und nicht auf die Beendigung des Programmierens warten,
sind die IRs dadurch nur sehr kurz (einige us) gesperrt.
Zum Thema Bootloader und Normal-Firmware gemeinsam übersetzen:
--------------------------------------------------------------
Vergiss es einfach!
dazu müssten nicht nur die Vektoren vom gcc doppelt angelegt werden,
auch die komplette Initialisierung müsste doppelt - für jeden
Programmteil separat - getätigt werden.
Die einzige Lösung, die realistisch erscheint:
* Übersetze Deinenn Bootloader separat.
* Erzeuge aus dem Output ein File, dass Du beim Linken der
Normal-Firmware
mit dazubinden kannst (und zwar ab der Bootloader-Startadresse).
Gruß, Stefan
Hallo Leute,
danke für Eure Geduld!!!!
Also wenn es ehh leichter ist mir 2 seperaten Programme dann mache ich
es auch so.
Ich habe nun mein Bootloader fertig, den aber nun koplett in ASM
gelassen weil ich da dann keinen Sinn sehe den in C zu portieren da der
ja ehh extra in den ATMEL geschrieben wird.
Meine normale Anwendung also das "Mainprogramm" habe ich nun in C
geschrieben, das compiliert sich und alles ist ok.
Nun würde es lediglich noch interessant sein wie ich in einem Rutsch ein
Mainprogramm und den Bootloader flashen kann.
Bootloader ist nun in ASM. Ausgabe .HEX
Mainprogramm in C. Ausgabe .HEX
Ihr schreibt immer wieder von "linken", welche Möglichkeiten gibt es da?
Was muß man da genau machen... null Ahnung habe ich noch nie gemacht.
:-(
Sicher kann man nur den Bootloader flashen und dann per Bootloader die
Software. Nur der andere Weg würde mich interessieren, erspart ein 2x
programmieren. So kann man jeweils das aktuelle Mainprogramm gleich
mitschreiben.
Danke, einen schönen Abend, Tobi...
tobiTob wrote:
> Bootloader ist nun in ASM. Ausgabe .HEX> Mainprogramm in C. Ausgabe .HEX
Hex-Files, die an unterschiedlichen Adressen stehen, lassen sich ganz
einfach zusammenpappen:
Man muß nur bei einem den Enderecord (letzte Zeile) löschen und dann das
andere anfügen.
Allerdings lassen wir in der Produktion absichtlich nur den Bootloader
brennen und dann die Applikation per Bootloader.
Damit ist gewährleistet, daß der Bootloader beim Kunden auch wirklich
funktioniert, wenn er mal ein Update kriegt.
Peter
Ich bins nochmal mit einem bestimmt kleinen Problem...
Ich weiß nun nur mal wieder wie man es in ASM machen würde, in C geht's
bestimmt auch...
Ich will mir lediglich eine CRC merken die sollte aber immer am Ende im
Flash liegen also in den letzten beiden Stellen VOR BOOTGO...
In ASM würde ich es so machen...
.org BOOTGO-1
FIRMCRC: .db 175,194 ;CRC
Danke im voraus... Gruß Tobi...
Peter Dannegger wrote:
> Hex-Files, die an unterschiedlichen Adressen stehen, lassen sich ganz> einfach zusammenpappen:
Für avrdude braucht man das nicht, man kann auch mit zwei separaten
-U Optionen beide Dateien angeben. Gelöscht wird der Flash natürlich
dabei nur einmal. ;-)
tobiTob wrote:
> Ich will mir lediglich eine CRC merken die sollte aber immer am Ende im> Flash liegen also in den letzten beiden Stellen VOR BOOTGO...
Eine separate .section anlegen und diese per Linkeroption
--section-start an diese Stelle schieben.
eigendlich sollte es ein extrad theard werden :( hab ich nicht
aufgepasst sorry!
>> Eine separate .section anlegen und diese per Linkeroption>> --section-start an diese Stelle schieben.
Ja da steh ich auf dem Schlauch.
Wie läuft das?
Habe folgenes probiert:
bei den Linker Optionen hab ich:
--section-start CRC_SECTION=0x6000 angegeben,
das klappt so nicht, was mach ich da falsch?
Habe im toturial auch nochmal nachgesehen, finde keine rechte
Beschreibung dazu schnief
Gruß Tobi...
hallo,
>das klappt so nicht, was mach ich da falsch?
das klappt so nicht, weil du verflixt nochmal nicht vollständig lesen
tust :)
weder was der linker dir an fehlermeldungen ausspuckt, noch was in der
FAQ steht. den link dahin gabs hier schon mal, von den anderen hinweisen
hier möchte ich gar nicht reden.
>bei den Linker Optionen hab ich:>--section-start CRC_SECTION=0x6000 angegeben
in anwendung der hinweise aus der avr-libc-FAQ: "How do I relocate code
to a fixed address?"
--section-start=.CRC_SECTION=0x6000
sollte es tun. im tutorial habe ich auch nichts gefunden, btw.
bye kosmo
Den Inhalt von .crcsection musst du mit avr-objcopy in ein eigenes
Hexfile auslagern und separat programmieren. Das ist vergleichbar
mit dem Erstellen des EEPROM-Ladefiles, für das du zahlreiche
Beispiele finden solltest.
Ok danke Euch!
Ich gib ja zu das es Neuland ist, ich bin wohl etwas eingefahren und hab
mich etwas schwer beim Nachvollziehen der einzelnen Passagen. :-(
Ich habe nun folgenes gemacht...
Nicht wundern, ich will mir von der CRC einmal das low und einmal das
high speichern, es geht sicher auch...
const int pgmcrc CRC_SECTION = 5512;
Angemeldet habe ich die Section über die Memorysettings im AVR Studio,
scheint zu klappen. ;-)
ein "static" davor bewirkt das FF an den Speicherstellen liegt. Also
lass ich das mal... ;-)
Danke für eure Hilfe, MfG Tobi...