Hallo
Für mein aktuelles Projekt (Bilderkennung) komme ich ziemlich an die
Grenzen des Speichers meines AVR. Nun wird mein Bild schrittweise
analysiert. Ein erster Schritt benötigt eine Anzahl Variabeln
(insbesondere Arrays), die später nicht mehr benötigt werden und nur
viel Platz wegnehmen.
Wie kann man solche Variabeln wieder 'löschen'? Natürlich könnte man
sie lokal in einer Funktion definieren, doch leider werden sie auch in
ISRs benötigt - es sind also Globalvariabeln.
Gruss
Michael
Variablen global definieren ist ein schlechter programmierstill.
Deklariere die Varialen lokal, und übergebe dann nur einen Pointer auf
die Daten, an die sub routine.
Hallo,
das würde mich mal auch interessieren.
Das mit dem Zeiger ist ja klar, aber wie macht man daß bei
einer Interruptroutine ?
Die ruft der Prozessor ja selber auf; da kann ich nichts übergeben.
Wie kriegt man also eine Verbindung zwischen der Variablen der ISR und
der einen lokalen Funktion ?
Ich wüßte auf die schnelle keinen praktikablen Weg.
Jogibär
Das geht entweder über globale Variablen (wobei man das volatile nicht
vergessen darf) oder eben (elegant), indem man die Bearbeitung des
Interrupt-Ereignisses an sich nicht in der ISR durchführt, sondern dort
nur ein Flag setzt und den Rest im Hauptprogramm (mit lokalen Variablen)
macht. Letztere Variante geht natürlich nicht in Fällen, wo es wirklich
zeitkritisch ist. Da bleibt einem dann nichts anderes übrig, als global
zu denken;-)
> Das mit dem Zeiger ist ja klar, aber wie macht man daß bei> einer Interruptroutine ?> Die ruft der Prozessor ja selber auf; da kann ich nichts übergeben.
Ohne eine globale Variable kommst du da nicht weg.
Aber die globale Variable kann ein Pointer sein, welcher
dann auf die eigentlichen Daten zeigt.
struct MeineDaten
{
int MemberA;
int MemberB;
char Buffer[200];
unsigned char Image[400];
};
volatile struct MeineDaten* pData;
ISR( was_auch_immer_vect )
{
if( pData ) {
// mach was mit den Daten
pData->MemberA = 5;
pData->MemberB = 8;
}
}
void foo()
{
struct MeineDaten Data;
// die lokalen Variablen für die ISR bereitstellen
pData = &Data;
//
// so , jetzt kann die ISR arbeiten
//
// funktion wird verlassen, die ISR wieder von den
// Daten abklemmen
pData = NULL;
}
int main()
{
.....
foo();
while( 1 );
}
> Ein erster Schritt benötigt eine Anzahl Variabeln> (insbesondere Arrays), die später nicht mehr benötigt werden und> nur viel Platz wegnehmen.
Genau diese Aufgabenstellung ist die Grundidee hinter einer
union:
* Ein Programm läuft in Abschnitten ab.
* Jeder Abschnitt hat seine eigenen Variablen, die nur in diesem
Abschnitt gebraucht werden
* Ausserhalb des Abschnittes sind die Variablen nutzlos und liegen
nur im Speicher rum
* Mittels einer union kann vereinbart werden, dass die Variablen
mehrerer Abschnitte quasi übereinandergelegt werden sollen und
damit verschiedene Abschnitte immer denselben Speicher benutzen.
Hallo
@Karl Heinz: Das hört sich schlüssig an! Werde es dann wohl so
machen. Irgendwie dachte ich an die Union, getraute mich aber nicht so
recht ;-)
Gruss
Michael
Hallo
Nochmals @Karl Heinz: Hört sich doch nicht so schlüssig an, weil: Eine
Union kann ja nur eine Variable pro Zeitpunkt speichern. Wenn ich nun
aber in meinem Programm in Abschnitt A zehn einfache Variabeln und fünf
längere Arrays habe und in Abschnitt B dann einfach ein längeres Array,
dann geht das leider nicht mit Unions.
Was haltet ihr von den Funktionen malloc() und free()?
Gruss
Michael
Kann eine Union denn mehrere Variabeln zum gleichen Zeitpunkt aufnehmen?
Hmmm...ich könnte für jeden Programmabschnitt ein struct 'reinpacken!
lichtaufgeht
Andere Frage: Overhead bei malloc/free? Wenn das alle paar Sekunden
geschieht, sollte das doch nicht allzuviel ausmachen?
> Hmmm...ich könnte für jeden Programmabschnitt> ein struct 'reinpacken! *lichtaufgeht*
Bingo!
> Andere Frage: Overhead bei malloc/free? Wenn das alle paar> Sekunden geschieht, sollte das doch nicht allzuviel ausmachen?
Zeitlich vermutlich nicht. Du mußt allerdings auch noch den
Speicherverbrauch dazurechnen. Einerseits brauchen die Funktionen
selbst wieder Flash, andererseits braucht die Speicherverwaltung noch
zusätzliches RAM.
Ich weiß ja nicht, um welchen AVR es geht und wieviele Ressourcen noch
verfügbar sind. Ehrlich gesagt weiß ich auch nicht, wieviel genau die
Speicherverwaltung kostet.
Noch eine Frage: Muss ich irgend etwas spezielles beachten, wenn ich
zwischen den verschiedenen Variabeln in der union wechsle? Ausser, dass
ich sie vor Gebrauch natürlich wieder mit einem sinnvollen Wert
initialisieren muss ;-)
> Ehrlich gesagt weiß ich auch nicht, wieviel genau die> Speicherverwaltung kostet.
10 Bytes statischen RAM-Verbrauch, sowie 2 Bytes RAM
zusätzlich pro alloziertem Block, um die Größe dieses Blocks
aufzuzeichnen. 1-Byte-Blöcke werden auf 2 Bytes aufgerundet.
542 Bytes Code auf den ,kleinen' Prozessoren (die kein MOVW
und MUL haben), 498 Bytes Code auf den großen Prozessoren.
Also vielleicht nicht gerade sinnvoll für einen ATtiny2313 :),
ab einem ATmega8 kann man drüber nachdenken, ab einem ATmega32
interessiert der Ressourcenverbrauch wohl kaum noch, da bleibt
dann nur noch die Frage nach den möglichen Auswirkungen der
Speicherfragmentierung. Da es im Thread um Bildverarbeitung
geht, wird es wohl nicht gerade der allerkleinste AVR sein.
Hallo
Ist ein Mega32 - Hauptproblem ist ganz klar das RAM (2 kB + 32 kB
extern (dämlich angesteuert über 4024 als Adress-Counter)), das
Programm passt locker rein und auch die Rechengeschwindigkeit ist ganz
ok (schnellere Echtzeitauswertung kann man auf einem AVR aber
vergessen).
Mit unions funktioniert das ganze eigentlich am besten - besser als mit
malloc() und free(), denn hier müsste jede einzelne Variable angefordert
und wieder entfernt werden, mit entsprechender Pointerorgie, bei der
union kann man bequem ein paar Structs für jeden Programmabschnitt
machen, die dann nacheinander benutzt werden. Einziger Nachteil: Man
schreibt genug: union.struct.variable - und ich weiss nicht, wie
schnell da der Zugriff intern gehandhabt wird.
Gruss
Michael
Kleiner Tip:
Mittels Makros hat sich schon so mancher so manchen
Schreibaufwand eingespart.
#define VARIABLE union.struct.variable
und schon wird aus einem
union.struct.variable = 5;
ein simples
VARIABLE = 5;
Nutze die Macht, Luke. Äh, mr. chip
> und ich weiss nicht, wie> schnell da der Zugriff intern gehandhabt wird.
Da beim Zugriff alles statisch ist, und der Compiler
die Adressen ausrechnen kann, kannst du mal davon ausgehen
dass er das auch tun wird.
> Da beim Zugriff alles statisch ist, und der Compiler> die Adressen ausrechnen kann, kannst du mal davon ausgehen> dass er das auch tun wird.
Das heisst dann, ein Zugriff auf eine 'union.struct.variable' ist vom
Aufwand her äquivalent zu einem Zugriff auf 'variable'?
> Mit unions funktioniert das ganze eigentlich am besten - besser als> mit malloc() und free(), denn hier müsste jede einzelne Variable> angefordert und wieder entfernt werden,
Ist eine Frage der Lebenszeit. Wenn die Variablen alle praktisch
immer leben, dann sind die unions sicher am besten. Wenn du eine
stochastische Verteilung der Lebensdauer hast, belegst du bei der
malloc()-Variante halt nur den Speicher, den du gerade brauchst.
> Ist eine Frage der Lebenszeit. Wenn die Variablen alle praktisch> immer leben, dann sind die unions sicher am besten. Wenn du eine> stochastische Verteilung der Lebensdauer hast, belegst du bei der> malloc()-Variante halt nur den Speicher, den du gerade brauchst.
Klingt logisch. Allerdings habe ich wie erwähnt eine ganz klare
Aufstellung, wann welche Variabeln existieren. Im ersten Abschnitt des
Programms jene, im zweiten andere. Es gibt weder Überlappungen noch
'Zufälligkeiten'. Ich denke, dies ist auf einem kleinen
Mikrocontroller bei derart speicherintensiven Anwendungen auch die
Regel - man muss jedes einzelne Byte genau einteilen, sonst hat das
wüste Folgen...
> Ich denke, dies ist auf einem kleinen Mikrocontroller bei derart> speicherintensiven Anwendungen auch die Regel - man muss jedes> einzelne Byte genau einteilen, sonst hat das wüste Folgen...
Würde ich so nicht ganz stehen lassen. Stochastik kann ebenfalls gut
funktionieren, auch wenn es auf den ersten Blick wie Chaos aussieht.
Die Diskussion erinnert mich an den Streit, was das bessere
Vernetzungsprinzip ist: die ,,reine Lehre'' besteht darauf, dass
jeder
nur dann senden kann, wenn er ,,dran'' ist. Zu diesem Zweck wird
ein
Staffelstab herumgereicht, der jeder Station sagt, wann sie dran ist.
Wenn sie nichts zu senden hat, gibt sie diesen weiter.
Die Alternative ist, dass jeder sendet, ,,wann er will'', nur zuvor
mal nachsieht, ob nicht vielleicht gerade jemand anders sendet. In
diesem Fall ,,ein bisschen'' wartet.
Das erste nennt sich `token ring', das zweite `Ethernet'.
Mittlerweile dürfte ziemlich klar sein, wer der Gewinner dieses
Streits war.
Mit dem Speicher ist das ganz genauso. Die Stochastik hat natürlich
ihre Grenzen: bei ,Verstopfung' ist das jeweilige deterministische
System zuverlässiger. Der Tote Ring erreicht gleichmäßige
Übertragungsraten auch noch kurz vor der Sättigung, während Ethernet
in diesem Bereich durch die häufigen retries einbricht. Wenn dein
Speicher also bis zum letzten Byte ausgereizt ist, wird die Stochastik
nicht mehr gut funktionieren, weil immer häufig der Zustand `out of
memory' zuschlägt.
> Wenn dein Speicher also bis zum letzten Byte ausgereizt ist, wird die> Stochastik nicht mehr gut funktionieren, weil immer häufig der
Zustand > `out of memory' zuschlägt.
Ich kann sozusagen frei wählen, wie voll ich meinen Speicher haben will
- je mehr Speicherplatz ich zur Verfügung habe, desto besser wird meine
Bildauswertung. Von daher werde ich also so nahe wie möglich ans Limit
gehen.