Hallo,
ich hab eher ein Lösungsansatz Problem.
Ich weis auch nicht ob ich es so Verständlich Beschreibe...
Ich will im Programm meine Port Konfiguration festlegen.
All Ports sind intern durch Nummeriert. Im Programm arbeite ich nur mit
Nummer. Hintergrund ist der, das das gleiche Programm praktisch
unverändert in vielen Platinen läuft. Der Einzige Unterschied ist die
Anordnung der Ausgänge auf der Platine. Es muss also nicht zur Laufzeit
geändert werden, nur zur Compilezeit.
Bisher habe ich eine Funktion und eine Structur die das machen, aber das
brauch natürlich Speicher.
Vor der main Loop habe ich etwas das stehen:
1
setOutputConfig(7,OUT_PORTB,PB7);
2
setOutputConfig(6,OUT_PORTB,PB6);
3
setOutputConfig(5,OUT_PORTB,PB5);
4
setOutputConfig(4,OUT_PORTB,PB4);
5
setOutputConfig(3,OUT_PORTB,PB3);
6
setOutputConfig(2,OUT_PORTB,PB2);
7
setOutputConfig(1,OUT_PORTB,PB1);
8
setOutputConfig(0,OUT_PORTB,PB0);
setOutputConfig sieht wie folgt aus, wobei das noch irrelevant ist:
Ich verdrehe mir gerade die Gehirnwindungen das irgendwie Statisch zur
Compilezeit zu machen.
Hat mir da jemand einen Tipp ?
Achja, das ganze unter avr-gcc und derzeit mit einem atmega32.
Danke
Juergen
Hallo,
das Problem ist bei Macros, dass ich dort nicht per Index darauf
Zugreifen kann.
Ich hab einige Laufzeitparameter die in einem Array stehen. Diese
erreiche ich über den gleichen Index wie die Ports bisher
vereinfacht:
port[channel] = 0xff;
port[channel] = 0xfe;
Da ich im Moment bis zu 24 "channels" habe, wird das mit Macros
unübersichtlich. und das ganze in einem switch case auswerten alla:
1
switch(channel)
2
{
3
case0:
4
PORT_0|=_BV(PIN_0);
5
break;
6
case.....
ist mühsam. Auch wenn ich dann mal nur 20 channels habe, muss ich schon
den switch anpassen. Bisher nicht. Nicht genutzte pins sind eben nicht
genutzt.
Was ich suche ist quasi ein Array, das zur Laufzeit "aufgelöst" wird.
Ich grüble auch ob ich das Array nicht "einfach" in den Flash schieben
kann, so wie Strings. Ich befürchte nur das dies langsam wird.
Und ich gebe hier Servosignale aus...
Ich hätte dann etwas wie hier:
1
struct_sChannel
2
{
3
uint8_tport;
4
uint8_tpin;
5
};
6
7
struct_sChannelchannels[]={
8
{OUT_PORT_A,PA1},
9
{OUT_PORT_B,PB1},
10
{OUT_PORT_A,PA0}
11
}
Jetzt das ganze noch ins flash und nur den Zugriff von
outputconfig[chan] auf die hier umbiegen mit read_byte(), der Rest der
Funktionen bleibt. Prickelnd ist das nicht. Und ob ich ein Structurarray
in den Flash bekomme und wie ich darauf Zugreife, grübel....
Gruss
Juergen
Schön ist es allerdings nicht unbedingt, weil du dem Compiler jegliche
Möglichkeit zur Optimierung auf den I/O Operationen raubst, dürfte
allerdings im Vergleich zu den if-then-else Orgien auch nicht schlechter
sein.
> das Problem ist bei Macros, dass ich dort nicht per> Index darauf Zugreifen kann.
Das müsstest du dir bei einer Makro Lösung allerdings abschminken.
Allerdings sollte man sich überlegen, ob man wirklich einen Index
braucht. Wenn du die Zuordnungen nur zur Compilezeit flexibel brauchst,
dann musst du im Programm auch jeden Kanal tatsächlich einzeln als
solchen ansprechen und nicht über einen Index.
So hab ich halt 7 (3*2+1) Byte Speicher pro Port verbraucht. Daher habe
ich nur die "Portreferenz" gespeichert und den if Block gebaut. So sind
es nur 2 Byte.
>
Ist e shie rnich so, das der compiler, vor allem durch volatile,
mehrfach auf den Struct zugreift ? Und so 2 Speicherzugriffe notwendig
sind ??? Erst die Struct ermitteln, dann den Offset addieren, dann den
Zugriff.
Zusätzlich muss er ja erst lesen, neuen wert hinzufügen und
zurückschreiben. Also 3 Zugriffe auf ein Struct. Aber da bin ich nun
nicht sicher...
>
>> Schön ist es allerdings nicht unbedingt, weil du dem Compiler jegliche> Möglichkeit zur Optimierung auf den I/O Operationen raubst, dürfte> allerdings im Vergleich zu den if-then-else Orgien auch nicht schlechter> sein.
Die Lösung ist nicht schlecht, nur hab ich so 2 Byte mehr pro Port im
RAM. Ich wollte ja eher versuchen weniger RAM zu benutzen.
Ich brauche es ja nicht Dynamisch zur Laufzeit.
Grübel
Jürgen
Dann bau deinen Code halt so um, dass du die "Verdrahtung" den
Präprozessor machen lässt. Das heißt du definierst dir die
entsprechenden Makros. Dann kommst du sogar auf 0 Byte Speicherverbrauch
im RAM...
MfG
Marius
Dafür suche im Moment ja eine Lösung.
Wie gesagt habe ich eine Structur Array in dem zur Laufzeit Parameter
pro Ausgang festgelegt werden können.
Minimalwert, Maximalwert, Mittel Stellung,Failsave aktiv, etc.
Diese Information bringe ich im Moment per Index, die Portnummerierung
entspricht quasi dem Index im Config Array, in Bezug zueinander.
Mache ich das nun per Makro, kann ich das nicht mehr machen. Da fehlt
mir im Moment der Ansatz. Mir fehlt hier dann nur ein riesiger switch
case Block ein. Das will mir nicht so gefallen.
Gruss
Juergen
Dann mach halt deinen riesigen Switch-Case-Block und vergib globale
GPIO-Nummern, aus denen sich der entsprechende PORT und die Pin-Maske
berechnen lassen. Ungefähr so:
PORTA, PA0: 0
PORTA, PA1: 1
...
PORTA, PA7: 7
PORTB, PB0: 8
usw.
Die unteren 3 Bit deiner GPIO-Nummer stellen den Pin dar, die restlichen
sind für den Port. Dann kannst du eine riesige switch-case bauen und
fertig...
MfG
Marius
Ne wichtige Frage vorab ist, wie schnell mußt Du darauf zugreifen?
Dieser ganze indirekte Zugriffs- und Umsortierkrams kann schnell mal 50
Zyklen kosten.
Für ein Relais steuern ist das kein Problem.
Aber für ne SW-PWM kann das die CPU ganz schön ins Schwitzen bringen.
Peter
Ich erzeuge Servosignale
Interruptgesteuert. In jedem Interrupt ändert sich der Portzustand eines
Ausgangs.
In outputConfig[] stehen die die bereits aufbereiteten Werte für das
OCR1A.
So muss ich in der ISR nichts mehr umrechnen.
Der Index ist hier auch wieder eine Referenz zu der portConfig.
Da die Ports zur Laufzeit von Proportional auf Schalten geändert werden
kann, prüfe ich immer auf den nächsten Kanal vom Typ OUT_TYPE_PROP.
Die Funktion "setOutputChannel()" Ist ja schon in einem früheren Post.
Jürgen Sachs schrieb:> So muss ich in der ISR nichts mehr umrechnen.
Guck Dir mal das Assemblerlisting an. Du wirst staunen, was der Compiler
im Interrupt so alles rechnen muß. Und dann noch ne Schleife und
Unterprogrammaufruf.
Ich schätze mal, der kommt leicht auf >200 CPU-Zyklen.
Peter
Ja, die ISR ist nicht kurz.
Die habe ich schon deutlich reduziert. Und die Unterprogramm aufrufe
bringe ich nicht raus. Die hauen richtig rein.
Ich habe auch schon versucht die while auszulagern in einer früheren
Version. Da konnte ich jedoch nicht mehr das Timing einhalten, da die
Mainline ziemlich busy ist mit anderen Dingen wie Seriell Parsen und
ausführen. Hier werden die Daten vom Uart per ISR gesammelt, Flag
gesetzt und dann per Mainline ausgewertet.
Da fliegt die Kuh :-)
Gruss
Juergen
PS: Im Moment ist der mega32 mit 16MHz getaktet. Später wäre es schön
mit dem internen 8MHz aus zu kommen. Aber das ist zweitrangig.
Da ich noch wusste in einem Thread eine Lösung gefunden zu haben, möchte
ich nur noch den Link zu dem Post anfügen.
Dann muss ich nicht mehr 3 Stunden danach suchen :-)
Link -> Beitrag "Re: Programm von mega32 auf mega328P convertieren"
Gruss
Juergen
Karl Heinz schrieb:> Schön ist es allerdings nicht unbedingt, weil du dem Compiler jegliche> Möglichkeit zur Optimierung auf den I/O Operationen raubst, dürfte> allerdings im Vergleich zu den if-then-else Orgien auch nicht schlechter> sein.
Der GCC kann ganz schön viel wegoptimieren, wenn man ihn lässt. Eine
Grundvoraussetzung dazu ist, wie ich habe festgestellt habe, dass man
alles, was nur geht, als static definiert. Am besten schreibt man den
ganzen Code in eine Datei. Oder in die Header und definiert die
Funktionen inline. Oder als C++-Templates (so hab' ich's gemacht).
Ich würde zuerst aus dieser outputConfig-Struktur den konstanten Teil
von dem variabelen Teil trennen. Der konstanter Teil lässt sich dann
statisch initialisieren und in Flash unterbringen.
Ich kann mir z.B. kaum vorstellen, dass cur_val wirklich einen
Konfigurationswert ist :-)