Forum: Compiler & IDEs Mehrere Module in eine Section packen


von Tobi (Gast)


Lesenswert?

Hallo zusammen, ich versuche gerade meinen TCP IP Stack auf einem 
ATMega32 direkt vor den Bootloader Bereich zu setzen.

Wenn ich dies z.b. mit dem Modul tcp.c/h mache indem ich in tcp.h

#define NET_SECTION _attribute_ ((section (".tcpipStack")))

schreibe und nach jeder Funktion "NET_SECTION" schreibe also:

void tcp_init(void)NET_SECTION;

als Linkerflag gebe ich folgendes mit:

-Wl,-section-start=.tcpipStack=0x4F00

... dann funktioniert das wunderbar.

Nun dachet ich mir, dass ich das define einfach in eine globale header 
Datei schreiben kann und dann auch z.b. das Modul udp.c/h an diese 
Section packe indem ich auch hier wieder in der udp.h hinter alle 
Funktionen das "NET_SECTION" setze.

Dies geht leider nicht, da dann folgender Linkerfehler kommt:

c:/programme/winavr-20090313/bin/../lib/gcc/avr/4.3.2/../../../../avr/bi 
n/ld.exe:  section .tcpipStack.1 [000088ee -> 00008917] overlaps section 
.data [000088ee -> 00008901]


Woran kann das liegen? Überlappen dürfte eigentlich nichts, da noch genu 
platz bleibt bis der eigentliche Bootloadercode anfängt.

Ich könnte mir vorstellen dass für das Modul tcp und udp jeweils 
versucht wird an die selbe Stelle (4F00) den Code jeweiligen Code zu 
setzen?!?

Funktioniren würde es natürlich wenn ich alles in einen .c/.h schreiben 
würde, jedoch ist das auch nicht das ziel.


Würde mich über einen Tip freuen!

Mfg
Tobi

von Tobi (Gast)


Lesenswert?

hm.. also irgendwie bekomme ich es nicht hin...

egal wie ich es drehe kommt ein Linkerfehler.

Ich muss doch irgendwie alle beliebigen Module ans Ende des RWW Teils 
bekommen.
Also vor den Bootloader?!?
Ich könnte auch mehrere Sektions erstellen - also für jedes Modul eins.
Jedoch wenn ich dann in einem Modul was ändere muss ich wieder alle 
manuell richtig platzieren damit keine Überschneidungen auftreten....

Das muss doch auch einfacher gehen.. Ich finde leider nichts dazu.

Würde mich über eine Hilfe freuen.

Mfg
Tobi

von 900ss (900ss)


Lesenswert?

1) Mal im Mapfile nachgesehen, ob es Überlappung gibt?
   Also keine Extrasection anlegen und dann mal schauen,
   wie groß TCP und UDP wird. Dann kannst du ausrechnen,
   ob es paßt.
2) Startaddresse der Section mal nach unten verschieben, ob es
   dann klappt? Das wäre allerdings stochern und du fliegst
   wahrscheinlich irgendwann nach einer Codeänderung wieder
   auf die Klappe.
3) Wenn du nur TCP in die Section packst, dann geht es?
   Wenn du nur UDP in die Section packst, dann geht es?
   Wenn beide Teile drin sind, geht es nicht? Dann sind beide
   Teile scheinbar zu groß.

von Stefan E. (sternst)


Lesenswert?

Das entscheidende kleine Detail in der Fehlermeldung ist das ".1". 
Sections gleichen Namens aus unterschiedlichen Modulen werden nicht 
automatisch zusammengeführt. Statt dessen bekommen sie einen 
Nummern-Suffix, um sie getrennt zu halten. Für .tcpipStack.1 hast du 
aber keine Startadresse vorgegeben, also landet es hinter .text und 
überlappt sich dann dort mit .data. Ich wüsste nicht, dass man das 
irgendwie direkt über die Kommandozeile handhaben könnte. Ich sehe zwei 
Möglichkeiten für dich:
1) Eigenes Linker-Script verwenden.
2) Eine ansonsten nicht benutzte Section verwenden, für die es schon im 
Default-Script eine entsprechende Zusammenlegung gibt. .bootloader würde 
sich z.B. anbieten.

Für mich ist die eigentliche Frage aber:
> Hallo zusammen, ich versuche gerade meinen TCP IP Stack auf einem
> ATMega32 direkt vor den Bootloader Bereich zu setzen.
Warum willst du das überhaupt machen?

von Tobi (Gast)


Lesenswert?

Hallo und danke für eure Antworten,

@900ss: Es ist schon so wie Stefan schrieb, dass ich geren möchte, das 
die Teile automatisch zusammengeführt werden, wenn ich eigene Sections 
anlege und eine Adresse zuweise klappt das schon. Nur sind es noch mehr 
Module als nur die beiden und ich möchte das das automatisch irgendwie 
funtkioniert.

@Stefan:

Stefan Ernst schrieb:
> Für .tcpipStack.1 hast du
> aber keine Startadresse vorgegeben, also landet es hinter .text und
> überlappt sich dann dort mit .data.

Ok das klingt sinnig. Scheinbar ist das passiert. Ich hatte gehofft, man 
kann eine Section vielleicht modulübergreifend per define irgendwie 
deklarieren und so mehrere Module in eine Section packen.. schade.
Das mit dem Linkerscript habe ich auch schon irgendwo gelesen in 
ähnlichem Zusammenhang. Leider hab ich da gar keine Ahnung wo ich da 
ansetzen muss. Gibt es dafür auch ein Tut so wie man hier sehr gute Tuts 
für alles mögliche andere findet? Oder hast du mir da ein paar kurze 
Tips um mir dahingehend Starthilfe zu geben? )

Warum das ganze? Weil ich den TCP/IP Stack im Bootloader UND in der 
Anwendung benötige und somit das gerne zentral ablegen würde. Da bietet 
sich der Bereich vro dem Bootloader sehr gut an.
Bootloader wird dann zusammen mit dem Stack geflashed und die Anwendung 
dann über den Bootloader über LAN.

Ich denke das mit dem Linkerscript wird die Lösung sein.
Vielen Dank für eure Hilfe bisher! :)

Tobi

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> Das mit dem Linkerscript habe ich auch schon irgendwo gelesen in
> ähnlichem Zusammenhang. Leider hab ich da gar keine Ahnung wo ich da
> ansetzen muss.

Warum dann nicht Möglichkeit 2?

Tobi schrieb:
> Warum das ganze? Weil ich den TCP/IP Stack im Bootloader UND in der
> Anwendung benötige und somit das gerne zentral ablegen würde.

Dir ist aber schon klar, dass dann noch ganz andere Probleme auf dich zu 
kommen? Ist dir z.B. klar, dass der TCP/IP Stack dann keine globalen 
(bzw. static) Daten direkt verwenden darf? Ansonsten müsstest du diesen 
Daten auch noch einen festen Bereich im RAM zuweisen und der Anwendung 
klar machen, dass dieser Bereich für sie tabu ist.

von Tobi (Gast)


Lesenswert?

also Möglichkeit 2 verstehe ich nicht ganz. Wieso die Bootloadersection 
nutzen? Dann wäre ich doch im Adressbereich des Bootloaders?!? Ich 
möchte die Daten doch im RWW Bereich nicht NRWW.

Wegen den Bedenken des gemeinsamen Nutzen des TCP/IP Stacks.. ich 
initialisiere den Stack sowohl im Bootloader als auch inder Anwendung 
jeweils für sich neu.

MfG
Tobi

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> also Möglichkeit 2 verstehe ich nicht ganz. Wieso die Bootloadersection
> nutzen? Dann wäre ich doch im Adressbereich des Bootloaders?!? Ich
> möchte die Daten doch im RWW Bereich nicht NRWW.

"bootloader" ist doch bloß ein Name, der den eigentlich zugedachten 
Adressbereich verdeutlichen soll. In Wirklichkeit kannst du die Section 
an jede beliebige Adresse legen.

Tobi schrieb:
> Wegen den Bedenken des gemeinsamen Nutzen des TCP/IP Stacks.. ich
> initialisiere den Stack sowohl im Bootloader als auch inder Anwendung
> jeweils für sich neu.

Vom Initialisieren der Daten habe ich nicht geredet, sondern von den 
Adressen der globalen und statischen Daten. Bei direkten Zugriffen 
kannst du in Applikation und Bootloader diese nicht neu vergeben.

von Tobi (Gast)


Lesenswert?

und wie kann ich der section "bootloader" mehrere Module zuweisen?

...

du meinst also wenn ich den Stack im Bootloader initialisiere, was 
bereits funktioniert, dann kann ich vom anwenderbereich später den Stack 
nicht mehr verwenden? Ich muss michda nochmal schlau machen

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> und wie kann ich der section "bootloader" mehrere Module zuweisen?

So, wie du es mit deiner eigenen Section versucht hast. Wie gesagt, das 
Zusammenführen für .bootloader müsste im Default-Script enthalten sein.

Tobi schrieb:
> du meinst also wenn ich den Stack im Bootloader initialisiere, was
> bereits funktioniert, dann kann ich vom anwenderbereich später den Stack
> nicht mehr verwenden?

Wieso redest du schon wieder vom Initialisieren? Ich rede von Adressen 
und Zugriffen auf diese im Allgemeinen. Machen wir ein konkretes 
Beispiel. Eine Funktion soll sich von Aufruf zu Aufruf etwas merken, 
sagen wir einfach irgendeinen Status (ein unit8_t reicht). Wie stellst 
du dir vor, soll das bei dir aussehen?

von Tobi (Gast)


Lesenswert?

blöd gefragt, wo finde ich das default script? Ich finde leider zum 
linker script nirgends etwas und habe da auch noch nie etwas ändern 
müssen.

...


Ich habe z.b. ein Modul "timer". Diesen benötige ich für den Timout beim 
TCP. Hier muss ich mir dann z.b. den Timerwert merken. Dieser stckt in 
einer Strukturvariablen. Die Instanz der Struktur ist global definiert. 
Das ist wohl worauf du hinaus willst. Ich hätte nun angenommen, das ich 
sowohl vom Bootloader (bereits erfolgreich getestet) eine solche Instanz 
erzeugen kann als auch vom Anwenderbereich und diese der globalen 
Variablen zuweisen?!?

