Hallo, ich bastle mir im AVR einen großen String zusammen (HTML-Datei mit dynamischem Inhalt). Hierzu benutze ich "strcpy" und "strcat". Der lange String ist wie folgt definiert: unsigned char ucsHTML_string[10000]; Das Prgramm spinnt, wenn der Zielstring ca. 3000 Zeichen übersteigt (das Programm macht nicht mehr, was es soll). Da der String ja 10.000 Byte groß ist, kann es kein Überlauf sein. Gibt es bei "strcat" eine Längenbegrenzung? Falls nicht, dann muß ich weiter suchen, an was es liegt.... Hier meine Tools / Hardware: * avr-gcc (GCC) 3.4.6 * ATMega128 * externes RAM, Typ IDT71024 (128k*8), A16 ist mit Prozessorport immer auf gleichem Pegel Gruß Martin
>Der lange String ist wie folgt definiert: >unsigned char ucsHTML_string[10000]; ATMega128 hat 4kB Speicher. Was ist an deinem Array also falsch?
Nachtrag: >>Der lange String ist wie folgt definiert: >>unsigned char ucsHTML_string[10000]; >ATMega128 hat 4kB Speicher. Was ist an deinem >Array also falsch? Er hat 4kB RAM. Und da wird dein String per strcat reinkopiert.
an dem ATMega 128 ist ein externes RAM dran (128k*8). Daher hab ich nicht nur 4k RAM.... Oder geht das mit dem externen RAM nicht mit Arrays?
>* externes RAM, Typ IDT71024 (128k*8), A16 ist mit Prozessorport immer >auf gleichem Pegel Upps, hatte ich übersehen :( Vieleicht kopiert strcat ja nicht in das externe RAM. Schnell weg!
Martin M. wrote: > an dem ATMega 128 ist ein externes RAM dran (128k*8). Daher hab ich > nicht nur 4k RAM.... Oder geht das mit dem externen RAM nicht mit > Arrays? Weiß dein Compiler vom externen Array?
holger wrote: >>* externes RAM, Typ IDT71024 (128k*8), A16 ist mit Prozessorport immer >>auf gleichem Pegel > > Upps, hatte ich übersehen :( > Vieleicht kopiert strcat ja nicht in das externe RAM. > > Schnell weg! Um den externen Speicher als normalen Speicher anzusprechen benötigst du in C ein angepasstes Startup Script. Zumindest muss der RAM Controller initialisiert werden, bevor das programm startet. Außerdem muss dies dem Compiler mitgeteilt werden. Ich glaube aber auch nicht, dass strcat das Mittel der Wahl ist. Immerhin muss der bei jedem Aufruf erneut das Ende des Strings finden. http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_ext_ram
ziemlich am Anfang des Main-Programms rufe ich folgendes Unterprogramm auf, mit dem das externe SRAM freigegeben wird: void enable_external_SRAM(void) { DDRG=0xFF; // set io-pins on PortG PORTG=0xFF; // RAM /WR,/RD,ALE,CE und Bank Select MCUCR|=1<<SRE; // Enable external RAM return; } Das Makefile habe ich im Dateianhang. So richtig klar ist mir die Sache allerdings nicht. Bin auch kein Software-Experte und kenne mich daher nicht sonderlich gut in der Matherie aus. Z.B. verwende ich kein malloc(), der RAM-Test mit einem eigenen Unterprogramm funktioniert problemlos. Den RAM-Test schicke ich in der nächsten Message als Anhang...
@Simon: > Um den externen Speicher als normalen Speicher > anzusprechen benötigst du in C ein angepasstes Startup Script. ....Wie geht denn das? Kannst Du mir da Tipps geben? > Ich glaube aber auch nicht, dass strcat das Mittel der > Wahl ist. Immerhin muss der bei jedem Aufruf erneut das > Ende des Strings finden. .... wenn es etwas länger dauert ist das kein Problem bei meiner Anwendung. Ich muß vor dem Senden des HTML-Strings die Länge wissen und es ist am einfachsten, wenn ich einen langen String erzeuge (die gesamte HTML-Daten) und dann mit strlen() die Länge abfrage. Ohne externes RAM ist das Berechnen der Länge ein ziemlich großer Aufwand, da der HTML-Code je nach Status unterschiedlich lag ist.
Martin M. wrote: > ziemlich am Anfang des Main-Programms rufe ich folgendes Unterprogramm > auf, mit dem das externe SRAM freigegeben wird: > > void enable_external_SRAM(void) > { > DDRG=0xFF; // set io-pins on PortG > PORTG=0xFF; // RAM /WR,/RD,ALE,CE und Bank Select > > MCUCR|=1<<SRE; // Enable external RAM > return; > } > Das ist schön. Nur leider hilft das in deinem Fall nicht. Dein Compiler weiß nichts davon, dass es da noch irgendwo ein externes SRAM gibt. Also hat er die Variablen auch nicht dorthin verfrachtet, sondern die liegen alle im internen SRAM. Aus Sicht der Compilers, hat dein Prozessor nur 4KB zur Verfügung. Lass es mich mal so sagen: Du kannst an dein Auto einen ganzen Tanklastzug mit Benzin hinten dran hängen. Solange du keine Leitung von diesem Tank zum Motor legst, wird dir trotzdem nach 600km der Sprit ausgehen. Dir fehlt diese Leitung. Dein Compiler weiß nichts vom externen SRAM und benutzt es daher auch nicht.
Martin M. wrote: > @Simon: > >> Um den externen Speicher als normalen Speicher >> anzusprechen benötigst du in C ein angepasstes Startup Script. > > ....Wie geht denn das? Kannst Du mir da Tipps geben? Steht alles im Link, den Simon weiter oben gepostet hat. Aber ich geh mit Simon konform. Wenn du den Speicher nur brauchst, um den String zusammenzubauen, dann ist es wahrscheinlich Overkill sich da durchzuarbeiten. Schreib dir ein eigenes strcat/strlen, welches mit deinem externen Speicher umgehen kann und fertig. Schreib dir als erstes eine Funktion, welche ein beliebiges Byte aus dem externen SRAM lesen/schreiben kann. In einem gewissen Sinne würde ich dieses externe SRAM wie eine einzige Variable auffassen, für die es spezielle Funktionen zur Manipulation gibt. Und genau diese Funktionen schreibst du dir jetzt erst mal.
das mit der eigenen Funktion könnte ich so machen, daran hatte ich am Anfang auch schon mal gedacht. Aber ich war der Meinung, daß es für mich einfacher ist, diese den C-Compiler machen zu lassen....
Der Memory Tester hätte dich schon stutzig machen müssen. Aber so schlimm ist das ganze dann auch wieder nicht. Das einzige Problem ist die RAM-Bank Umschaltung. Wenn du mit nur einer RAM-Bank auskommst, könntest du sogar die originalen str... Funktionen benutzen. Du benutzt dann einfach alles über XRAMSTART als eine spezielle String Variable die genau an dieser Adresse liegt und fertig. Genauso wie es der Memory Tester auch macht. Brauchst du allerdings beide RAM-Bänke wirds ein klein wenig aufwändiger. Allerdings kannst du vieles davon dann durch eine spezielle Append Funktion, die sich nicht mehr das Stringende suchen muss, wieder abfangen. Aber probehalber kannst du ja mal folgendes machen
1 | unsigned char* ucsHTML_string = (unsigned char*)XRAMSTART; |
Das meiste in deinem Programm sollte eigentlich weiterhin genauso kompilieren wie vorher. Und deine maximal mögliche Stringlänge sollte jetzt eigentlich deutlich höher sein. Allerdings benutzt du damit nur eine RAM-Bank. Aber vielleicht reichen dir ja ~60kB als maximale Stringlänge schon.
Imi Übrigen: > Ich muß vor dem Senden des HTML-Strings die Länge wissen und > es ist am einfachsten, wenn ich einen langen String erzeuge > (die gesamte HTML-Daten) und dann mit strlen() die Länge abfrage. Das ist nicht unbedingt am Einfachsten. Um die Länge zu kennen, musst du den kompletten String nicht generieren. Du musst nur die Längen der Einzelteile addieren. Aber dazu muss der Komplettstring nicht als solcher existieren.
Simon K. wrote: > Ich glaube aber auch nicht, dass strcat das Mittel der Wahl ist. > Immerhin muss der bei jedem Aufruf erneut das Ende des Strings finden. Wobei man das noch elegant umgehen kann. Im Zweifelsfall, indem man einen Zeiger auf das abschließende Null-Zeichen benutzt und den händisch mitverschiebt. Zwar eine Addition mehr, aber besser, als immer von Anfang an durch den String zu latschen. Irgendwo gabs auch mal einen strcat-Verschnitt, der direkt als Rückgabewert einen Zeiger auf das Stringende lieferte.
Warum muss der der Kompette HTML string überhaupt im speicher sein? wenn du ihn bloss zusammenbaust um ihn dann zu senden dann kannst du die kleinen stückchen auch sofort senden. Der Browser warten schon bis alles da ist.
Peter wrote:
> Warum muss der der Kompette HTML string überhaupt im speicher sein?
Weil sie vorher die Stringlänge kennen muss.
Ich vermute mal, dass der HTML String nicht direkt zum Browser geht,
sondern über eine Zwischenstation. Und das Protokoll dorthin sieht vor,
dass zuerst die Datenlänge und dann die Daten selbst gesendet werden.
Aber ich geb dir vom Prinzip her recht. Der komplette String muss nie
tatsächlich existieren. Muss man halt den String im Grunde genommen
2-mal zusammenbauen: Einmal um die Länge zu ermitteln und einmal um die
Einzelteile zu verschicken. Mit ein bischen C-Trickserei rund um
Funktionspointer kann man das ganze so hinkriegen, dass eine einzige
HTML-Generierroutine beides bei 2 Aufrufen erledigen kann. Einmal zeigt
ein Funktionspointer auf eine Funktion, welche die Einzellängen addiert
und das andere mal zeigt er auf eine Funktion, welche die Einzelteile
verschickt. Dadurch bleibt das ganze auch wartbar und man läuft nicht
Gefahr, dass die Zählroutine was anderes zählt als die Verschickroutine
dann tatsächlich auf den Weg bringt. Und das beste am Ganzen: Die Größe
des HTML Strings ist überhaupt nicht mehr durch den vorhandenen lokalen
Speicher begrenzt. Lediglich die Einzelteile müssen in den Speicher
passen.
Am Anfang habe ich die Länge per Hand zusammen gezählt (etliche Zeilen mit strlen() ). Das ist aber ein ziemlicher Programmieraufwand und ziemlich fehlerbehaftet. Wenn ich etwas in der HTML-Datei hinzufüge, muß ich immer an 2 Stellen herum basteln. Das war bisher ein ziemliches Gefiesel.... Mit dem externen RAM will ich mir den Aufwand sparen: 1. String zusammen basteln 2. Länge mit strlen() erzeugen 3. HTTP-Header mit der Länge generieren und senden 4. HTML-String senden 5. fertig Die Länge benötigt der Browser (HTTP-Header). Wenn man eine zu geringe Länge anbibt, dann wartet der Browser unendlich lange auf den Rest (der nie kommt). Wenn man mehr schickt als die Länge im Header, dann gibts auch Probleme. Es scheint auch irgend eine Möglichkeit zu geben ohne die Angabe der Länge, aber das ist keine "saubere" Sache. In der Zwischenzeit habe ich Routinen erstellt: * strcpy_XRAM * strcat_XRAM * strlen_XRAM Geht auch prima mit Texten vom internen RAM. Nur habe ich ein neues Problem: 80...90% meiner Texte sind fest und stehen daher im Flash. Wie mache ich da eine Zuweisung von einer Speicherstelle im Flash in das externe RAM???? Den String vom Flash mit "strcpy_P" zuvor in einen temporären String ins RAM zu legen ist ja ziemlich umständlich. Aber wenn es nicht anders geht, müßte ich es halt so machen....
@Karl heinz Buchegger (kbuchegg) (Moderator) das mit dem... unsigned char* ucsHTML_string = (unsigned char*)XRAMSTART; ... werde ich mal probieren. Klingt irgendwie plausibel (obwohl ich nicht allzuviel Ahnung von der Programmierung habe).
Martin M. wrote: > Am Anfang habe ich die Länge per Hand zusammen gezählt (etliche Zeilen > mit strlen() ). Das ist aber ein ziemlicher Programmieraufwand und > ziemlich fehlerbehaftet. Wenn ich etwas in der HTML-Datei hinzufüge, muß > ich immer an 2 Stellen herum basteln. Das war bisher ein ziemliches > Gefiesel.... :-) Das kann man in C auch so machen, dass man nur an einer Stelle verändern muss. Zugegeben: ist ein bischen trickreich, aber machbar. :-) > Den String vom Flash mit "strcpy_P" zuvor in einen temporären String ins > RAM zu legen ist ja ziemlich umständlich. Aber wenn es nicht anders > geht, müßte ich es halt so machen.... Es geht immer auch anders. Die Frage ist immer nur, ob der Aufwand dafür steht :-) Nichts und niemand hindert dich daran, eine Funktion strcpy_XRAM_P zu schreiben. Ist doch nur ein 5-Zeiler.
Ich muss noch mal nachfragen, die Länge ist kein Pflichfeld in HTTP, du darfst sie nicht falsch machen das ist klar - lass sie doch einfach weg. Sobalt die verbindung geschlossen wurde zeig der Browser die webseite an.
> Nichts und niemand hindert dich daran, eine Funktion > strcpy_XRAM_P zu schreiben. Ist doch nur ein 5-Zeiler. sorry, daß ich mich vielleicht etwas blöde anstelle, aber wie kopiere ich Bytes vom Flash? Wenn ich irgend eine Adresse angebe, dann meint der Compiler doch immer, daß es eine im RAM ist, oder? Wie sage ich dem Compiler, daß es eine Adresse vom Flash ist?
avr-libc Doku die Zweite: http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html Tutorial: http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29
Martin M. wrote: >> Nichts und niemand hindert dich daran, eine Funktion >> strcpy_XRAM_P zu schreiben. Ist doch nur ein 5-Zeiler. > > sorry, daß ich mich vielleicht etwas blöde anstelle, aber wie kopiere > ich Bytes vom Flash? Wenn ich irgend eine Adresse angebe, dann meint der > Compiler doch immer, daß es eine im RAM ist, oder? Wie sage ich dem > Compiler, daß es eine Adresse vom Flash ist? pgm_read_byte() http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29
1 | void strcpy_XRAM_P( char* XRAMAddr, const char* FlashAddr ) |
2 | {
|
3 | char c; |
4 | |
5 | do { |
6 | c = pgm_read_byte( FlashAddr++ ); |
7 | XRAM_write_byte( XRAMAddr++, c ); |
8 | } while( c != '\0' ); |
9 | }
|
(Oder was du dann auch immer für einen Datentyp für die Adressangabe ins XRAM genommen hast. Pointer wird zu klein sein (bei 128KB) wird wohl auf long hinausgelaufen sein)
Danke! Ich werde es später ausprobieren. Jetzt ist erst mal verspätetes Mittagessen dran.
Hi, du mußt tatsächlich nicht die Länge angeben. HTTP/1.0 200 OK Content-Type: text/html <html><body><h1>It works!</h1></body></html> Einfach die strings rausschieben und am Ende die Connection zu machenh. man kann zwar alles andere implementieren, muß man aber nicht :) Boris
@Karl heinz Buchegger das mit dem ... unsigned char* ucsHTML_string = (unsigned char*)XRAMSTART; ... war ein super Tipp!! Das finde ich besser, als eigenen strcat, ... zu programmieren. Im Anhang ein Beispiel, wie das nun aussieht. Nochmals vielen Dank an alle, die sich meinem Problem gewidmet haben. Gruß Martin
> Einfach die strings rausschieben und am Ende die Connection zu machenh. jetzt ist es eigentlich schon nicht mehr interessant für mich, aber trotzdem bin ich neugierig. Wie macht man eine Connection zu? Ich benutze ein XPORT zum Verbinden von Ethernet und AVR.
Ich habe bisher nur unter Linux/Unix TCP Server Programmiert. Wenn du mir einen Link zu deinem TCP Stack oder der Server Software gibst, kann ich dir zeigen wie du den Code stark vereinfachen kannst. Boris
ich habe auf dem Layout 2 Typen vorgesehen: * XPort Direct+ http://www.lantronix.com/device-networking/embedded-device-servers/xport-direct-plus.html und den * XPORT http://www.lantronix.com/device-networking/embedded-device-servers/xport.html Die Server-Funktionalität im XPORT´s nutze ich jedoch nicht. Da hätte man mit Java was programmieren müssen, das war mir dann doch zu viel Aufwand, mich da einzuarbeiten. Ich sende vom AVR die HTML´s an den XPORT und der wandelt diese dann als Ethernet-Signale.
Bei HTTP/1.1 fähigem Browser kann man sogar in "Teilen" alles rübersenden... http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.