Forum: Compiler & IDEs optimierung und itoa


von S. L. (goldencue)


Lesenswert?

Tachchen ihr Dioden;)

Heut hab ich mal ein Prob, welches ich nun seit 24h nicht gelöst bekomm 
und hoffe auf Eure Hilfe.

Zum System:
Atmega32
AVR STUDIO 4.13 SP1
F_CPU 8000000UL
Optimierung -01


Zum Prob:
Ich habe ein Menue, in dem ich eine einfache Zahl ( als volatile uint8_t 
gespeichert ) inkrementieren lassen kann und sie über itoa aufs lcd 
angezeigt wird. Alles funkt, wenn ich den Controller quasi beim Start ( 
vor der while(1) ) in dieses Menue gehen lass und dann den Wert per 
Taste ändere. Rufe ich ein anderes ( z.B. das Hauptmenue ) erst auf und 
"springe" dann in besagtes Menue, verursacht mir itoa nach genau neun 
Tasterzyklen ein Reset und es wird auch keine Änderung der uint8-Zahl 
angezeigt. Hier mal die Routine was abgespeckt fürs Menue:

ExIvOn ist volatile uint8_t und wird in get_ExIv_EEdata() mit dem eeprom 
gefüllt. Eine Kontrolle des Integer brauch ich nicht, da die 255 und der 
Überlauf gewollt wären.

void Menue_Ex_IV(void)
{
  get_ExIv_EEdata();
  STHM_yn = 0;             //Auswahlschalter On/Off 0 = On
  lcd_command(0x0C);       //Cursor löschen
  lcd_command(0x01);       //Clear Display
  lcd_pos(0,0);
  lcd_text( (u8*) "Ex Interval:");
  lcd_pos(1,9);
  lcd_text( (u8*) "ON: ");
  //Minuten
  lcd_pos(1,13);
  volatile char EXOnSekAsk[4];
  itoa(ExIvOn,EXOnSekAsk,10);
  lcd_text((u8*)EXOnSekAsk);
  lcd_pos(1,15);
  lcd_command(0x0F); //Cursor setzen

}

Hier mal der Code der Tasterroutine:

switch(STHM_yn){
                  default:
                    STHM_yn = 0;
                    break;
                  case 0:
                    ExIvOn++;
  lcd_pos(1,13);
  volatile char EXOnSekAsk[10];
  itoa(ExIvOn,EXOnSekAsk,10);
  lcd_text((u8*)EXOnSekAsk);
  lcd_pos(1,15);
  break;
                  case 1:
        // kommt später
  break;
}

