getmem funktioniert nicht

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1079
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

getmem funktioniert nicht

Beitrag von fliegermichl »

Hallo,

Wenn ich in einem AVR Pascalprogramm getmem aufrufe, so kehrt dieser nie wieder zum Aufrufer zurück.
Gibt es hier irgendwie einen workaround um dynamisch Speicherplatz zu reservieren?

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 5097
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: getmem funktioniert nicht

Beitrag von af0815 »

Gegenfrage, gehen dynamische Objekte überhaupt am AVR ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1079
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: getmem funktioniert nicht

Beitrag von fliegermichl »

af0815 hat geschrieben:
Mo 8. Feb 2021, 12:42
Gegenfrage, gehen dynamische Objekte überhaupt am AVR ?
Nein dynamische Objekte gehen nicht. Nur statische. Aber es funktioniert auch ohne Objekte nicht.

Code: Alles auswählen

program test;
var p : PByte;
begin
 getmem(p, 1024);
 freemem(p, 1024);
end.
Wenn ich das Hexfile in AVR Studio lade, dann wird sysgetmem aufgerufen und da kehrt er niemals mehr zurück.
Ich hatte FPC stable 3.2 und wollte es jetzt mal mit Trunk ausprobieren. Da läßt sich aktuell aber der Compiler nicht übersetzen.

PascalDragon
Beiträge: 535
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: getmem funktioniert nicht

Beitrag von PascalDragon »

fliegermichl hat geschrieben:
Mo 8. Feb 2021, 09:49
Wenn ich in einem AVR Pascalprogramm getmem aufrufe, so kehrt dieser nie wieder zum Aufrufer zurück.
Gibt es hier irgendwie einen workaround um dynamisch Speicherplatz zu reservieren?
Die Embedded Platform hat standardmäßig keinen Heap Manager installiert. Dazu musst du die Unit heapmgr einbinden und ihr mittels eines oder mehreren Aufrufen von RegisterHeapBlock(AAddress: Pointer; ASize: PtrUInt) mitteilen in welchen Speicherbereichen sich der Heap Manager austoben darf.
FPC Compiler Entwickler

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1079
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: getmem funktioniert nicht

Beitrag von fliegermichl »

Vielen Dank für die Info.

Ich hätte mir zwei Tage Suche erspart, wenn da vielleicht wenigstens eine Warnung ausgegeben worden wäre.
laut Datenblatt beginnt das SRAM bei dem ATMega328P bei 0x02FF. Kann ich einfach diese Adresse angeben?

Timm Thaler
Beiträge: 1220
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: getmem funktioniert nicht

Beitrag von Timm Thaler »

Im SRAM tummeln sich ja noch Deine anderen Variablen, der Stack, Strings...

Und: Warum? Was bringt Dir die dynamische Zuweisung? Globale Variablen, Arrays, Strings werden unverrückbar im SRAM angelegt. Lokale Variablen werden temporär im Stack oder in Registern angelegt.

Selbst wenn Du einen SRAM-Bereich wieder freigibst - er wird nicht dynamisch von Variablen belegt. Er wird nur verwendet, wenn DU ihn wieder zuweist.

Und dann kannst Du gleich ein globales Array dauerhaft festlegen.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1079
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: getmem funktioniert nicht

Beitrag von fliegermichl »

Ja eben, da bin ich mir nicht sicher.
Momentan brauche ich das für die Verwaltung der Neopixel.
Für jedes Pixel werden abhängig vom Typ 36 (RGB) oder 42 (RGBW) Bytes benötigt und zwar abhängig von der Anzahl der Pixel.

In einem normalen Programm muss man sich da keinen Kopf drum machen. Man reserviert Speicher via getmem, weist den einer Variablen zu und um den Rest kümmert sich der Compiler. Hier soll ich jetzt dem Heapmanager sagen, wo der zu verwaltende Speicherbereich liegt und wie groß der sein soll und das ohne Kenntnis darüber was der Compiler so im Hintergrund da noch alles treibt.

PascalDragon
Beiträge: 535
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: getmem funktioniert nicht

Beitrag von PascalDragon »

fliegermichl hat geschrieben:
Mo 8. Feb 2021, 17:41
Ich hätte mir zwei Tage Suche erspart, wenn da vielleicht wenigstens eine Warnung ausgegeben worden wäre.
Der Compiler hat keine Ahnung was mit den Heapfunktionen angestellt wird, da diese keine wirkliche Compilermagic beinhalten.

