qinyunti 发表于 2024-7-20 00:01

【超小型 Linux 开发套件Quantum Tiny Linux】基于fb封装TFT操作接口

<div class='showpostmsg'><p>为了方便后续移植GUI, 基于fb实现TTF的点的操作接口。</p>

<p>&nbsp;</p>

<p>初始化打开设备,映射mmap</p>

<pre>
<code class="language-cpp">int lcd_init(char* dev)   
{   
    s_fp = open(dev, O_RDWR);

    if(s_fp &lt; 0)
    {
      printf("Error : Can not open framebuffer device/n");
      return -1;
    }

    if(ioctl(s_fp, FBIOGET_FSCREENINFO, &amp;s_finfo))
    {
      if(s_fp &gt; 0)                     /* 关闭设备 */
      {
            close (s_fp);
            s_fp = -1;
      }
      printf("Error reading fixed information/n");
      return -2;
    }

    if(ioctl(s_fp, FBIOGET_VSCREENINFO, &amp;s_vinfo))
    {
      if(s_fp &gt; 0)                     /* 关闭设备 */
      {
            close (s_fp);
            s_fp = -1;
      }
      printf("Error reading variable information/n");
      return -3;
    }

    s_screensize = s_vinfo.xres * s_vinfo.yres * s_vinfo.bits_per_pixel / 8;

    printf("The phy mem = 0x%lx, total size = %d(byte)\n", s_finfo.smem_start, s_finfo.smem_len);
    printf("xres =%d, yres =%d, bits_per_pixel = %d\n", s_vinfo.xres, s_vinfo.yres, s_vinfo.bits_per_pixel);
    printf("So the s_screensize = %d(byte), using %d frame\n", s_screensize, s_finfo.smem_len/s_screensize);
    printf("s_vinfo.xoffset = %d, s_vinfo.yoffset = %d\n", s_vinfo.xoffset, s_vinfo.yoffset);
    printf("s_vinfo.vmode is :%d\n", s_vinfo.vmode);
    printf("s_finfo.ypanstep is :%d\n", s_finfo.ypanstep);
    printf("s_vinfo.red.offset=0x%x\n", s_vinfo.red.offset);
    printf("s_vinfo.red.length=0x%x\n", s_vinfo.red.length);
    printf("s_vinfo.green.offset=0x%x\n", s_vinfo.green.offset);
    printf("s_vinfo.green.length=0x%x\n", s_vinfo.green.length);
    printf("s_vinfo.blue.offset=0x%x\n", s_vinfo.blue.offset);
    printf("s_vinfo.blue.length=0x%x\n", s_vinfo.blue.length);
    printf("s_vinfo.transp.offset=0x%x\n", s_vinfo.transp.offset);
    printf("s_vinfo.transp.length=0x%x\n", s_vinfo.transp.length);
   

    s_fbp =(char *)mmap(0, s_screensize, PROT_READ | PROT_WRITE, MAP_SHARED, s_fp, 0);
    if ((void *)s_fbp == MAP_FAILED)
    {   
      printf ("Error: failed to map framebuffer device to memory./n");
      if(s_fp &gt; 0)                     /* 关闭设备 */
      {
            close (s_fp);
            s_fp = -1;
      }
      return -4;
    }
    printf("Get virt mem = %p\n", s_fbp);

    /* using first frame, for FBIOPAN_DISPLAY
   * 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
   * 如果使用第二帧buffer -&gt; s_vinfo.xoffset = 0; s_vinfo.yoffset = s_vinfo.yres;
   */
    s_vinfo.xoffset = 0;
    s_vinfo.yoffset = 0;

    return 0;
}
</code></pre>

<p>解除初始化</p>

<pre>
<code class="language-cpp">int lcd_deinit(void)
{
    if(s_fbp != NULL)
    {
      munmap(s_fbp, s_screensize); /* 解除映射 */
      s_fbp = NULL;
    }
    if(s_fp &gt; 0)                     /* 关闭设备 */
    {
      close (s_fp);
      s_fp = -1;
    }
}
</code></pre>

<p>&nbsp;</p>

<p>写点</p>

<pre>
<code class="language-cpp">int lcd_set_pixel(uint32_t x, uint32_t y, uint32_t color)
{
    uint32_t location = x * (s_vinfo.bits_per_pixel / 8) + y*s_finfo.line_length;

    if(s_vinfo.bits_per_pixel == 8)
    {
      *(uint8_t*)(s_fbp+location) = (uint8_t)(color&amp;0xFF);
    }
    else if(s_vinfo.bits_per_pixel == 16)
    {
      *(uint16_t*)(s_fbp+location) = (uint16_t)(color&amp;0xFFFF);
    }
    else if(s_vinfo.bits_per_pixel == 32)
    {
      *(uint32_t*)(s_fbp+location) = color;
    }
    else{}
    //ioctl(s_fp, FBIOPAN_DISPLAY, &amp;s_vinfo);
}</code></pre>

<p>读点</p>

<pre>
<code class="language-cpp">int lcd_get_pixel(uint32_t x, uint32_t y, uint32_t* color)
{
    uint32_t location = x * (s_vinfo.bits_per_pixel / 8) + y*s_finfo.line_length;
    if(s_vinfo.bits_per_pixel == 8)
    {
      *color = *(uint8_t*)(s_fbp+location);
    }
    else if(s_vinfo.bits_per_pixel == 16)
    {
      *color = *(uint16_t*)(s_fbp+location);
    }
    else if(s_vinfo.bits_per_pixel == 32)
    {
      *color = *(uint32_t*)(s_fbp+location);
    }
    else{}
}
</code></pre>

<p>测试,RGB刷屏</p>

<pre>
<code class="language-cpp">#if FB_TEST
int main(int argc, char* argv[])
{
    if(argc == 2)
    {
       int res = lcd_init(argv);
       if(res != 0)
       {
            printf("lcd init err:%d\r\n",res);
            return -1;
       }

       uint32_t xres;
       uint32_t yres;
       lcd_get_res(&amp;xres, &amp;yres);

       for(int t=0; t&lt;10; t++)
       {
            for(uint32_t i=0; i&lt;xres; i++)
            {
                  for(uint32_t j=0; j&lt;yres; j++)
                  {
                        lcd_set_pixel(i, j, 0xF800);
                  }
            }
            sleep(1);

            for(uint32_t i=0; i&lt;xres; i++)
            {
                  for(uint32_t j=0; j&lt;yres; j++)
                  {
                        lcd_set_pixel(i, j, 0x07E0);
                  }
            }
            sleep(1);

            for(uint32_t i=0; i&lt;xres; i++)
            {
                  for(uint32_t j=0; j&lt;yres; j++)
                  {
                        lcd_set_pixel(i, j, 0x1F);
                  }
            }
            sleep(1);
       }

       lcd_deinit();
    }
    else
    {
      printf("usage:./fb dev\r\n");
      return -2;
    }
}
#endif</code></pre>

<p>&nbsp;</p>

<p>完整的lcd.c</p>

<pre>
<code class="language-cpp">#include &lt;unistd.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;linux/fb.h&gt;
#include &lt;sys/mman.h&gt;
#include &lt;sys/ioctl.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#define FB_TEST 1

static int s_fp=0;
static uint8_t *s_fbp = NULL;
static uint32_t s_screensize=0;
static struct fb_var_screeninfo s_vinfo;
static struct fb_fix_screeninfo s_finfo;


int lcd_sync(void)
{
    return 0;
}

int lcd_set_pixel(uint32_t x, uint32_t y, uint32_t color)
{
    uint32_t location = x * (s_vinfo.bits_per_pixel / 8) + y*s_finfo.line_length;

    if(s_vinfo.bits_per_pixel == 8)
    {
      *(uint8_t*)(s_fbp+location) = (uint8_t)(color&amp;0xFF);
    }
    else if(s_vinfo.bits_per_pixel == 16)
    {
      *(uint16_t*)(s_fbp+location) = (uint16_t)(color&amp;0xFFFF);
    }
    else if(s_vinfo.bits_per_pixel == 32)
    {
      *(uint32_t*)(s_fbp+location) = color;
    }
    else{}
    //ioctl(s_fp, FBIOPAN_DISPLAY, &amp;s_vinfo);
}

int lcd_get_pixel(uint32_t x, uint32_t y, uint32_t* color)
{
    uint32_t location = x * (s_vinfo.bits_per_pixel / 8) + y*s_finfo.line_length;
    if(s_vinfo.bits_per_pixel == 8)
    {
      *color = *(uint8_t*)(s_fbp+location);
    }
    else if(s_vinfo.bits_per_pixel == 16)
    {
      *color = *(uint16_t*)(s_fbp+location);
    }
    else if(s_vinfo.bits_per_pixel == 32)
    {
      *color = *(uint32_t*)(s_fbp+location);
    }
    else{}
}

int lcd_get_res(uint32_t* x, uint32_t* y)
{
    *x = s_vinfo.xres;
    *y = s_vinfo.yres;
    return 0;
}

