ATtiny85 - bei 3.5kB ist Schluss

OP #4021042
Lesenswert?

Hallo *,

ich möchte mit einem '85er einen "tiny-computer" bauen. Eigentlich 
funktioniert alles wie gewünscht, bis der Programmcode grösser 3.5kB 
wird. Dann fängt der tiny an zu spinnen. Das Programm läuft nicht durch, 
verrückte Zeichen auf dem Display, usw. ...

Die Idee:
An einem ATtiny85 hängen in Modulbauweise Netzteil, Display, 
Portexpander, Analogeingänge / -ausgänge, Soundausgang, ähnliches. 
Portexpander werden erkannt und können über Menüstruktur manuell 
geschaltet oder mit Zeitschaltern programmiert werden. Das Menü wird 
über Taster und ein Poti eingestellt und gewählt.

Umsetzung:
a) Hardware:
Der "Computer" ist experimentell schon aufgebaut (siehe Foto). Er 
verfügt über Reset-Knopf, links, rechts, rauf, runter, Eingabe - Taster, 
Poti an analog Eingang, funktionierende i2c Schnittstelle und 2x16 
Display.
b) Software:
Die SW wird entwickelt über die Arduino GUI 1.0.5-r2 und die 
arduino-tiny Umgebung ( https://code.google.com/p/arduino-tiny/ ).
Zum Einsatz kommen die libraries TinyWireM für den i2c Bus ( 
http://playground.arduino.cc/Code/USIi2c ) und LiquidCrystal_I2C_85V1 
für das Display ( gleiche Webseite auf arduino playground ).
Programmiert wird der uC über die 'Arduino as ISP' Funktion am Arduino 
UNO.
Ich habe schon mehrere Programm-Module geschrieben, echte 
Problemlösungen für Menü, Display, Tasten, usw.

Das Problem:
Alle Programm-Module funktionieren für sich ganz gut. Bis der Code 
ungefähr die 3.5 kB Grenze überschreitet. Dann wird's seltsam (wenn es 
komisch wäre, müsste ich ja lachen). An ein Zusammenfügen der Programme 
ist erst gar nicht zu denken.

Die Fragen:
Hat jemand schon Erfahrung mit dem arduino-tiny Aufsatz auf die arduino 
GUI gemacht? Hier vermute ich das Problem.
Kennt jemand libraries (i2c und i2c-display) für c - 
Programmierumgebungen wie programmers notepad oder Atmel - Studio? Mit 
libraries kenne ich mich überhaupt nicht aus, besonders die i2c-Display 
Ansteuerung deucht mir höchst komplex und über meine 
Programmier-Kenntnisse.

Aufruf:
Bei Interesse bin ich gerne bereit, alles bereits entwickelte frei zu 
geben, HW und SW.
Vielleicht könnte man ja in einer gemeinsamen Projektarbeit zu einem 
guten Ergebnis kommen?

Sorry für den langen Roman, aber ich fische mit dem Fehler absolut im 
Trüben. Vielleicht findet ja der Eine oder Andere Interesse an der Idee 
und macht mit ...
Danke jedenfalls für das coole Forum hier.

Viele Grüsse aus Augsburg,
Helge
Angehängte Dateien:
#4021072
Lesenswert?

Helge Schick schrieb:
> So etwas habe ich mir auch schon gedacht, aber wie kann ich das
> nachvollziehen? Und vor Allem: Wie könnte ich das vermeiden?
> Gruss, Helge

Kannst Du einen Chip mit mehr SRAM verwenden? Ausrechnen ist nicht so 
leicht - Du müsstest theoretisch in der Ausgabe vom Compiler sehen, wie 
weit die Variablen gehen. (oder Du überschlägst es anhand der Typen und 
ihrer Anzahl, besonders bei Arrays, Strings, ..) Im Programm kannst Du 
den SP (Stack pointer) auslesen.

Generell weniger verschachtelte Funktions- bzw. Unterprogrammaufrufe 
verwenden ist nur eine Notlösung.
#4021077
Lesenswert?

Auf Peter hat niemand gehört. Daher nochmal:

Die Programmgröße (FLASH) hat nichts mit Heap oder Stack (SRAM) zu tun.

Den Flash kannst du zu 100% zuknallen. Kein Problem. Beim SRAM muss 
Platz für den gelassen werden.

Stammen die 3,5kb von der avr-size Ausgabe?

Welche Belegung zeigt es für den Ram an?
Moderator Persönliche Seite #4021087
Lesenswert?

Peter II schrieb:
> Rainer Unsinn schrieb:
>> Vielleicht läuft Dein Stack in Deine Variablen 'rein?
>
> der Stack hat doch nichts mit der Programmgröße zu tun.

Je mehr Programmcode, desto mehr Variablen, desto mehr RAM. Die 
Beziehung ist vielleicht nicht linear, aber Du wirst mir zustimmen, dass 
man in den seltensten Fällen durch Hinzufügen von Programmcode den 
RAM-Bedarf verringert ;-)

Das "komische Verhalten", dass der TO anführt, spricht auch dafür. Oft 
trifft das Problem bei LCD-Routinen auf, die viel Texte ausgeben, welche 
beim Start vom flash ins RAM kopiert werden. PROGMEM hilft dagegen.
OP #4021102
Lesenswert?

Danke an alle
1
#include <TinyWireM.h>
2
#include <LiquidCrystal_I2C.h>
3

4

5
LiquidCrystal_I2C lcd(0x23,16,2);
6

7
byte myStat;
8
byte myByte;
9

10
byte ch_up[8] = {
11
  0b00100,
12
  0b01110,
13
  0b11111,
14
  0b00000,
15
  0b00000,
16
  0b00000,
17
  0b00000,
18
  0b00000
19
};
20
byte ch_down[8] = {
21
  0b00000,
22
  0b00000,
23
  0b00000,
24
  0b00000,
25
  0b00000,
26
  0b11111,
27
  0b01110,
28
  0b00100
29
};
30
byte ch_left[8] = {
31
  0b00000,
32
  0b00100,
33
  0b01100,
34
  0b11100,
35
  0b01100,
36
  0b00100,
37
  0b00000,
38
  0b00000
39
};
40
byte ch_right[8] = {
41
  0b00000,
42
  0b00100,
43
  0b00110,
44
  0b00111,
45
  0b00110,
46
  0b00100,
47
  0b00000,
48
  0b00000
49
};
50
byte ch_enter[8] = {
51
  0b00001,
52
  0b00001,
53
  0b00001,
54
  0b10010,
55
  0b11100,
56
  0b11100,
57
  0b11110,
58
  0b00000
59
};
60
byte ch_logo[8] = {
61
  0b00000,
62
  0b10110,
63
  0b10101,
64
  0b01101,
65
  0b00000,
66
  0b00111,
67
  0b00100,
68
  0b11111
69
};
70
byte ch_tiny1[8] = {
71
  0b10110,
72
  0b00000,
73
  0b01000,
74
  0b11110,
75
  0b01000,
76
  0b00000,
77
  0b00000,
78
  0b00000
79
};
80
byte ch_tiny2[8] = {
81
  0b00000,
82
  0b00111,
83
  0b00010,
84
  0b00110,
85
  0b00000,
86
  0b00110,
87
  0b00100,
88
  0b00110
89
};
90

