Forum: Mikrocontroller und Digitale Elektronik Problem Inbetriebnahme OLED-Display DD-160128FC-2A (Densitron)


von Billy _. (slowflyer)


Angehängte Dateien:

Lesenswert?

Ich versuche gerade das (Densitron) DD-160128FC-2A in Betrieb zu nehmen 
und komme nicht weiter. Es will einfach nichts anzeigen. Das Display hat 
einen SEPS-525 Controller (http://www.farnell.com/datasheets/4146.pdf) 
und ich hab da so meine Zweifel ob ich alles richtig interpretiert habe.

Es ist folgendermaßen angeschlossen (an einen AVR32):

Pin 1  2   3    4   5      6     7 8   9  10
Fkt NC GND +14V GND 68K-PD |-10K-| +3V NC GND

PIN 11  12  13  14    15    16  17   18   19 bis 24
Fkt GND GND GND 1K-PD 1K-PD SCK MOSI MISO GND

PIN 25  26 27  28  29   30  31  32  33   34  35 bis 37
Fkt D/C CS GND GND nRes GND +3V GND +14V GND NC

Quelltext habe ich hinten dran gehängt (hab der Übersicht wegen alles 
Unnötige entfernt, vielleicht nicht ganz fehlerfrei).

Hat jemand Erfahrung mit dem SEPS und SPI Ansteuerung? Schaut mal über 
den Code, ob ich da generell irgendetwas missinterpretiert habe. Die SPI 
funktioniert soweit (sehe die Bytes übers Osci huschen).

Tips wären ganz nett...

von Billy _. (slowflyer)


Lesenswert?

OK, hab jetzt einen kleinen Satz im Datenblatt entdeckt: "*Note : When 
the SPI mode is selected, DB[15] pin must be unconnected.". Gesagt, 
getan.

Die Initialisierung bewirkt jetzt wenigstens, dass eine Zeile von oben 
nach unten langsam mit zufälligen Muster durchblinkt. Und das Display 
reagiert auf das Einschalt-Kommando (0x06, 0x01). Lass ich es weg, so 
bleibt das Display dunkel. Schicke ich irgendwelche Daten zum Display so 
ändert sich nichts und es blinkt weiter fröhlich vor sich hin. 
Irgendetwas ist an der Initialisierung noch nicht ok. Suche geht 
weiter...

von Billy _. (slowflyer)


Lesenswert?

Sorry, aber langsam treibt mich das Display in Richtung Wahnsinn.

Das Display hört auf Kommandos (ein/auschalten etc.). Ein chaotisches 
buntes Bild wird angezeigt. Aber ich schaffe es nicht zu löschen oder 
sonst irgendwie anders zu beschreiben.

Folgendermaßen gehe ich vor:

- Display initialisieren (ziemlich viele Varianten durchprobiert)
1
send(0x06,0x00); //aus
2
send(0x04,0x01); //REDUCE_CURRENT
3
send(0x02,0x41); //OSC
4
send(0x03,0x00); //CLK
5
send(0x80,0x00); //IREF
6
send(0x13,0x00); //DISPLAY_MODE_SET
7
send(0x14,0x10); //RGB_IF
8
send(0x16,0x66); //MEMORY_WRITE_MODE
9
send(0x17,0x00); //window
10
send(0x18,0x9F);
11
send(0x19,0x00);
12
send(0x1A,0x7F);
13
send(0x3B,0x00); //Scrsav aus
14
send(0x04,0x00); //REDUCE_CURRENT
15
send(0x06,0x01); //an

dann erscheint das zufällige Bild aufm Display

Dann versuche ich einfach mal das DDRAM zu ändern nur um zu sehen ob 
sich was tut (bisher ohne Erfolg).
1
send(0x17,0x00); //window
2
send(0x18,0x9F);
3
send(0x19,0x00);
4
send(0x1A,0x7F);
5
send(0x20,0x00); //memmory access pointer
6
send(0x21,0x00);
7
8
9
10
for (i = 0; i < 160*128; i++)
11
{
12
  //send_com(0x22); //variante mit DDRAM_DATA_ACCESS_PORT
13
  send_data(0xFFFF); // 16/2*8 Bit (weiss)
14
}

Und nichts passiert. Die Daten flitzen über die SPI (sehe ich im Scope).
1
send_data (unsigned short data) //2*8Bit
2
{
3
        select_display();
4
  gpio_set_gpio_pin(RS);
5
  spi_write(&AVR32_SPI0, data>>8);
6
  spi_ready(&AVR32_SPI0, CS_DISPLAY);
7
  unselect_display();
8
9
//variante 8bit mit cs zw. zwei byte
10
//variante 8bit ohne cs zw. zwei byte
11
//variante 1*16bit statt 2*8bit mit cs
12
//variante 1*16bit statt 2*8bit ohne cs
13
14
  select_display();
15
  spi_write(&AVR32_SPI0, data);
16
  spi_ready(&AVR32_SPI0, CS_DISPLAY);
17
  unselect_display();
18
}

Send_data hab schon zig Male geändert. 16Bit und 2*8Bit Daten mit 
CS-Flanke zw. den Bytes ohne CS. Mit vorangestellten Commando 0x22 und 
ohne. Varianten über Varianten. Ergebnis ist immer das gleiche: ich 
bekomme offensichtlich das DDRAM des Displays nicht mit Daten 
beschrieben. Auf Kommandos reagiert es, denn ich bekomme es per Commando 
ein und ausgeschaltet und die Oscillator-Frequenz lässt sich auch 
beinflussen. Nur mit dem RAM haut es nicht hin.

Hat jemand Erfahrung mit dem SEPS 525 Displaycontroller (Google gibt ein 
Beispiel her: http://www.omniboard.be/projects/kit2/, leider nur 
parallel).

Hat jemand Kritik, Ideen, Vorschläge? Hilfe ist sehr willkommen!!!

von sdz55 (Gast)


Lesenswert?

Schau mal da: tune-x.ch

von Ulrich P. (uprinz)


Lesenswert?

Ich habe das Display am EIR laufen und musste auch mit eingen zusammen 
geklaubten Code Fetzen aus dem Netz vorlieb nehmen, was die 
Initialisierung angeht. Allerdings nutze ich das Display im 9-Bit Modus 
am parallelen Datenbus. Die init kann ich mal raussuchen, denn das 
Display läuft bei mir.
War aber eine wilde Probiererei, da Densitron keine brauchbaren 
Init-Parameter für das Display im Datenblatt abgedruckt hat. Ein Überl, 
das bei immer mehr Display Herstellern einreißt. Selbst essentielle 
Informationen fehlen gerne schon mal oder man muss sie sich aus Glas und 
Controller Datenblatt selber zusammen rechnen. Überl, übel.

Gruß, Ulrich

von Billy _. (slowflyer)


Lesenswert?

Hab mich mal an Densitron direkt gewandt und c-code erhalten. Funzt auch 
soweit. Erste Analyse erbrachte: Software-SPI. Jetzt müsste ich nur 
rausfinden was nun anders ist (ja ja die liebe Zeit, die einem immer 
fehlt). Ich bin mir noch nicht sicher ob ich bei der SPI Variante 
bleibe, denn der Bildaufbau hängt direkt an der Übertragungsrate der 
SPI. Mal sehen ...

von Ulrich P. (uprinz)


Lesenswert?

Hi Willum,

kannst Du den Code mal mailen? Wäre nett. Ich habe mich gegen SPI 
entschieden, weil fast alle SPI-Displays nur das Schreiben, aber nicht 
das Lesen des Moduls unterstützen. Man kann dadurch sehr viel mehr 
Funktionalität bei sehr viel weniger Speicher Verbrauch erreichen. 
Allerdings ist der Pincount sehr hoch, jedenfalls für einen AVR. Aber 
selbst bei einem SAM7 wird es mit RAM und Pinnen eng, wenn man keine 
Variante mit Datenbus benutzt. Ist immer eine Frage was man will, was 
man kann und was übrig bleibt :)