Diese Instanz wird allerdings nicht von beiden Bereichen gleichzeitig 
verwendet bzw. soll nicht über diese hinaus von bestand bleiben.

Danke für deine Geduld! :)

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> blöd gefragt, wo finde ich das default script?

Ok, dann frage ich mal blöd zurück: wozu willst du das wissen? Es ist 
doch gerade der Vorteil von Variante 2, dass du mit Linker-Skripten 
nichts zu tun hast. Das Default-Skript ist das, was passend zum 
gewählten AVR-Typ automatisch verwendet wird.

Tobi schrieb:
> Die Instanz der Struktur ist global definiert.
> Das ist wohl worauf du hinaus willst. Ich hätte nun angenommen, das ich
> sowohl vom Bootloader (bereits erfolgreich getestet) eine solche Instanz
> erzeugen kann als auch vom Anwenderbereich und diese der globalen
> Variablen zuweisen?!?

Zeige die Deklaration/Definition dieser globalen Variable und den 
Zugriff darauf in der Funktion (konkreten Code, keine Beschreibung).

von Tobi (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Ok, dann frage ich mal blöd zurück: wozu willst du das wissen? Es ist
> doch gerade der Vorteil von Variante 2, dass du mit Linker-Skripten
> nichts zu tun hast. Das Default-Skript ist das, was passend zum
> gewählten AVR-Typ automatisch verwendet wird.

hm... ich verstehe nun immernoch nicht wie ich dann mehrere Module da 
reinbekommen soll...

Stefan Ernst schrieb:
> Zeige die Deklaration/Definition dieser globalen Variable und den
> Zugriff darauf in der Funktion (konkreten Code, keine Beschreibung).

ok als beispiel die globale instanz eines tcp_sockets
1
tcp_Socket tcp_Sockettable[MAX_TCP_CONNECTIONS];

dann Ausschnitt der Funtion zum Senden eines TCP Packets. Es wird ein 
TCP Packet mit den richtigen Daten gefüllt, gesendet und ein Timer 
gestartet welcher sich in der TCP Struktur befindet.
1
uint8_t TCP_SendPacket(uint8_t SOCKET, unsigned int Datalenght, unsigned char * TCP_Databuffer)
2
{
3
  //....
4
  
5
  // Send packet first time
6
  MakeTCPheader(SOCKET,(TCP_PSH_FLAG | TCP_ACK_FLAG),Datalenght,MAX_RECIVEBUFFER_LENGHT);  
7
  ethSendFrame(ethBuffer, ETHERNET_HEADER_LENGTH + IP_HEADER_LENGHT + TCP_HEADER_LENGHT + Datalenght);
8
9
  // Start sending timer
10
  startTimer(&tcp_Sockettable[SOCKET].resentTimer, 50);
11
12
  return(0xFF);  
13
}

Ein Observer überprüft diese TimerVariable und sendet Paket evtl. neu
1
void PacketObserver()
2
{
3
  for (uint8_t socket=0;socket<MAX_TCP_CONNECTIONS;socket++){    
4
5
//...
6
    if((tcp_Sockettable[socket].ConnectionState != CLOSED) && (tcp_Sockettable[socket].maxSend) && (checkTimer(&tcp_Sockettable[socket].resentTimer))){
7
          
8
      if(tcp_Sockettable[socket].ConnectionState == CONNECTED){
9
        MakeTCPheader(socket,(TCP_PSH_FLAG | TCP_ACK_FLAG),tcp_Sockettable[socket].dataBufLen,MAX_RECIVEBUFFER_LENGHT);
10
  
11
        for(uint8_t i=0;i<tcp_Sockettable[socket].dataBufLen;i++) 
12
          ethBuffer[ETHERNET_HEADER_LENGTH + IP_HEADER_LENGHT + TCP_HEADER_LENGHT + i] = tcp_Sockettable[socket].dataBuffer[i];
13
  
14
        ethSendFrame(ethBuffer, ETHERNET_HEADER_LENGTH + IP_HEADER_LENGHT + TCP_HEADER_LENGHT + tcp_Sockettable[socket].dataBufLen);
15
        tcp_Sockettable[socket].maxSend--;        
16
        startTimer(&tcp_Sockettable[socket].resentTimer, 50);
17
      }
18
   }
19
}
20
//...
21
}

Wäre das so ein Beispiel wobei es Probleme geben wird?

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> hm... ich verstehe nun immernoch nicht wie ich dann mehrere Module da
> reinbekommen soll...

Liest du nicht, was ich schreibe? Was ist an "So, wie du es mit deiner 
eigenen Section versucht hast." unklar? Du hast bereits einen Versuch 
mit ".tcpipStack" unternommen. Jetzt machst du das gleiche mit 
".bootloader".

Tobi schrieb:
> ok als beispiel ...

Und genau das geht so in die Hose. Wenn du jetzt in der Applikation die 
gleiche globale Variable anlegst, hat die dort eine andere Adresse. Die 
Funktion greift aber direkt zu, was bedeutet, dass die Adresse fest im 
Binär-Code verankert ist. Wenn die Funktion also aus der Applikation 
heraus aufgerufen wird, greift die Funktion trotzdem auf die Adressen 
zu, die die Variable im Bootloader hat, in der Applikation stehen an 
diesen Adressen aber ganz andere Dinge.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Unabhängig von globalen Variablen: ich halte das Konzept so für
tödlich.  Wenn der Bootloader Dinge benutzen will, sollten sie sich
auch in seinem Bereich befinden, alles andere ist riskant (weil der
Bootloader es ggf. selbst überschreiben könnte, und weil die CPU
angehalten wird, wenn der NRWW-Bereich geschrieben wird).

Wenn du das Zeug, das im Bootloader steht, dann außerdem noch aus
der Applikation benutzen willst, dann platzierst du dir am einfachsten
an den Anfang des Bootloaders eine Vektortabelle, die auf die
eigentlichen Einsprungpunkte im Loader verzweigt.  Aus Sicht der
Applikation wird dann immer die gleiche Adresse aufgerufen für eine
bestimmte Funktion (genauso wie weiland im CP/M-BIOS), und wo diese
genau dann implementiert ist, interessiert kein Schwein mehr.

Bei dieser Vorgehensweise kannst du Bootloader (mit dem IP-Stack)
und eigentliche Applikation völlig separat entwickeln und linken,
was für einen Bootloader eigentlich auch nur so Sinn hat, denn am Ende
müssen beide voneinander (bis auf den Einsprungvektor) logisch
unabhängig sein.

von Stefan E. (sternst)


Lesenswert?

Jörg Wunsch schrieb:
> Wenn du das Zeug, das im Bootloader steht, dann außerdem noch aus
> der Applikation benutzen willst, dann platzierst du dir am einfachsten
> an den Anfang des Bootloaders eine Vektortabelle, die auf die
> eigentlichen Einsprungpunkte im Loader verzweigt.  Aus Sicht der
> Applikation wird dann immer die gleiche Adresse aufgerufen für eine
> bestimmte Funktion (genauso wie weiland im CP/M-BIOS), und wo diese
> genau dann implementiert ist, interessiert kein Schwein mehr.
>
> Bei dieser Vorgehensweise kannst du Bootloader (mit dem IP-Stack)
> und eigentliche Applikation völlig separat entwickeln und linken,
> was für einen Bootloader eigentlich auch nur so Sinn hat, denn am Ende
> müssen beide voneinander (bis auf den Einsprungvektor) logisch
> unabhängig sein.

Nur so als Hinweis an Tobi:
Das löst aber nicht die von mir angesprochene
Problematik, sondern behandelt einen anderen Aspekt dieses “Recyclings“.

von Tobi (Gast)


Lesenswert?

Das Grundproblem das ich habe ist dass der ganze Tcp Stack nicht in den 
Bootloader reinpasst. Sonst haette ich ihn sowieso zweimal 
implementiert. Einmal fuer den Bootloader abgespeckt und einmal komplett 
fuer die anwendung.

Ich komme leider nicht unter 6500Bytes in der abgespeckten Version. 
Daher kommt die Idee es nun in den Anwenderbereich zu packen und es dann 
gleich fuer beide Bereiche zu nutzen.
Ansonsten muesste ich den naechst groesseren chip nehmen... Wollte aber 
gerne den mega32 behalten.
Oder ich implementiere nur udp im Bootloader und mach ne eigene kleine 
Flussteuerung. Wird einfach da ich eh die Pakete sequenziell erwarte und 
vorher nicht weiter mache.
Wie waere die Idee den Tcp Stack einmal normal und einmal abgespecktim 
anwenderbereich zu implementieren und den abgespeckten nurim Bootloader 
zu nutzen? Kommt ja eigentlich vom platzbedarf auf meine urspruengliche 
Idee aufs gleiche raus?!?

Sorry Stefan. .. Klar verstehe ich das mit der bootloadersection... 
Alsogeht das dass ich in beliebigen Modulen an beliebigen Funktionen 
diese Section deklariere? Muss ich heute abend mal testen.

Das mit den globalen variablen war mir so noch nicht bewusst... Danke 
fuer den Hinweis.

Joerg danke fuer den Tip mit der Vektortabelle... Ich muss mal 
ueberlegen in wieweit mir das hilfreich sein koennte.

Danke fuer eure Hilfe!

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> Das mit den globalen variablen war mir so noch nicht bewusst... Danke
> fuer den Hinweis.

Nur so nebenbei, das gleiche gilt natürlich auch für 
Static-Local-Variablen.

von Tobi (Gast)


Lesenswert?

hm.. Also das mit der .bootloader Section funktioniert so scheinbar 
nicht.

Folgendes in einer config.h definiert:

#define NET_SECTION _attribute_ ((section (".bootloader")))

und das in der tcp.h:

void tcp_init(void)NET_SECTION;

und in udp.h:

void udp_init(void)NET_SECTION;

im linker dann die Adresse für .bootloader auf 0x0200

funktioniert leider nicht. wen ich die deklaration z.b. in udp.h 
weglasse funktioniert es. So wie mit meiner .tcpipStack Section...

Also was mache ich falsch?

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> funktioniert leider nicht. wen ich die deklaration z.b. in udp.h
> weglasse funktioniert es. So wie mit meiner .tcpipStack Section...

Ich habe mal in die Default-Linker-Skripte geschaut, und die von mir 
vermutete Zusammenführung der .bootloader.* Sections gibt es dort 
tatsächlich nicht.
Sorry, dass ich dich diesbezüglich in die Irre geführt habe.

von Paul P. (dorpreuss)


Lesenswert?

Hallo,

ich habe auf der Startseite gerade diesen Thread entdeckt und ich muss 
gestehen, dass ich ihn nicht komplett durchgelesen habe.

Ich habe aber vor kurzem den LwIP-Stack auf einem Cortex M3 
implementiert und den Stack in den oberen Flashbereich gelinkt. Die 
Adressen der Funktionen des Stacks kommen in ein Array, welches man an 
eine absolute Adresse linkt. Wie schon oben beschrieben kann man sowohl 
den Stack als auch die eigentliche Anwendung unabhängig voneinander 
entwickeln ohne das irgendwas später nicht mehr funktioniert. Ich 
brauchte nur ein ganz einfaches Linkerscript zu schreiben, welches dies 
erledigt. Und ich hatte vorher keine Ahnung von Linkerscripts. Dann 
schreibt man nur noch ein Modul welches die Arrayadresse und damit die 
Funktionsadressen wieder auflöst. Die Anwendung sieht von dem Stack 
eigentlich nichts. Und das JTAG-Interface auch nicht, was die 
Codegrößenbegrenzung aushebelt. Das war eigentlich auch der Sinn warum 
ich es gemacht habe.

Nur mal nebenbei. Die NXP LPC-134X Serie enthält ab Werk im oberen 
Flashbereich (nur Lesezugriff) USB Treiber für HID und Mass-Storage. Der 
Zugriff erfolgt hier ebenfalls über absolute Adressen.

von tom (Gast)


Lesenswert?

gurgel doch mal wie man mit hilfe einer jump-table code von zwei 
applikationen gemeinsam nutzen kann.
den residenten code (in deinem fall der tcp/ip stack) sinnvoll in eine 
eigene section mit bekannter startadresse lokieren. dazu musst du ggf. 
das default linker script modifizieren.

gruss, tom.

von Tobi (Gast)


Lesenswert?

also haltet mich für blöd, aber wo fidne ich denn das linker script das 
AVR Studio verwendet... es müsste doch eine *.x Endung haben... Ich 
finde aber nichts dazu.

Gibt es denn irgendwo hier ein gutes Tut wie man das Script zu verstehen 
hat und was man da für Möglichkeiten hat?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobi schrieb:
> also haltet mich für blöd, aber wo fidne ich denn das linker script das
> AVR Studio verwendet... es müsste doch eine *.x Endung haben... Ich
> finde aber nichts dazu.

Bei mir ist es unter /usr/local/avr/lib/ldscripts, aber du kannst
daran zumindest erkennen, dass ich kein AVR Studio benutze. ;-)