91
// Buttons & PCF8574 0x20
92
byte PCF0_ADDR = 0x20;
93
byte    b_left = 0b10000000;    // 128
94
byte   b_right = 0b01000000;    //  64
95
byte      b_up = 0b00100000;    //  32
96
byte    b_down = 0b00010000;    //  16
97
byte   b_enter = 0b00000001;    //   1
98

99
// Characters
100
byte   c_enter = 0;
101
byte   c_tiny1 = 1;
102
byte   c_tiny2 = 2;
103
byte    c_logo = 3;
104
byte    c_down = 4;
105
byte      c_up = 5;
106
byte   c_right = 6;
107
byte    c_left = 7;
108

109
void setup(){
110
        // µC related
111
  //noInterrupts();
112
  //CLKPR = 0x80;    // run at
113
  //CLKPR = 0x00;    // 8MHz internal Osc.
114
  //interrupts();
115

116
  // LCD_I²C related
117
  lcd.init();
118

119
  // custom characters prog.
120
        lcd.setCursor(0,0);
121
        lcd.print("setting up ...  ");
122
  lcd.createChar(0, ch_enter);
123
  lcd.createChar(1, ch_tiny1);
124
  lcd.createChar(2, ch_tiny2);
125
  lcd.createChar(3, ch_logo);
126
  lcd.createChar(4, ch_down);
127
  lcd.createChar(5, ch_up);
128
  lcd.createChar(6, ch_right);
129
  lcd.createChar(7, ch_left);
130
        waitkey(b_enter);
131
        
132
        // check I/O Expanders
133
        lcd.clear();
134
  lcd.setCursor(0,0);
135
        lcd.print("PCF8574 @:      ");
136
  lcd.setCursor(0,1);
137
  for(int i = 32; i < 40; i++){
138
              myStat =  TinyWireM.requestFrom(i, 0);
139
          if(myStat == 0){
140
                lcd.print("0x2"); //delay(100);
141
                lcd.print(i-32);  //delay(100);
142
                lcd.print(" ");   //delay(100);
143
                }
144
        }
145
        waitkey(b_enter);
146

147
        // ready message
148
//  ready();
149

150
    lcd.clear();
151
                lcd.setCursor(0,0);
152
                lcd.write(2);
153
                //         0123456789012345           
154
                lcd.print(" ready, press  ");
155
                lcd.setCursor(0,1);
156
    lcd.write(1);
157
                //         0123456789012345 
158
    lcd.print(" tinycomputer ");
159
                lcd.write(3);
160
    waitkey(b_enter);
161
    lcd.clear();
162

163
}
164

165
void loop(){
166

167
}
168

169
// get buttons from I²C port 0
170
void pcf0_get(){
171
        //delay(150);
172
        noInterrupts();
173
          myStat =  TinyWireM.requestFrom(0x20, 1);
174
          if(myStat != 0){error();}
175
          myByte = TinyWireM.receive();
176
        interrupts();
177
}
178
// wait4key
179
void waitkey(byte button){
180
        lcd.setCursor(15,0);
181
        if(button == b_enter){lcd.write(c_enter);}
182
        if(button == b_up   ){lcd.write(c_up   );}
183
        if(button == b_down ){lcd.write(c_down );}
184
        if(button == b_left ){lcd.write(c_left );}
185
        if(button == b_right){lcd.write(c_right);}
186
  pcf0_get();
187
  while((myByte & button) == button){pcf0_get();} // await press
188
        delay(50); pcf0_get();
189
        while((myByte & button) == 0){pcf0_get();}      // await release
190
}
191
// I²C errorhandling (2bcancelled4RAM)
192
void error(){                     // called when myStat != 0
193
  lcd.clear();
194
  lcd.setCursor(0,0);
195
  lcd.print("* IIC error:");
196
  lcd.setCursor(0,1);
197
  if(myStat == 1){lcd.print("no ACK 4 address");}      // The slave did not acknowledge the address
198
  if(myStat == 2){lcd.print("no ACK 4 data   ");}      // The slave did not acknowledge all data
199
  if(myStat == 3){lcd.print("no START Cond.  ");}      // Generated Start Condition not detected on bus
200
  if(myStat == 4){lcd.print("no STOP Cond.   ");}      // Generated Stop Condition not detected on bus
201
  if(myStat == 5){lcd.print("arbitration     ");}      // Unexpected Data Collision (arbitration)
202
  if(myStat == 6){lcd.print("unexpected STOP ");}      // Unexpected Stop Condition
203
  if(myStat == 7){lcd.print("unexpected START");}      // Unexpected Start Condition
204
  if(myStat == 8){lcd.print("TX buff. empty  ");}      // Transmission buffer is empty
205
  if(myStat == 9){lcd.print("TX buff. out RAM");}      // Transmission buffer is outside SRAM space
206
  if(myStat ==10){lcd.print("no ext. RAM read");}      // Error during external memory read
207
  waitkey(1);
208
}
209
// ready message
210
//void ready(){
211
//    lcd.clear();
212
//                lcd.setCursor(0,0);
213
//                lcd.write(2);
214
//                //         0123456789012345           
215
//                lcd.print(" ready, press  ");
216
//                lcd.setCursor(0,1);
217
//    lcd.write(1);
218
//                //         0123456789012345 
219
//    lcd.print(" tinycomputer ");
220
//                lcd.write(3);
221
//    waitkey(b_enter);
222
//    lcd.clear();
223
//}

Das ist doch verrückt, oder?
Gast #4021103
Lesenswert?

Frank M. schrieb:
> Je mehr Programmcode, desto mehr Variablen, desto mehr RAM. Die
> Beziehung ist vielleicht nicht linear, aber Du wirst mir zustimmen, dass
> man in den seltensten Fällen durch Hinzufügen von Programmcode den
> RAM-Bedarf verringert ;-)

das nicht, aber es wird auch nicht mehr Ram verbraucht wenn ich noch 2 
zusätzliche Funktionen schreibe.
Gast #4021126
Lesenswert?

Ralf G. schrieb:
> Vielleicht werden die aber auch mal aufgerufen?

auch dann nicht zwingend. Denn es laufen ja nicht alle Funktionen 
gleichzeitig.

Es gibt keine wirklichen Zusammenhang zwischen Flash und Ram verbrauch. 
Man kann 8kb Flash nutzen und nur 10byte Ram, oder auch 10byte Flash und 
8kb RAM.
OP #4021127
Lesenswert?

Bitte nicht falsch verstehen: Der Arduino ist eigentlich nur der ISP. OK 
die Entwicklungsumgebung ist fragwürdig. Habe ich ja anfangs auch 
geschrieben. Würde ja auf pn oder Atmel Studio wechseln, nach C, aber 
die libraries schreibe ICH auf keinen Fall, zu wenig Programmierpower 
...
Moderator Persönliche Seite #4021131
Lesenswert?

Helge Schick schrieb:
>         lcd.print("PCF8574 @:      ");
>                 lcd.print(" ready, press  ");
> //    lcd.print(" tinycomputer ");
>   lcd.print("* IIC error:");
> [und noch ca. 20 weitere Zeilen mit lcd.print]
> Das ist doch verrückt, oder?

Nein, überhaupt nicht verrückt. Du verwendest jede Menge Textkonstanten, 
die alle beim Boot ins RAM kopiert werden.

Stelle das für alle Textkonstanten um auf:

    lcd.print(F("My string in FLASH"));
#4021132
Lesenswert?

Ach das Problem liegt, wie immer, darin dass man natürlich Arduino 
Module nicht einfach so kombinieren kann. Niemand weiß welche Resourcen 
die Module belegen. Und dann noch das Arduino-Tiny Gefrickel. Ich würde 
als TE mal die lib "info-to-brain" ausprobieren und den Tiny direkt in C 
programmieren. Aber neee das geht natürlich nicht. Dafür ist man zu 
faul, aber auf dicke Hose mit nem "tiny computer" machen. Ist doch 
lächerlich dafür dann Arduino zu nehmen. Da braucht man erst recht 
direktere Zugriff auf seine Resourcen. ich gönne solchen Leuten 
jeglichen Fehler und alle Probeme im Projekt. Nur zu. So lernt man das. 
Auf die harte Tour.
#4021147
Lesenswert?

Moby AVR schrieb im Beitrag #4021145:
> Prinzipiell und wenn man seinen Code 100%ig selbst unter Kontrolle hat
> natürlich nicht. Bei Hochsprachenverwendung ist dann aber doch

Weil Hochsprachen in Mobys kranker troll Phantasie gerne mal 
kilobyteweise Ram belegen, einfach so. Spontan. Kannste nix dagegen 
machen. Hilft nur Assembler. iss so.
Moderator Persönliche Seite #4021156
Lesenswert?

Helge Schick schrieb:
> Hallo Frank,
> das ist es bestimmt! Aber die Zeile
>     lcd.print(F("My string in FLASH"));
> verstehe ich nicht. Wo ist das dokumentiert? Was bedeutet das "F"? Wie
> kommt dann die Meldung

Das Makro F(s) definiert einen konstanten String im Flash, welcher zur 
Laufzeit NICHT ins RAM kopiert wird. Ich hatte ja oben schon in meinem 
ersten Posting das Stichwort PROGMEM angegeben. Aber offenbar ist es so, 
dass man erstmal Tipps ignoriert, welche man nicht versteht ;-)

Übrigens: Dieses Problem tritt nicht nur bei Arduino-AVRs auf, sondern 
auch, wenn man in "nacktem C" AVRs programmiert. Das nur mal so nebenbei 
als Hinweis an cyblord. (Auch wenn ich ihm recht gebe: Man braucht keine 
Arduino-Lib, um AVRs zu programmieren).

Zurück zum Thema. Google-Suche nach "Arduino PROGMEM" wirft u.a. 
folgende Links aus:

  http://arduino.cc/en/pmwiki.php?n=Reference/PROGMEM
  https://learn.adafruit.com/memories-of-an-arduino/optimizing-sram

(und noch viele andere)

> Wie kommt dann die Meldung
>     Binäre Sketchgröße: 3.368 Bytes (von einem Maximum von 8.192 Bytes)
> zustande?

Je mehr lcd.print()-Aufrufe Du machst, desto mehr Speicher im RAM 
brauchst Du, wenn Du die Text-Konstanten nicht ausdrücklich für den 
Flash-Speicher deklarierst. Insofern sieht das Peter etwas zu 
engstirnig.
Moderator Persönliche Seite #4021191
Lesenswert?

Helge Schick schrieb:
> PS: Die adafruit - Seite ist gut.

Wie gesagt: Es gibt auch noch andere Seiten, wo PROGMEM & Co näher 
erklärt werden.

Auch Arduino dokumentiert das F(s) in der print()-Methode:

    http://arduino.cc/en/Serial/print

Zitat:

-------------------------------- schnipp -------------------------------
You can pass flash-memory based strings to Serial.print() by wrapping 
them with F(). For example :

    Serial.print(F(“Hello World”))
-------------------------------- schnapp -------------------------------

Das ist zwar jetzt das print() für serielle Schnittstellen, aber das 
Zeugs ist ja sowieso alles voneinander abgeleitet bzw. irgendwo vererbt.
#4021201
Lesenswert?

Das hier
1
byte ch_up[8] = {
2
  0b00100,
3
  0b01110,
4
  0b11111,
5
  0b00000,
6
  0b00000,
7
  0b00000,
8
  0b00000,
9
  0b00000
10
};
11
byte ch_down[8] = {
12
  0b00000,
13
  0b00000,
14
  0b00000,
15
  0b00000,
16
  0b00000,
17
  0b11111,
18
  0b01110,
19
  0b00100
20
};
21
byte ch_left[8] = {
22
  0b00000,
23
  0b00100,
24
  0b01100,
25
  0b11100,
26
  0b01100,
27
  0b00100,
28
  0b00000,
29
  0b00000
30
};
31
byte ch_right[8] = {
32
  0b00000,
33
  0b00100,
34
  0b00110,
35
  0b00111,
36
  0b00110,
37
  0b00100,
38
  0b00000,
39
  0b00000
40
};
41
byte ch_enter[8] = {
42
  0b00001,
43
  0b00001,
44
  0b00001,
45
  0b10010,
46
  0b11100,
47
  0b11100,
48
  0b11110,
49
  0b00000
50
};
51
byte ch_logo[8] = {
52
  0b00000,
53
  0b10110,
54
  0b10101,
55
  0b01101,
56
  0b00000,
57
  0b00111,
58
  0b00100,
59
  0b11111
60
};
61
byte ch_tiny1[8] = {
62
  0b10110,
63
  0b00000,
64
  0b01000,
65
  0b11110,
66
  0b01000,
67
  0b00000,
68
  0b00000,
69
  0b00000
70
};
71
byte ch_tiny2[8] = {
72
  0b00000,
73
  0b00111,
74
  0b00010,
75
  0b00110,
76
  0b00000,
77
  0b00110,
78
  0b00100,
79
  0b00110
80
};

kann auch alles im Flash bleiben.
Bei verfügbaren 512 Bytes kannst du dir 64 Bytes Verschwendung nicht 
einfach so erlauben.
Gast #4021209
Lesenswert?

Helge Schick schrieb:
> Man muss Textkonstanten explizit in den Flash schreiben, dann geht es.
>
> Frage gelöst ...

Das wird das Problem lediglich verschoben haben, nur wenn das der 
fertige Code ist, dann wäre die Sache erledigt.

Der ATiny85 besitzt 512 Byte SRam, das Programm sieht nicht nach 100 
genutzten Bytes SRam aus, keine rekursiven Funktionen, keine Arrays 
usw., da bleibt jede Menge für den Stack über.

Wenn so kurzer Code dabei versagt, liegt der tatsächliche Fehler 
woanders.
Moderator Persönliche Seite #4021210
Lesenswert?

Cyblord ---- schrieb:
> Wenn man mit einer Umgebung arbeiten würde, die den statischen SRAM
> Verbrauch direkt anzeigt, dann hätte man das sofort gesehen. Aber man
> will es sich ja schwer machen.

Das ist natürlich das Totschlagargument gegen Arduino! ;-)

Nicht schlecht, zu welchen Strohhalmen Du manchmal greifst, um mit 
diesen dann um Dich zu werfen, wenn all Deine Argumente vorher 
entkräftet werden.

Ich teile ja Deine Meinung zu Arduino. Aber diese übermäßige Schimpferei 
ist kontraproduktiv. Leben und leben lassen.
Persönliche Seite #4021213
Lesenswert?

Cyblord ---- schrieb:
> Moby AVR schrieb im Beitrag #4021145:
>> Prinzipiell und wenn man seinen Code 100%ig selbst unter Kontrolle hat
>> natürlich nicht. Bei Hochsprachenverwendung ist dann aber doch
>
> Weil Hochsprachen in Mobys kranker troll Phantasie gerne mal
> kilobyteweise Ram belegen, einfach so. Spontan. Kannste nix dagegen
> machen. Hilft nur Assembler. iss so.

Nicht kilobyteweise. Aber bei kleinen AVRs (Tiny85 haben gerade 0,5K 
SRAM) können auch schon mal wenige dutzend Bytes zuviel sein. Zum 
Beispiel durch unnützes Push/Pop... iss so ;-)
#4021221
Lesenswert?

Frank M. schrieb:
> Nicht schlecht, zu welchen Strohhalmen Du manchmal greifst, um mit
> diesen dann um Dich zu werfen, wenn all Deine Argumente vorher
> entkräftet werden ;-)
Was wird denn da entkräftet? Wie MWS richtig bemerkt, das Problem ist ja 
nicht gelöst.
Der dynmische Teil mit Stack und Rekursionen ist bei knappem RAM nochmal 
eine Aufgabe für sich. Und mit Arduino nicht zu handeln. Da hilft nur 
unmengen am RAM, Augen zu und durch.
Wenn aber noch nichtmal einen Überblick über den einfachen statischen 
RAM Verbrauch hat, wie soll man da bitte was vernünftiges zustane 
bringen?
>
> Ich teile ja Deine Meinung zu Arduino. Aber diese übermäßige Schimpferei
> ist kontraproduktiv. Leben und leben lassen.
Nur sieht man hier schön deutlich wo das Problem mit Arduino liegt. Null 
Übersicht, null Kontrolle.
OP #4021247
Lesenswert?

Hallo Karl Heinz,
hier nochmal der Code in
, aber ist nur ein Teil ...
1
#include <TinyWireM.h>
2
#include <LiquidCrystal_I2C.h>
3

4

5
LiquidCrystal_I2C lcd(0x23,16,2);
6

7
byte myStat;
8
byte myByte;
9

10
byte ch_up[8] = {
11
  0b00100,
12
  0b01110,
13
  0b11111,
14
  0b00000,
15
  0b00000,
16
  0b00000,
17
  0b00000,
18
  0b00000
19
};
20
byte ch_down[8] = {
21
  0b00000,
22
  0b00000,
23
  0b00000,
24
  0b00000,
25
  0b00000,
26
  0b11111,
27
  0b01110,
28
  0b00100
29
};
30
byte ch_left[8] = {
31
  0b00000,
32
  0b00100,
33
  0b01100,
34
  0b11100,
35
  0b01100,
36
  0b00100,
37
  0b00000,
38
  0b00000
39
};
40
byte ch_right[8] = {
41
  0b00000,
42
  0b00100,
43
  0b00110,
44
  0b00111,
45
  0b00110,
46
  0b00100,
47
  0b00000,
48
  0b00000
49
};
50
byte ch_enter[8] = {
51
  0b00001,
52
  0b00001,
53
  0b00001,
54
  0b10010,
55
  0b11100,
56
  0b11100,
57
  0b11110,
58
  0b00000
59
};
60
byte ch_logo[8] = {
61
  0b00000,
62
  0b10110,
63
  0b10101,
64
  0b01101,
65
  0b00000,
66
  0b00111,
67
  0b00100,
68
  0b11111
69
};
70
byte ch_tiny1[8] = {
71
  0b10110,
72
  0b00000,
73
  0b01000,
74
  0b11110,
75
  0b01000,
76
  0b00000,
77
  0b00000,
78
  0b00000
79
};
80
byte ch_tiny2[8] = {
81
  0b00000,
82
  0b00111,
83
  0b00010,
84
  0b00110,
85
  0b00000,
86
  0b00110,
87
  0b00100,
88
  0b00110
89
};
90

91
// Buttons & PCF8574 0x20
92
byte PCF0_ADDR = 0x20;
93
byte    b_left = 0b10000000;    // 128
94
byte   b_right = 0b01000000;    //  64
95
byte      b_up = 0b00100000;    //  32
96
byte    b_down = 0b00010000;    //  16
97
byte   b_enter = 0b00000001;    //   1
98

99
// Characters
100
byte   c_enter = 0;
101
byte   c_tiny1 = 1;
102
byte   c_tiny2 = 2;
103
byte    c_logo = 3;
104
byte    c_down = 4;
105
byte      c_up = 5;
106
byte   c_right = 6;
107
byte    c_left = 7;
108

109
void setup(){
110
        // µC related
111
  //noInterrupts();
112
  //CLKPR = 0x80;    // run at
113
  //CLKPR = 0x00;    // 8MHz internal Osc.
114
  //interrupts();
115

116
  // LCD_I²C related
117
  lcd.init();
118

119
  // custom characters prog.
120
        lcd.setCursor(0,0);
121
        lcd.print(F("setting up ...  "));
122
  lcd.createChar(0, ch_enter);
123
  lcd.createChar(1, ch_tiny1);
124
  lcd.createChar(2, ch_tiny2);
125
  lcd.createChar(3, ch_logo);
126
  lcd.createChar(4, ch_down);
127
  lcd.createChar(5, ch_up);
128
  lcd.createChar(6, ch_right);
129
  lcd.createChar(7, ch_left);
130
        waitkey(b_enter);
131
        
132
        // check I/O Expanders
133
        lcd.clear();
134
  lcd.setCursor(0,0);
135
        lcd.print(F("PCF8574 @:      "));
136
  lcd.setCursor(0,1);
137
  for(int i = 32; i < 40; i++){
138
              myStat =  TinyWireM.requestFrom(i, 0);
139
          if(myStat == 0){
140
                lcd.print(F("0x2")); //delay(100);
141
                lcd.print(i-32);  //delay(100);
142
                lcd.print(F(" "));   //delay(100);
143
                }
144
        }
145
        waitkey(b_enter);
146

147
        // ready message
148
//  ready();
149

150
    lcd.clear();
151
                lcd.setCursor(0,0);
152
                lcd.write(2);
153
                //         0123456789012345           
154
                lcd.print(F(" ready, press  "));
155
                lcd.setCursor(0,1);
156
    lcd.write(1);
157
                //         0123456789012345 
158
    lcd.print(F(" tinycomputer "));
159
                lcd.write(3);
160
    waitkey(b_enter);
161
    lcd.clear();
162

163
}
164

165
void loop(){
166

167
}
168

