Forum: Mikrocontroller und Digitale Elektronik Framebuffer im Raspberry Pi direkt ansprechen: so geht es


von Andreas W. (andy_w)


Lesenswert?

Hallo,
auf 
http://raspberrycompote.blogspot.de/2013/03/low-level-graphics-on-raspberry-pi-part.html 
ist erklärt, wie man den Framebuffer des HDMI-Ausgangs direkt ansprechen 
kann. Das ist bereits Teil 4, die anderen Teile sind vorbereitungen 
dazu. Leider ist das Beispiel nur für 8Bit/Pixel vorgesehen, ich habe es 
für 24Bit/Pixel angepaßt. Erstaunlicherweise hat es mit relativ wenig 
Ärger funktionmiert, immerhin hatte ich schon beim ersten Versuch erste, 
wenn auch noch fehlerhafte sichtbare Ergebnisse.

Hier der Code, es ist nur das main.c erforderlich. Das Beispiel ist 
natürlich rudimentär, es sollte für ein eigenes Projekt aufgehübscht 
werden und die Funktionen auch in andere Sourcefiles gepackt werden. 
Aber so sieht man erst einmal, wie es überhaupt funktioniert.

Die printf-Funktionen sind auskommentiert, da ich keinen seriellen 
Anschluß habe, sie sollten funktionieren, aber das habe ich nicht 
getestet.

Für mich bedeutet das, daß ich kein QT mit dem ganzen riesigen Overhead 
benutzen muß, ebenso auch kein C++, das für die Anwendung doch zu 
aufwendig wäre. Außerdem weiß ich nicht, ob die Hardwarefunktionen 
(Ports, SPI-Bus, IIC-Bus, PWM usw.) mit QT zusammen spielen.

So ist das nur ein normales C-Programm. Allerdings kann man nur Pixel 
direkt beschreiben. Für alles andere wie Rechtecke, Linien, 
ASCII-Zeichen, Strings usw, muß man selber Funktionen schreiben, aber 
das habe ich schon für die Ferbedienung mit einem Arduino Due mit 
angeschlossenem, "nackten" LCD mit Touchscreen gemacht. Die Funktionen 
kann ich nahezu 1:1 auch für den Raspberry Pi verwenden.
1
#include <unistd.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <string.h>
5
#include <fcntl.h>
6
#include <linux/fb.h>
7
#include <sys/mman.h>
8
9
// 'global' variables to store screen info
10
char *fbp = 0;
11
struct fb_var_screeninfo vinfo;
12
struct fb_fix_screeninfo finfo;
13
14
// helper function to 'plot' a pixel in given color
15
//
16
// x, y sind Pixelkoordinaten, (0,0) ist links oben
17
// color ist Farbe als unsigned long: 0x00rrggbb für RGB
18
//
19
void put_pixel(long x, long y, long c)
20
{
21
  unsigned long pix_offset;
22
23
  pix_offset = 3 * x + y * finfo.line_length;
24
  *((char*)(fbp + pix_offset  )) = (unsigned char)(c         & 0x000000ff);
25
  *((char*)(fbp + pix_offset+1)) = (unsigned char)((c >>  8) & 0x000000ff);
26
  *((char*)(fbp + pix_offset+2)) = (unsigned char)((c >> 16) & 0x000000ff);
27
  return;
28
}
29
30
// helper function for drawing - no more need to go mess with the main function when just want to change what to draw...
31
void draw(void)
32
{
33
  long      x, y, c;
34
  unsigned char r, g, b;
35
36
  for (y = 0; y < vinfo.yres; y++)
37
  {
38
    for (x = 0; x < vinfo.xres; x++)
39
    {
40
      r = 0;
41
      g = 0;
42
      b = 0;
43
// oberes Bildviertel: Balken, links schwarz,
44
// nach rechts überblenden zu rot
45
      if ((y >= 0) && (y < vinfo.yres/4))
46
      {
47
        r = (unsigned char)((255*x)/vinfo.xres);
48
      }
49
// zweites Bildviertel: Balken, links schwarz,
50
// nach rechts überblenden zu grün
51
      if ((y >= vinfo.yres/4) && (y < vinfo.yres/2))
52
      {
53
        g = (unsigned char)((255*x)/vinfo.xres);
54
      }
55
// drittes Bildviertel: Balken, links schwarz,
56
// nach rechts überblenden zu blau
57
      if ((y >= vinfo.yres/2) && (y < vinfo.yres*3/4))
58
      {
59
        b = (unsigned char)((255*x)/vinfo.xres);
60
      }
61
// unteres Bildviertel: Balken, links schwarz,
62
// nach rechts überblenden zu weiß
63
      if ((y >= vinfo.yres*3/4) && (y <= vinfo.yres))
64
      {
65
        r = (unsigned char)((255*x)/vinfo.xres);
66
        g = (unsigned char)((255*x)/vinfo.xres);
67
        b = (unsigned char)((255*x)/vinfo.xres);
68
      }
69
      c = (int)(((r << 16) & 0x00ff0000) | ((g << 8) & 0x0000ff00) | (b & 0x000000ff));
70
      put_pixel(x, y, c);
71
    }
72
  }
73
  return;
74
}
75
76
// application entry point
77
int main(int argc, char* argv[])
78
{
79
  int fbfd = 0;
80
  struct fb_var_screeninfo orig_vinfo;
81
  long int screensize = 0;
82
  long int x;
83
84
  fbfd = open("/dev/fb0", O_RDWR); // Open the file for reading and writing
85
  if (!fbfd)
86
  {
87
//    printf("Error: cannot open framebuffer device.\n");
88
    return(1);
89
  }
90
//  printf("The framebuffer device was opened successfully.\n");
91
92
  if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) // Get variable screen information
