简体   繁体   English

在 Linux 中的帧缓冲区上显示“Hello World”

[英]Display “Hello World” on framebuffer in linux

I have used the linux 3.14 version on my ARM target and i want to show some line of characters in the display using frame buffer.我在我的 ARM 目标上使用了 linux 3.14 版本,我想使用帧缓冲区在显示器中显示一些字符行。 I can change the colors of the display using the below code.我可以使用以下代码更改显示器的颜色。

#include <stdio.h>

unsigned char colours[8][4] = {
    { 0x00, 0xFF, 0x00, 0xFF }, // green
    { 0x00, 0xFF, 0x00, 0xFF }, // green
    { 0x00, 0xFF, 0x00, 0xFF }, // green
    { 0x00, 0xFF, 0x00, 0xFF }, // green
    { 0x00, 0xFF, 0x00, 0xFF }, // green
    { 0x00, 0xFF, 0x00, 0xFF }, // green
    { 0x00, 0xFF, 0x00, 0xFF }, // green
    { 0x00, 0xFF, 0x00, 0xFF }, // green
};

int frames[] = {0,5,10,15,20,25,30};

int columns = 800;
int lines = 480;

#define ARRAY_SIZE(a)   (sizeof(a)/sizeof(a[0]))        

int frame(int c, int l){
    int i;
    for(i=0; i < ARRAY_SIZE(frames); i++){
        if((c==frames[i])&&((l>=frames[i])&&l<=(lines-frames[i]))){
            return 1;
        }
        if((c==columns-frames[i])&&((l>=frames[i])&&l<=(lines-frames[i]))){
            return 1;
        }
        if((l==frames[i])&&((c>=frames[i])&&c<=(columns-frames[i]))){
            return 1;
        }
        if((l==lines-frames[i])&&((c>=frames[i])&&c<=(columns-frames[i]))){
            return 1;
        }
    }
    return 0;
}

int main(int argc, char **argv)
{
    unsigned char pixel[3];
    int l, c;
    char *filename = argv[1];       
    printf ("Device : %s\n",filename);
    FILE *f = fopen(filename,"wb");

    if(f){
    printf("Device open success \n");
        for(l=0; l<lines; l++){
            for(c=0; c < columns; c++){
                if(frame(c,l)){
                    fwrite(colours[3], 1, sizeof(colours[3]), f);
                }else{
                    int colour = c/(columns/ARRAY_SIZE(colours)); 
                    fwrite(colours[colour], 1, sizeof(colours[colour]), f);
                }
            }
        }
        fclose(f);
    }
    else
        printf("Device open failed \n");

    return 0;
}

In the same way i want to show some lines of character to the display.以同样的方式,我想向显示器显示一些字符行。 Example, I want to show characters "Hello world !!!"例如,我想显示字符“Hello world !!!” in the display using frame buffer.在显示中使用帧缓冲区。

Could any one help me to work it out.谁能帮我解决一下。

You can find an elegant piece of code to do this in tslib .您可以在tslib 中找到一段优雅的代码来执行此操作。 tslib is ac library for filtering touchscreen events. tslib 是用于过滤触摸屏事件的 ac 库。 Actually, you don't need tslib for your purpose (yes, you don't have to build it).实际上,您不需要 tslib 来达到您的目的(是的,您不必构建它)。 In their tests you can find a utility to access the framebuffer.在他们的测试中,您可以找到访问帧缓冲区的实用程序。

They have provided the fbutils.h whose implementation you can find in fbutils-linux.c .他们提供了fbutils.h ,你可以在fbutils-linux.c找到它的实现。 This code is very simple in that it directly manipulates the linux framebuffer and does not have any dependencies.这段代码非常简单,它直接操作linux framebuffer,没有任何依赖。 Currently it's not even 500 lines, and if you only want to display text, you can remove other irrelevant functionality.目前连500行都没有,如果只想显示文字,可以去掉其他不相关的功能。 It supports two fonts - font_8x8 and font_8x16 - whose definitions you can find in the respective .c files.它支持两种字体 - font_8x8font_8x16 - 您可以在各自的 .c 文件中找到font_8x16的定义。

I won't go into code details as it is easy to understand.我不会深入代码细节,因为它很容易理解。 Will just list the current API and provide a simpler code for open and close functionality.将只列出当前的 API 并为打开和关闭功能提供更简单的代码。

int open_framebuffer(void);
void close_framebuffer(void);
void setcolor(unsigned colidx, unsigned value);
void put_cross(int x, int y, unsigned colidx);
void put_string(int x, int y, char *s, unsigned colidx);
void put_string_center(int x, int y, char *s, unsigned colidx);
void pixel(int x, int y, unsigned colidx);
void line(int x1, int y1, int x2, int y2, unsigned colidx);
void rect(int x1, int y1, int x2, int y2, unsigned colidx);
void fillrect(int x1, int y1, int x2, int y2, unsigned colidx);

To manipulate the linux framebuffer, first you should memory map it into your process address space.要操作 linux 帧缓冲区,首先您应该将其内存映射到您的进程地址空间。 After memory mapping you can access it just like an array.在内存映射之后,您可以像访问数组一样访问它。 Using some ioctl you can get information about the framebuffer such as resolution, bytes-per-pixel etc. See here for details.使用某些ioctl您可以获得有关帧缓冲区的信息,例如分辨率、每像素字节数等。有关详细信息,请参见此处 In the code below, you can pass the name of the fb device to open it, such as /dev/fb0 .在下面的代码中,您可以传递 fb 设备的名称来打开它,例如/dev/fb0 You can use the rest of the functions in the original code for drawing.您可以使用原始代码中的其余功能进行绘图。

int open_framebuffer(const char *fbdevice)
{
    uint32_t y, addr;

    fb_fd = open(fbdevice, O_RDWR);
    if (fb_fd == -1) {
        perror("open fbdevice");
        return -1;
    }

    if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix) < 0) {
        perror("ioctl FBIOGET_FSCREENINFO");
        close(fb_fd);
        return -1;
    }

    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var) < 0) {
        perror("ioctl FBIOGET_VSCREENINFO");
        close(fb_fd);
        return -1;
    }

    xres_orig = var.xres;
    yres_orig = var.yres;

    if (rotation & 1) {
        /* 1 or 3 */
        y = var.yres;
        yres = var.xres;
        xres = y;
    } else {
        /* 0 or 2 */
        xres = var.xres;
        yres = var.yres;
    }

    fbuffer = mmap(NULL,
               fix.smem_len,
               PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED,
               fb_fd,
               0);

    if (fbuffer == (unsigned char *)-1) {
        perror("mmap framebuffer");
        close(fb_fd);
        return -1;
    }
    memset(fbuffer, 0, fix.smem_len);

    bytes_per_pixel = (var.bits_per_pixel + 7) / 8;
    transp_mask = ((1 << var.transp.length) - 1) <<
        var.transp.offset; /* transp.length unlikely > 32 */
    line_addr = malloc(sizeof(*line_addr) * var.yres_virtual);
    addr = 0;
    for (y = 0; y < var.yres_virtual; y++, addr += fix.line_length)
        line_addr[y] = fbuffer + addr;

    return 0;
}

void close_framebuffer(void)
{
    memset(fbuffer, 0, fix.smem_len);
    munmap(fbuffer, fix.smem_len);
    close(fb_fd);

    free(line_addr);

    xres = 0;
    yres = 0;
    rotation = 0;
}

You can find examples of its usage in test programs in the folder, such as ts_test.c .您可以在文件夹中的测试程序中找到它的使用示例,例如ts_test.c

You can extend this code to support other fonts, display images etc.您可以扩展此代码以支持其他字体、显示图像等。

Good luck!祝你好运!

First, I strongly suggest to avoid use of fopen/fwrite function to access devices.首先,我强烈建议避免使用 fopen/fwrite 函数来访问设备。 These function handle internal buffers that can be troublesome.这些函数处理可能很麻烦的内部缓冲区。 Prefers functions open and write.更喜欢函数 open 和 write。

Next, you can't continue with series of if .. then .. else .. to render a true graphic.接下来,您不能继续使用一系列if .. then .. else ..来渲染真正的图形。 You need to allocate a buffer that represent your framebuffer.您需要分配一个代表您的帧缓冲区的缓冲区。 Its size will, be columns * lines * 4 (you need 1 byte per primary color).它的大小将为columns * lines * 4 (每种原色需要 1 个字节)。 To write a pixel, you have to use something like:要写一个像素,你必须使用类似的东西:

buf[l * columns + c * 4 + 0] = red_value;
buf[l * columns + c * 4 + 1] = green_value;
buf[l * columns + c * 4 + 2] = blue_value;
buf[l * columns + c * 4 + 3] = alpha_value;

Once you buffer is fully filled, write it with:一旦你的缓冲区被完全填满,写成:

write(fd, buf, sizeof(buf));

(where fd is file descriptor return by fd = open("/dev/fbdev0", O_WRONLY); ) (其中fdfd = open("/dev/fbdev0", O_WRONLY);返回的fd = open("/dev/fbdev0", O_WRONLY);

Check that you are now able to set arbitrary pixels on our framebuffer.检查您现在是否能够在我们的帧缓冲区上设置任意像素。

Finally, you need a database of rendered characters.最后,您需要一个渲染字符的数据库。 You could create it yourself, but I suggest to use https://github.com/dhepper/font8x8 .您可以自己创建它,但我建议使用https://github.com/dhepper/font8x8

Fonts are monochrome so each bit represent one pixel.字体是单色的,所以每一位代表一个像素。 On your framebuffer, you need 4bytes for one pixel.在您的帧缓冲区上,一个像素需要 4 个字节。 So you will have to do some conversion.所以你必须做一些转换。

This is a really basic way to access framebuffer, there are plenty of improvements to do:这是访问帧缓冲区的一种非常基本的方法,还有很多改进要做:

  • columns, lines and pixel representation should negotiated/retrieved using FBIO*ET_*SCREENINFO ioctl.列、行和像素表示应使用FBIO*ET_*SCREENINFO ioctl 协商/检索。
  • using write to access framebuffer is not the preferred method.使用write访问帧缓冲区不是首选方法。 It is slow and does not allow to updating framebuffer easily.它很慢,并且不允许轻松更新帧缓冲区。 The preferred method use mmap .首选方法使用mmap
  • if you want to to animate framebuffer, you to use a double buffer: allocate a buffer twice larger than necessary, write alternatively first part or second part and update shown buffer with FBIOPAN_DISPLAY如果要为帧缓冲区设置动画,请使用双缓冲区:分配比所需大两倍的缓冲区,交替写入第一部分或第二部分并使用FBIOPAN_DISPLAY更新显示的缓冲区
  • font8x8 is not ideal. font8x8并不理想。 You may want to use any other font available on web.您可能想要使用网络上可用的任何其他字体。 You need a library to decode font format ( libfreetype ) and a library to render a glyph (= a letter) in a particular size to a buffer (aka rasterize step) that you can copy to your screen (libpango)您需要一个库来解码字体格式( libfreetype )和一个库来将特定大小的字形(= 字母)渲染到缓冲区(又名光栅化步骤),您可以将其复制到您的屏幕(libpango)
  • you may want to accelerate buffer copy between your glyph database and your screen framebuffer (aka compose step), but it is a far longer story that involve true GPU drivers您可能希望加速字形数据库和屏幕帧缓冲区之间的缓冲区复制(又名撰写步骤),但这是一个涉及真正 GPU 驱动程序的更长的故事

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM