Forum: Mikrocontroller und Digitale Elektronik Attiny 2313A - ROM am Limit? Probleme mit Optimierer


von Alex B. (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite


Lesenswert?

Hallo zusammen,
ich stehe vor einer kleinen Herausforderung, die mir so neu ist.

Ich habe ein kleines Projekt für einen Attiny 2313A aufgesetzt. Das 
Projekt besteht - mehr oder weniger - aus zwei unabhängigen Teilen:
1) Kommunikation mit einem Master via MODBUS-ASCII
2) Auslesen von Sensoren via I2C

Ich habe für die Entwicklung die beiden Teile unabhängig programmiert 
und erfolgreich getestet.

Beide Teile zusammen erzeugen leider unsinnige Ergebnisse. Meine 
Vermutung ist, dass es etwas mit doppelter Belegung des Speichers zu tun 
hat.

Leider bemerkte ich dann auch, dass schon Optimierung "-Os" aktiviert 
war. AVR-GCC meldet auch ca. 98% ROM-Auslastung.

Ich habe versucht mit "-O1" zu kompilieren, was jedoch mit Fehler 
abbricht ("Program memory 114% Full").

Ich habe schon alle konstanten als "const" angelegt und alle Variablen 
als "static".

Habt ihr schon mal ähnliches Erlebt?
Habt ihr einen Tipp, wie man die Sache angehen kann?

Zur Not würde ich auf den Attiny 4313 umsteigen.

Viele Grüße,
Alex

von Peter II (Gast)


Lesenswert?

Alex B. schrieb:
> AVR-GCC meldet auch ca. 98% ROM-Auslastung.

ist doch ok. Flash wird zur Laufzeit nicht gebraucht.

> Beide Teile zusammen erzeugen leider unsinnige Ergebnisse. Meine
> Vermutung ist, dass es etwas mit doppelter Belegung des Speichers zu tun
> hat.
kann nur passieren, wenn du selber den Speicher vergibst, wenn es der 
GCC macht (was üblich bei C ist) dann passiert das nicht.

von Fabian H. (hdr)


Lesenswert?

Timing? Doppelte Interrupt- bzw. Timer-nutzung?

von Uwe S. (de0508)


Lesenswert?

Hallo Alex,

zum Glück gibt es ja noch einen größern attiny mit 4kB Flash.

Hast Du modular Programmiert und saubere Schnittstellen zwischen den 
Modulen  festgelegt ?

Zeig uns doch einfach mal den gesamten Code und Schaltplan.

von Peter II (Gast)


Lesenswert?

Uwe S. schrieb:
> zum Glück gibt es ja noch einen größern attiny mit 4kB Flash.

damit wird das Problem aber nicht automatisch verschwinden.

von Max D. (max_d)


Lesenswert?

ATTiny4313 nehmen und testen....

von Uwe S. (de0508)


Lesenswert?

Peter II schrieb:
> Uwe S. schrieb:
>> zum Glück gibt es ja noch einen größern attiny mit 4kB Flash.
>
> damit wird das Problem aber nicht automatisch verschwinden.

Das habe ich auch nicht behauptet.