169
// get buttons from I²C port 0
170
void pcf0_get(){
171
        //delay(150);
172
        noInterrupts();
173
          myStat =  TinyWireM.requestFrom(0x20, 1);
174
          if(myStat != 0){error();}
175
          myByte = TinyWireM.receive();
176
        interrupts();
177
}
178
// wait4key
179
void waitkey(byte button){
180
        lcd.setCursor(15,0);
181
        if(button == b_enter){lcd.write(c_enter);}
182
        if(button == b_up   ){lcd.write(c_up   );}
183
        if(button == b_down ){lcd.write(c_down );}
184
        if(button == b_left ){lcd.write(c_left );}
185
        if(button == b_right){lcd.write(c_right);}
186
  pcf0_get();
187
  while((myByte & button) == button){pcf0_get();} // await press
188
        delay(50); pcf0_get();
189
        while((myByte & button) == 0){pcf0_get();}      // await release
190
}
191
// I²C errorhandling (2bcancelled4RAM)
192
void error(){                     // called when myStat != 0
193
  lcd.clear();
194
  lcd.setCursor(0,0);
195
  lcd.print("* IIC error:");
196
  lcd.setCursor(0,1);
197
  if(myStat == 1){lcd.print(F("no ACK 4 address"));}      // The slave did not acknowledge the address
198
  if(myStat == 2){lcd.print(F("no ACK 4 data   "));}      // The slave did not acknowledge all data
199
  if(myStat == 3){lcd.print(F("no START Cond.  "));}      // Generated Start Condition not detected on bus
200
  if(myStat == 4){lcd.print(F("no STOP Cond.   "));}      // Generated Stop Condition not detected on bus
201
  if(myStat == 5){lcd.print(F("arbitration     "));}      // Unexpected Data Collision (arbitration)
202
  if(myStat == 6){lcd.print(F("unexpected STOP "));}      // Unexpected Stop Condition
203
  if(myStat == 7){lcd.print(F("unexpected START"));}      // Unexpected Start Condition
204
  if(myStat == 8){lcd.print(F("TX buff. empty  "));}      // Transmission buffer is empty
205
  if(myStat == 9){lcd.print(F("TX buff. out RAM"));}      // Transmission buffer is outside SRAM space
206
  if(myStat ==10){lcd.print(F("no ext. RAM read"));}      // Error during external memory read
207
  waitkey(1);
208
}
209
// ready message
210
//void ready(){
211
//    lcd.clear();
212
//                lcd.setCursor(0,0);
213
//                lcd.write(2);
214
//                //         0123456789012345           
215
//                lcd.print(" ready, press  ");
216
//                lcd.setCursor(0,1);
217
//    lcd.write(1);
218
//                //         0123456789012345 
219
//    lcd.print(" tinycomputer ");
220
//                lcd.write(3);
221
//    waitkey(b_enter);
222
//    lcd.clear();
223
//}
Moderator Persönliche Seite #4021257
Lesenswert?

