【超小型 Linux 开发套件Quantum Tiny Linux】基于fb封装TFT操作接口
<div class='showpostmsg'><p>为了方便后续移植GUI, 基于fb实现TTF的点的操作接口。</p><p> </p>
<p>初始化打开设备,映射mmap</p>
<pre>
<code class="language-cpp">int lcd_init(char* dev)
{
s_fp = open(dev, O_RDWR);
if(s_fp < 0)
{
printf("Error : Can not open framebuffer device/n");
return -1;
}
if(ioctl(s_fp, FBIOGET_FSCREENINFO, &s_finfo))
{
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
printf("Error reading fixed information/n");
return -2;
}
if(ioctl(s_fp, FBIOGET_VSCREENINFO, &s_vinfo))
{
if(s_fp > 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 > 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 -> 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 > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
}
</code></pre>
<p> </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&0xFF);
}
else if(s_vinfo.bits_per_pixel == 16)
{
*(uint16_t*)(s_fbp+location) = (uint16_t)(color&0xFFFF);
}
else if(s_vinfo.bits_per_pixel == 32)
{
*(uint32_t*)(s_fbp+location) = color;
}
else{}
//ioctl(s_fp, FBIOPAN_DISPLAY, &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(&xres, &yres);
for(int t=0; t<10; t++)
{
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0xF800);
}
}
sleep(1);
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0x07E0);
}
}
sleep(1);
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<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> </p>
<p>完整的lcd.c</p>
<pre>
<code class="language-cpp">#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#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&0xFF);
}
else if(s_vinfo.bits_per_pixel == 16)
{
*(uint16_t*)(s_fbp+location) = (uint16_t)(color&0xFFFF);
}
else if(s_vinfo.bits_per_pixel == 32)
{
*(uint32_t*)(s_fbp+location) = color;
}
else{}
//ioctl(s_fp, FBIOPAN_DISPLAY, &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 < 0)
{
printf("Error : Can not open framebuffer device/n");
return -1;
}
if(ioctl(s_fp, FBIOGET_FSCREENINFO, &s_finfo))
{
if(s_fp > 0) /* 关闭设备 */
{
close (s_fp);
s_fp = -1;
}
printf("Error reading fixed information/n");
return -2;
}
if(ioctl(s_fp, FBIOGET_VSCREENINFO, &s_vinfo))
{
if(s_fp > 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 > 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 -> 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 > 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(&xres, &yres);
for(int t=0; t<10; t++)
{
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0xF800);
}
}
sleep(1);
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<yres; j++)
{
lcd_set_pixel(i, j, 0x07E0);
}
}
sleep(1);
for(uint32_t i=0; i<xres; i++)
{
for(uint32_t j=0; j<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 <stdint.h>
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> </p>
<p>测试</p>
<p>将代码导入到开发板</p>
<p>编译</p>
<p>gcc lcd.c -o lcd</p>
<p>运行</p>
<p>./lcd /dev/fb1</p>
<p> </p>
<p>可以看到屏幕RGB刷屏</p>
<p> </p>
<p> </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> <p>fb实现TTF的点的操作接口,前期工作已经做好,期待后续</p>
页:
[1]