Forum: Mikrocontroller und Digitale Elektronik Bitmap auf TFT darstellen. Klappt, FAST!


von C. H. (hedie)


Angehängte Dateien:

Lesenswert?

Hallo zusammen

Ich versuche ein Bitmap, welches angehängt ist, auf meinem TFT 
darzustellen.

Eigentlich funktioniert dies auch. Aber eben nur fast.
Es gibt einen schmalen Rand welcher verschoben ist.

Diesen habe ich markiert.

Zudem ist das Bild nicht hoch genug.

Es handelt sich vermutlich um einen Denkfehler oder ähnliches.

Das Bitmap ist im 16bit RGB 565 Format
Also pro Pixel 2 bytes.

Das Bitmapt wird von einer SD-Karte geladen.
Zuerst wird der Dateiheader in ein Struct geladen (54 Bytes 
übersprungen)

Dannach immer zwei Bytes als Farbinformation ans Display gesendet.


Hat jemand eine Idee, was hier schief laufen könnte?

### EDIT: Das forum hat das original blumen2.bmp automatisch in ein png 
gewandelt...


Hier mein Code:
1
unsigned int ucBufferCounter = 0;
2
  unsigned int y1,x1;
3
4
  unsigned char ucBuffer[550];
5
  unsigned long temp = 0;
6
7
  long  p2;
8
  unsigned char res;
9
  unsigned short s1;
10
  FATFS fs;
11
12
  while(disk_initialize() != 0);
13
  set_max_speed();
14
  res = pf_mount(&fs);
15
  res = pf_open("blumen2.bmp");
16
  p2 = fs.fptr;
17
18
  if(res == 0)
19
  {
20
                //54 Bytes einlesen (den FileHeader)
21
    pf_read(ucBuffer,54,&s1);
22
23
    ColorTypeDef color;
24
25
                //Strukt beladen
26
    struct bmp_file_header *bmp_f_hdr;
27
    struct bmp_info_header *bmp_i_hdr;
28
    bmp_f_hdr = (struct bmp_file_header *)&ucBuffer[0];
29
    bmp_i_hdr = (struct bmp_info_header *)&ucBuffer[14];
30
31
    x1 = bmp_i_hdr->biWidth -1 + x;
32
    y1 = bmp_i_hdr->biHeight -1 + y;
33
34
               //Hier kann man auch anstelle von 300 und 180 x1 und y1 nehmen
35
    LCD_SetArea(x,y,300+x-1,180+y-1);
36
    LCD_WriteCommand(CMD_WR_MEMSTART);
37
38
    Clr_Cs;
39
40
                // erste 512 Bytes in den internen Buffer laden
41
    ucBufferCounter = 0;
42
    pf_read(ucBuffer,512,&s1);
43
44
    for (temp = 0; temp < (300*180); temp++)
45
    {
46
                       //sobald wir 256 * 2 bytes also 512 geladen haben
47
      if(ucBufferCounter == 256)
48
      {
49
        ucBufferCounter = 0;
50
        pf_read(ucBuffer,512,&s1);
51
      }
52
53
      color.U8[0] = ucBuffer[(ucBufferCounter * 2)];
54
      color.U8[1] = ucBuffer[1 + (ucBufferCounter * 2)];
55
56
      LCD_WriteData(color.U16);
57
      ucBufferCounter++;
58
    }
59
    Set_Cs;
60
  }

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Claudio Hediger schrieb:
> Ich versuche ein Bitmap, welches angehängt ist, auf meinem TFT
> darzustellen.
Womit auf welcher Hardware?

von holger (Gast)


Lesenswert?

>### EDIT: Das forum hat das original blumen2.bmp automatisch in ein png
>gewandelt...

Mach ein ZIP draus und häng es noch mal an.

von Rainer V. (rudi994)


Lesenswert?

Die Bildteile auf Foto.jpg sind je seitenverkehrt (vertikal gespiegelt). 
Bei umgekehrter Pixelfolge in jeweils beiden Abschnitten wäre das Bild 
fast richtig, es würde nur noch der obere Teil vom Bild fehlen.

von c-hater (Gast)


Lesenswert?

Claudio Hediger schrieb:

> Das Bitmap ist im 16bit RGB 565 Format
> Also pro Pixel 2 bytes.

Beides sollte beim Laden geprüft werden und nicht einfach als gegeben 
angenommen.

> Zuerst wird der Dateiheader in ein Struct geladen (54 Bytes
> übersprungen)

Auch das sollte geprüft werden. Weder ist sicher, daß die Datei 
überhaupt eine Bitmap ist, noch daß der Header 54Byte lang ist.

>     y1 = bmp_i_hdr->biHeight -1 + y;

Was soll das sein? biHeight kann auch mal negativ sein. Das sollte 
zumindest geprüft werden.

>                //Hier kann man auch anstelle von 300 und 180 x1 und y1
> nehmen

Dann tue das!

>   LCD_SetArea(x,y,300+x-1,180+y-1);

Bist du sicher, daß der Endpunkt angegeben werden muß und nicht etwa der 
Punkt danach oder die Breite?

>                 // erste 512 Bytes in den internen Buffer laden
>     ucBufferCounter = 0;
>     pf_read(ucBuffer,512,&s1);

Und wenn das Bild kleiner als 512 Bytes ist?

>     for (temp = 0; temp < (300*180); temp++)

