韦东山嵌入式Liunx驱动大全二


本人学习完韦老师的视频,因此来复习巩固,写以笔记记之。
韦老师的课比较难,第一遍不知道在说什么,但是坚持看完一遍,再来复习,基本上就水到渠成了。
看完视频复习的同学观看最佳!
基于 IMX6ULL-PRO

一、LCD

1-1 不同接口的LCD硬件操作原理

bpp:bits per pixel,每个像素用多少位来表示
在这里插入图片描述
假设每个像素的颜色用16位来表示,那么一个LCD的所有像素点假设有xresy res个,需要的内存为:xresyres*16 / 8,也就是要设置所有像素的颜色,需要这么大小的内存。这块内存就被称为framebuffer:

  • Framebuffer中每块数据对应一个像素
  • 每块数据的大小可能是16位、32位,这跟LCD上像素的颜色格式有关
  • 设置好LCD硬件后,只需要把颜色数据写入Framebuffer即可

统一的LCD硬件模型
在这里插入图片描述
MIPI表示Mobile Industry Processor Interface,即移动产业处理器接口。是MIPI联盟发起的为移动应用处理器制定的开放标准和一个规范。
MIPI接口可以分为3类:MIPI-DBI (Display Bus Interface) ,既能发送数据,也能发送命令,常用的8080接口就属于DBI接口;MIPI-DPI (Display Pixel Interface) ,Pixel(像素),强调的是操作单个像素,在MPU上的LCD控制器就是这种接口

1-2 LCD驱动程序框架

字符设备驱动程序框架
在这里插入图片描述
① 驱动主设备号 ② 构造file_operations结构体,填充open/read/write等成员函数
③ 注册驱动:register_chrdev(major, name, &fops) ④ 入口函数 ⑤出口函数

Framebuffer驱动程序框架
分为上下两层:
(1) fbmem.c:承上启下
实现、注册file_operations结构体;把APP的调用向下转发到具体的硬件驱动程序
(2) xxx_fb.c:硬件相关的驱动程序
实现、注册fb_info结构体;实现硬件操作
编写硬件程序如下
分配fb_info:framebuffer_alloc
设置fb_info:var、fbops、硬件相关操作
注册fb_info:register_framebuffer

在这里插入图片描述

1-3 结合APP分析LCD驱动程序框架

参考:04_fb_test文件夹

open函数分析:Linux根据主设备号找到驱动程序,根据次设备号来确定驱动程序中的那一个设备。此时会调用fbmen.c文件中fb_open函数,从registered_fb[i]数组中去获取fb_info。底层驱动在此前已经注册设备驱动,并registered_fb[i] = 定义的fb_info结构体。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/*设备驱动程序的注册信息*/
static struct fb_info *myfb_info;
register_framebuffer(myfb_info);
registered_fb[i] = fb_info;

ioctl函数分析:ioctl对应于底层fb_ioctl函数再调用到do_fb_ioctl
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1-4 LCD硬件时序图

在这里插入图片描述
HSD:水平方向同步信号
VSD:垂直方向同步信号
thd:每行像素个数
LCD控制器时序图
在这里插入图片描述

1-5 分析内核自带的LCD驱动程序

(1) 打开mxsfb.c文件,首先,platform_driver结构体中的属性与内核中设备树进行匹配。
在这里插入图片描述
ubuntu系统中,通过grep查找(第一个属性的值没找到),第二个属性找到内核的imx6ull.dtsi文件的第1017行,并打开。
Dtsi:可以理解为dts的公共部分,添加、变更非常灵活。Dtsi包含在dts中。

grep "fsl,imx28-lcdif" * -nr

设备树通过compatible属性来匹配驱动程序

vi imx6ull.dtsi +1017

在这里插入图片描述
而单板的设备树需要访问100ask_imx6ull-14x14.dts设备树文件,里面有硬件的配置。
在这里插入图片描述
(2) 匹配成功,则调用probe函数。并在里面分配、设置、注册fb_info
分配
在这里插入图片描述
在这里插入图片描述
设置
在这里插入图片描述
注册
在这里插入图片描述

(3) 硬件操作
我们只需要针对IMX6ULL的编写硬件相关的代码,涉及3部分:

GPIO设置

  • LCD引脚
  • 背光引脚
  • GPIO设置使用设备树,在设备树中设置pinctrl。

时钟设置

  • 确定LCD控制器的时钟
  • 根据LCD的DCLK计算相关时钟

LCD控制器本身的设置

  • 比如设置Framebuffer的地址
  • 设置Framebuffer中数据格式、LCD数据格式
  • 设置时序

1-6 编程LCD驱动程序框架_使用设备树

将03文件的驱动程序进行改进
使用platform_driver注册,在probe函数里分配fb_info、设置fb_info、注册fb_info、硬件相关的设置。设备树中需要有对应的节点
驱动框架

static int mylcd_probe(struct platform_device *pdev)
{
	/*简要代码*/
	/* 1.1 分配fb_info */
	myfb_info = framebuffer_alloc(0, NULL);

	/* 1.2 设置fb_info */
	/* a. var : LCD分辨率、颜色格式 */
	myfb_info->var.xres_virtual = myfb_info->var.xres = 500;
	myfb_info->var.yres_virtual = myfb_info->var.yres = 300

	/* 1.3 注册fb_info */
	register_framebuffer(myfb_info);

	/* 1.4 硬件操作 */
	mylcd_regs = ioremap(0x021C8000, sizeof(struct lcd_regs));
	mylcd_regs->fb_base_phys = phy_addr;
	mylcd_regs->fb_xres = 500;
	mylcd_regs->fb_yres = 300;
	mylcd_regs->fb_bpp  = 16;

	return 0;
}

static int mylcd_remove(struct platform_device *pdev)
{
	/* 反过来操作 */
	/* 2.1 反注册fb_info */
	unregister_framebuffer(myfb_info);
	/* 2.2 释放fb_info */
	framebuffer_release(myfb_info);
	iounmap(mylcd_regs);
	return 0;
}

static const struct of_device_id mylcd_of_match[] = {
	{ .compatible = "100ask,lcd_drv", },
	{ },
};
MODULE_DEVICE_TABLE(of, simplefb_of_match);

static struct platform_driver mylcd_driver = {
	.driver = {
		.name = "mylcd",
		.of_match_table = mylcd_of_match,
	},
	.probe = mylcd_probe,
	.remove = mylcd_remove,
};

static int __init lcd_drv_init(void)
{
	int ret;
	struct device_node *np;

	ret = platform_driver_register(&mylcd_driver);
	if (ret)
		return ret;

	return 0;
}

/* 2. 出口 */
static void __exit lcd_drv_exit(void)
{
	platform_driver_unregister(&mylcd_driver);
}

设备树信息

framebuffer-mylcd {
	compatible = "100ask,lcd_drv"; /*未待完续*/
};

1-7 LCD驱动程序框架_引脚配置

GPIO设置:配置LCD引脚和背光引脚GPIO,在设备树中设置pinctrl。
根据原理图确定需要配置那些引脚,打开引脚配置工具/设备树生成工具,把引脚配置成LCD引脚和背光引脚。
在这里插入图片描述
在这里插入图片描述
设备树节点信息和pinctrl信息(省略,如上图所示)

framebuffer-mylcd {
	compatible = "100ask,lcd_drv";
	pinctrl-names = "default";
    pinctrl-0 = <&mylcd_pinctrl>;
	backlight-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
};
/*probe函数获取GPIO*/
	/* get gpio from device tree */
	bl_gpio = gpiod_get(&pdev->dev, "backlight", 0);

	/* config bl_gpio as output */
	gpiod_direction_output(bl_gpio, 1);

	/* set val: gpiod_set_value(bl_gpio, status); */

1-8 LCD驱动程序框架_时钟配置

时钟设置:确定LCD控制器的时钟和根据LCD的DCLK计算相关时钟
翻阅芯片手册Chapter 34 Enhanced LCD Interface (eLCDIF),查看LCD时钟
在这里插入图片描述

设备树添加时钟属性

framebuffer-mylcd {
	compatible = "100ask,lcd_drv";
	pinctrl-names = "default";
    pinctrl-0 = <&mylcd_pinctrl>;
	backlight-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
	
	clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,
			<&clks IMX6UL_CLK_LCDIF_APB>,
       clock-names = "pix", "axi";

};

驱动代码添加设置时钟

/*probe函数中设置CLK*/
	/*get clk form device tree*/
	clk_pix = devm_clk_get(&pdev->dev,"pix");
	clk_axi = devm_clk_get(&pdev->dev,"axi");

	/*set clk rate*/
	/*clk_axi系统启动后自动设置
	*50Mhz以后会由设备树来设置
	*/
	clk_set_rate(clk_pix, 50000000);

	/*enable clk*/
	clk_prepare_enable(clk_pix);
	clk_prepare_enable(clk_axi);

1-9 LCD驱动程序框架_LCD控制器配置

LCD控制器本身的设置:设置Framebuffer的地址、设置Framebuffer中数据格式、LCD数据格式、设置时序
设备树

display = <&display0>;

display0: display {
	bits-per-pixel = <24>;
	bus-width = <24>;

	display-timings {
		native-mode = <&timing0>;

		 timing0: timing0_1024x600 {
		 clock-frequency = <50000000>;
		 hactive = <1024>;
		 vactive = <600>;
		 hfront-porch = <160>;
		 hback-porch = <140>;
		 hsync-len = <20>;
		 vback-porch = <20>;
		 vfront-porch = <12>;
		 vsync-len = <3>;

		 hsync-active = <0>;
		 vsync-active = <0>;
		 de-active = <1>;
		 pixelclk-active = <0>;
		 };

	};
};

驱动程序

	struct device_node *display_np;
	int ret;
	int bits_per_pixel;
	struct display_timings *timings = NULL;
	
	display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);

	/*get common info*/
	ret = of_property_read_u32(display_np, "bus-width", &width);
	ret = of_property_read_u32(display_np, "bits-per-pixel",
				   &bits_per_pixel);
	
	/*get timming*/
	timings = of_get_display_timings(display_np);

时序参数、引脚极性等信息,都被保存在一个display_timing结构体里:
在这里插入图片描述

1-10 LCD驱动程序框架_寄存器操作

设备树添加lcd物理地址

reg = <0x021c8000 0x4000>;