int lcd_init(char* dev)   
{   
    s_fp = open(dev, O_RDWR);

    if(s_fp &lt; 0)
    {
      printf("Error : Can not open framebuffer device/n");
      return -1;
    }

    if(ioctl(s_fp, FBIOGET_FSCREENINFO, &amp;s_finfo))
    {
      if(s_fp &gt; 0)                     /* 关闭设备 */
      {
            close (s_fp);
            s_fp = -1;
      }
      printf("Error reading fixed information/n");
      return -2;
    }

    if(ioctl(s_fp, FBIOGET_VSCREENINFO, &amp;s_vinfo))
    {
      if(s_fp &gt; 0)                     /* 关闭设备 */
      {
            close (s_fp);
            s_fp = -1;
      }
      printf("Error reading variable information/n");
      return -3;
    }

    s_screensize = s_vinfo.xres * s_vinfo.yres * s_vinfo.bits_per_pixel / 8;

    printf("The phy mem = 0x%lx, total size = %d(byte)\n", s_finfo.smem_start, s_finfo.smem_len);
    printf("xres =%d, yres =%d, bits_per_pixel = %d\n", s_vinfo.xres, s_vinfo.yres, s_vinfo.bits_per_pixel);
    printf("So the s_screensize = %d(byte), using %d frame\n", s_screensize, s_finfo.smem_len/s_screensize);
    printf("s_vinfo.xoffset = %d, s_vinfo.yoffset = %d\n", s_vinfo.xoffset, s_vinfo.yoffset);
    printf("s_vinfo.vmode is :%d\n", s_vinfo.vmode);
    printf("s_finfo.ypanstep is :%d\n", s_finfo.ypanstep);
    printf("s_vinfo.red.offset=0x%x\n", s_vinfo.red.offset);
    printf("s_vinfo.red.length=0x%x\n", s_vinfo.red.length);
    printf("s_vinfo.green.offset=0x%x\n", s_vinfo.green.offset);
    printf("s_vinfo.green.length=0x%x\n", s_vinfo.green.length);
    printf("s_vinfo.blue.offset=0x%x\n", s_vinfo.blue.offset);
    printf("s_vinfo.blue.length=0x%x\n", s_vinfo.blue.length);
    printf("s_vinfo.transp.offset=0x%x\n", s_vinfo.transp.offset);
    printf("s_vinfo.transp.length=0x%x\n", s_vinfo.transp.length);
   

    s_fbp =(char *)mmap(0, s_screensize, PROT_READ | PROT_WRITE, MAP_SHARED, s_fp, 0);
    if ((void *)s_fbp == MAP_FAILED)
    {   
      printf ("Error: failed to map framebuffer device to memory./n");
      if(s_fp &gt; 0)                     /* 关闭设备 */
      {
            close (s_fp);
            s_fp = -1;
      }
      return -4;
    }
    printf("Get virt mem = %p\n", s_fbp);

    /* using first frame, for FBIOPAN_DISPLAY
   * 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
   * 如果使用第二帧buffer -&gt; s_vinfo.xoffset = 0; s_vinfo.yoffset = s_vinfo.yres;
   */
    s_vinfo.xoffset = 0;
    s_vinfo.yoffset = 0;

    return 0;
}


int lcd_deinit(void)
{
    if(s_fbp != NULL)
    {
      munmap(s_fbp, s_screensize); /* 解除映射 */
      s_fbp = NULL;
    }
    if(s_fp &gt; 0)                     /* 关闭设备 */
    {
      close (s_fp);
      s_fp = -1;
    }
}


#if FB_TEST
int main(int argc, char* argv[])
{
    if(argc == 2)
    {
       int res = lcd_init(argv);
       if(res != 0)
       {
            printf("lcd init err:%d\r\n",res);
            return -1;
       }

       uint32_t xres;
       uint32_t yres;
       lcd_get_res(&amp;xres, &amp;yres);

       for(int t=0; t&lt;10; t++)
       {
            for(uint32_t i=0; i&lt;xres; i++)
            {
                  for(uint32_t j=0; j&lt;yres; j++)
                  {
                        lcd_set_pixel(i, j, 0xF800);
                  }
            }
            sleep(1);

            for(uint32_t i=0; i&lt;xres; i++)
            {
                  for(uint32_t j=0; j&lt;yres; j++)
                  {
                        lcd_set_pixel(i, j, 0x07E0);
                  }
            }
            sleep(1);

            for(uint32_t i=0; i&lt;xres; i++)
            {
                  for(uint32_t j=0; j&lt;yres; j++)
                  {
                        lcd_set_pixel(i, j, 0x1F);
                  }
            }
            sleep(1);
       }

       lcd_deinit();
    }
    else
    {
      printf("usage:./fb dev\r\n");
      return -2;
    }
}
#endif</code></pre>

<p>完整的lcd.h</p>

<pre>
<code class="language-cpp">#ifndef LCD_H
#define LCD_H

#ifdef __cplusplus
extern "C" {
#endif

#include &lt;stdint.h&gt;

int lcd_deinit(void);
int lcd_init(char* dev);
int lcd_get_res(uint32_t* x, uint32_t* y);
int lcd_get_pixel(uint32_t x, uint32_t y, uint32_t* color);
int lcd_set_pixel(uint32_t x, uint32_t y, uint32_t color);
int lcd_sync(void);

#ifdef __cplusplus
}
#endif

#endif
</code></pre>

<p>&nbsp;</p>

<p>测试</p>

<p>将代码导入到开发板</p>

<p>编译</p>

<p>gcc lcd.c -o lcd</p>

<p>运行</p>

<p>./lcd /dev/fb1</p>

<p>&nbsp;</p>

<p>可以看到屏幕RGB刷屏</p>

<p>&nbsp;</p>

<p> &nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

Jacktang 发表于 2024-7-20 07:43

<p>fb实现TTF的点的操作接口,前期工作已经做好,期待后续</p>
页: [1]
查看完整版本: 【超小型 Linux 开发套件Quantum Tiny Linux】基于fb封装TFT操作接口