Helge Schick schrieb:
1
> byte ch_up[8] = {
2
> byte ch_down[8] = {
3
> byte ch_left[8] = {
4
> byte ch_right[8] = {
5
> byte ch_enter[8] = {
6
> byte ch_logo[8] = {
7
> byte ch_tiny1[8] = {
8
> byte ch_tiny2[8] = {

Auch diese Arrays könnte man mittels PROGMEM komplett im Flash belassen. 
Man müsste sie allerdings mit memcopy_P() vorher einzeln in ein im RAM 
befindliches befindliches Array kopieren, bevor man sie mit 
lcd.createChar() anwendet.

Spart weitere 8 * 8 = 64 Bytes im RAM - abzüglich des einen RAM-Arrays. 
Verbleiben also 56 Bytes Ersparnis.
Gast #4021276
Lesenswert?

Frank M. schrieb:
> Unsinn. Hast Du mal die Bytes seiner mehrere Dutzend vielen Strings
> zusammengezählt? Da kommen schon ein paar hundert Bytes zusammen.

Nun, da täuscht Du Dich ein ganz klein wenig.

Ein:
1
lcd.print(" ready, press ");

dürfte auch in Arduinisch keine extra Variable mit Inhalt " ready, press 
" dauerhaft im SRam anlegen. Da wird nur temporär SRam verwendet, um den 
String aus dem Flash für die Ausgabe in's SRam zu kopieren.

Die Anweisung F("...") dürfte also lediglich den Ausgabepuffer und auch 
das Umkopieren sparen, die Ausgaberoutine gibt dann direkt aus dem Flash 
wieder.
Das deckt sich mit dem hier, ganz unten:

http://forum.arduino.cc/index.php?topic=111131.0

Die "mehrere Dutzend vielen Strings" muss ich also nicht zusammenzählen, 
denn die finden sich nicht als selbstständige Variablen wieder.

Also nicht Unsinn ;-)
#4021280
Lesenswert?

Frank M. schrieb:
> Helge Schick schrieb:
>
1
>> byte ch_up[8] = {
2
>> byte ch_down[8] = {
3
>> byte ch_left[8] = {
4
>> byte ch_right[8] = {
5
>> byte ch_enter[8] = {
6
>> byte ch_logo[8] = {
7
>> byte ch_tiny1[8] = {
8
>> byte ch_tiny2[8] = {
9
>
>
> Auch diese Arrays könnte man mittels PROGMEM komplett im Flash belassen.
> Man müsste sie allerdings mit memcopy_P() vorher einzeln in ein im RAM
> befindliches befindliches Array kopieren, bevor man sie mit
> lcd.createChar() anwendet.

Hmm.
Verblüfft mich, dass es da am Arduino noch keine andere Lösung gibt.
Immerhin muss der COmpiler ja auch bei
1
  lcd.print(F("PCF8574 @:      "));
damit klar kommen, dass er einen Pointer auf einen String im Flash 
kriegt und die entsprechende print Methode raussuchen. Ergo muss es eine 
print Methode geben, die auf Pointer ins Flash 'reagiert'.
Moderator Persönliche Seite #4021281
Lesenswert?

MWS schrieb:
> Ein:
>
1
lcd.print(" ready, press ");
>
> dürfte auch in Arduinisch keine extra Variable mit Inhalt " ready, press
> " dauerhaft im SRam anlegen. Da wird nur temporär SRam verwendet, um den
> String aus dem Flash für die Ausgabe in's SRam zu kopieren.

Falsch. Alle Stringkonstanten werden von der StartUp-Routine ins RAM 
kopiert. Sowohl bei Arduino als auch bei nackter Verwendung der 
avr-libc.

Das hat auch nichts mit Arduino, sondern mit der Harvard-Struktur der 
AVRs zu tun.
Moderator Persönliche Seite #4021287
Lesenswert?

Karl Heinz schrieb:
> Verblüfft mich, dass es da am Arduino noch keine andere Lösung gibt.
> Immerhin muss der COmpiler ja auch bei
>
1
>   lcd.print(F("PCF8574 @:      "));
2
>
> damit klar kommen, dass er einen Pointer auf einen String im Flash
> kriegt und die entsprechende print Methode raussuchen. Ergo muss es eine
> print Methode geben, die auf Pointer ins Flash 'reagiert'.

Ja, das scheint eine simple Überladung von print() zu sein.
#4021288
Lesenswert?

Karl Heinz schrieb:

> Verblüfft mich, dass es da am Arduino noch keine andere Lösung gibt.
> Immerhin muss der COmpiler ja auch bei
>
1
>   lcd.print(F("PCF8574 @:      "));
2
>
> damit klar kommen, dass er einen Pointer auf einen String im Flash
> kriegt und die entsprechende print Methode raussuchen. Ergo muss es eine
> print Methode geben, die auf Pointer ins Flash 'reagiert'.

Ahhh.
Die benutzen eine Zwischenklasse _FlashStringHelper um die korrekte 
Methode anzusprechen. Ja, dann ist es klar wie das funktioniert.
Das F Makro legt den String mittels PSTR in den Flash und castet den 
Pointer um auf einen _FlashStringHelper Pointer. Und dafür gibt es eine 
print Methode.

Wenns für createChar keine entsprechende Methode gibt (und das bezweifle 
ich mal), dann gehts momentan nur mit dem pgm_xxxx Funktionen.
Gast #4021302
Lesenswert?

@MWS
>dürfte auch in Arduinisch keine extra Variable mit Inhalt " ready, press

Wenn es wirklich einen entsprechenden Algorithmus gibt, müsste ja der 
Compiler einen Parser-Abschnitt enthalten, der nach dem Motto: "Wer hat 
den Längsten" den Source-Code durchforstet, um dann, anhand dieses 
Wertes, einen Speicherbereich vor dem Benutzer zu "verstecken".

Kann ich mir, auch wegen der vielen Nebeneffekte nicht vorstellen.

Zwei einfache Gleichungen bleiben aber erhalten:
1. Dein Code (+) die Bibliotheken (=) viel mehr Code.
2. Dein RAM  (+) die Bibliotheken (=) viel mehr RAM.
Moderator Persönliche Seite #4021326
Lesenswert?

MWS schrieb:
> Nun, da täuscht Du Dich ein ganz klein wenig.
>
> Ein:
>
1
lcd.print(" ready, press ");
>
> dürfte auch in Arduinisch keine extra Variable mit Inhalt " ready, press
> " dauerhaft im SRam anlegen. Da wird nur temporär SRam verwendet, um den
> String aus dem Flash für die Ausgabe in's SRam zu kopieren.

Hier der Beweis, dass alle Stringkonstanten schon beim Boot im RAM 
landen:
1
#include <avr/io.h>
2

3
// dieses print() ist ein disfunktionales Fake, dient nur dazu, dass der Compiler nichts wegoptimieren kann
4
void print (char * s)
5
{
6
    while (*s)
7
    {
8
        PORTB = *s++;
9
    }
10
}
11

12
int main (void)
13
{
14
    while (1)
15
    {
16
        print ("Hello");
17
        print ("World");
18
    }
19
}

Übersetzt mit avr-gcc und avr-libc:

Program:     198 bytes (1.2% Full)
(.text + .data + .bootloader)

Data:         12 bytes (1.2% Full)
(.data + .bss + .noinit)

Und hier ein Auszug der lss-Datei dazu:
1
00000074 <__do_copy_data>:
2
  74:  11 e0         ldi  r17, 0x01  ; 1
3
  76:  a0 e0         ldi  r26, 0x00  ; 0
4
  78:  b1 e0         ldi  r27, 0x01  ; 1
5
  7a:  ea eb         ldi  r30, 0xBA  ; 186
6
  7c:  f0 e0         ldi  r31, 0x00  ; 0
7
  7e:  02 c0         rjmp  .+4        ; 0x84 <__do_copy_data+0x10>
8
  80:  05 90         lpm  r0, Z+
9
  82:  0d 92         st  X+, r0
10
  84:  ac 30         cpi  r26, 0x0C  ; 12
11
  86:  b1 07         cpc  r27, r17
12
  88:  d9 f7         brne  .-10       ; 0x80 <__do_copy_data+0xc>
13
  8a:  0e 94 4b 00   call  0x96  ; 0x96 <main>
14
  8e:  0c 94 5b 00   jmp  0xb6  ; 0xb6 <_exit>

Bevor die main-Funktion angesprungen wird, werden 12 Bytes ins RAM 
kopiert. Dreimal darfst Du raten, woher die 12 Bytes kommen und was 
passiert, wenn ich eine weitere (abweichende) Stringkonstante hinzufüge.

P.S.
Strings, die den gleichen Inhalt haben, werden übrigens vom gcc auf 
eine Stringkonstante reduziert. Wenn Du also 28 mal hintereinander 
schreibst:

    print ("Hello");
    ...
    print ("Hello");

werden im RAM trotzdem nur 6 Bytes benutzt. Sobald die Stringkonstanten 
abweichen, greift diese Optimierung natürlich nicht mehr.
Gast #4021679
Lesenswert?

Peter II schrieb:

> Es gibt keine wirklichen Zusammenhang zwischen Flash und Ram verbrauch.
> Man kann 8kb Flash nutzen und nur 10byte Ram, oder auch 10byte Flash und
> 8kb RAM.

Natürlich gibt es keinen mathematisch im Sinne eine Funktion faßbaren 
Zusammenhang.

Aber es gibt sehr wohl einen statistisch überaus signifikanten 
tendenziellen Zusammenhang zwischen Codegröße und RAM-Nutzung und dies 
quer über alle Programmiersprachen und CPU/µC-Architekturen.

Was meinst du wohl, wo z.B. der über alle AVR-Baureihen zu beobachtende 
Fakt herkommt, dass bei Teilen mit größerem Flash i.d.R. auch mehr RAM 
zur Verfügung gestellt wird. Das ist nichts anderes als die Konsequenz, 
die die Atmel-Entwickler und Marketingstrategen aus diesem allgemeinen 
statistisch gesicherten Zusammenhang gezogen haben.

Von diesem allgemeinen Zusdammenhang mal abgesehen: Der Füllgrad des 
Flash an sich kann keine Probleme hervorrufen, wie sie der OP beobachtet 
hat, das kann nur stärkere RAM-Nutzung durch den zusätzlichen Code.

Oder natürlich ein Fehler im hinzugefügten Code, das wäre genauso 
möglich.
Gast #4021751
Lesenswert?

Frank M. schrieb:
> Und hier ein Auszug der lss-Datei dazu:

Hab's mir selbst kompiliert, simuliert, bzw. das erzeugte ASM angesehen, 
schönes Glump ;D (Ohne jetzt hier einen Flamewar lostreten zu wollen)

Frank M. schrieb:
> Das hat auch nichts mit Arduino, sondern mit der Harvard-Struktur der
> AVRs zu tun.

Es mag schon sein, dass die Beachtung der Architektur und strikte C'sche 
Logik zu solchen Kapriolen führt, aber bezogen auf einen 8-Bit AVR ist 
das völliger Krampf.

Auf eine Stringkonstante wie "Hello" kann über Zeiger auf den Flash 
genauso zugegriffen werden, wie es über's SRam geschieht.

Auch ist der String konstant, eine Veränderung ist weder zulässig noch 
möglich und damit ist dieses Verhalten doch eher peinlich. Hab' mir 
solch dieses Verhalten des gcc tatsächlich nicht vorstellen können, aber 
wieder etwas dazugelernt, danke dafür.
#4021782
Lesenswert?

@MWS (Gast)

>Auf eine Stringkonstante wie "Hello" kann über Zeiger auf den Flash
>genauso zugegriffen werden, wie es über's SRam geschieht.

Falsch! Dazu braucht der AVR  verschiedene Befehle! Ein lds ist kein 
lpm!

ALLERDINGs kann man mittlerweile das so "hintricksen", dass man sowohl 
Flash-Konstanten und RAM Variablen über ein und die selbe Funktion 
verarbeitet werden. Das könnte man auch in den Arduion einbauen.

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Flash_mit_flash_und_Embedded-C

Abschnitt Jenseits von __flash, man muss die Daten mit __memx 
platzieren.
#4021786
Lesenswert?

MWS schrieb:
> Auf eine Stringkonstante wie "Hello" kann über Zeiger auf den Flash
> genauso zugegriffen werden, wie es über's SRam geschieht.

Nein. Lies mal http://www.atmel.com/images/doc0856.pdf. Der Zugriff auf 
SRAM (Data space) und der Zugriff auf Flash (Program memory) 
unterscheiden sich auf Assembler-Ebene.

Der gcc-Compiler bildet das über progmem und die pgm_xxx-Routinen ab. 
Siehe http://www.nongnu.org/avr-libc/user-manual/pgmspace.html.

LG, Sebastian
#4021820
Lesenswert?

Hallo Helge,

Helge Schick schrieb:
> die Meldung
>      Binäre Sketchgröße: 3.368 Bytes (von einem Maximum von 8.192 Bytes)
> stammt aus der Arduino IDE nach dem upload.

Das ist nur der Flash-Speicherverbrauch. Es ist ein Ärgernis, dass die 
Arduino-IDE nicht auch den statischen SRAM-Speicherverbrauch listet.

Aber der lässt sich wie folgt ermitteln: In der Arduino-IDE unter 
Datei->Einstellungen ist unten der Speicheort der preferences.txt 
angegeben. Kann man auch anklicken, öffnet den Speicherort. Nun die 
Arduino-IDE beenden, dann die preferences.txt öffnen, und dort die Zeile
1
build.verbose=true
einfügen. Speichern. Nun die Arduino-IDE wieder öffnen. Jetzt sollten 
alle avr-gcc,avr-g++, avr-ar, avr-objcopy etc. Befehle die die IDE 
absetzt, sowie deren Fehlerausgaben, angezeigt. Die letzte Zeile beim 
Verifizieren lautet zum Beispiel:
1
C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avr-objcopy -O ihex -R .eeprom C:\Users\SEBAST~1\AppData\Local\Temp\build8114256259554875073.tmp\porta_100khz.cpp.elf C:\Users\SEBAST~1\AppData\Local\Temp\build8114256259554875073.tmp\porta_100khz.cpp.hex

Jetzt ein Terminal öffnen, ins Verzeichnis 
C:\Users\SEBAST~1\AppData\Local\Temp\build8114256259554875073.tmp 
wechseln, und dort "C:\Program Files 
(x86)\Arduino\hardware\tools\avr\bin\avr-size" porta_100khz.cpp.elf 
eingeben.

Dann erhält man die Größen der .text, .data und .bss-Segmente. .data und 
.bss zusammen sind der statisch belegte SRAM-Speicher.

LG, Sebastian
OP #4021887
Lesenswert?

Hallo Sebastian,
habs noch nicht ausprobiert, klingt jedenfalls interessant. Für dieses 
Problem habe ich ein paar Codezeilen aus der adafruit Doku übernommen, 
die zeigen mir den noch vorhandenen Heap/Stack RAM auf dem Display an:
1
int freeSRAM() 
2
{
3
  extern int __heap_start, *__brkval; 
4
  int v; 
5
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
6
}

... und im tinycomputer etwa:
1
// ready message
2
void ready(){
3
    lcd.clear();
4
                lcd.setCursor(0,0);
5
                lcd.write(2);
6
                //         0123456789012345           
7
                lcd.print(F(" ready, press  "));
8
                lcd.setCursor(0,1);
9
    lcd.write(1);
10
                //         0123456789012345 
11
    lcd.print(F(" tinycomputer "));
12
                lcd.write(3);
13
    waitkey(b_enter);
14
    lcd.clear();
15
                lcd.setCursor(0,0);
16
                lcd.print(F("* SRAM avail.: "));
17
                lcd.setCursor(0,1);
18
                lcd.print(F("  "));
19
                lcd.print(freeSRAM());
20
                lcd.print(F(" bytes"));
21
                waitkey(b_enter);
22
}

Übrigens hat der Tip von Frank wirklich Abhilfe geschaffen, der SRAM ist 
mit dem F-Macro wie geputzt und wird kaum noch in Anspruch genommen. Nur 
die Arrays bekomme ich nach PROGMEM noch nicht wieder ausgelesen. Meine 
eigenen Character bleiben verschollen ...
Und über die Fragmentierung des Heap mache ich mir gerade einige 
Gedanken, da ist wohl noch Optimierung nötig!

Gruss, Helge
OP #4021902
Lesenswert?

Hallo Sebastian,

da bekomme ich:

C:\DOKUME~1\Helge\LOKALE~1\Temp\build5088002893342191290.tmp>(x86)\Ardui 
no\hardware\tools\avr\bin\avr-size"  _04_tiny_computer.cpp.elf
"\Arduino\hardware\tools\avr\bin\avr-size" _04_tiny_computer.cpp.elf" 
ist syntaktisch an dieser Stelle nicht verarbeitbar.

Gruss, Helge
Gast #4021906
Lesenswert?

> ALLERDINGs kann man mittlerweile das so "hintricksen", dass man sowohl
> Flash-Konstanten und RAM Variablen über ein und die selbe Funktion
> verarbeitet werden. Das könnte man auch in den Arduion einbauen.

Arduino ist doch C++, oder? Da gibt es leider _flash, usw. nicht.
#4021947
Lesenswert?

Helge Schick schrieb:
> C:\DOKUME~1\Helge\LOKALE~1\Temp\build5088002893342191290.tmp>

> (x86)\Arduino\hardware\tools\avr\bin\avr-size"  _04_tiny_computer.cpp.elf
> "\Arduino\hardware\tools\avr\bin\avr-size" _04_tiny_computer.cpp.elf"
> ist syntaktisch an dieser Stelle nicht verarbeitbar.

Da fehlt noch was an der Kommandozeile.

So sieht das bei mir als Beispiel aus:
1
C:\Users\SEBAST~1\AppData\Local\Temp\build8114256259554875073.tmp>"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avr-size.exe" porta_100khz.cpp.elf
2
   text    data     bss     dec     hex filename
3
   1024       0      13    1037     40d porta_100khz.cpp.elf

LG, Sebastian
#4021959
Lesenswert?

Helge Schick schrieb:
> Nur die Arrays bekomme ich nach PROGMEM noch nicht wieder ausgelesen. Meine
> eigenen Character bleiben verschollen ...

Das sollte so gehen:
1
byte ch_up[8] PROGMEM = {
2
  0b00100,
3
  0b01110,
4
  0b11111,
5
  0b00000,
6
  0b00000,
7
  0b00000,
8
  0b00000,
9
  0b00000
10
};
11
byte ch_down[8] PROGMEM = {
12
  0b00000,
13
  0b00000,
14
  0b00000,
15
  0b00000,
16
  0b00000,
17
  0b11111,
18
  0b01110,
19
  0b00100
20
};
21
...
22
  byte create[8];
23
  memcpy_P(create,ch_down,sizeof(create));
24
  lcd.createChar(4, create);
25
  memcpy_P(create,ch_up,sizeof(create));
26
  lcd.createChar(5, create);
27
  ...

LG, Sebastian
Gast #4022027
Lesenswert?

Falk Brunner schrieb:
> @MWS (Gast)
>
>>Auf eine Stringkonstante wie "Hello" kann über Zeiger auf den Flash
>>genauso zugegriffen werden, wie es über's SRam geschieht.
>
> Falsch! Dazu braucht der AVR  verschiedene Befehle! Ein lds ist kein
> lpm!

LOL, Du darfst schon voraussetzen, dass mir der Unterschied bekannt ist, 
die Betonung lag auf "Zeiger".

Dass aufgrund von irgendwelchen Kontinuitätsgründen von C dieser 
Superkrampf passiert, ist mir mittlerweile schon klar.

Dennoch, lass mal diese ganzen Zwänge von C beiseite, es wäre logisch, 
wenn konstante Strings, die sich im Flash befinden, auch aus diesem 
bedient werden und nicht das SRam sinnlos vollgemüllt wird.

Das ist etwas, das ich von einem modernen Compiler erwarte und deswegen 
war ich auch baff, als ich das Gegenteil erkennen musste.

Und wenn Du mir schon mit LDS und LPM kommst, dann muss ich Dir sagen, 
dass das Äquivalent zu LPM der Opcode LD und nicht LDS ist ;-)
#4022051
Lesenswert?

MWS schrieb:
> Das ist etwas, das ich von einem modernen Compiler erwarte und deswegen
> war ich auch baff, als ich das Gegenteil erkennen musste.

Wenn der Flash-Speicher nicht durch die Hardware auf SRAM-Adressen 
gemappt wird ist das gar nicht so einfach.

Ein Beispiel: Du speicherst die Adresse eines Flash-Strings in einer 
Variablen. Diese Variable (ein "Zeiger") muss dann aber einen anderen 
Typ haben als eine andere Variable, die eine Adresse im SRAM enthält. 
Aber welchen?

Dann brauchst du für die Stringprozeduren in der Standard-Bibliothek 
jeweils mehrere Versionen, solche mit normalen SRAM-Zeigerparametern, 
und solche mit Flash-Zeigerparametern.

Man kommt da vom Hölzchen aufs Stöckchen.

LG, Sebastian
Gast #4022084
Lesenswert?

Sebastian Wangnick schrieb:
> Wenn der Flash-Speicher nicht durch die Hardware auf SRAM-Adressen
> gemappt wird ist das gar nicht so einfach.
>
> Ein Beispiel: Du speicherst die Adresse eines Flash-Strings in einer
> Variablen. Diese Variable (ein "Zeiger") muss dann aber einen anderen
> Typ haben als eine andere Variable, die eine Adresse im SRAM enthält.

Es behauptet niemand, dass es einfach sein muss.

Dem Compiler ist der Typ, ob Variable oder Konstante zur Compilezit 
bekannt, der muss dann halt die Zugriffe in entsprechenden Routinen 
kapseln. Schafft er ja auch dann, wenn er mit Progmem dazu gezwungen 
wird.

Dieses Interface zum Flash über Progmem wirkt drangepfriemelt, dennoch 
wohl so notwendig, weil der Compiler offenbar aufgrund seiner Herkunft 
aus anderer Architektur, diejenige des 8-Bit AVR nur mit solchen Krücken 
verarbeiten kann. Und dann passiert solcher Unsinn, wie das SRam mit 
Konstanten aus dem Flash vollzukleistern.
#4022094
Lesenswert?

MWS schrieb:
> Dieses Interface zum Flash über Progmem wirkt drangepfriemelt, dennoch
> wohl so notwendig, weil der Compiler offenbar aufgrund seiner Herkunft
> aus anderer Architektur, diejenige des 8-Bit AVR nur mit solchen Krücken
> verarbeiten kann. Und dann passiert solcher Unsinn, wie das SRam mit
> Konstanten aus dem Flash vollzukleistern.

Deutlich eleganter wirken __flash und __memx, zeigen aber auch wo der 
Hase im Pfeffer liegt: AVRs haben hardwareseitig mehrere Adressräume. 
Das hat Folgen.

Entweder beschränkt man sich bei Datenadressierung auf jeweils einen 
davon. Dann kann man mit solchen Adressen/Pointern nur Daten in diesem 
Adressraum erreichen. Muss sich also entscheiden, ob der Pointer auf RAM 
zeigt (normal) und auf ROM (__flash). Eine Funktion, die eine 
RAM-Adresse erwartet, kann man dann nicht mit einer ROM-Adresse füttern. 
Und umgekehrt.

Oder man lässt das offen und verlangt, dass Pointer auf alles zeigen 
können (__memx). Dann aber findet jeder Zugriff über einen solchen 
Pointer in einer Laufzeitfunktion statt, in der erst der Adressbereich 
festgestellt werden muss. Das ist viel langsamer.

Dieses Problem ist ziemlich wenig von der Programmiersprache abhängig, 
solange es sich um eine kompilierte Sprache handelt. Es muss dazu auch 
keine expliziten Pointer in der Sprache geben, Referenz-Parameter 
reichen schon (Fortran).

Einen anderen - besseren - Weg ist Microchip bei den PIC24 gegangen. Die 
blenden in der oberen 32KB Hälfte des Datenadressraumes ROM aus dem 
Programmadressraum ein. Wodurch trotz formal getrennter Daten- und 
Programmadressräume genug Flash-ROM im Datenadressraum liegt, um die 
üblichen Strings dort lassen zu können.
#4022283
Lesenswert?

@ Bastler (Gast)

>> ALLERDINGs kann man mittlerweile das so "hintricksen", dass man sowohl
>> Flash-Konstanten und RAM Variablen über ein und die selbe Funktion
>> verarbeitet werden. Das könnte man auch in den Arduion einbauen.

>Arduino ist doch C++, oder?

Naja, ein Leichtgewicht C++.

> Da gibt es leider _flash, usw. nicht.

AFAIK schon, denn der Compiler unten drunter ist auch der avr gcc.
Gast #4022298
Lesenswert?

Der GCC läuft aber schon beim leichtesten Hauch von C++ mit eben diesem 
Parser und der, dazu gab es schon diverse Diskussionen, wird in 
absehbarer Zeit keine getrennten Adressräume unterstützen. Schade um 
_flash & co, aber so ist es eben.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren