Guten Tag,
ich versuche mich gerade am Bootloader für die "neuen" Tiny1 Serie (hier
Tiny3217).
Ich habe das Programm fertig und es funktioniert. Jetzt wollte ich es
über flash segmentierung auf .text=0x100 setzen. Technisch geht das
auch, Flash fängt jetzt mit dem Programm entsprechend an, aber das
Programm funktioniert nicht mehr richtig.
Interrupts gehen gar nicht mehr
Inputs von Tastern geht auch nicht mehr
Das einzige was noch geht ist ADC und DAC Ausgabe (hier ist ADC geht auf
den Dac mit Umrechnung).
Kann mir jmd sagen was ich falsch mache?
Verstehe ich es richtig: da sitzt der (recht kompakte) Bootloader von
0x0000 bis 0x00FF, das Anwenderprogramm (mit seinen Interrupts) beginnt
bei 0x0100, und die Fuse BOOTEND steht auf 0x01?
PS:
Das sind Byte-Adressen; ich hätte 0x0000...0x007F resp. 0x0080 schreiben
sollen.
Markus M. schrieb:
> Interrupts gehen gar nicht mehr
Dann ist was falsch konfiguriert.
Der Linker muß wissen, wo die Applikation beginnt.
Und natürlich muß auch FUSE.BOOTEND entsprechend gesetzt werden.
S. L. schrieb:
> Verstehe ich es richtig: da sitzt der (recht kompakte) Bootloader
> von
> 0x0000 bis 0x00FF, das Anwenderprogramm (mit seinen Interrupts) beginnt
> bei 0x0100, und die Fuse BOOTEND steht auf 0x01?
>
> PS:
> Das sind Byte-Adressen; ich hätte 0x0000...0x007F resp. 0x0080 schreiben
> sollen.
Danke für die Antwort.
es ist 0x100 nicht 0x0100!
Der Tiny3217 hat keine BOOTEND Fuses. Oder habe ich die übersehen?!
Peter D. schrieb:
> Markus M. schrieb:
>> Interrupts gehen gar nicht mehr
>
> Dann ist was falsch konfiguriert.
> Der Linker muß wissen, wo die Applikation beginnt.
> Und natürlich muß auch FUSE.BOOTEND entsprechend gesetzt werden.
Danke für die Antwort.
Der Tiny3217 hat keine BOOTEND Fuses. Oder habe ich die übersehen?!
Können Sie mir sagen was ich noch einstellen muss? Linker ?!
Also in den Settings vom Atmel Studio
Markus M. schrieb:
> Der Tiny3217 hat keine BOOTEND Fuses.
> es ist 0x100 nicht 0x0100!
?
Was stört an der führenden Null?
> Der Tiny3217 hat keine BOOTEND Fuses.
Au contraire!
Von deren Einstellung hängt nämlich ab, wo im Flash der
Interruptvektoren-Bereich liegt (s.a. 'Memory Map'):
> Interrupts gehen gar nicht mehr
Markus M. schrieb:
> Also in den Settings vom Atmel Studio
APPEND
BOOTEND
> Der Tiny3217 hat keine BOOTEND Fuses.
Wenn ich noch nachtragen darf - ein CTRL-F im Datenblatt mit 'BOOTEND'
bringt u.a. dieses Bild.
Danke für die Infos. Bootend habe ich in der Tat übersehen, verrückt.
Dennoch verstehe ich es noch nicht so ganz.
Mein Bootloader ist 2048 byte groß. Im .text gibt man ja Byteadressen
an.
Jetzt die Fragen:
1. Flash muss bei .text=0x0800 sein muss oder? Sprich Appdata fängt bei
0x800 an.
2. Bootend ist auf 8 zu setzen (2048/256 = 8)
=> An diesem Punkt geht erstmal noch genauso wenig wie vorher.
(Aktuell ist kein Bootloader drauf, sondern nur das Programm, heißt es
startet bei 0x0800. Das sollte ja nicht stören da die Zellen davor FF
haben und er da einfach "durchrutscht" bis er beim Programm landet).
=> Zu den IVSEL, das müsste dann auf 1 gesetzt werden? Verstehe ich
nicht wirklich, m.E. muss das auf 0 bleiben, da der Bootloader ein
separates Atmel Studio Projekt ist was dann ab 0 den Speicherplatz
belegt.
Später setze ich die 2 generierten .hex Files einfach zusammen. So mache
ich es aktuell bei den Xmega/Mega die aber eine richtige Bootsection (am
ende des flashes) haben und das funktioniert gut.
Ich habe in das Programm folgendes gemacht am Start (nach dem CLKCTRL
Settings)
1 | CPU_CCP = 0xD8;
| 2 | CPUINT_CTRLA = CPUINT_IVSEL_bm;
|
Wirklich ändern tut sich nichts. ?!
Irgendwas mache ich falsch
> IVSEL ... m.E. muss das auf 0 bleiben
Dem schließe ich mich an, denn:
"0: Interrupt vectors are placed at the start of the application section
of the Flash".
Und weil dies der Reset-Wert ist, CPUINT_CTRLA gar nicht anfassen.
(Dass ich die entsprechende Seite anhängte, sollte nur den Einfluss von
FUSE.BOOTEND zeigen)
> ... da die Zellen davor FF haben ...
Da wäre ich nicht so sicher - vorher vielleicht ein Chip-Erase
durchführen.
S. L. schrieb:
>> IVSEL ... m.E. muss das auf 0 bleiben
>
> Dem schließe ich mich an, denn:
> "0: Interrupt vectors are placed at the start of the application section
> of the Flash".
> Und weil dies der Reset-Wert ist, CPUINT_CTRLA gar nicht anfassen.
> (Dass ich die entsprechende Seite anhängte, sollte nur den Einfluss von
> FUSE.BOOTEND zeigen)
>
>> ... da die Zellen davor FF haben ...
>
> Da wäre ich nicht so sicher - vorher vielleicht ein Chip-Erase
> durchführen.
Ich verstehe das leider nicht und hoffe wirklich auf Hilfe. Der rest ist
leer (FF), erase passiert immer vor dem neu flashen.
Ich habe jetzt folgendes gemacht:
1. .text section angelegt unter Toolchain/Memory Settings
2. Toolchain/General "Do not use standard start files" aktiviert.
Jetzt passiert was richtig verrücktes. Mein Programm (20kb) besteht nur
noch aus 4 HEX Zeilen. ?! Warum generiert er das denn jetzt so?!
Bootend so gesetzt wie beschrieben
Append 0 gelassen
> ... Toolchain ...
Da kann ich leider nicht weiterhelfen - ich programmiere in Assembler
und verwende (ausschließlich) ein Eigenbauprogrammiergerät.
Bei mir läuft (auf einem ATtiny1614): ein Einfachstblinkprogramm (per
TCB0_INT_vect) ab 0x0400 (Wortadresse), FUSE.BOOTEND=8.
> Der rest ist leer (FF), erase passiert immer vor dem neu flashen.
Da sind Sie sicher? Ist nämlich bei den 'neueren' nicht zwingend, im
Gegensatz zu den 'alten' AVR8.
PS:
Ich würde in dieser Anfangsphase auch nicht mit einem 20 kB-Programm
arbeiten - vielleicht finden Sie im Anhang eine Anregung für etwas
Einfaches.
S. L. schrieb:
>> ... Toolchain ...
>
> Da kann ich leider nicht weiterhelfen - ich programmiere in Assembler
> und verwende (ausschließlich) ein Eigenbauprogrammiergerät.
>
> Bei mir läuft (auf einem ATtiny1614): ein Einfachstblinkprogramm (per
> TCB0_INT_vect) ab 0x0400 (Wortadresse), FUSE.BOOTEND=8.
>
>> Der rest ist leer (FF), erase passiert immer vor dem neu flashen.
>
> Da sind Sie sicher? Ist nämlich bei den 'neueren' nicht zwingend, im
> Gegensatz zu den 'alten' AVR8.
>
> PS:
> Ich würde in dieser Anfangsphase auch nicht mit einem 20 kB-Programm
> arbeiten - vielleicht finden Sie im Anhang eine Anregung für etwas
> Einfaches.
Danke für die Hilfe. Ich habe den Fehler gefunden, was ein Quark
meinerseits.
Bootloader ist 2048 bytes / 256 (scale of bootend) = 8. Also BOOTEND
fuse auf 8 (boot section startet bei 0x800.
Bei .text im Atmel Studio muss man aber Wordadresse angeben (also 0x800
/ 2 = 0x400) und schon geht alles!
Machen Sie auch große Programmer in Assembler? Ich finde das wird sehr
sehr schnell super unübersichtlich, oder?
> Fehler gefunden
Das freut mich.
> ... Assembler ...
Ist vielleicht in erster Linie eine Frage der Gewöhnung.
Das Programm für besagtes Programmiergerät zum Beispiel hat knapp 10
kB (ohne die Tabellen).
Markus M. schrieb:
> Machen Sie auch große Programmer in Assembler? Ich finde das wird sehr
> sehr schnell super unübersichtlich, oder?
Ich hatte mit dem 8051 (AT89S8253) erst in Assembler angefangen. Ich war
bei fast 8kB Flash, aber es war noch nicht fertig. Ich habe es dann 6
Monate liegen lassen und als ich weiter machen wollte, merkte ich, ich
hab den Durchblick völlig verloren.
In der Firma war aber eine Lizenz des Keil C51 verfügbar und so habe ich
damit gearbeitet. Es ist mir sprichwörtlich die Kinnlade runtergefallen,
so kompakt und effizient hat der Herr Keil programmiert. Ich konnte das
Projekt nun problemlos beenden und es war weiterhin wartbar. Viele
Funktionen waren kleiner und schneller, als mein altes
Assemblergebastel. Durch die Overlaytechnik wurde auch der SRAM deutlich
sparsamer genutzt.
Ich kämpfe grade damit, einen Bootloader für einen ATtiny412 zu
schreiben. Ich verstehe nicht, warum das Hauptprogramm offenbar nicht
von meinem absoluten Minimal-Bootloader aufgerufen wird.
Der Bootloader soll gerade einmal die Taktfrequenz umstellen, zwei GPIOs
ausschalten und dann ins Hauptprogramm springen. Braucht dementsprechend
auch nur 38 Bytes und hat damit in einer Flash-Section Platz, die beim
ATtiny412 256 Bytes groß sind. 1 | #include <avr/io.h>
| 2 | #include <avr/cpufunc.h>
| 3 | #include <util/delay.h>
| 4 |
| 5 | #include "fuses.h"
| 6 |
| 7 | __attribute__((naked)) __attribute__((section(".ctors"))) void boot(void)
| 8 | {
| 9 | asm volatile ("clr r1");
| 10 |
| 11 | // 16 MHz / 4 = 4 MHz
| 12 | ccp_write_io((uint8_t *) &(CLKCTRL.MCLKCTRLB), CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc);
| 13 |
| 14 | PORTA.DIRSET = PIN1_bm | PIN2_bm;
| 15 | PORTA.OUTCLR = PIN1_bm | PIN2_bm;
| 16 |
| 17 | ((void (*)(void)) BOOTEND_WORDS )(); // 0x0080
| 18 | }
|
Den Bootloader kompiliere ich mit -nostartfiles und
-Wl,--section-start=.text=0x0000
Im Hauptprogramm wird ebenfalls die Taktfrequenz angepasst und die
beiden GPIOs werden im Halbsekundentakt getoggelt. An einem der GPIOs
hängt eine LED, die blinken sollte: 1 | #include <avr/io.h>
| 2 | #include <avr/cpufunc.h>
| 3 | #include <util/delay.h>
| 4 |
| 5 | #include "fuses.h"
| 6 |
| 7 | int main(void)
| 8 | {
| 9 | // 16 MHz / 4 = 4 MHz
| 10 | ccp_write_io((uint8_t *) &(CLKCTRL.MCLKCTRLB), CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc);
| 11 |
| 12 | PORTA.DIRSET = PIN1_bm | PIN2_bm;
| 13 |
| 14 | while(1) {
| 15 | PORTA.OUTTGL = PIN1_bm | PIN2_bm;
| 16 | _delay_ms(500);
| 17 | }
| 18 | }
|
Das Hauptprogramm kompiliere ich mit -Wl,--section-start=.text=0x0080
Die Headerdatei fuses.h ist bei Bootloader und Hauptprogramm gleich und
setzt FUSES.BOOTEND auf 1: 1 | #ifndef _FUSES_H_
| 2 | #define _FUSES_H_
| 3 |
| 4 | #include <avr/io.h>
| 5 |
| 6 | FUSES = {
| 7 | .WDTCFG = 0x00,
| 8 | .BODCFG = 0x00,
| 9 | .OSCCFG = FREQSEL_16MHZ_gc,
| 10 | .reserved_1 = { 0xFF },
| 11 | .TCD0CFG = 0x00,
| 12 | .SYSCFG0 = (CRCSRC_NOCRC_gc | RSTPINCFG_UPDI_gc | FUSE_EESAVE_bm),
| 13 | .SYSCFG1 = SUT_64MS_gc,
| 14 | .APPEND = 0,
| 15 | .BOOTEND = BOOTEND_VALUE, // 1 -> Boot section size 1*256 bytes = 256 bytes
| 16 | };
| 17 |
| 18 | #endif
|
Folgende Beobachtung: Liegt nur das Hauptprogramm im Flash (ab Adresse
0x0080), funktioniert das Programm und die LED blinkt. Mit Bootloader
funktionierts aber nicht mehr. Anbei zwei Flashdumps - einmal ohne
Bootloader (funktioniert-dump.lst) und einmal mit
(funktioniert-nicht-dump.lst).
Die Konstanten BOOTEND_WORDS und BOOTEND_VALUE werden übrigens im
Kommandozeilenaufruf von avr-gcc übergeben.
Edit: Aus irgendeinem Grund wurde der Beitrag veröffentlicht statt die
Vorschau anzuzeigen. Ups.
M. T. schrieb:
> Die Headerdatei fuses.h ist bei Bootloader und Hauptprogramm gleich und
> setzt FUSES.BOOTEND auf 1:
Seit wann kann man die Fuses zur Laufzeit ändern?
Außerdem würde das ständige Schreiben bei jedem Reset ein hohes Wearout
bewirken.
Es ist keine gute Idee, einen fremden Thread zu kapern :-(
Neue Frage -> neuer Thread!!!
Peter D. schrieb:
> M. T. schrieb:
>> Die Headerdatei fuses.h ist bei Bootloader und Hauptprogramm gleich und
>> setzt FUSES.BOOTEND auf 1:
>
> Seit wann kann man die Fuses zur Laufzeit ändern?
Kann man nicht, aber seit einer Weile kann man mit der avr-libc die
Fuses so im Code deklarieren. Mit avrdude ... -U fuses:w:foo.elf:e
können die Fuses dann geschrieben werden.
Siehe auch
https://www.nongnu.org/avr-libc/user-manual/group__avr__fuse.html
> Außerdem würde das ständige Schreiben bei jedem Reset ein hohes Wearout
> bewirken.
Das ist gut zu wissen, danke.
> Es ist keine gute Idee, einen fremden Thread zu kapern :-( Neue Frage -> neuer
Thread!!!
Ich dachte mir, das Problem ist ähnlich genug, dass ich mich gleich hier
anhänge.
Eigentlich sehen beide .lst für mich korrekt aus; allerdings frage ich
mich, was es mit diesem 'asm volatile ("clr r1");' auf sich hat und wo
es im
'funktioniert-nicht-dump.lst' zu finden ist.
> Aus irgendeinem Grund wurde der Beitrag veröffentlicht statt
> die Vorschau anzuzeigen.
Ja, ich bin auch der Meinung, dass die beiden Schaltflächen zu nahe
beieinander liegen.
Wie ich sehe lädst du Wortadresse 0x80 im Loader und sprngst dahin, das
ist aber Byte-Adresse 0x100.
Anstatt ccp_write_io würde ich lieber _PROTECTED_WRITE, weil kein
Funktionsaufruf im Loader:
https://avrdudes.github.io/avr-libc/avr-libc-user-manual/group__avr__io.html#gaaaa396e67cc85f68fa0474d70edf3d4c
icall benutzt doch Wortadressen? 0x0080, entsprechend dem
256-Byte-Boot-Block.
M. T. schrieb:
> __attribute__((naked)) __attribute__((section(".ctors"))) void
> boot(void)
> {
Das ist nicht korrekt. Section .ctors ist für was anderes, nämlich für
Funktionsadressen statischer Konstruktoren.
Wenn, dann sowas wie1 | __attribute__((naked, section(".init0"), used))
| 2 | void boot(void)
| 3 | {
|
S. L. schrieb:
> Eigentlich sehen beide .lst für mich korrekt aus; allerdings frage ich
> mich, was es mit diesem 'asm volatile ("clr r1");' auf sich hat und wo
> es im 'funktioniert-nicht-dump.lst' zu finden ist.
Das habe ich aus der Appnote AN2634:
https://ww1.microchip.com/downloads/en/AppNotes/AN2634-Bootloader-for-tinyAVR-and-megaAVR-00002634C.pdf
Das 'asm volatile ("clr r1");' wird in ein "eor r1, r1" (r1 xor r1)
übersetzt.
Johann L. schrieb:
> Das ist nicht korrekt. Section .ctors ist für was anderes, nämlich für
> Funktionsadressen statischer Konstruktoren.
>
> Wenn, dann sowas wie
Auch das hab ich aus der Appnote. Ich habe deine Variante gerade
ausprobiert, die wird aber auch in den genau gleichen Maschinencode
übersetzt.
M. T. schrieb:
> Johann L. schrieb:
>> Das ist nicht korrekt. Section .ctors ist für was anderes, nämlich
>> für Funktionsadressen statischer Konstruktoren.
>
> Auch das hab ich aus der Appnote. Ich habe deine Variante gerade
> ausprobiert, die wird aber auch in den genau gleichen Maschinencode
> übersetzt.
.ctors ist trotzdem falsch.
> icall benutzt doch Wortadressen? 0x0080, entsprechend dem
> 256-Byte-Boot-Block.
Ja, ICALL verwendet Wort-Adressen. Das Dump sieht aber so aus:
M. T. schrieb: 1 | > 00000000 <.sec1>:
| 2 | > 0: 11 24 eor r1, r1
| 3 | > ...
| 4 | > 14: e0 e8 ldi r30, 0x80 ; 128
| 5 | > 16: f0 e0 ldi r31, 0x00 ; 0
| 6 | > 18: 09 95 icall
| 7 | > ...
| 8 | > 7c: ff ff .word 0xffff ; ????
| 9 | > 7e: ff ff .word 0xffff ; ????
| 10 | > 80: 19 c0 rjmp .+50 ; 0xb4
| 11 | > 82: 20 c0 rjmp .+64 ; 0xc4
| 12 | > ...
|
und das sieht für mich so aus, als würde die App in 0x80 Byteadresse
starten, zumindest sieht der Code wie ne Vektortabelle aus. Das ICALL
springt aber zu 0x100! Außerdem:
> Das Hauptprogramm kompiliere ich mit -Wl,--section-start=.text=0x0080
Und das ist auch Byte-Adresse 0x80, aber eben Word-Adresse 0x40.
>> --section-start=.text=0x0080
> Und das ist auch Byte-Adresse 0x80, aber eben Word-Adresse 0x40.
Aber warum beginnt dann in beiden Dumps das Hauptprogramm bei 0x0080?
> Das 'asm volatile ("clr r1");' wird in ein "eor r1, r1"
> (r1 xor r1) übersetzt.
Das "clr r1" wird vollautomatisch übersetzt? Aha.
Da ich aber (fast) ausschließlich in Assembler programmiere, sollte ich
mich wohl ab jetzt heraushalten.
S. L. schrieb:
>>> --section-start=.text=0x0080
>> Und das ist auch Byte-Adresse 0x80, aber eben Word-Adresse 0x40.
>
> Aber warum beginnt dann in beiden Dumps das Hauptprogramm bei 0x0080?
Ei weil
> Das Hauptprogramm kompiliere ich mit -Wl,--section-start=.text=0x0080
Also beginnt das Programm bei 0x80. Der Loader springt aber zu 0w80 =
0x100.
> Das "clr r1" wird vollautomatisch übersetzt?
CLR ist syntaktische Zucker, genauso wie ROL, LSL, SBR, CBR, TST, SER
und wie sie alle heißen.
Johann L. schrieb:
>> Das Hauptprogramm kompiliere ich mit -Wl,--section-start=.text=0x0080
>
> Also beginnt das Programm bei 0x80. Der Loader springt aber zu 0w80 =
> 0x100.
Danke!!! Das wars! Mit -Wl,--section-start=.text=0x0100 funktionierts
endlich.
Aber ist dann die Appnote fehlerhaft, oder hab ich die falsch
verstanden? Dort steht nämlich auf Seite 11:
>... the start of the .text code section must be configured to correspond with the
location of the Flash sections. The input is word-aligned so the following numbers
should be used:
>* Application Code start: BOOTEND * 0x80
>
>Using BOOTEND fuse setting 0x02 as an example (256 word boot size), relocation of
the Application Code .text section is done by using the following linker option:
>
>-Wl,--section-start=.text=0x100
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|