Servus allerseits
Vermutlich sind's mehr als 15 Jahre her, als ich zuletzt mit AVR-MCUs gearbeitet hatte.
Deshalb fühle ich mich so in etwa wie ein Fisch, den's aufs Land gespühlt hat.
Meine Arbeitsumgebung:
Debian
MATLAB X
PICKIT 4
avr-gcc (Toolchain_3.6.7_489) 5.4.0
ATTiny 414
Die MCU ist meist im power-down und wird durch den Watschdog aufgeweckt.
Mein Wunsch wäre es, dass der Inhalt einiger Variablen erhalten bleibt, ohne dass ich dazu das EEprom verwenden muss.
Zu Testzwecken habe ich mir ein uint8_t mit attribute ((section (".noinit"))) angelegt; aber diese wird bei jedem Neustart mit 0 übersschrieben.
Wenn ich mit avr-objdump die elf-Datei mir angucke, sehe ich hingegen die Section .noinit.
Zuerst dache ich, der Debugger verfälsche das Ergebnis; aber auch ohne Debugger bleibt die LED dunkel.
Vermutlich ist irgendwas mit meinem Test nicht ganz koscher ... aber ich finde den Fehler nicht.
Attribut section(".noinit") ist schon ok. Section .noinit folgt auf .bss, wird also nicht vom Startup-Code initialisiert; dieser initialisiert nur bis __bss_end, siehe
.noinit ADDR(.bss) + SIZEOF (.bss) : AT (ADDR (.noinit))
13
{
14
PROVIDE (__noinit_start = .) ;
15
*(.noinit .noinit.* .gnu.linkonce.n.*)
16
PROVIDE (__noinit_end = .) ;
17
_end = . ;
18
PROVIDE (__heap_start = .) ;
19
} > data
Wenn also in einer .noinit-Variablen ein Wert drinne steht, dann von einem vorhergehenden Lauf, oder es steht ein (teilweise) zufälliger Wert drinne nach PowerUp Reset.
Keine Ahnung, wo man beim MPLAB das Linker-Skript findet. Aber wie bereits erwähnt: avr-objdump zeigt mir korrekt dieses eine Byte in der .noinit Sektion an.
Keine Ahnung, wo man beim MPLAB das Linker-Skript findet.
Es ist schon bemerkenswert, dass man mit Dingen ausserhalb
von .code, .data und .bss operieren will, und dann nicht mal
das verwenderte Linkerscript vorzeigen kann.
Wenn es nicht in der Dokumentation steht, vielleicht einfach
mal eigeninitiativ danach suchen?
Nein, kein Bootloader.
Da ich schon längst mit Try-and-Error im Trüben fische, habe ich dieses noinit in eine c-Datei verlagert. Aber das hat's auch nicht gebracht.
Der Linker-Script ist die Datei avrxmega3.xn und befindet sich im Ordner /opt/microchip/xc8/v2.41/avr/avr/lib/ldscripts
Mein erster Gedanke war ein "Aha!", aber das scheint schon seine Richtigkeit zu haben.
Dann habe ich den Test-Code dahingehend geändert, dass ich auch in der init3 Sektion die Variable inkrementiere und gleich ein Restart durchführte.
Und siehe da: sie wurde nicht mit 0 überschrieben.
Gemäss der Online-Dokumentation von microchip (*) kommt nur init4 als Spielverderber in Frage.
1
.init4:
2
For devices with > 64 KB of ROM, .init4 defines the code which takes care of copying the contents of .data from the flash to SRAM. For all other devices, this code as well as the code to zero out the .bss section is loaded from libgcc.a.
Lass doch mal die Reset-Ursache mit ausgeben, die brauchst ja eh um test_val initialisieren zu können. Steht in MCUSR (MCU Status Register) oder RSTFR (Reset Flag Register).
Nicht vergessen, dass die Reset-Bits in MCUSR bei einem Reset nicht gelöscht werden. Nur bei Power-on werden diese alle gelöscht (und dann das entsprechende Flag gesetzt).
Um den Wachhund anschließend abschalten zu können, musst du das entsprechende Reset-Bit unbedingt löschen, sonst beißt der gleich wieder zu.
Nach Beendung des
Sleep-Modes wird doch kein Reset ausgeführt
Leider doch. Bei den neueren AVRs ist der Watchdoginterrupt wieder entfernt worden.
Man kann aber den PIT zum Aufwachen nehmen mit den internen 32kHz ULP.
Über Reset zu gehen, finde ich auch unschön. Denn da gehen ja wieder alle IOs kurz in tristate. Z.B. eine LED würde kurz flackern, ein Magnet kurz abfallen.
Nicht vergessen, dass die Reset-Bits in MCUSR bei einem Reset nicht
gelöscht werden.
Okay, diesen Flag hatte ich nicht beachtet. Beim Attiny414 ist das im Register STCTRL.RSTFR versteckt.
Tat aber insofern nicht weh, weil das Watchdog-Register im OFF-Zustand daherkam. Wie es dem auch sei: an meiner ganzen Misere hat sich leider nichts geäendert.
Ich musste aber feststellen, dass der Attiny von der ganzen Toolchain nicht korrekt unterstützt wird.
1
wdt_enable(WDTO_500MS);
führt zum Bsp. zu einer 125ms Verzögerung weil
1
wdt.h
2
#define WDTO_500MS 5
Auch sind die Werte 4 und 8 Sekunden auskommentiert.
Mit anderen Worten, man muss mit
1
_PROTECTED_WRITE(WDT.CTRLA,WDT_PERIOD_512CLK_gc);
arbeiten. Vermutlich gibt es noch weitere Ungereimtheiten, unter einer denen mein Problem vergraben liegt. Also ich geb's auf. Das Ganze übersteigt bei weitem meine Fähigkeiten.
Ich musste aber feststellen, dass der Attiny von der ganzen Toolchain
nicht korrekt unterstützt wird.
Naja, den Watchdog-Support hat dafür jetzt noch keiner angepasst.
Hat aber mit dem (Nicht-)Funktionieren von .noinit nichts direkt zu tun.
Ich habe von diesen neuen Tinys gerade kein Board zur Hand (irgendwo muss ich noch einen ATtiny1634 oder sowas liegen haben, aber ohne Board), insofern kann ich darauf nicht testen. Allgemein AVR0 habe ich aber was (AVR128DA48 oder so), um da was zu probieren.
Allgemein AVR0 habe ich
aber was (AVR128DA48 oder so), um da was zu probieren.
Da reicht es doch, sich im Startup-Code anzuschauen, ob der .noinint-Bereich genullt wird oder nicht. Dafür braucht es keine physische hardware zum testen.
Mein Hinweis wegen dem Watchdog war nur als Beispiel angedacht gewesen. Es sind mir noch ein paar andere Ungereimheiten aufgefallen; aber wegen meiner Aus-Zeit von mehr als 15 Jahren dachte ich stets, es liege ein Missverständis meinerseits vor.
Auf den power-down möchte ich sehr ungern verzichten, weil bei meinem Testaufbau es mir nicht gelungen ist, den Stromverbrauch zu messen.
Ich werde vermutlich mein Problem mit dem Periodic Interrupt Timer des RTC
lösen. Der Watchdog wäre zwar eleganter und einfacher gewesen ... aber was soll's.
Der Watchdog wäre zwar eleganter und einfacher gewesen ... aber was
soll's.
Ein Watchdog, der immer einen Reset schmeißt? Finde ich nicht. Beim ATmega128RFA1 habe ich ihn für ebendiesen Zweck (Aufwachen aus dem Sleep) schon benutzt, aber im Interrupt-Modus. Schade, dass der bei den neuen AVR0 nun wieder entfallen ist. Reset macht ziemlich viel kaputt, wie Peter oben schon schrieb.
OK, mein Fazit: Microchip hat da was am Startup-Code der avr-libc herum gepfuscht. Offenbar wollen sie mehre mögliche bss-Segmente unterstützen und legen nun eine Map für die einzelnen Segmente im Flash ab, statt (wie original avr-libc) diese direkt durch den Linker in den Code eintragen zu lassen. (Dabei haben sie nicht einmal verstanden, warum man globale Symbole mit zwei Unterstrichen beginnen sollte …)
Jedenfalls haben sie auf diese Weise dein .noinit kaputt gemacht, weil sie mit dem Ausnullen des vermeintlichen bss ab 0x3f00 (RAM-Start) beginnen.
Mach ein Ticket bei Microchip auf dafür. Sie haben es ja auch nicht nötig, ihre Änderungen ins avr-libc-Projekt zurück zu spielen. Weiß nicht, ob sie irgendwo den Sourcecode für ihre Änderung liegen haben oder rausgeben, aber sie sollen bitteschön jetzt ihr Gemurkse selbst supporten.
Achso: wenn du für das Ticket eine englische Beschreibung brauchst, schreibe ich die dir gerne. Ich gebe mir auch Mühe, nicht so angepisst zu klingen. ;-)
Aber erzeuge dafür bitte ein minimales Beispiel, mit dem deren Support das Problem nachvollziehen kann, also irgendwas mit nur zwei Variablen und 'ner blinkenden LED oder so, und bitte auch in C, nicht C++.
Falls Du es aus dem Ärmel schütteln kannst: Ein Link für die
Ticket-Anlaufstelle?
Nee, hab ich auch nicht. Solltest du aber fündig werden. Landest dann sicher irgendwo in Indien, wo du dem Supporter als erstes nachweisen musst, dass es nicht deine eigene Blödheit war. Daher ein nachvollziehbares Beispiel.
Jörg, vielen Dank für Deine Hilfe. Dank Dir muss ich jetzt nicht mehr mit gesenktem Kopf durch das Office schleichen, weil ich dachte, das Fehlverhalten beruhe auf meinem Fehler :)
Wie ich in meiner Einganspost erwähnt habe: seit mehr als 15 Jahren habe ich mit den AVRs nichts mehr gemacht. Deshalb erschien es mir am einfachsten, etwas aus einem Guss zu installieren und mit Hilfe meiner alten Sources und copy&paste etwas schnell zusammenzustellen. Okay, "schnell" ist was anderes.
Wenn Du mir also einen Link hast, mit dessen Hilfe ich ohne viel Klimmzüge eine stabile Toolchain erhalten kann: sehr gerne!
Und "eigene" Toolchain oder aus einer Distro sind i.d.R plain vanilla und ohne Device-Support für neuere Devices wie ATtiny414: Speziell ATtiny414 wird erst ab v8 (Release 2018) offiziell unterstützt.
Für ältere Versonen besorgt man sich ein Device Pack, z.B. von
Wie man die Device-Packs verwendet findet man hier im Forum, das wurde schon x mal durchgenudelt.
-mmcu=avrxmega3 gibt's auch erst ab v8, fur ältere Versionen des Compilers bis runter zu v5.4.0 muss man auf avrxmega2 abbilden, und noch ältere Versionen können garnicht auf ATtiny414 gepimpt werden.
Wenn Mikrochip da wirklich an den Tools rumgemurxt hat, ist die Frage,
warum nicht eine orgiginale Toolchain ohne
Microchip-Verschlimmbesserung?
Ich würde mal sagen, dass es mit dem öffentlichen Code funktioniert. Habe jetzt keinen passenden Controller, das nachzuvollziehen, aber ich sehe folgende Effekte (GCC 11.2.0, avr-libc mehr oder minder aktueller Entwicklungsstand):
nur .noinit-Variable, kein .bss und .data: es wird keinerlei RAM-Initialisierung überhaupt eingebunden, damit bleibt die .noinit-Variable unangetastet
zusätzlich noch .bss und .data Dummies eingebaut: diese landen dann am Anfang des RAMs und werden mit den normalen Schleifen initialisiert; die .noinit-Variable steht dahinter und wird von den Schleifen nicht angefasst
Sollte also funktionieren (bis auf das schon genannte falsche WDT-Timing).
Das wundert mich bei deiner Toolchain jetzt nicht so richtig.
Irgendein Vorschlag, wie ich diesen (mit einfachen Mitteln) upgraden
kann?
Ich habe keine rechte Idee, wo die wie und was vergurkt haben. Da ich kein Windows-Nutzer bin, kann ich dir nicht einmal sagen, wo die ihre Toolchain liegen haben.
Hast du denn das ELF-File von mir mal getestet? Also, ich weiß natürlich nicht, wo bei dir die LED hängt ;-). Da du den Teil des Codes nicht gepostet hattest, hab' ich da einfach mal PB0 mit einer high-aktiven "LED" reingesetzt. Ich kann dir das aber auch noch für einen beliebigen anderen Port und andere Polarität bauen.
Gestern abend fand ich keine Möglichkeit via MPLab IDE das ELF-File zu testen. Heute morgen nochmals mit klarem Kopf danach gesucht, aber anscheinend ist sowas nicht vorgesehen.
Bezogen auf den Testcase in PR90706 ist der gcc-13.0.1 wieder optimal. Bei Deinen zusätzlichen Testcases ist er wieder auf dem Niveau von gcc-8.5.
Betrachte ich "echte" größere Projekte, so stelle ich zwischen gcc-12.2.0 und gc-13.0.1 Unterschiede fest, aber in beide Richtungen: mal ist der eine besser, mal der andere (bezogen auf die Größe).
Gestern abend fand ich keine Möglichkeit via MPLab IDE das ELF-File zu
testen. Heute morgen nochmals mit klarem Kopf danach gesucht, aber
anscheinend ist sowas nicht vorgesehen.
Auf der Microchip-Seite fand ich eine neuere Version und damit hat noinit nun endlich seine Aufgabe richtig erfüllt.
avr-g++ (AVR_8_bit_GNU_Toolchain_3.7.0_1796) 7.3.0
Ich habs mal mit der Windows-Version probiert, die nutzt
GNU C++ (AVR_8_bit_GNU_Toolchain_3.6.2_1778) version 5.4.0 (avr)
Egal, was ich auch probiert habe, die .noinit-section liegt immer hinter der .bss-section, und wird auch nicht genullt. Auch nutzt der diese seltsame Adresstabelle im Flash nicht, die Adressen kommen wohl direkt aus dem linker.
Keine Ahnung, was die da für Linux zusammengebastelt haben.