Wobei es durchaus sinnvoll wäre irgendwo prominenter im Wiki zu erwähnen, dass dynamische Allokationen entweder vermieden werden sollen, oder man sich zumindest etwas selbst darum kümmern muss...
fliegermichl hat geschrieben:
Mo 8. Feb 2021, 21:34
In einem normalen Programm muss man sich da keinen Kopf drum machen. Man reserviert Speicher via getmem, weist den einer Variablen zu und um den Rest kümmert sich der Compiler. Hier soll ich jetzt dem Heapmanager sagen, wo der zu verwaltende Speicherbereich liegt und wie groß der sein soll und das ohne Kenntnis darüber was der Compiler so im Hintergrund da noch alles treibt.
Das ist eben mit ein Grund, warum du im Embedded Bereich weniger dynamische Allokationen verwenden solltest. Und wenn doch, dann musst du eben die entsprechenden involvierten Typen studieren und dementsprechend wissen, was für eine Größe sie brauchen.
FPC Compiler Entwickler

Timm Thaler
Beiträge: 1220
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: getmem funktioniert nicht

Beitrag von Timm Thaler »

fliegermichl hat geschrieben:
Mo 8. Feb 2021, 21:34
Für jedes Pixel werden abhängig vom Typ 36 (RGB) oder 42 (RGBW) Bytes benötigt und zwar abhängig von der Anzahl der Pixel.
Und die sollen plug&play angestöpselt werden und Du weißt vorher nicht welche und wieviele oder was?

Dann legst Du ein globales Array mit der maximalen Anzahl an, welches Du als Buffer verwendest.

Mem dynamisch anfordern fliegt Dir spätestens um die Ohren, wenn Du ein Neo mehr anstöpselst als Speicher dafür vorhanden ist.

So ein AVR ist halt kein PC oder Raspberry.

Benutzeravatar
kupferstecher
Beiträge: 373
Registriert: Do 17. Nov 2016, 11:52

Re: getmem funktioniert nicht

Beitrag von kupferstecher »

PascalDragon hat geschrieben:
Mo 8. Feb 2021, 13:28
Dazu musst du die Unit heapmgr einbinden und ihr mittels eines oder mehreren Aufrufen von RegisterHeapBlock(AAddress: Pointer; ASize: PtrUInt) mitteilen in welchen Speicherbereichen sich der Heap Manager austoben darf.
D.h. man kann eine statische Variable als Heap-Block definieren, bei der Initialisierung zuweisen, und der Compiler kümmert sich dann um den ganzen Rest?

So etwa:

Code: Alles auswählen

uses
  heapmgr;
Const
  HeapSize = 1024; //Byte
var
  HeapArea: Array[1..HeapSize] of Byte;

begin
  RegisterHeapBlock(@HeapArea, HeapSize);
 ...

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 5097
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: getmem funktioniert nicht

Beitrag von af0815 »

Grundlegende Frage, bringt der Heapmanager wirklich soviel, das man den braucht. Der wird ja von der Codegröße auch nicht umsonst sein. Und das am AVR.

Schon mal den Speicherverbrauch des Heapmanagers im Codebereich in Erfahrung gebracht, der Overhead würde mich interessieren.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

PascalDragon
Beiträge: 535
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: getmem funktioniert nicht

Beitrag von PascalDragon »

kupferstecher hat geschrieben:
Di 9. Feb 2021, 23:07
PascalDragon hat geschrieben:
Mo 8. Feb 2021, 13:28
Dazu musst du die Unit heapmgr einbinden und ihr mittels eines oder mehreren Aufrufen von RegisterHeapBlock(AAddress: Pointer; ASize: PtrUInt) mitteilen in welchen Speicherbereichen sich der Heap Manager austoben darf.
D.h. man kann eine statische Variable als Heap-Block definieren, bei der Initialisierung zuweisen, und der Compiler kümmert sich dann um den ganzen Rest?
Nicht der Compiler, sondern die RTL. Aber ansonsten ja, nur dass der hier verwendete Heapmanager einfacher gestrickt ist als der auf „großen” Systemen. (Und siehe meine Anmerkung weiter unten, dass RegisterHeapBlock normalerweise sogar gar nicht nötig ist)
af0815 hat geschrieben:
Mi 10. Feb 2021, 06:47
Grundlegende Frage, bringt der Heapmanager wirklich soviel, das man den braucht. Der wird ja von der Codegröße auch nicht umsonst sein. Und das am AVR.
Das muss man glaub ich selbst wissen, ob einem der Einsatz des Heapmanagers wert ist. Vielleicht nicht gerade auf dem kleinsten AVR, aber auf den etwas größeren ARM Microcontrollern oder den ESPs könnte es Einsatzzwecke dafür geben. FreeRTOS unterstützt ja glaube ich auch dynamische Allokation.
af0815 hat geschrieben:
Mi 10. Feb 2021, 06:47
Schon mal den Speicherverbrauch des Heapmanagers im Codebereich in Erfahrung gebracht, der Overhead würde mich interessieren.
Probier's einfach aus. Du musst nur die Unit einbinden, du brauchst noch nichtmal was mit RegisterHeapBlock registrieren, da der Compiler einen initialen Heapbereich vorsieht (kann mit -ChXXX oder {$memory stacksize,heapsize} geändert werden), der nur eben normalerweise nicht mitgelinkt wird, da keine Unit ihn referenziert.
FPC Compiler Entwickler