Mein Prog verursacht keine Fehler oder Warnungen beim Compilieren. 
Kommentiere ich itoa in der Tasterabfrage aus, zählt sie ExIvOn auch 
hoch. MIT itoa wird ( sobald ich von wo anders aus das Menue aufruf ) 
nach 9 Zyklen ein Reset ausgelöst und itoa auch scheinbar garnicht 
abgearbeitet. Optimierung -00 kann und will ich mir nicht leisten, weil 
mein Prog sonst nicht inne Flash passt unds hilft auch nich ab. Wie im 
QT zu sehen hab ich schon alles mögliche volatilisiert g aber hilft 
nix:(

Bitte helft mir. Wie kann dieses Verhalten auftreten? Beim einen Mal 
korrekt, beim anderen mal ERROR?

: Verschoben durch User
von thorstendb (Gast)


Lesenswert?

> Ich habe ein Menue,
mhhhh .... legger ^^

von Schorsch (Gast)


Lesenswert?

Matthias T. schrieb:
> QT zu sehen hab ich schon alles mögliche volatilisiert

Alle Volatiles die ich oben sehe sind falsch. Versuch lieber zu 
verstehen, was volatile genau macht, und setz es dann "richtig" ein.
Als zweite Stufe: Verstehen, warum volatile zwar hilft, aber eigentlich 
doch nicht "Das Richtige"™ ist, und stattdessen mit Atomic_blocks und 
Memory barriers arbeiten.

Zum Problem: Ich vermute einen Überlauf. Entweder der Stack ist zu 
klein, oder der buffer "EXOnSekAsk[4];"

von Schorsch (Gast)


Lesenswert?

Schorsch schrieb:
> klein, oder der buffer "EXOnSekAsk[4];"

Zur Erklärung: Du verwendest itoa, das ist für Signed Integers. d.H. 
aus deinem uin8_t wird bei der Parameterübergabe ein (auch gerne 
negativer) int.
und "-100\0" passt nicht mehr in die 4 Characters des Buffers.

von S. L. (goldencue)


Lesenswert?

Dank dir Schorsch!

Das Volatile versteh ich soweit ich auch die Controllerstruktur verstehe 
( und das noch nicht so ganz! ) Allerdings vermutete ich eine 
Rationalisierung des Optimierers und versuchte so den Compiler daran zu 
hindern, Code anders zu interpretieren als ich es vorsah. Deshalb die 
volatiles und es hat ja auch nix geändert.
Warum nur falsch gesetzt? daran hätte es doch liegen können, wenn der 
Compiler die Variablen hätte erst im Zwischenspeicher abgelegt und so 
der unkontrollierten Manipulation freigegeben. Wo hätten die volatiles 
denn Sinn?

Das mit dem Stack werd ich gleich mal testen, obwohl ExIvOn nie >255 und 
kleiner als 0 sein kann ( uint8 halt ) und daher EXOnSekAsk[4] auch nur 
zum einen positiv und zum anderen nicht überlaufen sein kann.

leider versteh ich von Atomic_blocks und
Memory barriers noch nix. wenn es aber dem Prob dienlich ist werd ich 
mich daran setzen. Mein Verständnis kommt aus der PC-Programmierung und 
tut sich daher bissi was schwer mit SRAM Register, Flag und dergleichen. 
Man lernt!

das mit itoa und unsigned ist mir schon klar, nur w.o. beschrieben kann 
der Wert von EXOnSekAsk nicht außerhalb 0-255 liegen...meines Wissens!

aber daaaanke erstmal ich bin hier am zweifeln:(

von thorstendb (Gast)


Lesenswert?

1
>   volatile char EXOnSekAsk[4];
2
>   itoa(ExIvOn,EXOnSekAsk,10);
3
4
5
>   volatile char EXOnSekAsk[10];
6
>   itoa(ExIvOn,EXOnSekAsk,10);
>
> Bitte helft mir.

1. raus mit dem volatile.
Ist nur wichtig, wenn du nicht direkt drauf zugreifst bzw. der Compiler 
die Verwendung nicht erahnen kann.

2. keine Magic Numbers. Gewöhn dir mal
1
#define TEXTLEN  10
en.

3. ein array ist 4, eins 10 gross. Hmm??
Mach ein globales
1
char text[10];
und fertich. Ist auch besser, und du sparst sogar 4 (nein, 10) Bytes 
RAM.
Ausserdem:
1
itoa(ExIvOn, text, TEXTLEN);
Vielleicht auch
1
itoa(ExIvOn, text, TEXTLEN-1);
benutze kein itoa.


VG,
/th.

von S. L. (goldencue)


Lesenswert?

klasse - danke! hab ich geändert. nur leider der Fehler bleibt:(

Die "Magic Number" ist "Schnicklschmack" und kann ich später sicher 
anpassen. Ich versteh ja, das es ins Dec wandelt.

Und wie bitte soll ich ohne itoa arbeiten? zumal es beim direkten 
ansteuern ( noch vor der while(1) ) funkt?!

übrigens...das itoa wird abgearbeitet (laut neuester Tests;). Nur 
verursacht genau das den Absturz?!

verbeug

von thorstendb (Gast)


Lesenswert?

Hi,

sry, zu schnell getippt, ich meinte: ICH verwende kein itoa() :-)

hast mal geschaut, ob itoa den string auch terminiert?


VG,
/th.

von thorstendb (Gast)


Lesenswert?

> und kann ich später sicher anpassen.

macht man nie **grins**

von Schorsch (Gast)


Lesenswert?

Matthias T. schrieb:
> übrigens...das itoa wird abgearbeitet (laut neuester Tests;).
Du hast gelesen, was ich dir oben geschrieben hab?

itoa ist FALSCH. Du brauchst utoa. Das ist nämlich extra für 
Unsigned Variablen gedacht, wie es dein uint8_t ist.

von S. L. (goldencue)


Lesenswert?

es gibt mir den wert ( ASCII ) aufs DISPLAY und zeigt mir eigene Zeichen 
aus meiner ASCII-Tabelle an, die den Werten 0x00-0x09 entsprechen. 
Danach - also nach 9 inkrements resetet er.

Über lcd_text ist aber gewährleistet, dass der String auch terminiert 
sein muss. Sonst käme ja der ganze Speicher aufs Display.

von S. L. (goldencue)


Lesenswert?

das mit utoa und itoa ist mir klar. nur ändert es am Ergebnis leider 
nix!

von Karl H. (kbuchegg)


Lesenswert?

Und dein neuer, geänderter Code sieht jetzt wie aus?

von Karl H. (kbuchegg)


Lesenswert?

PS. Deine lcd_text Funktion ist falsch definiert. Die sollte keinen u8* 
übernehmen, sondern einen ordinären char*

von S. L. (goldencue)


Lesenswert?

So - gelöst ******breitgrins**********

hab die char EXOnSekAsk[4]; laut thorstendb mal global gemacht und alles 
funzt. Sparen kann ich daran allerdings nicht. die Variante lokal hat 
die Vars ja nach beenden immer wieder aufgelöst und nun nich mehr.

Warum nun der Fehler behoben ist...ich würde es Euch gern sagen; Aber 
weiss es auch nicht.

Danke aller Hilfe eurerseits!

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> So - gelöst ******breitgrins**********
>
> hab die char EXOnSekAsk[4]; laut thorstendb mal global gemacht und alles
> funzt.

Sieht nur so aus.
Du hast das eigentliche Problem höchst wahrscheinlich nicht behoben, 
sondern nur an eine andere Stelle verfrachtet.

> Sparen kann ich daran allerdings nicht. die Variante lokal hat
> die Vars ja nach beenden immer wieder aufgelöst und nun nich mehr.
>
> Warum nun der Fehler behoben ist...ich würde es Euch gern sagen; Aber
> weiss es auch nicht.

Und genau ds ist das bedenkliche an der Situation.

von Schorsch (Gast)


Lesenswert?

Wieviel Platz hast du am Stack noch frei? geht sich das genau um das 
Byte nicht mehr aus, wenn das "innere" utoa ein char mehr schreiben muss 
("9" => "10")

MAch mal ein paar bytes mehr platz im Ram, z.B. duch kürzen des Strings
1
lcd_text( (u8*) "Ex Interval:");
in
"ExI" o.Ä.

Saubere Lösung: pgmspace.h, PSTR, lcd_text_P.

von S. L. (goldencue)


Lesenswert?

global:
uint8_t ExIvOff;
unsigned char EXOnSekAsk[4];

Menuecode:

get_ExIv_EEdata();
STHM_yn = 0; //Auswahlschalter On/Off 0 = On
lcd_command(0x0C); //Cursor löschen
lcd_command(0x01); //Clear Display
lcd_pos(0,0);
lcd_text( (u8*) "Ex Interval:");
lcd_pos(1,9);
lcd_text( (u8*) "ON: ");
//Minuten
lcd_pos(1,13);
utoa(ExIvOn,EXOnSekAsk,10);
lcd_text((u8*)EXOnSekAsk);


Tastercode:

ExIvOn++;
lcd_pos(1,13);
utoa(ExIvOn,EXOnSekAsk,10);
lcd_text((u8*)EXOnSekAsk);
lcd_pos(1,15);



ist natürlich nur der heilwegs relevante Text!

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Schorsch schrieb:
> Wieviel Platz hast du am Stack noch frei? geht sich das genau um das
> Byte nicht mehr aus, wenn das "innere" utoa ein char mehr schreiben muss
> ("9" => "10")
>
> MAch mal ein paar bytes mehr platz im Ram, z.B. duch kürzen des Strings
>
1
> lcd_text( (u8*) "Ex Interval:");
2
>
> in
> "ExI" o.Ä.
>
> Saubere Lösung: pgmspace.h, PSTR, lcd_text_P.

genau, PROGMEM für diese Konstanten verwenden, dann landen die im Flash. 
Dann ggf. den Pointer drauf holen und weiterverwenden:
char *pText = ....

Strings sind - wie mein Vorredner schon sagte - immer (char *).


VG,
/th.

von S. L. (goldencue)


Lesenswert?

AVR Memory Usage
----------------
Device: atmega32

Program:   14596 bytes (44.5% Full)
(.text + .data + .bootloader)

Data:        435 bytes (21.2% Full)
(.data + .bss + .noinit)

EEPROM:       16 bytes (1.6% Full)
(.eeprom)

Mit - im Stack platz machen - kenne ich mich noch nicht aus. Was es ist 
und wie er funkt weiß ich heilwegs. Aber wie lese ich den Stand des 
Stack zur Runtime aus?

von S. L. (goldencue)


Lesenswert?

Random ... schrieb:
> Strings sind - wie mein Vorredner schon sagte - immer (char *).

ich verwende Peter F.s LCD-Routinen und ( ohne es zu ändern ) die 
verlangen bei lcd_text ein u8 ??!

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:

> Data:        435 bytes (21.2% Full)
> (.data + .bss + .noinit)

wenn da nicht exzessiv große Arrays am Stack allokiert werden, ist der 
Speicher kein Problem

von S. L. (goldencue)


Lesenswert?

Random ... schrieb:
> genau, PROGMEM für diese Konstanten verwenden, dann landen die im Flash.
> Dann ggf. den Pointer drauf holen und weiterverwenden:
> char *pText = ....

joi - da bin ich an nen Fachmann geraten ;) Keeeeine Ahnung im Mom wovon 
du sprichst. Aber ich verfolge es weiter!

von Schorsch (Gast)


Lesenswert?

Matthias T. schrieb:
> Aber wie lese ich den Stand des
> Stack zur Runtime aus?

Gibts ein kleines C-Schnippselchen für, z.B. in diesem Thread:
Beitrag "Compilerfehler bei mem-check"

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> Random ... schrieb:
>> Strings sind - wie mein Vorredner schon sagte - immer (char *).
>
> ich verwende Peter F.s LCD-Routinen und ( ohne es zu ändern ) die
> verlangen bei lcd_text ein u8 ??!

Das kann ich mir nicht wirklich vorstellen.
Schon alleine deswegen, weil die entsprechende Routine beim Peter Fleury
1
void lcd_puts(const char *s)
2
{
3
  ..
4
}

heißt und nicht lcd_text

von S. L. (goldencue)


Lesenswert?

ups

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> global:
> uint8_t ExIvOff;



> utoa(ExIvOn,EXOnSekAsk,10);


> ist natürlich nur der heilwegs relevante Text!

Glaub ich nicht. Die Variablen heißen ganz anders.

Poste ALLES

Dein Code ist ein einziger Saustall!

> Die "Magic Number" ist "Schnicklschmack" und kann ich später
> sicher anpassen.

Das sagen sie immer. Hinten nach, hinten nach

Nur eigenartigerweise sind es immer genau die Progammierer mit dem 
scheuslichsten Code, die die meisten Fehler haben.

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> global:
> uint8_t ExIvOff;
> unsigned char EXOnSekAsk[4];

Bei derartigen Arrays definiert man die Länge nie auf 'passt genau', 
sondern man lässt sich immer einen kleinen Überhang, damit sich Fehler 
nicht gleich in Desaster auswirken.

von S. L. (goldencue)


Lesenswert?

ah - ok! das kann ich berücksichtigen. Danke!

geb ich da besser mehr Bytes ( also zb [10]) oder gleich []?

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> ah - ok! das kann ich berücksichtigen. Danke!
>
> geb ich da besser mehr Bytes ( also zb [10]) oder gleich []?

Du brauchst ein C-Buch

Wie willst du denn ein Array mit[] definieren?
In C muss alles eine definierte Größe haben. Von alleine wächst da gar 
nichts.

von S. L. (goldencue)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du brauchst ein C-Buch
>
> Wie willst du denn ein Array mit[] definieren?
> In C muss alles eine definierte Größe haben. Von alleine wächst da gar
> nichts.

"Jetzt lerne ich C" S.210 Z.007 ( mit 1 beginnend ) ISBN 3-8272-5361-6 
Verlag Markt&Technik.  Zugegeben etwas älter und ob es auf µC funkt weiß 
ich auch nicht.

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> Karl heinz Buchegger schrieb:
>> Du brauchst ein C-Buch
>>
>> Wie willst du denn ein Array mit[] definieren?
>> In C muss alles eine definierte Größe haben. Von alleine wächst da gar
>> nichts.
>
> "Jetzt lerne ich C" S.210 Z.007 ( mit 1 beginnend ) ISBN 3-8272-5361-6
> Verlag Markt&Technik.  Zugegeben etwas älter und ob es auf µC funkt weiß
> ich auch nicht.

OK. Jetzt musst du es nur noch durcharbeiten :-)