> Gibt es denn irgendwo hier ein gutes Tut wie man das Script zu verstehen
> hat und was man da für Möglichkeiten hat?

Ein was?  Ein Tut?  Klingt wie'n Auto auf dem Kinderkarussel ... :)

Der Linker ist Bestandteil der GNU binutils und dort dokumentiert.
Da sollte es auch eine Beschreibung der Linkerscripts geben.  Nein,
ein "Tut" wird dafür noch niemand geschrieben haben.  Die, die sowas
anfassen, sollten normalerweise mit der Doku zurecht kommen.

von Tobi (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Ein was?  Ein Tut?  Klingt wie'n Auto auf dem Kinderkarussel ... :)

loooool

Jörg Wunsch schrieb:
> ein,
> ein "Tut" wird dafür noch niemand geschrieben haben.  Die, die sowas
> anfassen, sollten normalerweise mit der Doku zurecht kommen.

Ok. Naja das könnte man beim Bootloader auch sagen und trotzdem gibts 
hier super Tutorials (Extra für dich ausgeschrieben :) dazu.

Also wenn das klappt mit dem Linkerscript, dann wären zumindest mal die 
Probleme mit den Sections gelöst.
Das zweite Problem mit den globalen und statischen Variablen werde ich 
wohl mit einer zusätzlichen Header lösen in der ich die Variablen auch 
fest an eine Adresse linke (geht ja glaub ich genauso mit "attribute 
section") und diese Header dann sowohl beim Bootloader als auch in der 
Anwendung linke.
Dann muss ich noch sicherstellen das der Bootloader nur von 0x0000 bis 
Beginn des TCP/IP Stacks flashed und das wars dann.

Falls jemand noch nen Tip zu alldem hat.. immer her damit.
Ich melde mich dann mit dem Erfahrungsbericht :)

Tobi

von Tobi (Gast)


Lesenswert?

Hallo nochmals zusammen,

also ich hab es jetzt hinbekommen dass alle Module einer Section 
zugeordnet werden können und zwar so:

Im avr5.x ( Linker file) direkt vor der text Section. ( diese ist an 
Adresse 0x7000 = Bootloadebereich verschoben)
1
.tcpipStack 0x7000-0x2238 : { *(.tcpipStack) }
2
  .text   :
3
  {

im Code hinter jede Funktion egal in welchem Modul folgendes:
1
__attribute__ ((section (".tcpipStack")))

das wars dann schon.

Nur leider kann ich zum Zeitpunkt an dem ich im Linker Script oben 
meiner Section die Adresse zuweise weder die Adresse des Bootloaders 
angeben werde die size meiner Section um GENAU vor den Bootloaderbereich 
zu kommen.

Desshalb ist das oben händisch implementiert.
Geht das nicht irgendwie? Hatte an sowas gehofft:
1
.tcpipStack : AT(ADDR(.text) - SIZEOF(.tcpipStack)) { *(.tcpipStack) }


Leider funktioniert das so nicht da zu diesem Zeitpunkt leider weder die 
Adresse von .text noch die Größe von meiner eigenen Section bekannt ist 
?!?

Geht das nicht irgendwie automatisch noch?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobi schrieb:
> Geht das nicht irgendwie automatisch noch?

Nein, der Linker arbeitet nur in einem Pass "von vorn nach hinten".

von Tobi (Gast)


Lesenswert?

Hallo nochmals,

also das mit der Section klappt ja soweit und alles was den TCP/IP Stack 
betrifft liegt nun direkt unter der Bootloadersection.

Scheinbar ergibt sich aber nun noch ein weitere Problem..

Wenn ich nun vom Bootloader eine Funktion aus dem Stack aufrufe, 
funktioniert das soweit. Die Funktion kehrt auch wieder korrekt zurück.

Wenn ich nun allerdings vom Bootloader in den Stack springe und von dort 
dann wiederum eine Funktion im Bootloader aufrufe, dann kehrt diese 
Funktion irgendwie nicht mehr korrekt in den Stack zurück.

Innerhalb des Stacks versuche ich an eine Funktion im Bootloader zu 
springen (über gesicherten Funktionspointer). Dies funktioniert soweit. 
Nur wenn ich dann zurückspringen möchte geht das wohl schief und 
dasProgramm landet im nirgendwo... weitere Kommunikaionen über LAN sind 
dann auch nicht mehr möglich. Der retrun scheint zwar irgendwo im Stack 
wieder zu landen, jedoch an falscher Stelle.

Diese Funktion wird über den Funktionspointer noch erfolgreich aus dem 
TCP/IP Stack aufgerufen:
1
uint8_t getData(uint8_t *buf, uint16_t len)
2
{
3
    72d0:  dc 01         movw  r26, r24
4
  uint8_t cmd = *buf++;  
5
6
  // if command is flash command
7
  if(cmd == 0x04){
8
    72d2:  8c 91         ld  r24, X
9
    72d4:  84 30         cpi  r24, 0x04  ; 4
10
    72d6:  71 f4         brne  .+28       ; 0x72f4 <getData+0x24>
11
  return 0;
12
}
13
14
uint8_t getData(uint8_t *buf, uint16_t len)
15
{
16
  uint8_t cmd = *buf++;  
17
    72d8:  fd 01         movw  r30, r26
18
    72da:  31 96         adiw  r30, 0x01  ; 1
19
20
  // if command is flash command
21
  if(cmd == 0x04){
22
    uint16_t addr = (*buf++)<<8;
23
    72dc:  11 96         adiw  r26, 0x01  ; 1
24
    72de:  7c 91         ld  r23, X
25
    72e0:  60 e0         ldi  r22, 0x00  ; 0
26
    addr += *buf++;
27
28
    flashPage(addr,buf);
29
    72e2:  21 81         ldd  r18, Z+1  ; 0x01
30
    72e4:  62 0f         add  r22, r18
31
    72e6:  71 1d         adc  r23, r1
32
    72e8:  80 e0         ldi  r24, 0x00  ; 0
33
    72ea:  90 e0         ldi  r25, 0x00  ; 0
34
    72ec:  32 96         adiw  r30, 0x02  ; 2
35
    72ee:  af 01         movw  r20, r30
36
    72f0:  0e 94 2d 39   call  0x725a  ; 0x725a <flashPage>
37
    //buf[0] = 0xab;
38
    //TCP_SendPacket(SOCKET, 1, buf);
39
  }
40
41
  return 0;
42
}
43
    72f4:  80 e0         ldi  r24, 0x00  ; 0
44
    72f6:  08 95         ret

Das Flashen der übergebenen Daten funktioniert, darum kann ich sicher 
sein das die Funktion korrekt aufgerufen wird.

"TCP_SendPacket(SOCKET, 1, buf);" ist hier auskommentiert, würde nicht 
funktionieren genau wie der return in den Stack. (Funktion liegt auch 
wieder im TCP/IP Stack welcher unter dem Bootloader-Bereich liegt)

Hoffe es kommt noch jemand mit :)

Jemand eine Ahnung an was das liegen könnte?

Danke!
Tobi

von Tobi (Gast)


Lesenswert?

hmmm..

also ich vermute es liegt am Aufruf der Funktion per Funktionspointer..
1
tcp_Sockettable[socket].fp(buf,dataLength);    
2
    5f1c:  e0 91 23 02   lds  r30, 0x0223
3
    5f20:  f0 91 24 02   lds  r31, 0x0224
4
    5f24:  ce 01         movw  r24, r28
5
    5f26:  02 96         adiw  r24, 0x02  ; 2
6
    5f28:  b5 01         movw  r22, r10
7
    5f2a:  09 95         icall

zwar funktioniert dieser Aufruf in den Bootloaderbereich jedoch komme 
ich hierher scheinbar nicht mehr zurück.. liegt dies an dem icall?

(Mit dem Codeausschnitt wird der obere Code im Beitrag zuvor aufgerufen)

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> also ich vermute es liegt am Aufruf der Funktion per Funktionspointer..

Ich vermute eher der Fehler liegt in flashPage.
Vielleicht RWW-Section nicht wieder enabled?

von Tobi (Gast)


Lesenswert?

ok.. blöder Fehler von mir.. hab eine Array von 100 Byte Größe 
deklariert gehabt und 128 Byte reingeschrieben... kann schlecht gehen..

kam nur nicht gleich drauf weil nicht irgendein Mist passiert ist 
sondern trotzdem eine andere Funktion ausgeführt wurde... Zufall..

Ok das funktioniert nun soweit.. nun komme ich zu dem Problem mit den 
globalen Vaiablen... ich finde dazu leider nicht viel.
Irgend ein Ansatz mit Sections... aber ist das das richtige?

Könnte jemand bitte ein kleines Beispiel posten wie man das zu 
realisieren hat?

Wie setze ich eine Variable an eine feste Adresse im Ram die dann auch 
noch der Anwendung später nach dem Switch in die Applikation bekannt 
ist?!?

Danke!

Tobi

von Tobi (Gast)


Lesenswert?

hallo zusammen,

also habe es nun mit sections folgendermaßen für eine Beispiel - Globale 
Variable versucht:

im main.c file:
1
int xx __attribute__ ((section (".myGlobals")));

als Linkeroption:
1
-Wl,--section-start=.version=0x800460

und dies bei beiden Projekten.. also im Bootloaderprojekt als auch im 
Anwenderprojekt.

Leider kommt beim Flashversuch des Bootloaders "0x00800460 is out of 
range"

Nur wie bestimme ich für beide Projekte eine möglichst praktische Stelle 
an die ich mehrere globale Variablen fest addressieren kann?

Die Section Übersicht in den *.lss files sehen folgendermaßen aus:

im Bootloader Projekt:
1
Sections:
2
Idx Name          Size      VMA       LMA       File off  Algn
3
  0 .tcpipStack   00002196  00004dc8  00004dc8  000000d4  2**0
4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
5
  1 .text         000003c8  00007000  00007000  0000226a  2**1
6
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
7
  2 .data         00000014  00800060  000073c8  00002632  2**0
8
                  CONTENTS, ALLOC, LOAD, DATA
9
  3 .bss          000003d5  00800074  00800074  00002646  2**0
10
                  ALLOC
11
  4 .debug_aranges 00000310  00000000  00000000  00002648  2**0
12
                  CONTENTS, READONLY, DEBUGGING
13
  5 .debug_pubnames 00000903  00000000  00000000  00002958  2**0
14
                  CONTENTS, READONLY, DEBUGGING
15
  6 .debug_info   00002bc7  00000000  00000000  0000325b  2**0
16
                  CONTENTS, READONLY, DEBUGGING
17
  7 .debug_abbrev 000010a0  00000000  00000000  00005e22  2**0
18
                  CONTENTS, READONLY, DEBUGGING
19
  8 .debug_line   000023a3  00000000  00000000  00006ec2  2**0
20
                  CONTENTS, READONLY, DEBUGGING
21
  9 .debug_frame  00000500  00000000  00000000  00009268  2**2
22
                  CONTENTS, READONLY, DEBUGGING
23
 10 .debug_str    00000b9a  00000000  00000000  00009768  2**0
24
                  CONTENTS, READONLY, DEBUGGING
25
 11 .debug_loc    00001581  00000000  00000000  0000a302  2**0
26
                  CONTENTS, READONLY, DEBUGGING
27
 12 .myGlobals    00000002  00800460  00800460  00002646  2**0
28
                  CONTENTS, ALLOC, LOAD, DATA
29
 13 .debug_ranges 00000310  00000000  00000000  0000b883  2**0
30
                  CONTENTS, READONLY, DEBUGGING

im Anwendungsprojekt:
1
Sections:
2
Idx Name          Size      VMA       LMA       File off  Algn
3
  0 .myGlobals    00000002  00800460  00800460  00002b5e  2**0
4
                  CONTENTS, ALLOC, LOAD, DATA
5
  1 .text         000029de  00000000  00000000  000000b4  2**1
6
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
7
  2 .data         000000cc  00800060  000029de  00002a92  2**0
8
                  CONTENTS, ALLOC, LOAD, DATA
9
  3 .bss          00000055  0080012c  0080012c  00002b5e  2**0
10
                  ALLOC
11
  4 .debug_aranges 00000120  00000000  00000000  00002b60  2**0
12
                  CONTENTS, READONLY, DEBUGGING
13
  5 .debug_pubnames 000009ec  00000000  00000000  00002c80  2**0
14
                  CONTENTS, READONLY, DEBUGGING
15
  6 .debug_info   00001d22  00000000  00000000  0000366c  2**0
16
                  CONTENTS, READONLY, DEBUGGING
17
  7 .debug_abbrev 000009a6  00000000  00000000  0000538e  2**0
18
                  CONTENTS, READONLY, DEBUGGING
19
  8 .debug_line   00001771  00000000  00000000  00005d34  2**0
20
                  CONTENTS, READONLY, DEBUGGING
21
  9 .debug_frame  00000330  00000000  00000000  000074a8  2**2
22
                  CONTENTS, READONLY, DEBUGGING
23
 10 .debug_str    000006c9  00000000  00000000  000077d8  2**0
24
                  CONTENTS, READONLY, DEBUGGING
25
 11 .debug_loc    00000c93  00000000  00000000  00007ea1  2**0
26
                  CONTENTS, READONLY, DEBUGGING
27
 12 .debug_ranges 00000030  00000000  00000000  00008b34  2**0
28
                  CONTENTS, READONLY, DEBUGGING

Danke für eure Hilfe!

Tobi

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> Leider kommt beim Flashversuch des Bootloaders "0x00800460 is out of
> range"

Dann musst du dein Makefile modifizieren, um die Section aus dem 
HEX-File rauszuhalten (hat darin ja auch nichts verloren).

Tobi schrieb:
> Nur wie bestimme ich für beide Projekte eine möglichst praktische Stelle
> an die ich mehrere globale Variablen fest addressieren kann?

Ich würde ja das ganze Geraffel vermeiden, und den Code entsprechend 
modifizieren, dass es keine direkten Zugriffe auf globale Daten gibt 
(sondern nur indirekte).

von Tobi (Gast)


Lesenswert?

Hy Stefan.
danke fuer deine antwort.

Wie muss ich denn das makefile modifizieren. und wie meinst du indirekte 
zugriffe? alle in einen struct und dann nur einen pointer drauf?

mir ist nicht ganz klar wie das dann aussehen koennte.
bin fuer verbesserungsvorschlaege offen :)

von Stefan E. (sternst)


Lesenswert?

Tobi schrieb:
> Wie muss ich denn das makefile modifizieren.

An passender Stelle ein "-R .myGlobals" einfügen.

Tobi schrieb:
> und wie meinst du indirekte
> zugriffe? alle in einen struct und dann nur einen pointer drauf?

Ja, wäre eine Möglichkeit.

Tobi schrieb:
> mir ist nicht ganz klar wie das dann aussehen koennte.

Zum Beispiel deine Funktion TCP_SendPacket oben.
Statt direkt
1
uint8_t TCP_SendPacket(uint8_t SOCKET, unsigned int Datalenght, unsigned char * TCP_Databuffer)
2
{
3
...
4
  // Start sending timer
5
  startTimer(&tcp_Sockettable[SOCKET].resentTimer, 50);
per übergebenen Pointer
1
uint8_t TCP_SendPacket(tcp_Socket *socket, unsigned int Datalenght, unsigned char * TCP_Databuffer)
2
{
3
...
4
  // Start sending timer
5
  startTimer(&socket->resentTimer, 50);

von Andreas (Gast)


Lesenswert?

Tobi schrieb:
> Wie setze ich eine Variable an eine feste Adresse im Ram die dann auch
> noch der Anwendung später nach dem Switch in die Applikation bekannt
> ist?!?

Das einfachste ist sicherlich, den Stack Pointer am Anfang des 
Programmes nicht auf die höchste Adresse zu setzen, sondern entsprechend 
niedriger. So schaffst Du einen sicheren Platz, in dem Du Deine globalen 
Daten speichern kannst.

von Tobi (Gast)


Lesenswert?

super.. endlich hab ich es hinbekommen...

im Makefile muss man wie Stefan schrieb noch etwas ändern:

Die passende Stelle für "-R .myGlobals" ist bei den HEX_FLASH_FLAGS.

Nun funktioniert es.. danke euch!!

Tobi

von Tobi (Gast)


Lesenswert?

Achso.. leider muss ich dazu vorher das Makefile exportieren und diese 
Änderung machen. Danach muss man dieses externe Makefile verwenden.

Gibt es keine Möglichkeit dies direkt im AVRStudio einzugeben?!?

Finde nichts dazu.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falls du Datensections verwendest:

Alle Variablen in .myGlobals zu machen ist keine gute Idee.

1) Du brauchst immer das gleiche Layout innerhalb der Section falls mehr 
als ein Objekt drinne ist. D.h. du willst eine Section für jedes 
globale Objekt.

2) Wenn du eine Section so nennst, kann es dir passieren, daß der 
Compiler keinen Startupcode zum Initialisieren der Section erzeugt :-)

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.