framebuffer驱动详解

2023-10-31

裸机中如何操作LCD

        LCD的显示原理:DDR中分出一块内存,将要显示的内容放到显存中,硬件自动将显存数据放到驱动器中,驱动器操控LCD显示内容。裸机操作LCD的方法由LCD的本身的工作原理决定。

在这里插入图片描述

 OS下操作LCD的难点

   内核(驱动)做底层硬件操作相关的那部分(初始化LCD控制器的寄存器、内存,建立显存与LCD之间的映射关系),应用做让LCD显示具体内容的那部分(把显示的内容丢到显存中去,让LCD显示具体的内容)。

应用与内核的显存的虚拟地址不同,应用使用的是应用层的虚拟地址空间,而内核使用的是内核层的虚拟地址空间,但是二者可以对应同一块物理地址,这样就可以提升效率。

内核与应用进行数据交换:
    小容量数据:copy_to_user,copy_from_user
    大容量数据:mmap(可用于显示的情况下,显示画面时数据量较大)

什么是framebuffer

framebuffer帧缓冲(简称fb)是linux内核中虚拟出的一个设备,使用代码构建出的一个设备,具有设备文件可以去读写,代替LCD显示器这个硬件设施以及LCD显示器所需的软件设施和硬件设施,如显卡驱动和显卡。framebuffer可以进行不同的配置从而支持不同的接口如VGA、HDMI等等。

很多人都会说操纵lcd显示就是操纵framebuffer,表面上来看是这样的。实际上是frambuffer就是linux内核驱动申请的一片内存空间,然后lcd内有一片sram,cpu内部有个lcd控制器,它有个单独的dma用来将frambuffer中的数据拷贝到lcd的sram中去 拷贝到lcd的sram中的数据就会显示在lcd上,LCD驱动和framebuffer驱动没有必然的联系,它只是驱动LCD正常工作的,比如有信号传过来,那么LCD驱动负责把信号转成显示屏上的内容,至于什么内容这就是应用层要处理的。

ls /dev/fb*
一般为fb0,fb为设备名称,数字为序号,有几个显示设备就有几个fbX,X表示从零开始的整数
一般只有一个屏幕但是却有好多个fbX文件,是因为这些表示的是虚拟屏幕

framebuffer向应用层提供一个统一标准接口的显示设备,忽略不同显示设备的差异,屏蔽了不同的硬件的差异

从驱动来看,fb是一个典型的字符设备,而且创建了一个类/sys/class/graphics

在这里插入图片描述

一、framebuffer的使用

(1)设备文件 /dev/fb0(我的开发板是这个,不同开发板不同内核驱动可能会有所差异)

(2)获取设备信息(显示设备的大小,分辨率等) #include <linux/fb.h>

(3)mmap做映射(详解:13.mmap内存映射_哔哩哔哩_bilibili

  在LINUX中我们可以使用mmap用来在进程虚拟内存地址空间中分配地址空间,创建和物理内存的映射关系。mmap将一个文件或者其它对象映射进内存。

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);

  mmap只是在虚拟内存分配了地址空间,只有在第一次访问虚拟内存的时候才分配物理内存。

  驱动在内核中申请一块显存,多个进程可同时操控LCD,可进行多对一映射,后来的覆盖前面的。

(4)填充framebuffer(即将显示的内容放到framebuffer中)

二、framebuffer驱动源码分析

1、驱动框架部分

  •  drivers/video/fbmem.c主要任务:fbmen_init()函数负责创建graphics类、注册FB的字符设备驱动、register_framebuffer()函数提供接口给具体framebuffer驱动编写着来注册fb设备。本文件相对于fb来说,地位和作用和misc.c文件相对于杂散类设备来说一样的,结构和分析方法也是类似的。
  •  drivers/video/fbsys.c这个文件是处理fb在/sys目录下的一些属性文件的
  •  drivers/video/modedb.c这个文件是管理显示模式的(譬如VGA、720P刷新率等等就是显示模式)。
  •  drivers/video/fb_notify.c这个文件是frame buff用来管理相关通知的,进行反向唤醒,管理了一个链表,链表发生变动时告知链表中的各个成员。

在这里插入图片描述

2、驱动部分

  •  drivers/video/samsung/s3cfb.c驱动主体
  •  drivers/video/samsung/s3cfb_fimd6x.c里面有很多LCD硬件操作的函数
  •  arch/arm/mach-s5pv210/mach-x210.c负责提供platform_device的
  •  arch/arm/plat-s5p/devs.c为platform_device提供一些硬件描述信息的

3、framebuffer驱动框架分析:

1、fbmem_init函数
(1)#ifdef MODULE

在这里插入图片描述
(2)fb_proc_fops和fb在proc文件系统中的表现

在这里插入图片描述

在驱动框架并不进行真正的硬件操作,而是通过函数指针指向一个真正可用的函数

(3)register_chrdev注册fb设备
(4)class_create创建graphics类
(5)fbmem_exit的对应当。以非模块的方式即以内核一部分集成编译进内核时,开机自动加载执行后是无法像模块卸载的,故而这种非模块方式并不需要fbmem_exit函数
在这里插入图片描述

【2】分析一下fbmem_init层的register_chrdev注册函数的参数struct file_operations fb_fops:

1、fb_fops

所有的framebuffer设备共用一个主设备号,用不同的次设备号进行区分,类似于misc类设备。
(1)read/write/mmap/ioctl函数
(2)registered_fb和num_registered_fb
(3)struct fb_info描述一个framebuffer设备
在这里插入图片描述

在这里插入图片描述
【3】例举fb_read,fb_open(流程图为在SI中查看源码,追进去看到的部分细节)

在这里插入图片描述

struct fb_info {
	int node;//当前这个framebuffer设备在framebuffer设备数组中的下表
	int flags;
	struct mutex lock;		/* Lock for open/release/ioctl funcs */
	struct mutex mm_lock;		/* Lock for fb_mmap and smem_* fields */
	struct fb_var_screeninfo var;	/* Current var */
	struct fb_fix_screeninfo fix;	/* Current fix */ 
	struct fb_monspecs monspecs;	/* Current Monitor specs */
	struct work_struct queue;	/* Framebuffer event queue */
	struct fb_pixmap pixmap;	/* Image hardware mapper */
	struct fb_pixmap sprite;	/* Cursor hardware mapper */
	struct fb_cmap cmap;		/* Current cmap */
	struct list_head modelist;      /* mode list */
	struct fb_videomode *mode;	/* current mode */
该结构体部分成员


【4】通过查询SI查询内核中使用了register_framebuffer的文件(即具体实现的有关硬件操作相关的驱动)有很多
在这里插入图片描述

【5】总结

在这里插入图片描述

4.framebuffer驱动分析


1、s3cfb.c

在这里插入图片描述

int register_framebuffer(struct fb_info *fb_info)
{
	int i;
	struct fb_event event;
	struct fb_videomode mode;//显示模式

	if (num_registered_fb == FB_MAX)//已注册的设备个数是否等于最大设备数
		return -ENXIO;

	if (fb_check_foreignness(fb_info))//判断大小端模式
		return -ENOSYS;

	remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
					 fb_is_primary_device(fb_info));//防止冲突机制

	num_registered_fb++;
	for (i = 0 ; i < FB_MAX; i++)//找到一个空的可用的
		if (!registered_fb[i])
			break;
	fb_info->node = i; 
	mutex_init(&fb_info->lock);
	mutex_init(&fb_info->mm_lock);

	fb_info->dev = device_create(fb_class, fb_info->device,
				     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);//创建设备
	if (IS_ERR(fb_info->dev)) {
		/* Not fatal */
		printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
		fb_info->dev = NULL;
	} else
		fb_init_device(fb_info);//对设备进行初始化

	if (fb_info->pixmap.addr == NULL) {
		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
		if (fb_info->pixmap.addr) {
			fb_info->pixmap.size = FBPIXMAPSIZE;
			fb_info->pixmap.buf_align = 1;
			fb_info->pixmap.scan_align = 1;
			fb_info->pixmap.access_align = 32;
			fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
		}
	}	
	fb_info->pixmap.offset = 0;

	if (!fb_info->pixmap.blit_x)
		fb_info->pixmap.blit_x = ~(u32)0;

	if (!fb_info->pixmap.blit_y)
		fb_info->pixmap.blit_y = ~(u32)0;

	if (!fb_info->modelist.prev || !fb_info->modelist.next)
		INIT_LIST_HEAD(&fb_info->modelist);

	fb_var_to_videomode(&mode, &fb_info->var);
	fb_add_videomode(&mode, &fb_info->modelist);
	registered_fb[i] = fb_info;

	event.info = fb_info;
	if (!lock_fb_info(fb_info))
		return -ENODEV;
	fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
	unlock_fb_info(fb_info);
	return 0;
}

2、s3c_device_fb

在这里插入图片描述

3、probe函数分析
(1)struct s3c_platform_fb 这个结构体是fb的platform_data结构体,这个结构体变量就是platform设备的私有数据,这个数据在platform_device.device.platform_data中存储。在mach文件中去准备并填充这些数据,在probe函数中通过传参的platform_device指针取出来。
(2)struct s3cfb_global: 这个结构体主要作用是在驱动部分的2个文件(s3cfb.c和s3cfb_fimd6x.c)的函数中做数据传递用的
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

framebuffer应用编程实践

实验步骤

1、打开设备
2、获取设备信息

        #include <linux/fb.h>是内核源码中的一个文件,但制作交叉编译链时也将这个文件加入了进去。分析查看文件该文件,可得知相关的设备信息。

(1)不可变信息FSCREENINFO,使用ioctl的FBIOGET_FSCREENINFO命令获得,操作命令码类似于上篇文章操作buzzer的那些命令码。

从fb.h文件摘录部分命令码
/* ioctls
   0x46 is 'F'								*/
#define FBIOGET_VSCREENINFO	0x4600
#define FBIOPUT_VSCREENINFO	0x4601
#define FBIOGET_FSCREENINFO	0x4602
#define FBIOGETCMAP		0x4604
#define FBIOPUTCMAP		0x4605
#define FBIOPAN_DISPLAY		0x4606
#ifdef __KERNEL__
struct fb_fix_screeninfo {
	char id[16];			/* identification string eg "TT Builtin" */
	unsigned long smem_start;	/* Start of frame buffer mem */
					/* (physical address) */
	__u32 smem_len;			/* Length of frame buffer mem */
	__u32 type;			/* see FB_TYPE_*		*/
	__u32 type_aux;			/* Interleave for interleaved Planes */
	__u32 visual;			/* see FB_VISUAL_*		*/ 
	__u16 xpanstep;			/* zero if no hardware panning  */
	__u16 ypanstep;			/* zero if no hardware panning  */
	__u16 ywrapstep;		/* zero if no hardware ywrap    */
	__u32 line_length;		/* length of a line in bytes    */
	unsigned long mmio_start;	/* Start of Memory Mapped I/O   */
					/* (physical address) */
	__u32 mmio_len;			/* Length of Memory Mapped I/O  */
	__u32 accel;			/* Indicate to driver which	*/
					/*  specific chip/card we have	*/
	__u16 reserved[3];		/* Reserved for future compatibility */
};

计算方法:smem_len = xres*yres*bpp/8

(2)可变信息VSCREENINFO,使用ioctl的FBIOGET_VSCREENINFO命令获得

struct fb_var_screeninfo {
	__u32 xres;			/* visible resolution	真实分辨率即屏幕分辨率*/
	__u32 yres;
	__u32 xres_virtual;		/* virtual resolution	虚拟分辨率,即实际图片的分辨率	*/
	__u32 yres_virtual;
	__u32 xoffset;			/* offset from virtual to visible,偏移量,开始显示的左上角坐标 */
	__u32 yoffset;			/* resolution			*/

	__u32 bits_per_pixel;		/* guess what,bpp,每个像素用多少个字节来表示			*/
	__u32 grayscale;		/* != 0 Graylevels instead of colors,灰度等级 */

	struct fb_bitfield red;		/* bitfield in fb mem if true color, */
	struct fb_bitfield green;	/* else only length is significant */
	struct fb_bitfield blue;	//struct fb_bitfield各个颜色以及透明度的阈值
	struct fb_bitfield transp;	/* transparency,透明度			*/	

	__u32 nonstd;			/* != 0 Non standard pixel format */

	__u32 activate;			/* see FB_ACTIVATE_*		*/

	__u32 height;			/* height of picture in mm,屏幕的物理尺寸大小    */
	__u32 width;			/* width of picture in mm     */

	__u32 accel_flags;		/* (OBSOLETE) see fb_info.flags */

	/* Timing: All values in pixclocks, except pixclock (of course) */
	__u32 pixclock;			/* pixel clock in ps (pico seconds) ,像素时钟*/
	__u32 left_margin;		/* time from sync to picture	*/
	__u32 right_margin;		/* time from picture to sync	*/
	__u32 upper_margin;		/* time from sync to picture	*/
	__u32 lower_margin;		//初始化LCD时序的六个参数
	__u32 hsync_len;		/* length of horizontal sync	*/
	__u32 vsync_len;		/* length of vertical sync	*/
	__u32 sync;			/* see FB_SYNC_*		*/

	__u32 vmode;			/* see FB_VMODE_*		*/
	__u32 rotate;			/* angle we rotate counter clockwise */
	__u32 reserved[5];		/* Reserved for future compatibility */

虚拟分辨率与真实分辨率最好的理解就是一张分辨率高于屏幕的图片无法在这个屏幕完全显示,需要通过滑动左右栏或者上下栏来查看整张图片。

   一个像素点数据由四个字节组成,包括RGB(RGB888颜色编码)以及透明度,各占一个字节。

   三星驱动的虚拟分辨率是真是分辨率的两倍,采用了双缓冲结构(有时也称乒乓结构),屏幕首先从(0,0)开始显示,当上半部分显示完后,可以直接切换到(0, 480),显示剩下的内容。
在这里插入图片描述

 

	#define FBDEVICE	"/dev/fb0"

    struct fb_fix_screeninfo finfo = {0};
	struct fb_var_screeninfo vinfo = {0};

    // 第1步:打开设备
	fd = open(FBDEVICE, O_RDWR);
	if (fd < 0)
	{
		perror("open");
		return -1;
	}
	printf("open %s success.\n", FBDEVICE);

    // 第2步:获取设备的硬件信息
	ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);//获取不变信息
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	printf("smem_start = 0x%x, smem_len = %u.\n", finfo.smem_start, finfo.smem_len);

	ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);//获取可变信息
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);
	printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);
	printf("bpp = %u.\n", vinfo.bits_per_pixel);

3、可设置一些东东比如分辨率

// 修改驱动中屏幕的分辨率
	vinfo.xres = 1024;
	vinfo.yres = 600;
	vinfo.xres_virtual = 1024;
	vinfo.yres_virtual = 1200;
	ret = ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo);
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	
	// 再次读出来检验一下
	ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	printf("修改过之后的参数:\n");
	printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);
	printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);
	printf("bpp = %u.\n", vinfo.bits_per_pixel);

4、mmap做映射
mmap返回值指向一段内存。做完了mmap后fb在当前进程中就已经就绪了,随时可以去读写LCD显示器了。

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
        是否指定映射地址   显存大小       权限   是否可共享         偏移量
                                               多线程同时
                                                操作
void *addr:传入NULL,让自动分配地址 

示例程序:
    // 全局变量
    unsigned int *pfb = NULL;
	//finfo.smem_len以虚拟分辨率进行计算的
	pfb = mmap(NULL, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (NULL == pfb)
	{
		perror("mmap fail");
		return -1;
	}
	printf("pfb = %p.\n", pfb);                 

5、做一些任务以及结束程序

	#define WHITE		0xffffffff
    #define RED			0xffff0000
    // 新开发板
    #define WIDTH		1024	
    #define HEIGHT		600

    draw_back(WIDTH, HEIGHT, WHITE);
	draw_line(RED);//(代码在下面)
	

	close(fd);
	
	return 0;
}

6、写字、画线、图片显示等