Warf
Beiträge: 1662
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: getmem funktioniert nicht

Beitrag von Warf »

Einen Heap Manager zu verwenden fügt overhead hinzu den man normalerweise auf Microcontrollern vermeiden will.
Wenn du Polymorphismen brauchst ist es meist einfacher statisch genug platz zu alloziieren und den dann abhängig von dem pixel typen drauf zugreifen.

Pascal bietet dafür bereits schon das syntaktische Feature der varianten Records an:

Code: Alles auswählen

  TPixelType = (ptRGB, ptRGBW);
  TRGBRec = packed record
    r, g, b: Byte;
  end;
  TRGBWRec = packed record
    r, g, b, w: Byte;
  end;

  generic TPixelArray<const Size: SizeInt> = record
    PixelType: TPixelType;
    case PixelType of
    ptRGB: (RGBPixels: Array[0..Size-1] of TRGBRec);
    ptRGBW: (RGBWPixels: Array[0..Size-1] of TRGBWRec);
  end; 
  
  var
    pixels: specialize TPixelArray<1024>;
  begin
    pixels := GeneratePixels;
    if pixels.PixelType = ptRGB;
      PrintRGB(Pixels.RGBPixels)
    else
      PrintRGBW(Pixels.RGBWPixels);  
  end.
  
Der Record TPixelArray ist dann so groß das entweder RGBPixels oder RGBWPixels komplett reinpassen. Die größe die vom Compiler alloziiert wird ist also max(SizeOf(RGBPixels), SizeOF(RGBWPixels). Wenn du das extra byte für pixeltype nicht brauchst, geht das auch so:

Code: Alles auswählen

  generic TPixelArray<const Size: SizeInt> = record
    case TPixelType of
    ptRGB: (RGBPixels: Array[0..Size-1] of TRGBRec);
    ptRGBW: (RGBWPixels: Array[0..Size-1] of TRGBWRec);
  end; 

siro
Beiträge: 572
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 10
CPU-Target: 64Bit
Wohnort: Berlin

Re: getmem funktioniert nicht

Beitrag von siro »

Bei diesen kleinen Controllern würde ich niemals dynamische Speicherverwaltung nutzen.
Der hat ja eh nur 2 KByte RAM.

Wenn der RAM knapp ist, kannst Du auch den RAM mehrfach benutzen.

Den Speicher für die NeoPixel kannst Du dann evtl. auch für andere Dinge nutzen.

Also Du bastelst deine Daten für die NeoPixel und schiebst sie dann aus.
Diese Daten bleiben ja in den LEDs erhalten und gehen nicht verloren.

Nun kannst Du den Speicher vorrübergehend auch für was anderes benutzen.
Danach must Du natürlich wieder die Daten für die NeoPixels aufbereiten

Im Prinzip funktioniert das wie ein Varianten Record.

Code: Alles auswählen

var UniRam : Array[0..1023] of Byte;   // 1 KByte für diverse Zwecke irgendwo im RAM

var NeoPixel:Array[0..43] of record
  r,g,b:Byte;
end absolute UniRam;   // Die Daten befinden sich an der Adresse UniRam, wo genau legt der Compiler bzw. Linker fest.

var Diverses:Array[0..16] of Integer absolute UniRam;  // Dieses Array liegt an gleicher Speicherstelle wie die NeoPixels

procedure Test;
begin
  NeoPixel[0].r:=$7f;
  Diverses[0]:=123;
end;                  
Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1079
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: getmem funktioniert nicht

Beitrag von fliegermichl »

Hört sich nach brauchbaren Lösungen an.
Ich hab zwar den ATMega328P mit 8Kb RAM aber verRAMschen muss man den trotzdem nicht.

Antworten