Forum: Mikrocontroller und Digitale Elektronik struct list_head Funktionalität auf Cortex-M4 nutzen


von Adam P. (adamap)


Lesenswert?

Hallo zusammen,

ich bin heute über die list.h & types.h (Linux) gestolpert und die 
Funktionalität der
1
struct list_head
ist genau das was ich gesucht habe.

Nun würde ich dies gern in meinem Projekt nutzen - Cortex-M4(Atmel).

Darf ich mir nun den Spaß machen und alle include Abhängigkeiten selbst 
auflösen (Dateien kopieren, ...).
Dazu kommen natürlich dann auch noch die arch include usw.

Oder gibt es da einen einfacheren Weg?
Ich möchte keine andere lib nutzen die das auch könnte, sonder schon den 
Linux source.

Klar, oder selbst nachschreiben...
jedoch, wozu das Rad neu erfinden.

Gruß

von Niklas Gürtler (Gast)


Lesenswert?

Adam P. schrieb:
> Oder gibt es da einen einfacheren Weg?
> Ich möchte keine andere lib nutzen die das auch könnte, sonder schon den
> Linux source.

Aber warum? Im Internet gibt es Tausende Implementationen von 
verketteten Listen. Man kann sie auch recht einfach selbst 
implementieren. Oder C++ verwenden, was bereits eine Liste eingebaut hat 
(std::list).

von Adam P. (adamap)


Lesenswert?

Niklas Gürtler schrieb:
> Aber warum?

Weil es sich bewährt hat?

Niklas Gürtler schrieb:
> Oder C++ verwenden

Geht nicht.

: Bearbeitet durch User
von Niklas Gürtler (Gast)


Lesenswert?

Adam P. schrieb:
> Weil es sich bewährt hat?

Das haben andere Bibliotheken auch...

von Adam P. (adamap)


Lesenswert?

Niklas Gürtler schrieb:
> Adam P. schrieb:
>> Weil es sich bewährt hat?
>
> Das haben andere Bibliotheken auch...

OK, bin ja immer offen für neues. Hast du mir eine Bsp.-Lib?

edit:
Ich greife aus Interesse für Neues erst zum Linux source.

: Bearbeitet durch User
von Adam P. (adamap)


Lesenswert?

Achso, was zu beachten wäre:

Ich benötige natürlich ebenfalls die Funktionalität von:
1
container_of()
2
offsetof()

Um die Member in meinen Strukturen zu finden.
https://www.fatalerrors.org/a/play-with-kernel-list_head-three-examples-of-super-cattle.html

Absatz: Example 1

Das offsetof() habe ich im arm-gcc compiler.h

: Bearbeitet durch User
von c++-hater.. (Gast)


Lesenswert?

> Geht nicht.
Sehr vernünftig!

von Adam P. (adamap)


Lesenswert?

c++-hater.. schrieb:
>> Geht nicht.
> Sehr vernünftig!

Hast du eine Idee @c++-hater?

Anscheinend bleibt wohl nichts übrig als einen eigenen Port zu basteln, 
oder?

edit:
Gerade mit einem Kollegen tel. und er meinte auch, das er sowas schon 
oft brauchte, aber es nie fertig zum nutzen gab, wenn man kein Linux 
nutzt.

: Bearbeitet durch User
von Klaus W. (mfgkw)


Lesenswert?

Adam P. schrieb:
> Hast du eine Idee @c++-hater?

Darauf kannst du lange warten.

"Meckern ko a jeder Bauer, besser machen werd ehm sauer."

von Niklas Gürtler (Gast)


Lesenswert?

Adam P. schrieb:
> OK, bin ja immer offen für neues. Hast du mir eine Bsp.-Lib?

Hier eine Auswahl:

https://github.com/oz123/awesome-c#data-structures

Adam P. schrieb:
> Das offsetof() habe ich im arm-gcc compiler.h

offsetof ist ein Standard-Makro und in <stddef.h> definiert, wozu 
braucht es da noch arm-gcc-compiler.h ?

Adam P. schrieb:
> Niklas Gürtler schrieb:
>
>> Oder C++ verwenden
>
> Geht nicht.

Aha... Datenstrukturen lassen sich in C++ sehr viel eleganter und 
sicherer implementieren.

Aber noch eine ganz andere Frage: Machen verkettete Listen und die damit 
meistens einhergehende dynamische Speicherverwaltung auf 
Mikrocontrollern Sinn? Ich komme meistens mit Arrays, Ringpuffern oder 
o.ä. aus.

von Adam P. (adamap)


Lesenswert?

Niklas Gürtler schrieb:
> offsetof ist ein Standard-Makro und in <stddef.h> definiert, wozu
> braucht es da noch arm-gcc-compiler.h ?

Sorry hatte mich vertan, natürlich meine ich die stddef.
Zu viele Header angeschaut und durcheinander gekommen.

Niklas Gürtler schrieb:
> Aber noch eine ganz andere Frage: Machen verkettete Listen und die damit
> meistens einhergehende dynamische Speicherverwaltung auf
> Mikrocontrollern Sinn? Ich komme meistens mit Arrays, Ringpuffern oder
> o.ä. aus.

