www.mikrocontroller.net

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


Autor: Billy __ (slowflyer)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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...

Autor: Billy __ (slowflyer)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Billy __ (slowflyer)
Datum:

Bewertung
0 lesenswert
nicht 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)
send(0x06,0x00); //aus
send(0x04,0x01); //REDUCE_CURRENT
send(0x02,0x41); //OSC
send(0x03,0x00); //CLK
send(0x80,0x00); //IREF
send(0x13,0x00); //DISPLAY_MODE_SET
send(0x14,0x10); //RGB_IF
send(0x16,0x66); //MEMORY_WRITE_MODE
send(0x17,0x00); //window
send(0x18,0x9F);
send(0x19,0x00);
send(0x1A,0x7F);
send(0x3B,0x00); //Scrsav aus
send(0x04,0x00); //REDUCE_CURRENT
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).
send(0x17,0x00); //window
send(0x18,0x9F);
send(0x19,0x00);
send(0x1A,0x7F);
send(0x20,0x00); //memmory access pointer
send(0x21,0x00);



for (i = 0; i < 160*128; i++)
{
  //send_com(0x22); //variante mit DDRAM_DATA_ACCESS_PORT
  send_data(0xFFFF); // 16/2*8 Bit (weiss)
}

Und nichts passiert. Die Daten flitzen über die SPI (sehe ich im Scope).
send_data (unsigned short data) //2*8Bit
{
        select_display();
  gpio_set_gpio_pin(RS);
  spi_write(&AVR32_SPI0, data>>8);
  spi_ready(&AVR32_SPI0, CS_DISPLAY);
  unselect_display();

//variante 8bit mit cs zw. zwei byte
//variante 8bit ohne cs zw. zwei byte
//variante 1*16bit statt 2*8bit mit cs
//variante 1*16bit statt 2*8bit ohne cs

  select_display();
  spi_write(&AVR32_SPI0, data);
  spi_ready(&AVR32_SPI0, CS_DISPLAY);
  unselect_display();
}

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!!!

Autor: sdz55 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau mal da: tune-x.ch

Autor: Ulrich P. (uprinz)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Billy __ (slowflyer)
Datum:

Bewertung
0 lesenswert
nicht 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 ...

Autor: Ulrich P. (uprinz)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Magnus Andersson (yeayeah)
Datum:

Bewertung
0 lesenswert
nicht 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:
PIO_Clear(pinOledResetB);
Wait(3); //10ms
PIO_Set(pinOledResetB);
Wait(5); //50ms
Cmd_OLED(pSPI, 0x16, 0x66, pinOled_RS); //Set MEMORY_WRITE_MODE //16-bit
Cmd_OLED(pSPI, 0x02, 0x41, pinOled_RS); //Set OSC_CTL
Cmd_OLED(pSPI, 0x03, 0x00, pinOled_RS); //Set CLOCK_DIV
Cmd_OLED(pSPI, 0x13, 0x00, pinOled_RS); //Set DISPLAY_MODE_SET
Cmd_OLED(pSPI, 0x14, 0x11, pinOled_RS); //Set RGB_IF // MPU-Mode
Cmd_OLED(pSPI, 0x15, 0x00, pinOled_RS); //Set RGB_POL
Cmd_OLED(pSPI, 0x80, 0x00, pinOled_RS); //Set IREF
Cmd_OLED(pSPI, 0x04, 0x00, pinOled_RS);//Turn on display, normal
Cmd_OLED(pSPI, 0x06, 0x01, pinOled_RS); //Set DISP_ON

The Cmd_OLED function:
void Cmd_OLED(AT91S_SPI *pSPI, unsigned int index,
    unsigned int control, const Pin *pinOled_RS)
{
//Send  INDEX
while ((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
PIO_Clear(pinOled_RS);//Pull down RS
Wait(1); //wait 1ms
pSPI->SPI_TDR = (index & 0xFF) | SPI_PCS(1); //1==npcs
while ((pSPI->SPI_SR & AT91C_SPI_TDRE) == 0);
while ((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
PIO_Set(pinOled_RS);//Pull up RS

Wait(1); //wait 1ms

//Send CONTROL
while ((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0)
pSPI->SPI_TDR = (control & 0xFF) | SPI_PCS(1); //1==npcs
while ((pSPI->SPI_SR & AT91C_SPI_TDRE) == 0);
while ((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0);

Wait(1); //wait 1ms
}

The spi is configured this way:
unsigned int config = AT91C_SPI_MSTR | AT91C_SPI_PS_VARIABLE | AT91C_SPI_MODFDIS
   | (AT91C_SPI_PCS & (0xF << 16))
  | (AT91C_SPI_DLYBCS & (0x00 << 24));
  SPI_Configure(pSPI,config);

//CONFIGURE ACCELEROMETER
unsigned int configCSR0 = AT91C_SPI_CPOL |
  AT91C_SPI_BITS_16 |
    (AT91C_SPI_SCBR & (0x10 <<  8)) |
      (AT91C_SPI_DLYBS & (0x00 <<  16)) ;
SPI_ConfigureNPCS(pSPI,0,configCSR0);

//CONFIGURE OLED
unsigned int configCSR1 = AT91C_SPI_CPOL | //read data from SDI in rising edge and change spi on falling edge of SCL
    AT91C_SPI_BITS_8 |
      (AT91C_SPI_SCBR & (0x10 <<  8)) | // 16/48MHz (0x10/MCK) gives speed 3MHz, max allowed speed is 16MHz so 3MHz should be OK!
        (AT91C_SPI_DLYBS & (0x08 <<  16)) ; //Wait 166ns before scl goes low
SPI_ConfigureNPCS(pSPI,1,configCSR1);

//ENABLE SPI
SPI_Enable(pSPI);


Please help me out! I'm going nuts!

Autor: Magnus Andersson (yeayeah)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh my god, it's working!

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

Autor: Billy __ (slowflyer)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Billy __ (slowflyer)
Datum:

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

Autor: Sebastian Loncar (arakis)
Datum:

Bewertung
0 lesenswert
nicht 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_LY7Nyb2M0dE...

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

Lieben Gruß,
Sebastian

Autor: Thomas D. (blackworker)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sebastian Loncar (arakis)
Datum:

Bewertung
0 lesenswert
nicht 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/...

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_LY7NyR0t...
  public class TOLEDDisplay
  {


    private const int _physical_width = 160;
    private const int _physical_height = 128;

    private int _row, _column, _rows, _columns, _tablength, _foreground, _background, _width, _height, _rotation;
    private bool _writing_pixels;

    private TOLEDDataBus bus;

    public TOLEDDisplay(TOLEDDataBus bus) {
      this.bus = bus;

      _row = 0;
      _column = 0;
      _width = _physical_width;
      _height = _physical_height;
      _rotation = 0;
      _columns = _width / 8;
      _rows = _height / 8;
      _tablength = 4;
      _writing_pixels = false;
      foreground(0x00FFFFFF);
      background(0x00000000);
      reset();
    }

    public void foreground(int v) {
      _foreground = v;
    }

    public void background(int v) {
      _background = v;
    }

    public void background(Color v) {
      _background = v.ToArgb();
    }

    public void orientation(int o) {
      _rotation = o & 3;

      //Set write direction
      command(0x16);
      switch (_rotation) {
        case 0:
        default:
          //HC=1, VC=1, HV=0
          data(0x76);
          _width = _physical_width;
          _height = _physical_height;
          break;
        case 1:
          //HC=0, VC=1, HV=1
          data(0x73);
          _width = _physical_height;
          _height = _physical_width;
          break;
        case 2:
          //HC=0, VC=0, HV=0
          data(0x70);
          _width = _physical_width;
          _height = _physical_height;
          break;
        case 3:
          //HC=1, VC=0, HV=1
          data(0x75);
          _width = _physical_height;
          _height = _physical_width;
          break;
      }
      _columns = _width / 8;
      _rows = _height / 8;
    }

    public void reset() {
      uint i = 0, j, k;
      uint[] init_commands = {
        0x06, // Display off
        0x00,
 
        //Osc control
        //Export1 internal clock and OSC operates with external resistor
        0x02,
        0x01,
 
        //Reduce current
        0x04,
        0x00,
 
        //Clock div ratio 1: freq setting 90Hz
        0x03,
        0x30,
 
        //Iref controlled by external resistor
        0x80,
        0x00,
 
        //Precharge time R
        0x08,
        0x01,
        //Precharge time G
        0x09,
        0x01,
        //Precharge time B
        0x0A,
        0x01,
 
        //Precharge current R
        0x0B,
        0x0A,
        //Precharge current G
        0x0C,
        0x0A,
        //Precharge current B
        0x0D,
        0x0A,
 
        //Driving current R = 82uA
        0x10,
        0x52,
        //Driving current G = 56uA
        0x11,
        0x38,
        //Driving current B = 58uA
        0x12,
        0x3A,
 
        //Display mode set
        //RGB,column=0-159, column data display=Normal display
        0x13,
        0x00,
 
        //External interface mode=MPU
        0x14,
        0x01,
 
        //Memory write mode
        //6 bits triple transfer, 262K support, Horizontal address counter is increased,
        //vertical address counter is increased. The data is continuously written
        //horizontally
        0x16,
        0x76,
 
        //Memory address setting range 0x17~0x19 to width x height
        0x17,  //Column start
        0x00,
        0x18,  //Column end
        _physical_width-1,
        0x19,  //row start
        0x00,
        0x1A,  //row end
        _physical_height-1,
 
        //Memory start address set to 0x20~0x21
        0x20,  //X
        0x00,
        0x21,  //Y
        0x00,
 
        //Duty
        0x29,
        0x00,
 
        //Display start line
        0x29,
        0x00,
 
        //DDRAM read address start point 0x2E~0x2F
        0x2E,  //X
        0x00,
        0x2F,  //Y
        0x00,
 
        //Display screen saver size 0x33~0x36
        0x33,  //Screen saver columns start
        0x00,
        0x34,  //Screen saver columns end
        _physical_width-1,
        0x35,  //screen saver row start
        0x00,
        0x36,  //Screen saver row end
        _physical_height-1,
 
        //Display ON
        0x06,
        0x01,
 
        //End of commands
        0xFF,
        0xFF
    };

      bus.reset();
      //_spi.format(8);
      //_spi.frequency(10000000);

      //Send initialization commands
      for (i = 0; ; i += 2) {
        j = init_commands[i];
        k = init_commands[i + 1];
        if ((j == 0xFF) && (k == 0xFF)) break;

        command(j);
        data(k);
      }

      //command(0x3b);
      //data(IOUtils.ToByteArray(new bool[] { true, true, true, true, true, true, true, true })[0]);

      //command(0x3c);
      //data(1);

      //command(0x3d);
      //data(255);

      //command(0x3e);
      //data(5);

      //command(0x3f);
      //data(5);

      //command(0x40);
      //data(5);

      //command(0x42);
      //data(255);
    }

    public void command(int value) {
      command((uint)value);
    }

    public void data(int value) {
      data((uint)value);
    }

    public void command(uint value) {
      _writing_pixels = (value == 0x22);
      bus.command(value);
    }

    public void data(uint value) {
      bus.data(value);
    }

    public void _window(ref int x, ref int y, ref int width, ref int height) {
      int x1, x2, y1, y2, start_x, start_y;
      switch (_rotation) {
        default:
        case 0:
          x1 = x;
          y1 = y;
          x2 = x + width - 1;
          y2 = y + height - 1;
          break;
        case 1:
          x1 = _physical_width - y - height;
          y1 = x;
          x2 = _physical_width - y - 1;
          y2 = x + width - 1;
          break;
        case 2:
          x1 = _physical_width - x - width;
          y1 = _physical_height - y - height;
          x2 = _physical_width - x - 1;
          y2 = _physical_height - y - 1;
          break;
        case 3:
          x1 = y;
          y1 = _physical_height - x - width;
          x2 = y + height - 1;
          y2 = _physical_height - x - 1;

          //x1 = y;
          //x2 = x1 + height;

          //y2 = _physical_height - x;
          //y1 = y2 - width;

          break;
      }
      //Limit values
      //if (x1 < 0) x1 = 0;
      //if (x1 >= _physical_width) x1 = _physical_width - 1;
      //if (x2 < 0) x2 = 0;
      //if (x2 >= _physical_width) x2 = _physical_width - 1;
      //if (y1 < 0) y1 = 0;
      //if (y1 >= _physical_height) y1 = _physical_height - 1;
      //if (y2 < 0) y2 = 0;
      //if (y2 >= _physical_height) y2 = _physical_height - 1;


      /*    if ((width > 100) || (height > 100))
          {
              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);
          }
      */

      command(0x19);  // Y start
      data(y1);
      command(0x1A);  // Y end
      data(y2);
      command(0x17);  // X start
      data(x1);
      command(0x18);  // x end
      data(x2);

      switch (_rotation) {
        default:
        case 0:
          start_x = x1;
          start_y = y1;
          break;
        case 1:
          start_x = x1;
          start_y = y2;
          break;
        case 2:
          start_x = x2;
          start_y = y2;
          break;
        case 3:
          //start_x = x2;
          //start_y = y1;

          start_x = x1;
          start_y = y2;

          break;
      }

      command(0x20);  // memory accesspointer x
      data(start_x);
      command(0x21);  // memory accesspointer y
      data(start_y);

      //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);
    }

    //public int _x1, _x2, _y1, _y2, _start_x, _start_y;

    //public void debug() {
    //  while (true) {
    //    cls();
    //    fillDebug(2, 1, 20, 30, Color.Red.ToArgb());
    //    try {
    //      var line = Console.ReadLine();
    //      var ar = line.Split(new char[] { ' ' });
    //      var num = int.Parse(ar[1]);
    //      if (ar[0] == "x1") _x1 = num;
    //      if (ar[0] == "x2") _x2 = num;
    //      if (ar[0] == "y1") _y1 = num;
    //      if (ar[0] == "y2") _y2 = num;
    //      if (ar[0] == "sx") _start_x = num;
    //      if (ar[0] == "sy") _start_y = num;
    //    }
    //    catch { }
    //  }
    //}

    //public void fillDebug(int x, int y, int width, int height, int colour) {
    //  int r, g, b;

    //  _windowDebug(_x1, _x2, _y1, _y2, _start_x, _start_y);
    //  //Start "write data" command if not done already
    //  if (!_writing_pixels) {
    //    command(0x22);
    //  }
    //  r = (colour & 0xFF0000) >> 16;
    //  g = (colour & 0x00FF00) >> 8;
    //  b = colour & 0xFF;

    //  var n = width * height;
    //  while (--n >= 0) {
    //    bus.rgbdot(r, g, b);
    //  }
    //  //_window(0, 0, _width, _height);
    //}

    //public void _windowDebug(int x1, int x2, int y1, int y2, int start_x, int start_y) {

    //  command(0x19);  // Y start
    //  data(y1);
    //  command(0x1A);  // Y end
    //  data(y2);
    //  command(0x17);  // X start
    //  data(x1);
    //  command(0x18);  // x end
    //  data(x2);

    //  command(0x20);  // memory accesspointer x
    //  data(start_x);
    //  command(0x21);  // memory accesspointer y
    //  data(start_y);

    //  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);
    //}

    public void cls() {
      fill(0, 0, _width, _height, _background);
      _row = 0;
      _column = 0;
    }

    public void fill(int x, int y, int width, int height, int colour) {
      int r, g, b;

      _window(ref x, ref y, ref width, ref height);
      //Start "write data" command if not done already
      if (!_writing_pixels) {
        command(0x22);
      }
      r = (colour & 0xFF0000) >> 16;
      g = (colour & 0x00FF00) >> 8;
      b = colour & 0xFF;

      var n = width * height;
      while (--n >= 0) {
        bus.rgbdot(r, g, b);
      }
      var xx = 0; var yy = 0; var ww = _width; var hh = _height;
      _window(ref xx, ref yy, ref ww, ref hh);
    }

    public void drawImage(Bitmap bmp, Point target, Point source, Size size) {
      drawImage(bmp, target.X, target.Y, source.X, source.Y, size.Width, size.Height);
    }

    public void drawImage(Bitmap bmp, int targetX, int targetY, int sourceX, int sourceY, int sizeWidth, int sizeHeight) {
      _window(ref targetX, ref targetY, ref sizeWidth, ref sizeHeight);

      if (!_writing_pixels) {
        command(0x22);
      }

      for (var y = 0; y < sizeHeight; y++) {
        for (var x = 0; x < sizeWidth; x++) {
          var c = bmp.GetPixel(x + sourceX, y + sourceY);
          //c = Color.FromArgb((int)(255 / width * ix), (int)(255 / height * iy), 0);
          bus.rgbdot(c.R, c.G, c.B);
          //pixel(ix, iy, c.ToArgb());
        }
      }

    }

    public void drawImage(int[,] bmp, Point target, Point source, Size size) {
      drawImage(bmp, target.X, target.Y, source.X, source.Y, size.Width, size.Height);
    }

    public void drawImage(int[,] bmp, int targetX, int targetY, int sourceX, int sourceY, int sizeWidth, int sizeHeight) {
      _window(ref targetX, ref targetY, ref sizeWidth, ref sizeHeight);

      if (!_writing_pixels) {
        command(0x22);
      }

      for (var y = 0; y < sizeHeight; y++) {
        for (var x = 0; x < sizeWidth; x++) {
          var c = Color.FromArgb(bmp[x + sourceX, y + sourceY]);
          //c = Color.FromArgb((int)(255 / width * ix), (int)(255 / height * iy), 0);
          bus.rgbdot(c.R, c.G, c.B);
          //pixel(ix, iy, c.ToArgb());
        }
      }

    }

    public void pixel(int x, int y, int colour) {
      var sizeWidth = 1;
      var sizeHeight = 1;
      _window(ref x, ref y, ref sizeWidth, ref sizeHeight);
      _putp(colour);
    }

    private int static_colour_prev = 0xF000000, static_r = 0, static_g = 0, static_b = 0;
    private void _putp(int colour) {

      //Start "write data" command if not done already
      if (!_writing_pixels) {
        command(0x22);
      }

      //Only calculate rgb values if colour has changed
      if (static_colour_prev != colour) {
        static_r = (colour & 0xFF0000) >> 16;
        static_g = (colour & 0x00FF00) >> 8;
        static_b = colour & 0xFF;
        static_colour_prev = colour;
      }

      bus.rgbdot(static_r, static_g, static_b);
    }

    public int width {
      get {
        return _width;
      }
    }

    public int height {
      get {
        return _height;
      }
    }


  }

Autor: Thomas D. (blackworker)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Sebastian Loncar (arakis)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.