Bei 300Pixel Breite und RGB565 könnte das tatsächlich klappen. Es wird 
aber definitiv nicht klappen, wenn die Zahl der Pixel/Zeile ungerade 
ist.
Zahl der Bytes/Zeile in der Datei berechnet sich 
((PixelsX*BitPerPixel)/32)*4.

>     {
>                        //sobald wir 256 * 2 bytes also 512 geladen haben
>       if(ucBufferCounter == 256)
>       {
>         ucBufferCounter = 0;
>         pf_read(ucBuffer,512,&s1);
>       }

Wieder das Problem. Was passiert bei EOF?

>       LCD_WriteData(color.U16);

Ich hoffe, daß der LCD-Treiber weniger fehlerbehaftet ist als dein Code 
und den Pitch korrekt handhabt...

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Produzier dir doch erstmal ein echtes RAW ohne Header und im Format, das 
es 'mundgerecht' für deine LCD Routine ist. Damit prüfst du die 
Geometrie und die LCD Routinen.
Wenn das alles funktioniert, verbessere deine BMP Routinen (wozu dieses 
Format auch immer gut sein mag) und mach sie flexibel gegenüber den 
Eigenschaften, die ein BMP haben kann.

von Claudio (Gast)


Lesenswert?

c-hater schrieb:
> Ich hoffe, daß der LCD-Treiber weniger fehlerbehaftet ist als dein Code
> und den Pitch korrekt handhabt...

Danke für deine tiefgehende Analyse meines codes.

Der derzeitige Stand ist nur für versuchszwecke.
Deshalb wird nicht geprüft, ob überhaupt ein bitmap geladen wurde 
etc....

Matthias Sch. schrieb:
> Produzier dir doch erstmal ein echtes RAW ohne Header und im Format, das
> es 'mundgerecht' für deine LCD Routine ist. Damit prüfst du die
> Geometrie und die LCD Routinen.

Das hat wunderbar geklappt mit dem selbern

LCD_SetArea(x0,y0,x1,y1);

Ich habe den code übernommen und schaufle nun die bytes einfach aus der 
SD-Karte.

Matthias Sch. schrieb:
> Wenn das alles funktioniert, verbessere deine BMP Routinen (wozu dieses
> Format auch immer gut sein mag) und mach sie flexibel gegenüber den
> Eigenschaften, die ein BMP haben kann.

Ich werde mich nun also nochmals eingehender damit beschäftigen :)
Danke für eure tipps

von c-hater (Gast)


Lesenswert?

c-hater schrieb:

> Zahl der Bytes/Zeile in der Datei berechnet sich
> ((PixelsX*BitPerPixel)/32)*4.

Das war natürlich Lötzinn, war wohl noch zu früh heut' morgen. Korrekt 
muß das natürlich so lauten:

((PixelsX*BitsPerPixel+31)/32)*4

Und ich habe auch noch vergessen, darauf hinzuweisen, daß die Bilddaten 
nicht nowendigerweise direkt nach dem Header beginnen müssen, es hilft 
also nichtmal, ein Pixelformat zu verwenden, welches implizit einen 
Header konstanter Größe produziert, wie es bei RGB565 tatsächlich der 
Fall ist. Siehe bmfh.bfOffBits.

Man kommt einfach nicht drumrum, diesen verschissenen Header (eigentlich 
sind es ja zwei) wirklich zu verstehen und die darin gebotenen Infos zu 
benutzen.

von c-hater (Gast)


Lesenswert?

Matthias Sch. schrieb:

> Wenn das alles funktioniert, verbessere deine BMP Routinen (wozu dieses
> Format auch immer gut sein mag)

Es ist ein sehr gutes Format, gerade für den Bereich µC. Denn es ist 
extrem flexibel betreffend der Pixelformate, die es beherbergen kann und 
es ist trotzdem sehr einfach gestrickt.

Nenne mir ein Format, welches ähnlich weit verbreitet ist, über ähnliche 
Flexibilität verfügt und gleichzeitig einen ähnlich geringem Footprint 
verursacht! Das wird dir verdammt schwer fallen...

von Rainer V. (rudi994)


Lesenswert?

c-hater schrieb:
> daß die Bilddaten
> nicht nowendigerweise direkt nach dem Header beginnen müssen

Wenn ich mich richtig erinnere, dann wird im BMP-Datei-Header neben der 
Dateigröße auch ein Byte-Offset für den Anfang der Pixeldaten angegeben. 
Der Offset sollte über die Datenstruktur des Headers zu finden sein.

von npn (Gast)


Lesenswert?

Rainer V. schrieb:
> c-hater schrieb:
>> daß die Bilddaten
>> nicht nowendigerweise direkt nach dem Header beginnen müssen
>
> Wenn ich mich richtig erinnere, dann wird im BMP-Datei-Header neben der
> Dateigröße auch ein Byte-Offset für den Anfang der Pixeldaten angegeben.
> Der Offset sollte über die Datenstruktur des Headers zu finden sein.

Deswegen hat sich c-hater ja hier in seiner unverwechselbaren Eloquenz 
zu dem Thema geäußert:
c-hater schrieb:
> Man kommt einfach nicht drumrum, diesen verschissenen Header (eigentlich
> sind es ja zwei) wirklich zu verstehen und die darin gebotenen Infos zu
> benutzen.

von Claudio (Gast)


Lesenswert?

Vielen Dank an euch alle...

Es läuft nun einwandfrei.

Ich werde es noch so gut wie möglich "failsafe" programmieren...

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.