Da magst du recht haben, habe das bis jetzt auch so gemacht.
Jedoch haben die Listen den Vorteil, dass man kein RAM verschwendet.

Bsp.:
Ich habe ein CLI (command line interface) Modul.
Andere Module können nun ihre Funktionen dort registrieren,
dafür besitzt das CLI Modul ein struct Array in dem die Callback 
Funktionen und der String abgelegt wird.
1
#define CLI_MAX_CMD_LENGTH  15
2
#define CLI_MAX_CMD_COUNT  50
3
4
typedef struct
5
{
6
  char cmd[CLI_MAX_CMD_LENGTH];
7
  cli_func func;
8
} cli_cmd_t;
9
10
static cli_cmd_t cli_cmd[CLI_MAX_CMD_COUNT];

Registriere ich nun nur 3 Funktionen, müsste ich das define anpassen um 
nicht unnötig RAM freizuhalten.

Würde man dies auf Listen umbauen, dann würde sich das Problem in Luft 
auflösen.

: Bearbeitet durch User
von Niklas Gürtler (Gast)


Lesenswert?

Adam P. schrieb:
> Jedoch haben die Listen den Vorteil, dass man kein RAM verschwendet.

Der Punkt ist - für gesparten RAM gibt es kein Geld zurück. Auf einem uC 
ohne OS kann schließlich kein anderes Programm laufen und den freien RAM 
nutzen, wie auf dem PC. Daher ist es für uC-Programme völlig legitim, 
den maximal benötigten RAM statisch zu allokieren.

Adam P. schrieb:
> Bsp.:
> Ich habe ein CLI (command line interface) Modul.
> Andere Module können nun ihre Funktionen dort registrieren,

Warum ist das überhaupt im RAM? Das ändert sich doch nicht. Warum nicht 
ein konstantes Array im Flash mit allen Funktionen? Du brauchst halt an 
zentraler Stelle einmal eine Auflistung aller Module bzw. der 
Funktionen. Die brauchst du aber sowieso, weil du die Module ja auch 
starten können musst.

von Adam P. (adamap)


Lesenswert?

Niklas Gürtler schrieb:
> Daher ist es für uC-Programme völlig legitim,
> den maximal benötigten RAM statisch zu allokieren.

Schon, jedoch geht es eher darum, RAM nicht zu verschwenden,
da dieser bekanntlich nicht im Bereich MB oder GB liegt sondern in 
meinem Fall nur 128K beträgt.

Auf meinem System A alles kein Problem, das System B hat jedoch noch ein 
OLED und da wird es sehr eng - Optimierungen wären da sehr hilfreich.

Niklas Gürtler schrieb:
> Warum ist das überhaupt im RAM? Das ändert sich doch nicht. Warum nicht
> ein konstantes Array im Flash mit allen Funktionen? Du brauchst halt an
> zentraler Stelle einmal eine Auflistung aller Module bzw. der
> Funktionen. Die brauchst du aber sowieso, weil du die Module ja auch
> starten können musst.

Da ich es als Blackbox betrachten möchte.
Jedes Modul kann es nutzen oder auch nicht, Anpassungen/Änderungen am 
CLI Modul selbst sind dann nicht notwendig.

von Adam P. (adamap)


Lesenswert?

Niklas Gürtler schrieb:
> Hier eine Auswahl:
>
> https://github.com/oz123/awesome-c#data-structures

Bin da mal drüber geflogen und müsste noch dazu sagen:
Auf malloc und der gleichen sollte verzeichtet werden.

von Johannes S. (Gast)


Lesenswert?

Das Zephyr OS erfreut sich wachsender Beliebtheit, ist von der Linux 
Foundation und macht wohl einiges wie Linux. Habe es selber noch nicht 
benutzt weil ich C++ lieber mag, aber linked lists sind da auch 
vorhanden.

von Adam P. (adamap)


Lesenswert?

Johannes S. schrieb:
> Das Zephyr OS

Stimmt, jetzt wo du es sagst. Hab das schon mal gesehen (Nordic 
nRF52840).
Werde mir das mal genauer anschauen.

von Rolf M. (rmagnus)


Lesenswert?

Adam P. schrieb:
> Jedoch haben die Listen den Vorteil, dass man kein RAM verschwendet.

Hm? Zunächst braucht jedes Listenelement einen zusätzlichen Zeiger auf 
seinen Nachfolger, und falls doppelt verkettet nötig ist, auch auf den 
Vorgänger. Dazu kommt, dass dann jedes Listenelement einzeln dynamisch 
allokiert wird und damit zusätzlichen Overhead für die internen 
Verwaltungsdaten des Speichermanagers hat (meist nochmal mindestens ein 
Zeiger).

> Registriere ich nun nur 3 Funktionen, müsste ich das define anpassen um
> nicht unnötig RAM freizuhalten.
>
> Würde man dies auf Listen umbauen, dann würde sich das Problem in Luft
> auflösen.

Was du dafür brauchst, ist dynamischer Speicher. Der geht auch ohne 
verkettete Listen.

