avr-gcc und .noinit

#7380429
Lesenswert?

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.

1
uint8_t test_val      __attribute__((section(".noinit")));
2
void DisableWDT(void) __attribute__((naked)) __attribute__((section(".init3")));
3

4
//=================================
5
// DisableWDT
6
//=================================
7
void DisableWDT(void) {
8
    wdt_disable();
9
}
10

11
//=================================
12
// Init
13
//=================================
14
void MyApp::Init(void) {
15

16
    //---------------------test start
17
    test_val++;
18
    if (test_val >= 3){
19
        Led.Init();
20
        Led.GreenOn();
21
        while(1){};
22
    }
23
    wdt_enable(WDTO_500MS);
24
    while(1) {};
25
    //---------------------test end
26
    ...
27

28
}
Persönliche Seite #7380471
Lesenswert?

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

https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/config/avr/lib1funcs.S;h=0870595111ad5b8121a57ee84a38994976c575d8;hb=cffa72fde8ce9c767e20c058892929d9c9b33ae7#l2432

Und default ld-Script setzt __bss_end vor den Anfang von .noinit:

1
  .bss  ADDR(.data) + SIZEOF (.data)   : AT (ADDR (.bss))
2
  {
3
     PROVIDE (__bss_start = .) ;
4
    *(.bss)
5
     *(.bss*)
6
     *(COMMON)
7
     PROVIDE (__bss_end = .) ;
8
  }  > data
9
   __data_load_start = LOADADDR(.data);
10
   __data_load_end = __data_load_start + SIZEOF(.data);
11
  /* Global data not cleared after reset.  */
12
  .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.

#7380575
Lesenswert?

Oliver S. schrieb:

Das vorhandene linkerscript

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.

1
Sections:
2
Idx Name          Size      VMA       LMA       File off  Algn
3
  0 .data         00000000  00803f00  00803f00  00000458  2**0
4
                  ALLOC, LOAD, DATA
5
  1 .text         0000009a  00000000  00000000  00000094  2**1
6
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
7
  2 .noinit       00000001  00803f00  00803f00  00000458  2**0
8
                  ALLOC
9
  ...
#7380679
Lesenswert?

Oder poste Dein Linkscript.

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?

#7380931
Lesenswert?

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.

Und hier bin ich am Ende mit meinem Latein.

(*) https://onlinedocs.microchip.com/pr/GUID-317042D4-BCCE-4065-BB05-AC4312DBC2C4-en-US-2/index.html?GUID-34931843-0F2B-49EE-A117-7AB61373F68D

Angehängte Dateien:
#7381081
Lesenswert?

Johann L. schrieb:

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.

#7381129
Lesenswert?

Jörg W. schrieb:

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.

Moderator Persönliche Seite #7381131
Lesenswert?

Mehmet K. schrieb:

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.

#7381151
Lesenswert?

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.

Moderator Persönliche Seite #7381184
Lesenswert?

Mehmet K. schrieb:

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.

Moderator Persönliche Seite #7381257
Lesenswert?

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.

Moderator Persönliche Seite #7381261
Lesenswert?

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++.

#7381376
Lesenswert?

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!

Persönliche Seite #7381434
Lesenswert?

Ubuntu.

Wilhelm M. schrieb:

Bei Arch-Linux ist es avr-gcc 12.2.0

Wegen https://gcc.gnu.org/PR90706 würde ich einen großen Bogen um v9, v10, v11 und v12 machen.

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

http://packs.download.atmel.com/

Die .pack-Dateien sind im zip Format gespeichert, z.B.:

1
> jar tf Atmel.ATtiny_DFP.2.0.368.atpack | grep 414
2

3
gcc/dev/attiny414/avrxmega3/short-calls/crtattiny414.o
4
gcc/dev/attiny414/avrxmega3/short-calls/libattiny414.a
5
gcc/dev/attiny414/device-specs/specs-attiny414
6
include/avr/iotn414.h
7
xc8/avr/device-specs/specs-attiny414
8
xc8/avr/include/avr/iotn414.h
9
xc8/avr/lib/avrxmega3/short-calls/crtattiny414.o
10
xc8/avr/lib/avrxmega3/short-calls/libattiny414.a

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.

Moderator Persönliche Seite #7381448
Lesenswert?

Johann L. schrieb:

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).

Edit: habe mein Testfile mal angehängt.

Angehängte Dateien:
Moderator Persönliche Seite #7381492
Lesenswert?

Mehmet K. schrieb:

Jörg W. schrieb:

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.

#7381569
Lesenswert?

Johann L. schrieb:

Ubuntu.

Wilhelm M. schrieb:

Bei Arch-Linux ist es avr-gcc 12.2.0

Wegen https://gcc.gnu.org/PR90706 würde ich einen großen Bogen um v9, v10, v11 und v12 machen.

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).

#7381694
Lesenswert?

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.

Oliver

Beitrag #7409932 wurde von einem Moderator gelöscht.
Beitrag #7410201 wurde von einem Moderator gelöscht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren