/*******************************************************************************
* Copyleft (c) 2021 Kcode
*
* @file fb.c
* @brief 支持Framebuffer的LCD设备文件
* @author K
* @version 0.0.1
* @date 2021-07-02
* @license MulanPSL-1.0
*
* 文件修改历史:
* <时间> | <版本> | <作者> | <描述>
* 2021-07-02 | v0.0.1 | Kcode | 支持Framebuffer的LCD设备文件
* -----------------------------------------------------------------------------
******************************************************************************/
#include <config.h>
#include <disp_manager.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <string.h>
#include "debug_manager.h"
static int s_FBFD;
static int s_ScreenSize;
static int s_LineWidth;
static int s_PixelWidth;
static struct fb_var_screeninfo s_tVar;
static struct fb_fix_screeninfo s_tFix;
static unsigned char *s_pFbmem;
static int FBDeviceInit(void);
static int FBShowPixel(int PenX, int PenY, unsigned int Color);
static int FBCleanScreen(unsigned int BackColor);
static int FBShowPage(PT_PIXELDATAS pixel_datas);
static T_DispOpr s_tFBDispOpr = {
.name = "fb",
.DeviceInit = FBDeviceInit,
.ShowPixel = FBShowPixel,
.CleanScreen = FBCleanScreen,
.ShowPage = FBShowPage,
};
/*!
* @brief "framebuffer显示设备"的初始化函数
* @param [in] 无
* @return 0:注册成功,其他值:失败
*/
static int FBDeviceInit(void)
{
/* 打开设备:支持读写 */
s_FBFD = open(FB_DEVICE_NAME, O_RDWR);
if (s_FBFD < 0) {
DBG_PRINTF("can not open %s , err code :%d\n", FB_DEVICE_NAME, s_FBFD);
return -1;
}
/* 获得可变信息 */
if (ioctl(s_FBFD, FBIOGET_VSCREENINFO, &s_tVar)) {
DBG_PRINTF("can not get s_tVar\n");
return -1;
}
/* 获得固定信息 */
if (ioctl(s_FBFD, FBIOGET_FSCREENINFO, &s_tFix)) {
DBG_PRINTF("can not get s_tVar\n");
return -1;
}
s_ScreenSize = s_tVar.xres * s_tVar.yres * s_tVar.bits_per_pixel / 8; // 屏幕总像素所占的字节数
s_LineWidth = s_tVar.xres * s_tVar.bits_per_pixel / 8; // 每行像素所占的字节数
s_PixelWidth = s_tVar.bits_per_pixel / 8; // 每个像素所占字节数
/*存入信息(为了之后可能会用到)*/
s_tFBDispOpr.Xres = s_tVar.xres;
s_tFBDispOpr.Yres = s_tVar.yres;
s_tFBDispOpr.Bpp = s_tVar.bits_per_pixel;
s_tFBDispOpr.LineWidth = s_LineWidth;
/* 直接映射到内存的Framebuffer s_pFbmem为LCD buffer的基地址,往地址里面写东西 就可以改变颜色*/
s_pFbmem = (unsigned char *)mmap(NULL, s_ScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, s_FBFD, 0);
if (s_pFbmem == (unsigned char *)-1) {
DBG_PRINTF("can not mmap\n");
return -1;
}
s_tFBDispOpr.pDispMem = s_pFbmem;
return 0;
}
/*!
* @brief 设置FrameBuffer的指定像素点为某颜色
* @param PenX[in] 像素的x坐标
* @param PenY[in] 像素的y坐标
* @param Color[in] 颜色值,格式为32Bpp,即0x00RRGGBB
* @return 0:成功,其他值:失败
*/
static int FBShowPixel(int PenX, int PenY, unsigned int Color)
{
unsigned char *pPen8;
unsigned short *pPen16;
unsigned int *pPen32;
unsigned int red, green, blue;
if ((PenX >= s_tVar.xres) || (PenY >= s_tVar.yres))
{
DBG_PRINTF("out of region\n");
return -1;
}
/* 该坐标在内存中对应像素的位置 */
pPen8 = s_pFbmem + PenY * s_LineWidth + PenX * s_PixelWidth;
pPen16 = (unsigned short *)pPen8;
pPen32 = (unsigned int *)pPen8;
switch (s_tFBDispOpr.Bpp) {
case 8:
*pPen8 = (unsigned char)Color;
break;
case 16:
/* RGB:565 */
red = ((Color >> 16) & 0xff) >> 3;
green = ((Color >> 8 ) & 0xff) >> 2;
blue = ((Color >> 0 ) & 0xff) >> 3;
*pPen16 = (red << 11) | (green << 5) | blue;
break;
case 32:
*pPen32 = Color;
break;
default:
DBG_PRINTF("can not surport %d bpp\n", s_tFBDispOpr.Bpp);
return -1;
}
return 0;
}
/*!
* @brief "framebuffer显示设备"的清屏函数
* @param BackColor[in] 整个屏幕设置为该颜色
* @return 0:成功,其他值:失败
*/
static int FBCleanScreen(unsigned int BackColor)
{
int i;
unsigned char *pPen8;
unsigned short *pPen16;
unsigned int *pPen32;
unsigned int red, green, blue;
pPen8 = s_pFbmem;
pPen16 = (unsigned short *)pPen8;
pPen32 = (unsigned int *)pPen8;
switch (s_tFBDispOpr.Bpp) {
case 8:
memset(pPen8, BackColor, s_ScreenSize);
break;
case 16:
/* RGB:565 */
red = ((BackColor >> 16) & 0xffff) >> 3;
green = ((BackColor >> 8 ) & 0xffff) >> 2;
blue = ((BackColor >> 0 ) & 0xffff) >> 3;
BackColor = (red << 11) | (green << 5) | blue;
/*循环写入像素点从而实现清屏*/
for (i = 0; i < s_ScreenSize;) {
*pPen16 = BackColor;
pPen16++;
i += 2; //因为是16位的 ,所以要加2
}
break;
case 32:
/*循环写入像素点从而实现清屏*/
for (i = 0; i < s_ScreenSize;) {
*pPen32 = BackColor;
pPen32++;
i += 4;//因为是32位的 ,所以要加2
}
break;
default:
DBG_PRINTF("can not surport %dbpp\n", s_tFBDispOpr.Bpp);
return -1;
}
return 0;
}
/*!
* @brief 把PT_VideoMem中的颜色数据在FrameBuffer上显示出来
* @param pixel_datas[in] 内含整屏的象素数据
* @return 0:成功,其他值:失败
*/
static int FBShowPage(PT_PIXELDATAS pixel_datas)
{
if (s_tFBDispOpr.pDispMem != pixel_datas->PixelDatas)
{
memcpy(s_tFBDispOpr.pDispMem, pixel_datas->PixelDatas, pixel_datas->TotalBytes);
}
return 0;
}
/*!
* @brief 注册"framebuffer显示设备"
* @param [in] 无
* @return 0:成功,其他值:失败
*/
int FBInit(void)
{
return RegisterDispOpr(&s_tFBDispOpr);
}
带有framebuffer的LCD读写的分层封装
于 2024-02-28 20:53:38 首次发布
本文介绍了如何在Linux系统中通过Framebuffer接口控制LCD设备,包括设备初始化、设置像素颜色、清屏以及显示内存中的颜色数据。主要涉及了文件操作、ioctl、mmap等系统调用。
摘要由CSDN通过智能技术生成