驱动程序在设备树中获取地址信息

	/* 1.4 硬件操作 */
	//lcdif = ioremap(0x021C8000, sizeof(*lcdif));
	
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	lcdif = devm_ioremap_resource(&pdev->dev, res);
  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很抱歉,我并不能完全理解您的问题。如果您是想了解关于嵌入式Linux机器人的开发,这需要考虑到硬件和软件两个方面。一般情况下,我们需要选择合适的硬件平台,并在其上安装嵌入式Linux系统,然后使用编程语言(如C/C++、Python等)编写机器人的控制程序。 以下是一个简单的示例代码,使用Python语言实现了一个基于嵌入式Linux机器人的前进和后退功能: ``` python import RPi.GPIO as GPIO import time # 设置GPIO口 GPIO.setmode(GPIO.BOARD) GPIO.setup(11, GPIO.OUT) GPIO.setup(13, GPIO.OUT) GPIO.setup(15, GPIO.OUT) GPIO.setup(19, GPIO.OUT) # 向前 def forward(): GPIO.output(11, GPIO.HIGH) GPIO.output(13, GPIO.LOW) GPIO.output(15, GPIO.HIGH) GPIO.output(19, GPIO.LOW) # 向后 def backward(): GPIO.output(11, GPIO.LOW) GPIO.output(13, GPIO.HIGH) GPIO.output(15, GPIO.LOW) GPIO.output(19, GPIO.HIGH) # 停止 def stop(): GPIO.output(11, GPIO.LOW) GPIO.output(13, GPIO.LOW) GPIO.output(15, GPIO.LOW) GPIO.output(19, GPIO.LOW) # 主函数 if __name__ == '__main__': try: while True: forward() time.sleep(2) stop() time.sleep(1) backward() time.sleep(2) stop() time.sleep(1) except KeyboardInterrupt: GPIO.cleanup() ``` 上述代码使用了树莓派(Raspberry Pi)的GPIO库,通过设置GPIO口的电平来控制机器人的前进和后退。当然,这只是一个简单的示例代码,实际的机器人开发还需要考虑到很多其他的因素,比如传感器、图像识别等等。 ### 回答2: 嵌入式Linux机器人的实现源代码可以分为几个关键方面: 1.硬件驱动程序:为了使机器人能够与外部设备进行通信和控制,需要编写硬件驱动程序。这些驱动程序可以包括控制底盘的驱动程序、传感器驱动程序、摄像头驱动程序等。 2.操作系统和内核定制:嵌入式Linux机器人需要一个适合嵌入式设备的操作系统和内核。在源代码中,我们需要对操作系统和内核进行定制,以满足机器人的需求。例如,可以选择定制轻量级的Linux发行版,去除不必要的组件和功能,加入对机器人硬件的支持等。 3.通信和控制程序:机器人要能够与其他设备、服务器或人机界面进行通信和控制。因此,我们需要编写通信和控制程序,以实现远程控制、信息传输等功能。这些程序可以使用网络协议、串口通信或其他通信方式。 4.感知和决策算法:机器人需要能够感知周围环境并做出相应决策。在源代码中,我们需要实现各种感知算法,如图像识别、目标跟踪、距离测量等,并结合决策算法,使机器人能够做出适当的行动。 5.用户界面和应用程序:为了更好地与机器人进行交互,我们可以编写用户界面和应用程序。这些程序可以包括机器人状态显示、地图生成、路径规划等。用户界面可以是图形化界面或命令行界面,根据实际需求进行选择。 总之,嵌入式Linux机器人的实现源代码是一个综合性的工程,需要涉及到硬件驱动、操作系统定制、通信和控制程序、感知和决策算法以及用户界面和应用程序等方面的编写和集成。这些源代码的编写需要深入理解嵌入式Linux系统的原理和机器人的工作原理,并结合实际的硬件和应用需求进行开发。 ### 回答3: 嵌入式Linux机器人的源代码实现可以包括以下几个方面: 1. 系统初始化:源代码需要实现嵌入式Linux系统的初始化,包括启动引导程序、加载内核镜像、初始化硬件设备、加载文件系统等。 2. 传感器驱动:机器人通常需要使用各种传感器来感知环境。源代码需要实现传感器驱动程序,以便与传感器进行通信和数据交换,如摄像头驱动、红外传感器驱动、超声波传感器驱动等。 3. 运动控制:机器人的运动控制涉及到电机、舵机等设备的驱动。源代码需要实现运动控制的相关算法,如PID控制算法、路径规划算法等,并与电机和舵机进行通信,控制机器人的运动。 4. 环境感知:源代码需要实现对机器人周围环境的感知和分析,以便进行智能决策。例如,图像处理算法可以用于识别目标物体,声音处理算法可以用于语音识别等。 5. 通信模块:机器人通常需要与其他系统进行通信,如与远程控制台进行通信、与其他机器人进行协作等。源代码需要实现通信模块,以便机器人能够与其他系统进行数据传输和指令交互。 6. 高级功能:根据机器人的具体应用场景,源代码还可以实现一些高级功能,如人脸识别、目标跟踪、自主导航等。这些功能需要依赖于相应的算法和模型,源代码需要与这些算法和模型进行集成。 总之,基于嵌入式Linux实现机器人的源代码包含了系统初始化、传感器驱动、运动控制、环境感知、通信模块以及各种高级功能的实现。这些源代码的编写需要结合具体的硬件平台和应用需求,并进行充分的调试和测试,确保机器人的正常运行和实现预期的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值