93
  {
94
//    printf("Error reading variable information.\n");
95
  }
96
//  printf("Original %dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
97
98
  memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo)); // Store for reset (copy vinfo to vinfo_orig)
99
100
  vinfo.bits_per_pixel = 24; // Change variable info
101
  if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo))
102
  {
103
//    printf("Error setting variable information.\n");
104
  }
105
106
  if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) // Get fixed screen information
107
  {
108
//    printf("Error reading fixed information.\n");
109
  }
110
111
  screensize = 3 * vinfo.xres * vinfo.yres; // map fb to user mem 
112
  fbp = (char*)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
113
114
  if ((int)fbp == -1)
115
  {
116
//    printf("Failed to mmap.\n");
117
  }
118
  else
119
  {
120
    // draw...
121
    draw();
122
    for (x = 0; x < 200000000; x++); // delay, danach Programm beenden
123
  }
124
125
  munmap(fbp, screensize); // cleanup
126
  if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo))
127
  {
128
//    printf("Error re-setting variable information.\n");
129
  }
130
  close(fbfd);
131
132
  return 0;
133
}

Vielleicht ist das für jemand nützlich.

Gruß
Andy

von Marian (phiarc) Benutzerseite


Lesenswert?

Andreas W. schrieb:
> Außerdem weiß ich nicht, ob die Hardwarefunktionen
> (Ports, SPI-Bus, IIC-Bus, PWM usw.) mit QT zusammen spielen.

??!

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Da fällt mir spontan das ein:

http://www.akrobiz.com/ezfb/


LibSDL läuft auch direkt auf Framebuffern, damit dann sdl_gfx z.B.
http://cms.ferzkopp.net/index.php/software/13-sdl-gfx

von Rolf M. (rmagnus)


Lesenswert?

Andreas W. schrieb:
> Leider ist das Beispiel nur für 8Bit/Pixel vorgesehen, ich habe es
> für 24Bit/Pixel angepaßt.

Ich würde 32 Bit nehmen.

Beitrag #7163316 wurde von einem Moderator gelöscht.
Beitrag #7180651 wurde von einem Moderator gelöscht.
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.