von S. L. (goldencue)


Lesenswert?

ich will ja hier kein konfrogespräch entfachen und mein text ist ( 
erstrecht ) insgesamt sicher lausig. Es gibt VIELES was ich noch nicht 
weiß und sich als Fehler herausstellen wird. Aber hast du auch vor 15 
Monaten begonnen und weißt jetzt alles? Mir geht es um lernen und das 
geht nur nach und nach.
Meines Wissens hast Du Karl Heinz mir vor nem halben Jahr schonmal mit 
meinem LCD geholfen und ich bin dir sehr dankbar, denn auch da hab ich 
ja viel gelernt. Hier soll es genau so sein. C hab ich gelesen ( auch in 
Ruhe ) Aber die Praxis muss noch wachsen. Hinzu kommen ja die ganzen 
Controllerarchitekturen, Datenblätter u.u. Muss ich auch alles lernen 
nach und nach.

bitte immer sachlich bleiben:)

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Matthias T. schrieb:
> Random ... schrieb:
>> genau, PROGMEM für diese Konstanten verwenden, dann landen die im Flash.
>> Dann ggf. den Pointer drauf holen und weiterverwenden:
>> char *pText = ....
>
> joi - da bin ich an nen Fachmann geraten ;) Keeeeine Ahnung im Mom wovon
> du sprichst. Aber ich verfolge es weiter!

Naja, genau das, was da steht.

Der AVR ist ein Harvard-Modell, d.h. er hat getrennte Busse für Befehle 
(Flash) und Daten (SRAM).

Konstante Strings kann man aus Platzgründen am besten im Flash ablegen. 
Wenn man auf diese Strings zugreifen muss, holt man sich die in einen 
char pointer, und übergibt diesen an print....(was auch immer). Dazu 
braucht man bestimmte Funktionen, die den Zugriff auf den Flash 
umlenken.

ARMs / Cortex Prozessoren z.B. basieren ebenfalls auf einem 
Harvard-Modell, aber da bei 32Bit (4Gig) mehr als genug Adressen da 
sind, ist der Flash mit in den Datenbereich gemapped, kurzum: der ganze 
Adressraum ist linearisiert ('Von Neumann' Programmiermodell). Dort 
braucht man diese Konstrukte nicht.

Der AVR ist aber nur 8Bit (16Bit Adressen?), und daher muss man diese 
Klimmzüge machen.

Hoffe, ich hab mich jetzt nirgendwo auf die Schnelle vertan :-)


Weiterhin:
Strings sind stets mit '\0' (DEC 0) terminiert, das kennzeichnet das 
Stringende. Bedeutet, dass in 'char text[10]' neun Zeichen plus '\0' 
passen, mit dem Index von [0...9].

Die Array-Klammern ohne Grössenangabe kann man zum Init eines Strings 
verwenden, z.B.
char text[] = "Hallo, Welt"

oder besser:
char *text = "Hallo, Welt"

Dabei wird Speicher für den String angelegt, und die Adresse des Strings 
im pointer 'text' gespeichert.
Will man (unsauber) diesen Text ändern, braucht man die Länge.


VG,
/th.

von S. L. (goldencue)


Lesenswert?

vielen Dank! Ich werde mich damit beschäftigen!

von Peter D. (peda)


Lesenswert?

Karl heinz Buchegger schrieb:
> Bei derartigen Arrays definiert man die Länge nie auf 'passt genau',
> sondern man lässt sich immer einen kleinen Überhang, damit sich Fehler
> nicht gleich in Desaster auswirken.

Das ist Unsinn.
Besser ist immer, man weiß, was man tut.
Und wenn ich weiß, daß ich max 30 Byte benötige, dann nehme ich auch 
genau 30. Mehr bringt nämlich genau 0,nix.

Hier mal ein Beispiel für einen Puffer für eine 32Bit-Zahl:
1
static uint8_t buff[sizeof("-2147483648")];    // maximum number length


Peter

von Karl H. (kbuchegg)


Lesenswert?

Peter Dannegger schrieb:
> Karl heinz Buchegger schrieb:
>> Bei derartigen Arrays definiert man die Länge nie auf 'passt genau',
>> sondern man lässt sich immer einen kleinen Überhang, damit sich Fehler
>> nicht gleich in Desaster auswirken.
>
> Das ist Unsinn.

Ja.
Bis dann in 3 Monaten man auf die Idee kommt, dass man da noch einen 
kleinen Text davor haben will.

Alles schon gesehen, alles schon gehabt, schon öfter drauf reingefallen.

> Besser ist immer, man weiß, was man tut.

Als ob Neulinge das im Regelfall tun.

> Und wenn ich weiß, daß ich max 30 Byte benötige, dann nehme ich auch
> genau 30. Mehr bringt nämlich genau 0,nix.

Wenn ich einen globalen Buffer zur Textwandlung habe, dann mach ich den 
nicht auf Knirsch, denn irgendwann in nächster Zeit fällt man nämlich 
drauf rein, dass 3 Zeichen bei einer int-Wandlung zu wenig ist. Und sei 
es nur, weil die Zahl aus irgendeinem Grund tatsächlich mal größer als 
255 wird.
Ist auch im Regelfall völlig wurscht, wenn ich dem noch 7 Bytes 
dazuspendiere. Das kostet nichts. 2 Stunden Fehlersuche wegen so einem 
Blödsinn hingegen kosten Geld.


Nennt sich defensives Programmierern.

von Peter D. (peda)


Lesenswert?

Karl heinz Buchegger schrieb:
> Wenn ich einen globalen Buffer zur Textwandlung habe, dann mach ich den
> nicht auf Knirsch, denn irgendwann in nächster Zeit fällt man nämlich
> drauf rein, dass 3 Zeichen bei einer int-Wandlung zu wenig ist.

Ist es ja auch. Du brauchst für 16Bit genau:
1
static uint8_t buff[sizeof("-32768")];    // maximum number length


Peter

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.