von Alex B. (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite


Lesenswert?

Uwe S. schrieb:
> Peter II schrieb:
>> Uwe S. schrieb:
>>> zum Glück gibt es ja noch einen größern attiny mit 4kB Flash.
>>
>> damit wird das Problem aber nicht automatisch verschwinden.
>
> Das habe ich auch nicht behauptet.

Vielen Dank für die ganzen Antworten bisher!

Uwe S. schrieb:
> Hast Du modular Programmiert und saubere Schnittstellen zwischen den
> Modulen  festgelegt ?

Hatte ich. Ich schmeiße aber gerade "alles in eine main()". Vorher hatte 
ich ein paar globale Variablen und die waren zum Teil "extern" 
deklariert.

Uwe S. schrieb:
> zum Glück gibt es ja noch einen größern attiny mit 4kB Flash.

Das ist auch meine Nofall-Lösung.

Uwe S. schrieb:
> Zeig uns doch einfach mal den gesamten Code und Schaltplan.

Damit warte ich mal noch ein bisschen... Ich will eure wertvolle Zeit 
nicht damit vergeuden in meinem Code einen Fehler zu finden...

Viele Grüße,
Alex

von Stefan F. (Gast)


Lesenswert?

Na dann sehen wir auch davon ab, unsere Zeit mit wildem herumraten zu 
vergeuden.

von Carl D. (jcw2)


Lesenswert?

Ausreichend neuen Compiler benutzen: "avr-GCC -v" sollte 4.8.2 oder 
größer melden.
Compiler und  Linker mit "-flto -Os" füttern, dann läuft der Optimizer 
über das ganze Programm.
Compiler probeweise mit "-mcall-prologues" füttern, das kann bei vielen 
Funktionen mit hoher Registerlast den Flash-Bedarf (bei minimaler 
Laufzeiterhöhung) verringern.
Static-Variablen müssen nicht gut sein, wenn sie nicht wirklich 
weiterleben müssen und jedesmal neu initialisiert werden, dann kann das 
auch nach hinten losgehen. Da hilft eine
1
#define FAKE_STATIC   static
2
//#define FAKE_STATIC
3
...
4
void foo() {
5
  FAKE_STATIC       int8_t tmp=1;
6
...
7
}
um beide Varianten schnell durchzuprobieren.

von Alex B. (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite


Angehängte Dateien:

Lesenswert?

Stefan U. schrieb:
> Na dann sehen wir auch davon ab, unsere Zeit mit wildem herumraten zu
> vergeuden.

Was sagt man dazu... angespornt durch diese Aussage habe ich mich daran 
gemacht den Code besser lesbar zu machen und habe ihn weiter in kleinere 
Funktionen unterteilt. Außerdem habe ich alle Variablen als 
"nicht-static" erstellt. Das Ergebnis:

Program Memory Usage   :  1858 bytes   90,7 % Full
Data Memory Usage   :  94 bytes   73,4 % Full
EEPROM Memory Usage   :  1 bytes   0,8 % Full

Das Programm ist ein paar Prozent kleiner.
Aber viel wichtiger: Es läuft!

Erklären kann ich es mir nicht.
Optimierung steht nun auf "-Os".

Für den Fall, dass sich dennoch jemand das Projekt anschauen möchte und 
ggf. ein paar Tipps hat, wie man die Performance noch verbessern kann, 
habe ich mal die Quelldateien angehängt.

Ich werde es jetzt mal ein paar Stunden laufen lassen um zu sehen, ob es 
auch dauerhaft stabil läuft...

Danke euch allen und viele Grüße,
Alex

von Stefan F. (Gast)


Lesenswert?

Na Herzlichen Glückwunsch. Du hast soeben gelernt, dass es sich lohnt, 
seine Arbeit gut zu strukturieren.

von Stefan F. (Gast)


Lesenswert?

> Erklären kann ich es mir nicht.

Manchmal liegt es an Stack überlauf. Hier im Forum wurden schon merhamls 
Tips gegeben, wie man Stack Überlauf mit ein paar Zeilen Code zur 
Laufzeit erkennen kann. Such mal danach. Du brauchst es zwar jetzt 
gerade nicht mehr, aber das kommt irgendwann wieder.

von Peter D. (peda)


Lesenswert?

Alex B. schrieb:
> Aber viel wichtiger: Es läuft!
>
> Erklären kann ich es mir nicht.

Kann gut sein, daß durch die Strukturierung weniger RAM verbraucht wird.
34 Byte Stack ist nicht gerade viel.

von Alex22 (Gast)


Lesenswert?

Peter D. schrieb:
> Alex B. schrieb:
>> Aber viel wichtiger: Es läuft!
>>
>> Erklären kann ich es mir nicht.
>
> Kann gut sein, daß durch die Strukturierung weniger RAM verbraucht wird.
> 34 Byte Stack ist nicht gerade viel.

Insgesamt sollen später ca. 20 Bus-Knoten am Modbus hängen. Der hier 
beschriebene war der erste Prototyp. Für die "Serie" werde ich dann doch 
lieber den Attiny4313 bestücken. Dann kann ich auch noch mal ohne 
Optimierung kompilieren lassen und vergleichen...

Vielen Dank und viele Grüße,
Alex

von Carl D. (jcw2)


Lesenswert?

Ist der gepostete Code der letzte Stand? Da sind nämlich immer noch 
diverse static Variablen in Funktionen, die wohl eher nicht statisch 
sind, da sie, bevor sie erstmals gelesen werden, überschrieben werden. 
Wenn man eh zuwenig RAM hat, dann reservieren die dauerhaft Platz (und 
der Compiler benutzt sie eventuell (fast) gar nicht). Gefährlich wird's 
dann, wenn man meint, man hätte sie initialisiert. Das passiert in der 
Form
1
void foo() {
2
   Static int i=0;
3
...
4
}
nämlich nur einmal. Beim Programmstart. Danach macht man mit den 
Hinterlassenschaften des letzte foo()-Aufrufs weiter. Wer das nicht 
vorher wußte, der tut sich auch mit dem debuggen schwer.
modbus_calcLRC() benutzt z.B. diesen "Trick" um die Prüfsumme über ALLE 
bisher geprüften Nachrichten zu berechnen. Das geht wohl nur einmal.

von Uwe S. (de0508)


Lesenswert?

Hallo Alex,

ich habe schon die Uart Interruput Routinen für TX und RX gesucht und 
sie nicht direkt gefunden.
Und im File Modbus.c sind sie.
Aua:
a) cli / sei in einer Interruputroutine - warum ?
b) was bezweckst Du mit dem Return, das ist überflüssig !
1
//USART (RS485) received character interrupt
2
ISR(USART_RX_vect){
3
  cli();
4
  modbusProccessRxChar(UDR); //interrupt is cleared automatically upon read of UDR
5
  sei();
6
  return;
7
}
8
9
//USART (RS485) transmit data completed interrupt
10
ISR(USART_TX_vect){
11
  cli();
12
  ; //interrupt is cleared automatically upon execution of this interrupt
13
  
14
  //check if last Byte was transmitted. If yes, disable Line-Driver to free RS485 lines
15
  if(modbusStatReg.pendingTxBytes == 0){
16
    PORTD &= ~(1<<RS485_DE); //disable driver
17
    PORTD &= ~(1<<RS485_NRE); //enable receiver   
18
  }
19
  sei();
20
  return;
21
}

von Lurchi (Gast)


Lesenswert?

Das sieht mehr nach zu wenig RAM aus, was dann zum Stack überlauf führen 
kann.

Ein Problem sind da z.B. Aufrufe von funktionen in ISRs, insbesondere 
solchen die nicht als Static deklariert sind. Das braucht unnötig viel 
Platz auf dem Stack. Wenn es wegen der Übersicht mit funktionen sein 
soll, dann bevorzugt als static inline ... . Flash Speicher scheint ja 
jetzt vorhanden zu sein.

Das SEI() in der ISR ist gefährlich. Es erlaubt verschaltelte Interrupts 
und damit zusätzlichen Bedarf an Platz auf dem Stack. Nötig ist es so 
wie gezeigt nicht (die Freigabe kurz vor ende bringt fast keinen 
Vorteil), und erzeugt die Gefahr selten auftretender und damit schwer zu 
findender Fehler.

von Stefan F. (Gast)


Lesenswert?

> Initialisierung... Das passiert in der Form
1
void foo() {
2
   Static int i=0;
3
...
4
}
> nämlich nur einmal.

Das dachte ich auch bis vor kurzem. Ist aber falsch.

Siehe Beitrag "Re: Unterschied zwischen int i; in while und vor while"

von Peter II (Gast)


Lesenswert?

Stefan U. schrieb:
> Das dachte ich auch bis vor kurzem. Ist aber falsch.

falsch, da ging es nicht um static.

static wird wirklich nur einmal initialisiert und liegt auch nicht auf 
dem Stack sondern auf dem Heap.

von Carl D. (jcw2)


Lesenswert?

> static wird wirklich nur einmal initialisiert

Und wird in "modbus.c" in der Prüfsummenberechnung als temporäre 
Variable für das Ergebnis benutz. Und wird nur einmal mit 0 
initialisiert.
Es stellen sich bei dem Programm also noch keine Optimierungfragen, denn 
noch funktioniert es nicht.
Sollte es inzwischen doch funktionieren, weil der TO die "static"-Orgien 
entfernt hat, so sollte er verstehen wollen, warum das jetzt tut. Sonst 
setzt sich neben der bekannten "Regel", "viel volatile hilft viel", auch 
noch die neue Regel, "mach dad static weg", zur Fehlerbehandlung durch. 
Das ist Woodoo-Programmierung.

von Alex B. (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite


Lesenswert?

Carl D. schrieb:
> Es stellen sich bei dem Programm also noch keine Optimierungfragen, denn
> noch funktioniert es nicht.
> Sollte es inzwischen doch funktionieren, weil der TO die "static"-Orgien
> entfernt hat, so sollte er verstehen wollen, warum das jetzt tut. Sonst
> setzt sich neben der bekannten "Regel", "viel volatile hilft viel", auch
> noch die neue Regel, "mach dad static weg", zur Fehlerbehandlung durch.
> Das ist Woodoo-Programmierung.

Erstaunlicherweise funktionierte es oft aber nicht immer. Von ca. 
100 Messungen kamen ca. 90% beim Master an. Es kann durchaus sein, 
dass es immer dann klappte, wenn die Prüfsumme zufällig korrekt war. 
Manchmal kamen leider keine Messwerte an und manchmal betrug die 
gesendete Temperatur 250 °C ... :-/

Wie dem auch sei. Ich werde es mir, sobald es meine Zeit zulässt, noch 
mal im Detail ansehen.

Und Ja ich möchte sinnvoll programmieren und halte nichts von Vodoo 
- weder in der Software, noch in der Hardware.

Bis dahin vielen Dank an alle, die sich an der Diskussion beteiligt 
haben!
Viele Grüße,
Alex

P.S.:

Uwe S. schrieb:
> ich habe schon die Uart Interruput Routinen für TX und RX gesucht und
> sie nicht direkt gefunden.
> Und im File Modbus.c sind sie.

Hältst du es für sinnvoller sie in uart.c unterzubringen? Dann müssen in 
uart.c aber die modbus-Variablen bekannt sein. Oder ich müsste mir noch 
mal Gedanken zur Schnittstelle machen...

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Carl D. schrieb:

> auch
> noch die neue Regel, "mach dad static weg", zur Fehlerbehandlung durch.
> Das ist Woodoo-Programmierung.

Ja und nein.
Klar, das static will man hier erst mal nicht im Sinne des Erfinders 
haben. Auf der anderen Seite kann es sinnvoll sein, auch lokale 
Variablen static zu machen, weil sie dann in der SRAM Statistik 
auftauchen, was gerade bei kleinen Prozessoren nicht ganz uninteressant 
ist. Das man dann sich natürlich nicht auf die Intialisierung verlassen 
kann, ist selbstredend und folgt aus der eigentlichen Bedeutung von 
'static'. Man verschwendet zwar ein paar Bytes, weiss aber exakt 
wieviele.

Dem gegenüber steht, dass der Compiler in solchen Funktionen
1
void modbus_convRxFrmToByteArray(uint8_t *modbusRxFrmBuffer)
2
{
3
    static uint8_t Digit;
4
    static uint8_t c, i;
5
6
  for(i=1;i<(MODBUSRXFRMLENGTH-2);i++){
7
      c = *(modbusRxFrmBuffer+i);
8
        if (c >= '0' && c <= '9')
9
            Digit = (uint8_t) (c - '0');
10
        else if (c >= 'a' && c <= 'f')
11
            Digit = (uint8_t) (c - 'a') + 10;
12
        else if (c >= 'A' && c <= 'F')
13
            Digit = (uint8_t) (c - 'A') + 10;
14
        else
15
            break;
16
17
        *(modbusRxFrmBuffer+i) = Digit;
18
    }
19
20
    return;
21
}
die lokalen Variablen sehr wahrscheinlich allesamt in Registern halten 
kann, wodurch sie zur Laufzeit überhaupt keinen SRAM Speicher benötigen 
würden.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

1
void modbus_convFrmByteToASCII(char *destiny, uint8_t val){
2
  const char hex_lookup[] = "0123456789ABCDEF";
3
  
4
  destiny[1] = hex_lookup[val & 0x0F];
5
  destiny[0] = hex_lookup[(val>>4) & 0x0F];
6
  
7
  return;
8
}

Beim gcc bringt dir das 'const' hier genau gar nichts. OK. Du kriegst 
hier einen Schönheitspreis.
Dein Problem ist das SRAM und das wird ohne und mit const genau gleich 
benutzt.

Wenn du dir diese 16, auf deinem Tiny kostbaren Bytes aus dem SRAM 
freischaufeln willst, dann musst das Array als __flash markieren oder 
bei einem älteren gcc den Weg über PROGMEM und die pgm_readxxx 
Funktionen gehen. Du zahlst dafür einen kleinen Preis in Form von ein 
paar Takzyklen aber ansonsten hat das keine Nachteile. Ausser natürlich, 
dass du 16 Bytes mehr SRAM zur Verfügung hast.

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Flash_mit_PROGMEM_und_pgm_read

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

@khb
Wenn ich ein Problem mit der RAM-Größe habe, dann wird das nicht besser, 
wenn ich für den lokalen Speicher aller Funktionen vorab RAM reserviere. 
Den kann der Compiler nämlich nicht so einfach wegoptimieren, der könnte 
ja tatsächlich bis zum nächsten Aufruf weiterleben müssen. Wegoptimieren 
kann er die nur, wenn sie vor der ersten Verwendung immer initialisiert 
wird. Aber genau das kann man dabei ja leicht falsch machen. Es kann 
sogar sein, das der Code dank "LD Rn,Y+idx" kürzer wird, wenn lokale 
Variablen, falls keine Register frei sind, im Stackframe liegen.

Viel einfacher spart man RAM tatsächlich, wenn man die 
AVR/const/Flash-Problematik angeht. Und neuere GCC-Versionen machen es 
(in C) ja leicht Dank "__flash". Wenn man die Sourcen anschaut, dann 
sieht man, daß der Schreiber nicht orginär aus der AVR-Welt kommt:
//Clock System Initialization
klingt nach MSP430, da hat man einen linearen Addressraum und der 
Compiler muß nicht mit "named address space" belästigt werden.

von Karl H. (kbuchegg)


Lesenswert?

Carl D. schrieb:
> @khb
> Wenn ich ein Problem mit der RAM-Größe habe, dann wird das nicht besser,
> wenn ich für den lokalen Speicher aller Funktionen vorab RAM reserviere.
Natürlich nicht.
Aber ich kann wenigstens in der SRAM Statistik sehen, dass ich ein 
Problem haben werde. Das kann hilfreich sein. Darauf wollte ich hinaus. 
Ein größeres Problem von dem ich weiß kann (muss nicht) mir lieber 
sein, als ein kleineres von dem ich nichts weiß.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Ein Compiler für einen AVR erzeugt den besten Code, wenn man möglichst 
wenig Variablen als "static" oder global nutzt. Am effizientesten kann 
der AVR nämlich mit lokalen non-static Variablen umgehen, sofern es 
keine Arrays sondern Basistypen sind (char, int, long, ...).

Lokale Variablen sollten nur dann "static" sein, wenn ihr Inhalt über 
die Aufrufe hinaus erhalten bleiben muss. Andernfalls kosten sie nur 
Platz und Zeit. Es spart auch keinen Platz, mehrfach verwendete 
Schleifenzähler "i" ausserhalb der Funktion zu definieren, ganz im 
Gegenteil.

Wenn du nicht wirklich weisst was du tust, dann versuch nicht, die 
Arbeit des Compilers zu übernehmen und im Quellcode unnötig zu 
optimieren. Ganz besonders nicht, wenn du dabei Regeln folgst, die 
zumindest beim verwendeten Prozessor ein Schuss in den Ofen sind.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Dazu bräuchte es etwas, an das ich mich dunkel zu erinnern glaube, es 
schon mal gesehen zu haben: eine Statistik der Stackbekegung, das geht 
natürlich nur für nicht-rekursive Aufrufe, aber die Meldung "Achtung 
Rekursion" wäre ja als Warnung auch ganz gut. Jede Funktion hat Bedarf 
an Stack für ihren Aufruf, das Register-Sichern und eine Stackframe mit 
lokalen Daten. Der Compiler kennt den. Und auch die Aufrufreihenfolge. 
Wie geschrieben: ich hab schon Listings gesehen, wo so was mit 
draufstand. Ich meine es wäre PLMxyz gewesen.

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> static wird wirklich nur einmal initialisiert und liegt auch nicht auf
> dem Stack sondern auf dem Heap.

Als Heap bezeichnet man nur den Speicher für explizit dynamisch 
allozierte Daten, via malloc/calloc.

Globale Variablen wie auch alle "static" Variablen liegen nicht auf dem 
Heap, sondern einträchtig nebeneinander in zwei festen Daten-Sektionen. 
Eine für explizit initialisierte Daten und eine für implizit beim Start 
genullte Daten. Der Unterschied ist nur, ob diese Variablen im gesamten 
Programm, nur im File oder nur in der Funktion bekannt sind.

Globals/statics explizit mit 0 zu initialisieren kann je nach Compiler 
unnötig Platz im ROM verbrauchen, nämlich für jene 0, mit der die 
Variable ohnehin initialisiert würde.

: Bearbeitet durch User
von Alex B. (Firma: Ucore Fotografie www.ucore.de) (alex22) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo zusammen!
Es freut mich, dass ich eine so angeregte Diskussion angestoßen habe.

Ich habe versucht die hier gegebenen Vorschläge umzusetzen. Insbesondere 
habe ich ein Update des AVR-GCC gemacht (war 4.3.3, ist jetzt 4.8.1).

Das Ergebnis:
Program Memory Usage   :  1940 bytes   94,7 % Full
Data Memory Usage   :  56 bytes   43,8 % Full
EEPROM Memory Usage   :  1 bytes   0,8 % Full

Insbesondere der RAM ist nun also leerer.
Ich habe jetzt auch Konstanten mit "__flash" angelegt.

Ich werde über Nacht den Sensor (Modbus-Slave) wieder messen lassen, um 
die "Stabilität" zu beobachten.

Carl D. schrieb:
> //Clock System Initialization
> klingt nach MSP430

Ich arbeite zumeist mit Freescale HCS08- und HCS12X- MCUs.

Uwe S. schrieb:
> ich habe schon die Uart Interruput Routinen für TX und RX gesucht und
> sie nicht direkt gefunden.
> Und im File Modbus.c sind sie.

Wie könnte man das geschickter anordnen?
Zum TX-Interrupt: Ich möchte den Driver möglichst schnell nach Senden 
des letzten Zeichens deaktivieren (da halb-duplex-Betrieb).
Zum RX-Interrupt: Da werden die Zeichen zu einem String zusammengepackt 
und wenn der String fertig ist ("\r\n") wird ein Flag gesetzt.

Das Problem der UART weiß ja nichts davon, dass er das 
"modbus-Protokoll" bedienen soll...

Für Vorschläge bin ich jederzeit offen.
Viele Grüße,
Alex

von (prx) A. K. (prx)


Lesenswert?

Alex B. schrieb:
> Ich arbeite zumeist mit Freescale HCS08- und HCS12X- MCUs.

Die haben keine für lokale Variablen geeigneten Register, weshalb alle 
nicht sowieso vom Compiler wegoptimierten Variablen unweigerlich im RAM 
landen, egal ob global oder lokal, ob static oder auto. Bei den AVRs mit 
32 Registern ist das anders. Regeln, die man sich für die Freescales 
angewöhnt haben mag, sind auf AVRs oft nicht anwendbar.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

> Die haben keine für lokale Variablen geeigneten Register, weshalb alle
nicht sowieso vom Compiler wegoptimierten Variablen unweigerlich im RAM
landen, egal ob global oder lokal, ob static oder auto.

Aber auch für den Fall gibt es den fiesen Unterschied ob ich static in 
der Deklaration oder erst später initialisiere. Also hinschreiben, was 
man meint. Legt der Compiler für die Freescale Dinger auto Variablen 
dann auf den Stack, oder haben die wirklich fixe Adressen? Kann der dann 
ohne Spezial-Keyword Reentrante Funktionen? Ich denke da an 51er 
Compiler.

BTW, "auto" (ja, ich hab's selbst benutzt) hat in neusten C++-Versionen 
eine geänderte Bedeutung. Nicht die Speicherklasse, "nicht static/nicht 
register" sonder der Typ wird aus dem Umfeld ermittelt. Man hat diese 
Inkompatible Änderung wohl deshalb gemacht, weil auto das "nie benutzte" 
Keyword ist.

von (prx) A. K. (prx)


Lesenswert?

Carl D. schrieb:
> Legt der Compiler für die Freescale Dinger auto Variablen
> dann auf den Stack, oder haben die wirklich fixe Adressen?

Da diese Prozessoren relativ zu Stackpointer adressieren können werden 
"auto" Vars wohl auf dem Stack landen. Neben Zirkus mit Reentrancy und 
Int-Handlern erspart das dem Compiler die Optimierung nie gleichzeitig 
genutzter Variablen auf die gleichen Adressen. Etwas, was für 8051 und 
PIC (12/14bit) Compiler wichtig ist. Ein Stack macht das automatisch - 
ist aber, wie oben schon erwähnt, schlechter kalkulierbar.

Letztlich bringt es auch bei diesen Prozessoren sicherlich nicht viel, 
nur lokal genutzte Variablen global/statisch zu definieren. Zumal man 
dem Compiler die Optimierung erschwert. Der Compiler ist (hoffentlich) 
für den üblichen C Stil gebaut.

Nur macht es im Code der Freescales keinen grossen Unterschied aus, ob 
die Daten mit 8 Bit Offset relativ zu SP adressiert werden, oder mit 
fester 8 Bit Adresse (wenn wenig Daten). Hingegen ist der Unterschied 
zwischen Register und RAM beim AVR sehr gross.

Ich wäre aber nicht erstaunt, im Kontext der Freescales Tipps zu finden, 
dass häufig genutzte Daten mit direkter 8-Bit Adresse besser sind als 
lokale. Denn 8-Bit relativ zu SP ist einen Takt langsamer ('08).

Für die 12er gibts übrigens eine GCC Implementierung. Wobei GCC für 
Akku-Architekturen alles andere als ideal ist. Darin finden sich einige 
Pseudo-Register im RAM. GCC wird vorgegaukelt, als hätte der einige 
Register. Auch in einer Version für die an Register etwas knappen 
Renesas R8C/M16C fand ich diese Technik.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Wenn so ein Compiler das Overlay-en von Daten beherscht, dann hat er 
auch wesentliche Informationen, die zur Berechnung der notwendigen 
Stack-Tiefe gebraucht werden. Auch daß er das Ende einer Rekursion nicht 
kennt, könnte er sagen. Dann müßte Informationsbedarf nicht zu falschen 
Programmierweises führen. "static" weils dann in .data Segment 
ausgewiesen wird.
 (das ist so wie der BWLer, dem Kosten egal sind, solange sie nicht an 
der falschen Stelle in der Bilanz auftauchen. "Extern sind keine Bösen 
Personalkosten".)

von (prx) A. K. (prx)


Lesenswert?

Carl D. schrieb:
> Wenn so ein Compiler das Overlay-en von Daten beherscht, dann hat er
> auch wesentliche Informationen, die zur Berechnung der notwendigen
> Stack-Tiefe gebraucht werden.

So herum schon. Aber nicht unbedingt anders herum. Ein Compiler, der 
Autos auf den Stack legt und somit keine RAM-Overlays braucht, der macht 
sich evtl. nicht diese Mühe. Zumal GCC nicht primär für Embedded 
entwickelt wird, und bei PCs interessiert das kein Schwein.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

> falsch, da ging es nicht um static.

Ach ja, Asche auf mein Haupt.

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
Noch kein Account? Hier anmelden.