Adam P. schrieb:
> Da ich es als Blackbox betrachten möchte.
> Jedes Modul kann es nutzen oder auch nicht, Anpassungen/Änderungen am
> CLI Modul selbst sind dann nicht notwendig.

Speicherplatz sparen zu wollen, passt aber nicht wirklich damit 
zusammen, dann die Registrierung von Modulen, die zur Compilezeit alle 
bekannt sind, erst dynamisch zur Laufzeit durchzuführen. Das erhöht 
nämlich den Bedarf an RAM und braucht auch zusätzlich flash, weil dafür 
ja auch zusätzlicher Code nötig ist.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Adam P. schrieb:
> Schon, jedoch geht es eher darum, RAM nicht zu verschwenden,

Du möchtest RAM sparen, aber dann...

Adam P. schrieb:
> Da ich es als Blackbox betrachten möchte.
> Jedes Modul kann es nutzen oder auch nicht, Anpassungen/Änderungen am
> CLI Modul selbst sind dann nicht notwendig.

Bei cleverer Programmierung geht auch das. Wenn du ein konstantes Array 
von Modulen hast, kann das CLI Modul zur Suche von Befehlen alle Module 
iterieren, und jedes Modul hat wieder ein statisches Array aus Befehlen, 
die einfach iteriert werden können (2 Schleifen ineinander). Das braucht 
dann überhaupt keinen RAM, fährt schnell hoch, und das Iterieren ist 
auch schneller.

von Oliver S. (oliverso)


Lesenswert?

Adam P. schrieb:
> Schon, jedoch geht es eher darum, RAM nicht zu verschwenden,
> da dieser bekanntlich nicht im Bereich MB oder GB liegt sondern in
> meinem Fall nur 128K beträgt.
>
> Auf meinem System A alles kein Problem, das System B hat jedoch noch ein
> OLED und da wird es sehr eng - Optimierungen wären da sehr hilfreich.

Je nun, wenn du mehr Listenelemente benötigst, als ins Ram passen, dann 
benötigst du mehr Listenelemente, als ins Ram passen. Beim statischen 
Ansatz mit festem Array findest du das (mit etwas Vorsorge) schon zur 
Compilezeit raus, mit dynamischen Listen gibt das einen Fehlerfall, der 
zur Laufzeit abgefangen werden muß. Ob man das auf einem Microcontroller 
will oder überhaupt sinnvoll kann, ist deine Entscheidung. Wenn das 
letzte Listenelement noch passt, dann aber der OLED-Code wegen 
Speichermangel crasht, wirds kompliziert.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Eine zentrale Komponente braucht's doch auch so oder so. Schließlich 
muss die Registrierfunktion aller Module ja auch von irgendwo aufgerufen 
werden. Wenn man jetzt stattdessen an dieser Stelle eine statische 
Tabelle der zu registrierenden Funktionen anlegt, die dann von deinem 
CLI als input genutzt wird, kann man sich die Registriererei zur 
Laufzeit sparen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

z.B. so in der Art:

module.h:
1
typedef struct {
2
  const char* name;
3
  int (*fPtr) (int argc, const char* argv []);
4
} CLIFun;
5
6
typedef struct {
7
  const char* name;
8
  const CLIFun* functions;
9
  size_t numFunctions;
10
} Module;

module_io.h:
1
extern const Module moduleIO;

module_io.c:
1
static const moduleIO_Functions [] = {
2
  { "set", &moduleIO_set },
3
  { "get", &moduleIO_get }
4
};
5
const Module moduleIO {
6
  "IO Module",
7
  &moduleIO_functions,
8
  sizeof(moduleIO_functions)/sizeof(moduleIO_functions[0])
9
};

modules_def.h:
1
#include <stddef.h>
2
#include "module.h"
3
4
extern const Module modules [3];
5
static const size_t numModules = 3;

module_def.c:
1
#include "modules_def.h"
2
#include "module_io.h"
3
#include "module_pwm.h"
4
#include "module_adc.h"
5
6
const Module modules [3] = {
7
  moduleIO,
8
  modulePWM,
9
  moduleADC
10
};

cli.c:
1
#include "module_def.h"
2
3
int cli_runCommand (const char* name, int argc, char* argv []) {
4
  for (size_t iModule = 0; iModule < numModules; ++iModule) {
5
    const Module* module = modules [iModule];
6
    for (size_t iFunction = 0; iFunction < module->numFunctions; ++iFunction) {
7
      const CLIFun* fun = module->functions [iFunction];
8
      if (strcmp (name, fun->name) == 0) {
9
        return (fun->fPtr) (argc, argv);
10
      }
11
    }
12
  }
13
  return ERR_FUN_NOT_FOUND;
14
}

Die redundante Größenangabe des Module-Arrays mittels Makro-Magic 
wegzuoptimieren sei als Übung überlassen :)

So entfällt die Initialisierung komplett und es wird überhaupt kein RAM 
benötigt. Externe Abhängigkeiten hat man sich auch gespart, und das 
hässliche offsetof() ebenfalls.

Beitrag #6898334 wurde vom Autor gelöscht.
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.