void draw_line(unsigned int color)
{
	unsigned int x, y;
	
	for (x=50; x<600; x++)
	{
		*(pfb + 200 * WIDTH + x) = color;
	}
}

//画1024*600像素的图片,图像数据存在pData所指向的数组中,图片数据可用专用的软件生成
//在下方我会给出我使用的软件的链接:Image2Lcd.rar
//https://www.aliyundrive.com/s/D4WwdKcfg63
void lcd_draw_picture(const unsigned char *pData)
{
	unsigned int x, y, color, p = 0;

		for(y = 0; y < 600;y++)
		{
			for(x = 0;x < 1024; x++)
			{
				// 在这里将坐标点(x, y)的那个像素填充上相应的颜色值即可
				
				color = ((pData[p+2] << 0)|(pData[p+1] << 8)|(pData[p+0] << 16));
				*(pfb + y * WIDTH + x) = color;
				p += 3;
				
			}
		}
	
}

上述的这些程序以及实验效果是无法在ubuntu实现的,因为ubuntu做了一些限制,是无法操作framebuffer的,要去开发板执行程序。要去开发板执行程序。要去开发板执行程序。

问题BUG

我写的代码的分辨率和板子上实际的分辨率不匹配,就导致显示不正常,导致刷屏只能刷出一部分,就想通过应用层去设置分辨率能不能行,通过应用层修改完分辨率后,结果显示失败了。

描述:试图在应用层设置分辨率失败了,原因何在?

(1)定位问题:肯定是驱动的事儿。

为什么?bpp是可通过应用层改的,但是x和y的resolution不可以改,但是他们又都在同一个位置,如果是应用层的问题,那肯定是都不可以通过应用层去修改。

(2)进一步驱动中定位:ioctl部分的事儿

因为fb是典型的字符设备驱动,注册自己是去fbmen.c框架那里的

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

framebuffer驱动详解 的相关文章

随机推荐

  • 叉积

    叉积的计算是线段方法的核心 考虑如图33 1 a 所示的向量p1和p2 我们可以把叉积解释为由点 0 0 p1 p2 和 p1 p2 x1 x2 y1 y2 所构成的平行四边形的有向面积 另一种与之等价但更有效的叉积定义方式是将之看做矩阵行
  • 《算法不好玩》专题三:循环不变量

    3 1循环不变量 循环不变量 在循环的过程中保持不变的性质 循环不变式主要用来帮助我们理解算法的正确性 关于循环不变式 我们必须证明三条性质 初始化 循环的第一次迭代之前 它为真 保持 如果循环的某次迭代之前它为真 那么下次迭代之前它仍为真
  • 压缩图片网站

    https tinypng com 压缩图片网站
  • java入职写不出代码_各位程序员是怎么度过看懂代码但写不出来的时期?

    说实话 我自己就没经历过这样的时期 说看得懂代码的 大概是很少看开源代码 想看懂不仅自己水平要过硬 还要花挺大的精力把前前后后的东西都做充分的研究 我自己总是会有自己写一个功能很有思路 但是搞懂别人同样功能代码却感觉很费力的体验 我猜测题主
  • safari ajax timeout,Safari ajax提交表单无响应?

    两个项目均遇到了Safari ajax提交无响应了 表单里有text file字段 file字段用于上传封面图片 创建的时候没问题 当修改的时候 我不想修改封面图 只修改内容 结果Safari提交后无响应 一直在转圈 到最后超时提示 Fai
  • 2020年,Java 开发者必须了解的 16 个Java 顶级开源项目

    2020年 值得你关注的16个Java 开源项目 本文已经收录自笔者开源的 JavaGuide https github com Snailclimb JavaGuide Java学习 面试指南 一份涵盖大部分Java程序员所需要掌握的核心
  • linux qt读写文件,QT 文件读写操作

    include include 1 打开文件 QFile f fn fn可以是一个相对路径或绝对路径 f open IO 一般不要IO ReadWrite 很容易出现赃数据 如果要在文件的后面添加内容要IO WriteOnly IO App
  • C/C++动态分配内存的几种方法

    使用C C 编程时 会经常动态分配内存 以便合理使用内存 本文主要讲述动态内存分配的几种方法及一些原理 理解不深刻之处欢迎指教 引言 为什么要进行动态内存分配 以数组为例 数组元素在内存中存储的地址是连续的 声明一个数组后 该数组需要的内存
  • 微信小程序设置背景图片

    var src1 images index wx56 png let src11 wx getFileSystemManager readFileSync src1 base64 var src111 data image jpg base
  • IntelliJ IDEA查看指定文件的文件类型、修改文件类型、解决无法正确识别文件类型的问题

    如下图 有时候明明创建的文件后缀名为 xml 可是点进去确是文本文件 一开始实在是觉得匪夷所思 那如何让编辑器识别他是xml文件呢 首先File Settings 然后 这里我要把RoleMapper xml识别为xml文件 编辑器提示Ro
  • windows下prometheus+mysqld_exporter+granafa监控mysql

    一 安装prometheus 可以从官网下载 也可以从github下载 从github下载快一点 官网 https prometheus io download github https github com prometheus prom
  • Python记1(输入/出,字符,数据类型,运算符,语句,with

    目录 1 杂 2 输入 输出 3 特殊字符 转义字符 5 数据类型 5 1数据类型转化 6 运算符 7 语句 7 1 条件分支 if elif elif else 7 2 条件表达式 7 3 循环while for 7 4 上下文管理类型
  • React中组件懒加载的使用

    为什么要使用懒加载 减少了应用启动时间 页面的加载速度变快 提升用户体验 懒加载 页面首次打开 不加载在路由中设置为懒加载的组件 只有用户在实际使用中 使用到了这个组件 才会开始加载 实现代码 import React lazy from
  • VMware Workstation Player与VMware Workstation Pro的区别

    linux开发与学习 免不了安装虚拟机 想想自己最开始只有一台电脑 为了体验最有滋味的linux 划重点 直接装了个双系统 之后就是各种苦不堪言 在ubuntu学着做着 为了个工具不得不关机重启回到windows 过了一分钟 切到windo
  • JS高级(4)函数高级 — 闭包

    闭包 循环遍历 给每个按钮都绑定上单击响应函数 var btns document getElementsByTagName button for var i 0 i lt btns length i 这样写会有一个问题 btns是一个伪数
  • 什么是区块链?区块链详解

    区块链简介 什么是区块链 目前没有看到很好的定义和介绍 网上要么是讲一些区块链意义的空泛文章 比如 区块链技术颠覆谁谁谁 又或 互联网已颠覆世界 区块链要颠覆互联网等等 要么就是通篇介绍比特币 矿工 挖矿等 那么区块链到底是个什么东西 它跟
  • python bottle 制作表单_使用Bottle(Python)的AJAX提交表单

    我在使用Bottle框架进行 AJAX通信时遇到了一些问题 这是我第一次使用AJAX 所以我可能只是错误的基础知识 希望瓶子 AJAX大师可以指出这个新手正确的方向 这是我正在使用的代码 usr bin env python from bo
  • dm9000网卡,uboot代码分析

    uboot移植 九 移植网卡DM9000 一 原理 TQ210 板载的网卡芯片是 DM9000A 接在 S5PV210 的 SROM 控制器的 BANK1 上 S5PV210 的 SROM 控制器支持 8 16 位 NOR Flash PR
  • 人工智能数学基础6:极限、极限运算、ε-δ语言、ε-N语言、级数和函数连续性

    老猿Python博文目录 一 极限的定义及四则运算 极限 某一个函数中的某一个变量 此变量在变大 或者变小 的永远变化的过程中 逐渐向某一个确定的数值A不断地逼近而 永远不能够重合到A 永远不能够等于A 但是取等于A 已经足够取得高精度计算
  • framebuffer驱动详解

    裸机中如何操作LCD LCD的显示原理 DDR中分出一块内存 将要显示的内容放到显存中 硬件自动将显存数据放到驱动器中 驱动器操控LCD显示内容 裸机操作LCD的方法由LCD的本身的工作原理决定 OS下操作LCD的难点 内核 驱动 做底层硬