Framebuffer im Raspberry Pi direkt ansprechen: so geht es

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

Antwort schreiben

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.