Gruß, Ulrich

von Magnus A. (yeayeah)


Lesenswert?

Hi!

I am also trying to start up DD-160128FC-2A.. It still remains dark even 
tho I tried for over 100hours :((

Did anyone get the SPI interface working?

I'm using at91sam7s256 and the mosi (SDO) is unconnected.
The init code:
1
PIO_Clear(pinOledResetB);
2
Wait(3); //10ms
3
PIO_Set(pinOledResetB);
4
Wait(5); //50ms
5
Cmd_OLED(pSPI, 0x16, 0x66, pinOled_RS); //Set MEMORY_WRITE_MODE //16-bit
6
Cmd_OLED(pSPI, 0x02, 0x41, pinOled_RS); //Set OSC_CTL
7
Cmd_OLED(pSPI, 0x03, 0x00, pinOled_RS); //Set CLOCK_DIV
8
Cmd_OLED(pSPI, 0x13, 0x00, pinOled_RS); //Set DISPLAY_MODE_SET
9
Cmd_OLED(pSPI, 0x14, 0x11, pinOled_RS); //Set RGB_IF // MPU-Mode
10
Cmd_OLED(pSPI, 0x15, 0x00, pinOled_RS); //Set RGB_POL
11
Cmd_OLED(pSPI, 0x80, 0x00, pinOled_RS); //Set IREF
12
Cmd_OLED(pSPI, 0x04, 0x00, pinOled_RS);//Turn on display, normal
13
Cmd_OLED(pSPI, 0x06, 0x01, pinOled_RS); //Set DISP_ON

The Cmd_OLED function:
1
void Cmd_OLED(AT91S_SPI *pSPI, unsigned int index,
2
    unsigned int control, const Pin *pinOled_RS)
3
{
4
//Send  INDEX
5
while ((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
6
PIO_Clear(pinOled_RS);//Pull down RS
7
Wait(1); //wait 1ms
8
pSPI->SPI_TDR = (index & 0xFF) | SPI_PCS(1); //1==npcs
9
while ((pSPI->SPI_SR & AT91C_SPI_TDRE) == 0);
10
while ((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
11
PIO_Set(pinOled_RS);//Pull up RS
12
13
Wait(1); //wait 1ms
14
15
//Send CONTROL
16
while ((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0)
17
pSPI->SPI_TDR = (control & 0xFF) | SPI_PCS(1); //1==npcs
18
while ((pSPI->SPI_SR & AT91C_SPI_TDRE) == 0);
19
while ((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
20
21
Wait(1); //wait 1ms
22
}

The spi is configured this way:
1
unsigned int config = AT91C_SPI_MSTR | AT91C_SPI_PS_VARIABLE | AT91C_SPI_MODFDIS
2
   | (AT91C_SPI_PCS & (0xF << 16))
3
  | (AT91C_SPI_DLYBCS & (0x00 << 24));
4
  SPI_Configure(pSPI,config);
5
6
//CONFIGURE ACCELEROMETER
7
unsigned int configCSR0 = AT91C_SPI_CPOL |
8
  AT91C_SPI_BITS_16 |
9
    (AT91C_SPI_SCBR & (0x10 <<  8)) |
10
      (AT91C_SPI_DLYBS & (0x00 <<  16)) ;
11
SPI_ConfigureNPCS(pSPI,0,configCSR0);
12
13
//CONFIGURE OLED
14
unsigned int configCSR1 = AT91C_SPI_CPOL | //read data from SDI in rising edge and change spi on falling edge of SCL
15
    AT91C_SPI_BITS_8 |
16
      (AT91C_SPI_SCBR & (0x10 <<  8)) | // 16/48MHz (0x10/MCK) gives speed 3MHz, max allowed speed is 16MHz so 3MHz should be OK!
17
        (AT91C_SPI_DLYBS & (0x08 <<  16)) ; //Wait 166ns before scl goes low
18
SPI_ConfigureNPCS(pSPI,1,configCSR1);
19
20
//ENABLE SPI
21
SPI_Enable(pSPI);


Please help me out! I'm going nuts!

von Magnus A. (yeayeah)


Lesenswert?

Oh my god, it's working!

One tips: Keep the Chip Select be low between the transfers when writing 
to the RGB-values...

von Billy _. (slowflyer)


Angehängte Dateien:

Lesenswert?

Um mich selbst mal zu zitieren:

> Ich bin mir noch nicht sicher ob ich bei der SPI Variante
> bleibe, denn der Bildaufbau hängt direkt an der Übertragungsrate der
> SPI. Mal sehen ...

Meine SPI ist relativ schnell (24 MHz) aber ich bekomme den 
Displayinhalt nicht schnell genug reingeschaufelt. Also bleibt mir nur 
noch die Parallelvariante. Ich hab die Routinen angepasst, die Daten 
flitzen über den Bus und doch ich bekomme das Display mal wieder nicht 
zum Leben erweckt. Das ist zum Mäuse melken, kann denn mal nicht 
irgendetwas auf Anhieb gehen?

In einem anderen Forum hab ich gelesen, dass das Timing entscheidend 
ist, also hab ich großzügige Waits eingebaut, später kann man sie immer 
noch optimieren. Nützt nichts, das Display bleibt einfach dunkel.

Hab mal Auszüge aus meinem Code drangehängt mit der Bitte mal drüber zu 
schauen.

von Billy _. (slowflyer)


Lesenswert?

Entwarnung, geht :))). Kaum macht man es richtig ... Kaum sichtbare 
Lötbrücke argh!!!

von Sebastian L. (arakis)


Lesenswert?

Moin,
auch wenn es schon "etwas" länger her ist: Hier ist eine Dokumentation 
zum SEPS525 Treiber Chip:

https://docs.google.com/file/d/0B_A2gK_LY7Nyb2M0dElyWFZ0UFU/edit

Falls gewünscht, kann ich auch verschiedene Source Codes 
bereitstellen(C++ und C#), habe das Display nämlich im Einsatz.

Lieben Gruß,
Sebastian

von Thomas D. (blackworker)


Lesenswert?

Hi Sebastian,

wäre super wenn du ein paar Quellcodes (C++) posten könntest :)

Ich bekomm die Initialisierung hin (buntes Bild) aber ich kann einfach 
kein weißes Bild erzeugen.

Benutze 80er Modus 8-Bit parallel/tristate :/

Wäre superschön wenn jemand was handfestes Codemäßig hätte...

mfg
Thomas

von Sebastian L. (arakis)


Lesenswert?

Hallo Thomas,
ich habe deine Antwort leider erst jetzt gesehen. Meine Implementierung 
ist als open source auf Github:
https://github.com/Arakis/TamaniChess/blob/master/src/chess.application/lib.cs

Suche dort nach "public class TOLEDDisplay". Der Rest sollte ich selber 
erklären.

Hier ein Foto, wie ich es einsetze:
https://drive.google.com/#folders/0B_A2gK_LY7NyR0ttTGtDRTJfcDA
1
  public class TOLEDDisplay
2
  {
3
4
5
    private const int _physical_width = 160;
6
    private const int _physical_height = 128;
7
8
    private int _row, _column, _rows, _columns, _tablength, _foreground, _background, _width, _height, _rotation;
9
    private bool _writing_pixels;
10
11
    private TOLEDDataBus bus;
12
13
    public TOLEDDisplay(TOLEDDataBus bus) {
14
      this.bus = bus;
15
16
      _row = 0;
17
      _column = 0;
18
      _width = _physical_width;
19
      _height = _physical_height;
20
      _rotation = 0;
21
      _columns = _width / 8;
22
      _rows = _height / 8;
23
      _tablength = 4;
24
      _writing_pixels = false;
25
      foreground(0x00FFFFFF);
26
      background(0x00000000);
27
      reset();
28
    }
29
30
    public void foreground(int v) {
31
      _foreground = v;
32
    }
33
34
    public void background(int v) {
35
      _background = v;
36
    }
37
38
    public void background(Color v) {
39
      _background = v.ToArgb();
40
    }
41
42
    public void orientation(int o) {
43
      _rotation = o & 3;
44
45
      //Set write direction
46
      command(0x16);
47
      switch (_rotation) {
48
        case 0:
49
        default:
50
          //HC=1, VC=1, HV=0
51
          data(0x76);
52
          _width = _physical_width;
53
          _height = _physical_height;
54
          break;
55
        case 1:
56
          //HC=0, VC=1, HV=1
57
          data(0x73);
58
          _width = _physical_height;
59
          _height = _physical_width;
60
          break;
61
        case 2:
62
          //HC=0, VC=0, HV=0
63
          data(0x70);
64
          _width = _physical_width;
65
          _height = _physical_height;
66
          break;
67
        case 3:
68
          //HC=1, VC=0, HV=1
69
          data(0x75);
70
          _width = _physical_height;
71
          _height = _physical_width;
72
          break;
73
      }
74
      _columns = _width / 8;
75
      _rows = _height / 8;
76
    }
77
78
    public void reset() {
79
      uint i = 0, j, k;
80
      uint[] init_commands = {
81
        0x06, // Display off
82
        0x00,
83
 
84
        //Osc control
85
        //Export1 internal clock and OSC operates with external resistor
86
        0x02,
87
        0x01,
88
 
89
        //Reduce current
90
        0x04,
91
        0x00,
92
 
93
        //Clock div ratio 1: freq setting 90Hz
94
        0x03,
95
        0x30,
96
 
97
        //Iref controlled by external resistor
98
        0x80,
99
        0x00,
100
 
101
        //Precharge time R
102
        0x08,
103
        0x01,
104
        //Precharge time G
105
        0x09,
106
        0x01,
107
        //Precharge time B
108
        0x0A,
109
        0x01,
110
 
111
        //Precharge current R
112
        0x0B,
113
        0x0A,
114
        //Precharge current G
115
        0x0C,
116
        0x0A,
117
        //Precharge current B
118
        0x0D,
119
        0x0A,
120
 
121
        //Driving current R = 82uA
122
        0x10,
123
        0x52,
124
        //Driving current G = 56uA
125
        0x11,
126
        0x38,
127
        //Driving current B = 58uA
128
        0x12,
129
        0x3A,
130
 
131
        //Display mode set
132
        //RGB,column=0-159, column data display=Normal display
133
        0x13,
134
        0x00,
135
 
136
        //External interface mode=MPU
137
        0x14,
138
        0x01,
139
 
140
        //Memory write mode
141
        //6 bits triple transfer, 262K support, Horizontal address counter is increased,
142
        //vertical address counter is increased. The data is continuously written
143
        //horizontally
144
        0x16,
145
        0x76,
146
 
147
        //Memory address setting range 0x17~0x19 to width x height
148
        0x17,  //Column start
149
        0x00,
150
        0x18,  //Column end
151
        _physical_width-1,
152
        0x19,  //row start
153
        0x00,
154
        0x1A,  //row end
155
        _physical_height-1,
156
 
157
        //Memory start address set to 0x20~0x21
158
        0x20,  //X
159
        0x00,
160
        0x21,  //Y
161
        0x00,
162
 
163
        //Duty
164
        0x29,
165
        0x00,
166
 
167
        //Display start line
168
        0x29,
169
        0x00,
170
 
171
        //DDRAM read address start point 0x2E~0x2F
172
        0x2E,  //X
173
        0x00,
174
        0x2F,  //Y
175
        0x00,
176
 
177
        //Display screen saver size 0x33~0x36
178
        0x33,  //Screen saver columns start
179
        0x00,
180
        0x34,  //Screen saver columns end
181
        _physical_width-1,
182
        0x35,  //screen saver row start
183
        0x00,
184
        0x36,  //Screen saver row end
185
        _physical_height-1,
186
 
187
        //Display ON
188
        0x06,
189
        0x01,
190
 
191
        //End of commands
192
        0xFF,
193
        0xFF
194
    };
195
196
      bus.reset();
197
      //_spi.format(8);
198
      //_spi.frequency(10000000);
199
200
      //Send initialization commands
201
      for (i = 0; ; i += 2) {
202
        j = init_commands[i];
203
        k = init_commands[i + 1];
204
        if ((j == 0xFF) && (k == 0xFF)) break;
205
206
        command(j);
207
        data(k);
208
      }
209
210
      //command(0x3b);
211
      //data(IOUtils.ToByteArray(new bool[] { true, true, true, true, true, true, true, true })[0]);
212
213
      //command(0x3c);
214
      //data(1);
215
216
      //command(0x3d);
217
      //data(255);
218
219
      //command(0x3e);
220
      //data(5);
221
222
      //command(0x3f);
223
      //data(5);
224
225
      //command(0x40);
226
      //data(5);
227
228
      //command(0x42);
229
      //data(255);
230
    }
231
232
    public void command(int value) {
233
      command((uint)value);
234
    }
235
236
    public void data(int value) {
237
      data((uint)value);
238
    }
239
240
    public void command(uint value) {
241
      _writing_pixels = (value == 0x22);
242
      bus.command(value);
243
    }
244
245
    public void data(uint value) {
246
      bus.data(value);
247
    }
248
249
    public void _window(ref int x, ref int y, ref int width, ref int height) {
250
      int x1, x2, y1, y2, start_x, start_y;
251
      switch (_rotation) {
252
        default:
253
        case 0:
254
          x1 = x;
255
          y1 = y;
256
          x2 = x + width - 1;
257
          y2 = y + height - 1;
258
          break;
259
        case 1:
260
          x1 = _physical_width - y - height;
261
          y1 = x;
262
          x2 = _physical_width - y - 1;
263
          y2 = x + width - 1;
264
          break;
265
        case 2:
266
          x1 = _physical_width - x - width;
267
          y1 = _physical_height - y - height;
268
          x2 = _physical_width - x - 1;
269
          y2 = _physical_height - y - 1;
270
          break;
271
        case 3:
272
          x1 = y;
273
          y1 = _physical_height - x - width;
274
          x2 = y + height - 1;
275
          y2 = _physical_height - x - 1;
276
277
          //x1 = y;
278
          //x2 = x1 + height;
279
280
          //y2 = _physical_height - x;
281
          //y1 = y2 - width;
282
283
          break;
284
      }
285
      //Limit values
286
      //if (x1 < 0) x1 = 0;
287
      //if (x1 >= _physical_width) x1 = _physical_width - 1;
288
      //if (x2 < 0) x2 = 0;
289
      //if (x2 >= _physical_width) x2 = _physical_width - 1;
290
      //if (y1 < 0) y1 = 0;
291
      //if (y1 >= _physical_height) y1 = _physical_height - 1;
292
      //if (y2 < 0) y2 = 0;
293
      //if (y2 >= _physical_height) y2 = _physical_height - 1;
294
295
296
      /*    if ((width > 100) || (height > 100))
297
          {
298
              pc1.printf("x=%d\ty=%d\twidth=%d\theight=%d\tx1=%d\tx2=%d\ty1=%d\ty2=%d\n",x,y,width,height,x1,x2,y1,y2);
299
          }
300
      */
301
302
      command(0x19);  // Y start
303
      data(y1);
304
      command(0x1A);  // Y end
305
      data(y2);
306
      command(0x17);  // X start
307
      data(x1);
308
      command(0x18);  // x end
309
      data(x2);
310
311
      switch (_rotation) {
312
        default:
313
        case 0:
314
          start_x = x1;
315
          start_y = y1;
316
          break;
317
        case 1:
318
          start_x = x1;
319
          start_y = y2;
320
          break;
321
        case 2:
322
          start_x = x2;
323
          start_y = y2;
324
          break;
325
        case 3:
326
          //start_x = x2;
327
          //start_y = y1;
328
329
          start_x = x1;
330
          start_y = y2;
331
332
          break;
333
      }
334
335
      command(0x20);  // memory accesspointer x
336
      data(start_x);
337
      command(0x21);  // memory accesspointer y
338
      data(start_y);
339
340
      //Console.WriteLine("x1:{0} x2:{1} y1:{2} y2:{3} w:{4} h:{5} sx:{6} sy:{7}", x1, x2, y1, y2, x2 - x1, y2 - y1, start_x, start_y);
341
    }
342
343
    //public int _x1, _x2, _y1, _y2, _start_x, _start_y;
344
345
    //public void debug() {
346
    //  while (true) {
347
    //    cls();
348
    //    fillDebug(2, 1, 20, 30, Color.Red.ToArgb());
349
    //    try {
350
    //      var line = Console.ReadLine();
351
    //      var ar = line.Split(new char[] { ' ' });
352
    //      var num = int.Parse(ar[1]);
353
    //      if (ar[0] == "x1") _x1 = num;
354
    //      if (ar[0] == "x2") _x2 = num;
355
    //      if (ar[0] == "y1") _y1 = num;
356
    //      if (ar[0] == "y2") _y2 = num;
357
    //      if (ar[0] == "sx") _start_x = num;
358
    //      if (ar[0] == "sy") _start_y = num;
359
    //    }
360
    //    catch { }
361
    //  }
362
    //}
363
364
    //public void fillDebug(int x, int y, int width, int height, int colour) {
365
    //  int r, g, b;
366
367
    //  _windowDebug(_x1, _x2, _y1, _y2, _start_x, _start_y);
368
    //  //Start "write data" command if not done already
369
    //  if (!_writing_pixels) {
370
    //    command(0x22);
371
    //  }
372
    //  r = (colour & 0xFF0000) >> 16;
373
    //  g = (colour & 0x00FF00) >> 8;
374
    //  b = colour & 0xFF;
375
376
    //  var n = width * height;
377
    //  while (--n >= 0) {
378
    //    bus.rgbdot(r, g, b);
379
    //  }
380
    //  //_window(0, 0, _width, _height);
381
    //}
382
383
    //public void _windowDebug(int x1, int x2, int y1, int y2, int start_x, int start_y) {
384
385
    //  command(0x19);  // Y start
386
    //  data(y1);
387
    //  command(0x1A);  // Y end
388
    //  data(y2);
389
    //  command(0x17);  // X start
390
    //  data(x1);
391
    //  command(0x18);  // x end
392
    //  data(x2);
393
394
    //  command(0x20);  // memory accesspointer x
395
    //  data(start_x);
396
    //  command(0x21);  // memory accesspointer y
397
    //  data(start_y);
398
399
    //  Console.WriteLine("x1:{0} x2:{1} y1:{2} y2:{3} w:{4} h:{5} sx:{6} sy:{7}", x1, x2, y1, y2, x2 - x1, y2 - y1, start_x, start_y);
400
    //}
401
402
    public void cls() {
403
      fill(0, 0, _width, _height, _background);
404
      _row = 0;
405
      _column = 0;
406
    }
407
408
    public void fill(int x, int y, int width, int height, int colour) {
409
      int r, g, b;
410
411
      _window(ref x, ref y, ref width, ref height);
412
      //Start "write data" command if not done already
413
      if (!_writing_pixels) {
414
        command(0x22);
415
      }
416
      r = (colour & 0xFF0000) >> 16;
417
      g = (colour & 0x00FF00) >> 8;
418
      b = colour & 0xFF;
419
420
      var n = width * height;
421
      while (--n >= 0) {
422
        bus.rgbdot(r, g, b);
423
      }
424
      var xx = 0; var yy = 0; var ww = _width; var hh = _height;
425
      _window(ref xx, ref yy, ref ww, ref hh);
426
    }
427
428
    public void drawImage(Bitmap bmp, Point target, Point source, Size size) {
429
      drawImage(bmp, target.X, target.Y, source.X, source.Y, size.Width, size.Height);
430
    }
431
432
    public void drawImage(Bitmap bmp, int targetX, int targetY, int sourceX, int sourceY, int sizeWidth, int sizeHeight) {
433
      _window(ref targetX, ref targetY, ref sizeWidth, ref sizeHeight);
434
435
      if (!_writing_pixels) {
436
        command(0x22);
437
      }
438
439
      for (var y = 0; y < sizeHeight; y++) {
440
        for (var x = 0; x < sizeWidth; x++) {
441
          var c = bmp.GetPixel(x + sourceX, y + sourceY);
442
          //c = Color.FromArgb((int)(255 / width * ix), (int)(255 / height * iy), 0);
443
          bus.rgbdot(c.R, c.G, c.B);
444
          //pixel(ix, iy, c.ToArgb());
445
        }
446
      }
447
448
    }
449
450
    public void drawImage(int[,] bmp, Point target, Point source, Size size) {
451
      drawImage(bmp, target.X, target.Y, source.X, source.Y, size.Width, size.Height);
452
    }
453
454
    public void drawImage(int[,] bmp, int targetX, int targetY, int sourceX, int sourceY, int sizeWidth, int sizeHeight) {
455
      _window(ref targetX, ref targetY, ref sizeWidth, ref sizeHeight);
456
457
      if (!_writing_pixels) {
458
        command(0x22);
459
      }
460
461
      for (var y = 0; y < sizeHeight; y++) {
462
        for (var x = 0; x < sizeWidth; x++) {
463
          var c = Color.FromArgb(bmp[x + sourceX, y + sourceY]);
464
          //c = Color.FromArgb((int)(255 / width * ix), (int)(255 / height * iy), 0);
465
          bus.rgbdot(c.R, c.G, c.B);
466
          //pixel(ix, iy, c.ToArgb());
467
        }
468
      }
469
470
    }
471
472
    public void pixel(int x, int y, int colour) {
473
      var sizeWidth = 1;
474
      var sizeHeight = 1;
475
      _window(ref x, ref y, ref sizeWidth, ref sizeHeight);
476
      _putp(colour);
477
    }
478
479
    private int static_colour_prev = 0xF000000, static_r = 0, static_g = 0, static_b = 0;
480
    private void _putp(int colour) {
481
482
      //Start "write data" command if not done already
483
      if (!_writing_pixels) {
484
        command(0x22);
485
      }
486
487
      //Only calculate rgb values if colour has changed
488
      if (static_colour_prev != colour) {
489
        static_r = (colour & 0xFF0000) >> 16;
490
        static_g = (colour & 0x00FF00) >> 8;
491
        static_b = colour & 0xFF;
492
        static_colour_prev = colour;
493
      }
494
495
      bus.rgbdot(static_r, static_g, static_b);
496
    }
497
498
    public int width {
499
      get {
500
        return _width;
501
      }
502
    }
503
504
    public int height {
505
      get {
506
        return _height;
507
      }
508
    }
509
510
511
  }

von Thomas D. (blackworker)


Lesenswert?

Perfekt, danke ;)

Mittlerweile hab ichs auch selbst einigermaßen hinbekommen, bin gerade 
an dem Stand mir eigene Zahlen zu malen, und eine Funktion zu schreiben, 
welche diese der Reihe nach ausgibt.

Wie ich sehe steuerst du das ganze mit dem Pi - Mich würde interessieren 
wie du das mit den Interrupts handlest. Ich bekomm fast schon Probleme 
wenn ich damit über den SMBus (100khz) kommunizieren möchte.

Schönes Projekt von dir!

von Sebastian L. (arakis)


Lesenswert?

Hallo Thomas,
ich nutze keine Interrupts. Ich lese "ständig" alle IO's ein (in einer 
loop).

Was die Geschwindigkeiten des Schreibens angeht, da gebe ich dir 
folgenden Rat: Kurze Leitungen!! So wenig Zwischenverdrahtungen wie nur 
möglich. Steckbrett meiden. Nutze so viele verschiedene GND-Leitungen 
vom Pi wie nur möglich, Stichwort Sternförmige Masseführung. Beachtest 
du das nicht, wirst du bei hohen Geschwindigkeiten mit 
Grafikfehlern/Abstürzen gestraft. Solltest du einen Levelshifter(5to2.8 
oder 3.3to2.8) verwenden, denke an die Entstör-Elkos! Vermeide 3.3V, 
weil es den IC zu warm werden lässt. Geh mit mit einem 3.9 Ohm 
Widerstand von 3.3 auf 2.8. Ein vollwertiger Spannungsteiler 
funktioniert nicht, weil das Display keine ohmsche Last ist. Oder ich 
war einfach nur zu dämlich.

Solltest du den rpi nutzen, und du brauchst "mehr speed": Nutze direkten 
Speicherzugriff. Sehe dir dazu die Klasse "public unsafe class 
TOLEDSPIFastDataBus : TOLEDDataBus" an. Dazu habe ich den Treiber etwas 
modifiziert, damit ich an die Speicheradresse rankomm. Findest du auch 
in meinem Github-Projekt. Ich nutze das native SPI vom RPI nicht. Hat 
irgendwie nicht geklappt. Keine Ahnung warum. SPI-Mode und so natürlich 
richig eingestelllt.

Welches OLED-Display nutzt du genau? Ich habe mich nun für das 
DD-160128FC-1A entschieden. Ist zwar kleiner, hat dafür aber 
brilliantere Farben und die Pixel sind sauberer. Das DD-160128FC-2B hat 
hässliche Subpixel, die Farben ließen sich aber vielleicht mit einem 
anderen Kontrast-Referenz-Widerstand ändern (also z.B. 30K statt 68k).

Noch was zum DD-160128FC-2B: Das scheint schwerer lieferbar zu sein, als 
das DD-160128FC-1A. Welche Displays gibt es eigentlich noch mit dem IC 
SEPS-525? Nur falls Densitron irgendwann nicht mehr liefert, ohne dass 
ich meine Platine völlig ändern muss. Aber für den Fall packe ich die 
Display-Logik auf eine separate Platine (Spannungsversorgung, 
Levelshifter, ON-OFF-Mechanismen, ...), damit ich im "Härtefall" nur die 
"kleine" Displayplatine auswechseln muss, ein wenig die Software, 
anstatt meine ganze Steuerplatine (für den Schachcomputer). Ich habe mir 
nämlich sagen lassen, dass OLED-Displays oftmals ganz schnell wieder vom 
Markt verschwinden (spezifische Modelle, versteht sich).

Mein Display läuft auf ca. 10-20Mhz (muss ich manchmal ändern, wenn ich 
Kabel "schlampig" verlege zu Testzwecken). Ein Bildaufbau ist schnell 
genaug um nicht zu sehen, dass er aufgebaut wird. Aber ich bau ja auch 
nur inkrepmentell auf (es werden nur die Änderungen Vorher/Nachher 
geschrieben). Für komplexe Grafikausgaben nutze ich schlicht die 
mächtige Grafikbibliothek von Mono.NET (System.Drawing), generiere 
daruas eine Bitmap und schreibe die Änderungen ans Display. Also ich 
schlage mich nicht mit einzelnen Zeichen rum ;)

Derzeit arbeite ich am Powerup/Powerdown Mechanismus (Auf 
Hardwareebene). Man soll ja nicht auf beides gleichzeitig Saft geben, 
wegen der Lebenserwartung. Da mein Produkt aber "haltbar" sein soll, 
beachte ich dies natürlich.

Lieben Gruß,
Sebastian

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.