32u4 Stackpointer verbiegen

Hi,

gibt es eine Möglichkeit in einer loop() welche bewusst mittels while(1){...} auf keinen Fall verlassen wird den Stackpointer sinnvoll um ein paar Bytes nach oben zu setzen um für memaloc noch ein paar Bytes freizuschaufeln?
Mit Serial.Print(SP); habe ich mir die Adresse anzeigen lassen und die liegt direkt am Anfang in der loop() bei 2778.
Höchst Möglicher Wert ist ja 2816 (256Byte I/O+2560Byte SRAM).
Aber bei einer Korrektur auf z. B. 2782 fehlen dann doch wieder ein paar Bytes für eine Funktion welche memaloc aufruft.
Wird im Stack ganz oben noch was anderes als Rücksprungadressen und gepushte Register gespeichert was bei Änderung des SP dann memaloc beeinflusst oder wie könnte man da vor gehen?

MfG
Andi

Hallo,
so eine Software könnte man auch als "Klingonen-Software" bezeichnen.
Aussage klingonischer Softwareentwickler: -- "Jeder Nutzer wird Furcht und Achtung vor dieser Software haben. Laßt die Software los! Laßt sie los, auf daß die Nutzer wie die Hunde fliehen, die sie sind." --
Viele Grüße Manfred

Da der Stack ganz oben im RAM platziert ist, geht das natürlich nicht.

Wenn dein Allokieren nicht mehr geht, könnte das an einer Fragmentierung der Heaps liegen,
nicht unbedingt an seiner (anscheinend zu kleinen) Größe.

Besser ist es auf dynamische Allokationen ganz zu verzichten (und damit natürlich auch auf Strings).

Der Stack beginnt ganz oben.
Es gibt kein Hochsetzen, ohne Versagen(Datenüberschreiben).

Verzichte doch auf setup() und loop(), wenn dir die nicht gefallen.

combie:
Verzichte doch auf setup() und loop(), wenn dir die nicht gefallen.

setup() ist (von Nebenwirkungen abgesehen) Speicher/Stack neutral,
die Rücksprungadresse von loop() kostet 2 Bytes RAM.

Ich wette, dass ich den dem Program mehr Speicher freibekomme, ohne loop zu entfernen.

Der Sketch verwendet 480 Bytes (1%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 9 Bytes (0%) des dynamischen Speichers, 2.039 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

Arduino leerer Rumpf.

Der Sketch verwendet 134 Bytes (0%) des Programmspeicherplatzes. Das Maximum sind 32.256 Bytes.
Globale Variablen verwenden 0 Bytes (0%) des dynamischen Speichers, 2.048 Bytes für lokale Variablen verbleiben. Das Maximum sind 2.048 Bytes.

Verzicht auf Loop und Setup

2 Byte ist übrigens nicht richtig...
Da fehlen dir noch eine ganze menge Push in der Rechnung.

combie:
2 Byte ist übrigens nicht richtig...
Da fehlen dir noch eine ganze menge Push in der Rechnung.

Na ja, für mich sieht das nicht so aus.

unsigned int lastSP;
void setup() {
  lastSP = SP;
  Serial.begin(250000);
  Serial.print(F("SP = 0x"));
  Serial.println(SP, HEX);
  loop();
}
void loop() {
  static byte count;
  if (count < 1) {
    count++;
    Serial.print(F("SP = 0x"));
    Serial.print(SP, HEX);
    if (lastSP != SP) {
      Serial.print(F(" Diff "));
      Serial.print(lastSP - SP, HEX);
    }
    Serial.println();
  }
}
SP = 0x8FD
SP = 0x8FB Diff 2

Auf setup() kann ich nicht verzichten da sonst die Anbindung an GLEdiator nicht mehr geht wegen fehlendem Serial-Support (32u4, USB-Serial).
Auf loop() könnte ich verzichten aber das ist dann auch wegen setup() wieder egal.
OK, da es tatsächlich nur die letzten 2 Bytes sind die man den Stack nach oben setzen könnte wenn die loop() nie verlassen wird habe ich das jetzt anders gelöst.
Es geht um die Neopixel-Library, updateLenght.
Da ich von einem "Setup-Modus" diese Funktion aufrufte und diese dann malloc wo dann wieder was auf den Stack kam war unter Umständen nicht mehr genügend frei.
Habe die paar Zeilen von updateLenght in die aufrufende Funktion kopiert und angepasst und nun klappt es.
Die meisten privaten Variablen habe ich sowieso schon auf public gesetzt und kann dadurch über die Neopixel-Klasse darauf zugreifen und ändern.
Muss halt noch beobachten ob sich was dadurch beeinflusst.

MfG
Andi

Haribo68:
Es geht um die Neopixel-Library, updateLenght.
Da ich von einem "Setup-Modus" diese Funktion aufrufte und diese dann malloc wo dann wieder was auf den Stack kam war unter Umständen nicht mehr genügend frei.
Habe die paar Zeilen von updateLenght in die aufrufende Funktion kopiert und angepasst und nun klappt es.

Ich kann mir nicht vorstellen updateLength benutzen zu wollen.
Ich weiss vorher wie lang meine LED Kette ist, das ändert sich nicht.

Wenn man es nur für sich machen möchte und ohne verstellbarer Konfiguration dann haste recht.

MfG
Andi

Da sehe ich keinen Unterschied.

Konfigurieren, Konfiguration in den EEPROM, mit der neuen 'festen' Konfiguration booten.

Na ja, ich sehe schon einen Unterschied zwischen mir der das ganze programmiert - zumindest versuch ichs^^ - oder einem der kein Arduino-IDE hat sich das hinnagelt und dann mittels FB die Anzahl der LEDs und was weis ich noch einstellt.

MfG
Andi

Whandall:
Na ja, für mich sieht das nicht so aus.

Ja, das optimiert er fein!

In loop() eine Kleinigkeit hinzufügen, dann sieht das schon anders aus.
for(int i = 0; i<5;i++ ) Serial.print(i);

000003a4 <loop>:
 3a4: cf 92       push r12
 3a6: df 92       push r13
 3a8: ef 92       push r14
 3aa: ff 92       push r15

Du hast dir da einen feinen Sonderfall raus gesucht.

Wo ist das vollständige kompilende Programm, dass das auch ausdruckt?

Wenn loop kurz genug ist, wird der Kompiler die Funktion ganz ohne zusätzliche Stackbelastung einbauen.

Mit einem attribute kann man das inline auch erzwingen, genaue Syntax habe ich nicht im Kopf.

Wenn loop kurz genug ist, wird der Kompiler die Funktion ganz ohne zusätzliche Stackbelastung einbauen.

:o Das habe ich doch gerade gesagt! :o
Oder?

Wo ist das vollständige kompilende Programm, dass das auch ausdruckt?

Dürfte ich dich bitten, das mal für doofe um zu formulieren?

Mit einem attribute kann man das inline auch erzwingen, genaue Syntax habe ich nicht im Kopf.

Wenn man Änderungen im Core vornehmen möchte......

Was du da gezeigt hast, könnte durchaus die Initialisierung lokaler Variablen sein,
oder das Retten der Registerinhalte, die jetzt die neuen Variablen darstellen,
die würde ich nicht zum loop-Funktions-Overhead zählen.

Mein Beispiel ist durchaus nicht-trivial, benutzt halt nur keine lokalen Variablen.
Wenn die benutzt werden kommt ein kleiner Stack-Frame zu den eigentlichen Variablen hinzu,
mit einem einfachen ret ist es dann nicht mehr getan.

Einen direkten Zusammenhang zwischen Variablentypen (byte/int/long) habe ich nicht sehen können.

Ist aber auch völlig egal, wenn die paar Byte bei einem malloc fehlen,
ist der Rechner zu klein, oder man hat etwas falsch gemacht.

Mit dem Kode habe ich rumgespielt

#define static_J
#define static_I
unsigned int lastSP;
void setup() {
  lastSP = SP;
  Serial.begin(250000);
  Serial.print(F("SP = 0x"));
  Serial.println(SP, HEX);
  loop();
}
void loop() {
  static byte count;
#ifdef static_I
  static byte i;
#endif
#ifdef static_J
  static byte j;
#endif
  if (count < 1) {
#ifdef static_I
    for (i = 0; i < 5; i++) {
#else
    for (byte i = 0; i < 5; i++) {
#endif
#ifdef static_J
      for (j = 0; j < 5; j++) {
#else
      for (byte j = 0; j < 5; j++) {
#endif
        Serial.print(j);
        Serial.write(' ');
      }
      Serial.println(i);
      count++;
    }
    Serial.print(F("SP = 0x"));
    Serial.print(SP, HEX);
    if (lastSP != SP) {
      Serial.print(F(" Diff "));
      Serial.print(lastSP - SP, HEX);
    }
    Serial.println();
  }
}

beide static

SP = 0x8FD
0 1 2 3 4 0
0 1 2 3 4 1
0 1 2 3 4 2
0 1 2 3 4 3
0 1 2 3 4 4
SP = 0x8FB Diff 2

nur i static

SP = 0x8FD
0 1 2 3 4 0
0 1 2 3 4 1
0 1 2 3 4 2
0 1 2 3 4 3
0 1 2 3 4 4
SP = 0x8F7 Diff 6

nur j static

SP = 0x8FD
0 1 2 3 4 0
0 1 2 3 4 1
0 1 2 3 4 2
0 1 2 3 4 3
0 1 2 3 4 4
SP = 0x8F7 Diff 6

beide lokal

SP = 0x8FD
0 1 2 3 4 0
0 1 2 3 4 1
0 1 2 3 4 2
0 1 2 3 4 3
0 1 2 3 4 4
SP = 0x8F3 Diff A