ZYNQ --- Linux成长之路 --- LCD显示屏

参考文章:

《3_领航者ZYNQ之嵌入式Linux开发指南_V2.2》---第50章LCD驱动实验

1、平台搭建

可以参考ZYNQ --- Linux成长之路 --- UIO引脚中断_GG_ber的博客-CSDN博客

的内容,LCD的引脚电路和正点原子的底板有些许的不同。

2、PL端设计

PL端的整体设计。在正点原子文档中P1179描述到:

它说LCD的像素时钟在《2_领航者ZYNQ之嵌入式SDK开发指南_V2.0》第十八章中所使用的IP核是AXI dynclk,而该章节中使用的是Clocking Wizard(推荐改为该IP核),说的是没啥区别。最终的PL端设计如下:

以下是各个IP核的参数设计

Clocking Wizard

Video Timing

AXI4-Stream to Video Out

rgb2lcd_V1_0

正点原子自己写的IP核,需要额外添加

AXI_GPIO

用来读LCD的ID号的

AXI Video Direct Memory Access

XDC文件内容

#----------------------LCD接口---------------------------
#--------- B 0-7 ---------
set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[0]}]
set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[1]}]
set_property -dict {PACKAGE_PIN F17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[2]}]
set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[3]}]
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[4]}]
set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[5]}]
set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[6]}]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[7]}]
#--------- G 0-7 ---------
set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[8]}]
set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[9]}]
set_property -dict {PACKAGE_PIN L19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[10]}]
set_property -dict {PACKAGE_PIN L20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[11]}]
set_property -dict {PACKAGE_PIN M18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[12]}]
set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[13]}]
set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[14]}]
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[15]}]
#--------- R 0-7 ---------
set_property -dict {PACKAGE_PIN J20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[16]}]
set_property -dict {PACKAGE_PIN H20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[17]}]
set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[18]}]
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[19]}]
set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[20]}]
set_property -dict {PACKAGE_PIN G20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[21]}]
set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[22]}]
set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb_0_tri_io[23]}]
#--------- LCD ---------
set_property -dict {PACKAGE_PIN F19  IOSTANDARD LVCMOS33} [get_ports lcd_0_hs]
set_property -dict {PACKAGE_PIN D20  IOSTANDARD LVCMOS33} [get_ports lcd_0_vs]
set_property -dict {PACKAGE_PIN D19  IOSTANDARD LVCMOS33} [get_ports lcd_0_de]
set_property -dict {PACKAGE_PIN C20  IOSTANDARD LVCMOS33} [get_ports lcd_bl_0]
set_property -dict {PACKAGE_PIN H16  IOSTANDARD LVCMOS33} [get_ports lcd_0_clk]
set_property -dict {PACKAGE_PIN B19  IOSTANDARD LVCMOS33} [get_ports lcd_rst_0]

3、Linux系统搭建

U-Boot: alientek-uboot-2018.01-xlnx-v2018.3

Kernel: alientek-linux-4.14.0-xlnx-v2018.3

这些都是正点原子论坛上面开源找的到的。

Linux系统的构建我主要使用Petalinux工具,和正点原子教程中方法不太一样。

通过Petalinux导入第2章编译好了的hdf硬件信息,在编译好了的Petalinux工程中(./components/plnx_workspace/device-tree/device-tree)可以找到pl.dtsi文件,该文件是对PL端硬件的设备树描述,主要有4个节点:axi_gpio_0、axi_vdma_0、clk_wiz_0、v_tc_0。如下:

在system-user.dtis(路径./project-spec/meta-user/recipes-bsp/device-tree/files)中添加设备树信息:


#define GPIO_ACTIVE_HIGH   0
#define GPIO_ACTIVE_LOW    1

/include/ "system-conf.dtsi"
/ {
};

&v_tc_0 {
	compatible = "xlnx,v-tc-5.01.a";
};

&amba_pl {

	xlnx_vdma_lcd {
		compatible = "xilinx,vdmafb";

		vtc = <&v_tc_0>;
		clocks = <&clk_wiz_0 0>;
		clock-names = "lcd_pclk";
		dmas = <&axi_vdma_0 0>;
		dma-names = "axi_vdma_0";

		lcdID-gpio = <&axi_gpio_0 0 0 GPIO_ACTIVE_LOW &axi_gpio_0 1 0 GPIO_ACTIVE_LOW &axi_gpio_0 2 0 GPIO_ACTIVE_LOW>;

		pixel-format = "RGB888";
		display-timings {
			timing_4342: timing0 {
				clock-frequency = <9000000>;
				hactive = <480>;
				vactive = <272>;
				hback-porch = <40>;
				hfront-porch = <5>;
				hsync-len = <1>;
				vback-porch = <8>;
				vfront-porch = <8>;
				vsync-len = <1>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <1>;
				pixelclk-active = <0>;
			};
			timing_4384: timing1 {
				clock-frequency = <31000000>;
				hactive = <800>;
				vactive = <480>;
				hback-porch = <88>;
				hfront-porch = <40>;
				hsync-len = <48>;
				vback-porch = <32>;
				vfront-porch = <13>;
				vsync-len = <3>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <1>;
				pixelclk-active = <0>;
			};
			timing_7084: timing2 {
				clock-frequency = <33300000>;
				hactive = <800>;
				vactive = <480>;
				hback-porch = <46>;
				hfront-porch = <210>;
				hsync-len = <1>;
				vback-porch = <23>;
				vfront-porch = <22>;
				vsync-len = <1>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <1>;
				pixelclk-active = <0>;
			};
			timing_7016: timing3 {
				clock-frequency = <51200000>;
				hactive = <1024>;
				vactive = <600>;
				hback-porch = <140>;
				hfront-porch = <160>;
				hsync-len = <20>;
				vback-porch = <20>;
				vfront-porch = <12>;
				vsync-len = <3>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <1>;
				pixelclk-active = <0>;
			};
			timing_1018: timing4 {
				clock-frequency = <71100000>;
				hactive = <1280>;
				vactive = <800>;
				hback-porch = <80>;
				hfront-porch = <70>;
				hsync-len = <10>;
				vback-porch = <10>;
				vfront-porch = <10>;
				vsync-len = <3>;
				hsync-active = <0>;
				vsync-active = <0>;
				de-active = <1>;
				pixelclk-active = <0>;
			};
		};
	};
};

设备树中修改了v_tc_0节点的compatible属性为"xlnx,v-tc-5.01.a",而原来系统自动生成的为“xlnx,v-tc-6.1”。这里修改是因为正点原子kernel中的lcd驱动文件(xilinx_vdmafc.c)所在目录下的vtc驱动文件(xilinx_vtc.c)中的of_match信息为"xlnx,v-tc-5.01.a",因此需要设备树与之对应。文件路径如下:

还有就是xlnx_vdma_lcd节点信息和正点原子的有所不同,修改了根节点引用的名字,去掉了pwms和reset-gpio的描述。对应的LCD驱动文件(xilinx_vdmafc.c)也要修改,如下:

1、删除了pwms和reset-gpio相关的代码

2、修改了驱动中的根节点名字

#include <linux/module.h>

#include <linux/platform_device.h>

#include <linux/fb.h>

#include <linux/clk.h>

#include <linux/dma/xilinx_dma.h>

#include <linux/of_dma.h>

#include <video/videomode.h>

#include <linux/delay.h>

#include <linux/of_gpio.h>

#include <video/of_videomode.h>

#include <linux/pwm.h>

#include "xilinx_vtc.h"





/* 正点原子LCD屏硬件ID */

#define ATK4342		0			// 4.3寸480*272

#define ATK4384		4			// 4.3寸800*480

#define ATK7084		1			// 7寸800*480

#define ATK7016		2			// 7寸1024*600

#define ATK1018		5			// 10寸1280*800



/* 自定义结构体用于描述我们的LCD设备 */

struct xilinx_vdmafb_dev {

	struct fb_info *info;			// FrameBuffer设备信息

	struct platform_device *pdev;	// platform平台设备

	struct clk *pclk;				// LCD像素时钟

	struct xilinx_vtc *vtc;			// 时序控制器

	struct dma_chan *vdma;			// VDMA通道

	int bl_gpio;					// LCD背光引脚

};



static int vdmafb_setcolreg(unsigned regno, unsigned red,

			unsigned green, unsigned blue,

			unsigned transp, struct fb_info *fb_info)

{

	u32 tmp;



	if (regno >= 16)

		return 1;



	red >>= 8; green >>= 8; blue >>= 8;

	tmp = (red << 16) | (green << 8) | blue;

	((u32*)(fb_info->pseudo_palette))[regno] = tmp;



	return 0;

}



static int vdmafb_check_var(struct fb_var_screeninfo *var,

			struct fb_info *fb_info)

{

	struct fb_var_screeninfo *fb_var = &fb_info->var;

	memcpy(var, fb_var, sizeof(struct fb_var_screeninfo));

	return 0;

}



/* Frame Buffer操作函数集 */

static struct fb_ops vdmafb_ops = {

	.owner 			= THIS_MODULE,

	.fb_setcolreg	= vdmafb_setcolreg,

	.fb_check_var	= vdmafb_check_var,

	.fb_fillrect	= cfb_fillrect,

	.fb_copyarea	= cfb_copyarea,

	.fb_imageblit	= cfb_imageblit,

};



static int vdmafb_init_fbinfo_dt(struct xilinx_vdmafb_dev *fbdev,

			struct videomode *vmode)

{

	struct device *dev = &fbdev->pdev->dev;

	int display_timing;

	int gpios[3];

	int lcd_id = 0;

	int ret;

	int i;



	/* 读取LCD屏ID */

	for (i = 0; i < 3; i++) {



		gpios[i] = of_get_named_gpio(dev->of_node, "lcdID-gpio", i);

		if (!gpio_is_valid(gpios[i])) {

			dev_err(dev, "Failed to get lcd id gpio\n");

			lcd_id = ATK4384;		// 设置为默认LCD屏 7寸800x480

			break;

		}



		ret = devm_gpio_request_one(dev, gpios[i], GPIOF_IN, "lcd hardware ID");

		if (ret < 0) {

			dev_err(dev, "Failed to request lcd id gpio\n");

			lcd_id = ATK4384;		// 设置为默认LCD屏 7寸800x480

			break;

		}



		lcd_id |= (gpio_get_value_cansleep(gpios[i]) << i);	// 读取GPIO数值

	}



	dev_info(dev, "LCD ID: %d \n", lcd_id);		// 打印ID值



	/* 再将ID引脚设置为输出模式 */

	msleep(5);		// 延时5ms

	for (i = 0; i < 3; i++)

		gpio_direction_output(gpios[i], 0);



	/* 根据LCD ID匹配对应的时序参数 */

	switch (lcd_id) {

	case ATK4342: display_timing = 0; break;

	case ATK4384: display_timing = 1; break;

	case ATK7084: display_timing = 2; break;

	case ATK7016: display_timing = 3; break;

	case ATK1018: display_timing = 4; break;

	default:

		display_timing = 2;

		dev_info(dev, "LCD ID Match failed, using default configuration\n");

		break;

	}



	ret = of_get_videomode(dev->of_node, vmode, display_timing);

	if (ret < 0) {

		dev_err(dev, "Failed to get videomode from DT\n");

		return ret;

	}



	return 0;

}



static int vdmafb_init_fbinfo(struct xilinx_vdmafb_dev *fbdev,

			struct videomode *vmode)

{

	struct device *dev = &fbdev->pdev->dev;

	struct fb_info *fb_info = fbdev->info;

	struct fb_videomode mode = {0};

	dma_addr_t fb_phys;		// 显存物理地址

	void *fb_virt;			// 显存虚拟地址

	unsigned fb_size;		// 显存大小

	int ret;



	/* 解析设备树获取LCD时序参数 */

	ret = vdmafb_init_fbinfo_dt(fbdev, vmode);

	if (ret < 0)

		return ret;



	/* 申请LCD显存 */

	fb_size = vmode->hactive * vmode->vactive * 3;

	fb_virt = dma_alloc_wc(dev, PAGE_ALIGN(fb_size), &fb_phys, GFP_KERNEL);

	if (!fb_virt)

		return -ENOMEM;



	memset(fb_virt, 0, fb_size);	// 显存清零



	/* 初始化fb_info */

	fb_info->fbops = &vdmafb_ops;

	fb_info->flags = FBINFO_FLAG_DEFAULT;

	fb_info->screen_base = fb_virt;

	fb_info->screen_size = fb_size;



	strcpy(fb_info->fix.id, "xlnx");

	fb_info->fix.type = FB_TYPE_PACKED_PIXELS;

	fb_info->fix.visual = FB_VISUAL_TRUECOLOR,

	fb_info->fix.accel = FB_ACCEL_NONE;

	fb_info->fix.line_length = vmode->hactive * 3;

	fb_info->fix.smem_start = fb_phys;

	fb_info->fix.smem_len = fb_size;



	fb_info->var.grayscale   = 0;		// 彩色

	fb_info->var.nonstd      = 0;		// 标准像素格式

	fb_info->var.activate    = FB_ACTIVATE_NOW;

	fb_info->var.accel_flags = FB_ACCEL_NONE;

	fb_info->var.bits_per_pixel = 24;	// 像素深度(bit位)

	//fb_info->var.width  = xxx;	LCD屏的物理宽度(单位毫米)

	//fb_info->var.height = yyy;	LCD屏的物理高度(单位毫米)



	fb_info->var.xres = fb_info->var.xres_virtual = vmode->hactive;

	fb_info->var.yres = fb_info->var.yres_virtual = vmode->vactive;

	fb_info->var.xoffset = fb_info->var.yoffset = 0;



	fb_info->var.red.offset = 0;

	fb_info->var.red.length = 8;

	fb_info->var.green.offset = 8;

	fb_info->var.green.length = 8;

	fb_info->var.blue.offset = 16;

	fb_info->var.blue.length = 8;

	fb_info->var.transp.offset = 0;

	fb_info->var.transp.length = 0;



	fb_videomode_from_videomode(vmode, &mode);

	fb_videomode_to_var(&fb_info->var, &mode);



	return 0;

}



static int vdmafb_init_vdma(struct xilinx_vdmafb_dev *fbdev)

{

	struct device *dev = &fbdev->pdev->dev;

	struct fb_info *info = fbdev->info;

	struct dma_interleaved_template dma_template = {0};

	struct dma_async_tx_descriptor *tx_desc;

	struct xilinx_vdma_config vdma_config = {0};



	/* 申请VDMA通道 */

	fbdev->vdma = of_dma_request_slave_channel(dev->of_node, "axi_vdma_0");

	if (IS_ERR(fbdev->vdma)) {

		dev_err(dev, "Failed to request vdma channel\n");

		return PTR_ERR(fbdev->vdma);

	}



	/* 终止VDMA通道数据传输 */

	dmaengine_terminate_all(fbdev->vdma);



	/* 初始化VDMA通道 */

	dma_template.dir         = DMA_MEM_TO_DEV;

	dma_template.numf        = info->var.yres;

	dma_template.sgl[0].size = info->fix.line_length;

	dma_template.frame_size  = 1;

	dma_template.sgl[0].icg  = 0;

	dma_template.src_start   = info->fix.smem_start;	// 物理地址

	dma_template.src_sgl     = 1;

	dma_template.src_inc     = 1;

	dma_template.dst_inc     = 0;

	dma_template.dst_sgl     = 0;



	tx_desc = dmaengine_prep_interleaved_dma(fbdev->vdma, &dma_template,

			DMA_CTRL_ACK | DMA_PREP_INTERRUPT);

	if (!tx_desc) {

		dev_err(dev, "Failed to prepare DMA descriptor\n");

		dma_release_channel(fbdev->vdma);

		return -1;

	}



	vdma_config.park = 1;

	xilinx_vdma_channel_set_config(fbdev->vdma, &vdma_config);



	/* 启动VDMA通道数据传输 */

	dmaengine_submit(tx_desc);

	dma_async_issue_pending(fbdev->vdma);



	return 0;

}



static int vdmafb_init_vtc(struct xilinx_vdmafb_dev *fbdev,

			struct videomode *vmode)

{

	struct device_node *node;

	struct device *dev = &fbdev->pdev->dev;



	/* 解析设备树得到vtc节点 */

	node = of_parse_phandle(dev->of_node, "vtc", 0);

	if (!node) {

		dev_err(dev, "Failed to parse VTC phandle 001 \n");

		return -ENODEV;

	}



	/* 获取vtc */

	fbdev->vtc = xilinx_vtc_probe(dev, node);

	of_node_put(node);

	if (IS_ERR(fbdev->vtc)) {

		dev_err(dev, "Failed to probe VTC\n");

		return PTR_ERR(fbdev->vtc);

	}



	xilinx_vtc_reset(fbdev->vtc);	// 复位vtc

	xilinx_vtc_disable(fbdev->vtc);	// 禁止vtc

	xilinx_vtc_config_sig(fbdev->vtc, vmode);	// 配置vtc时序参数

	xilinx_vtc_enable(fbdev->vtc);	// 使能vtc



	return 0;

}



static int vdmafb_probe(struct platform_device *pdev)

{

	struct xilinx_vdmafb_dev *fbdev;

	struct fb_info *info;

	struct videomode vmode;

	int ret;



	/* 实例化一个fb_info结构体对象 */

	info = framebuffer_alloc(sizeof(struct xilinx_vdmafb_dev), &pdev->dev);

	if (!info) {

		dev_err(&pdev->dev, "Failed to allocate memory\n");

		return -ENOMEM;

	}



	fbdev = info->par;

	fbdev->info = info;

	fbdev->pdev = pdev;



	/* 获取LCD所需的像素时钟 */

	fbdev->pclk = devm_clk_get(&pdev->dev, "lcd_pclk");

	if (IS_ERR(fbdev->pclk)) {

		dev_err(&pdev->dev, "Failed to get pixel clock\n");

		ret = PTR_ERR(fbdev->pclk);

		goto out1;

	}



	clk_disable_unprepare(fbdev->pclk);		// 先禁止时钟输出



	/* 初始化info变量 */

	ret = vdmafb_init_fbinfo(fbdev, &vmode);

	if (ret)

		goto out1;



	ret = fb_alloc_cmap(&info->cmap, 256, 0);

	if (ret < 0) {

		dev_err(&pdev->dev, "Failed to allocate color map\n");

		goto out2;

	}



	info->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16, GFP_KERNEL);

	if (!info->pseudo_palette) {

		ret = -ENOMEM;

		goto out3;

	}



	/* 设置LCD像素时钟、使能时钟 */

	clk_set_rate(fbdev->pclk, PICOS2KHZ(info->var.pixclock) * 1000);

	clk_prepare_enable(fbdev->pclk);

	msleep(5);  // delay



	/* 初始化LCD时序控制器vtc */

	ret = vdmafb_init_vtc(fbdev, &vmode);

	if (ret)

		goto out4;



	/* 初始化LCD VDMA */

	ret = vdmafb_init_vdma(fbdev);

	if (ret)

		goto out5;



	/* 注册FrameBuffer设备 */

	ret = register_framebuffer(info);

	if (ret < 0) {

		dev_err(&pdev->dev,"Failed to register framebuffer device\n");

		goto out6;

	}



	platform_set_drvdata(pdev, fbdev);

	return 0;



out7:

	unregister_framebuffer(info);	// 卸载FrameBuffer设备



out6:

	dmaengine_terminate_all(fbdev->vdma);	// 终止VDMA通道所有数据传输

	dma_release_channel(fbdev->vdma);		// 释放VDMA通道



out5:

	xilinx_vtc_disable(fbdev->vtc);			// 禁止vtc时序控制器



out4:

	clk_disable_unprepare(fbdev->pclk);		// 禁止时钟输出



out3:

	fb_dealloc_cmap(&info->cmap);			// 销毁colormap



out2:

	dma_free_wc(&pdev->dev, info->screen_size,	// 释放DMA内存

				info->screen_base, info->fix.smem_start);



out1:

	framebuffer_release(info);				// 释放fb_info对象

	return ret;

}



static int vdmafb_remove(struct platform_device *pdev)

{

	struct xilinx_vdmafb_dev *fbdev = platform_get_drvdata(pdev);

	struct fb_info *info = fbdev->info;



	unregister_framebuffer(info);

	dmaengine_terminate_all(fbdev->vdma);

	dma_release_channel(fbdev->vdma);

	xilinx_vtc_disable(fbdev->vtc);

	clk_disable_unprepare(fbdev->pclk);

	fb_dealloc_cmap(&info->cmap);

	dma_free_wc(&pdev->dev, info->screen_size,

				info->screen_base, info->fix.smem_start);

	framebuffer_release(info);

	return 0;

}



static void vdmafb_shutdown(struct platform_device *pdev)

{

	struct xilinx_vdmafb_dev *fbdev = platform_get_drvdata(pdev);

	xilinx_vtc_disable(fbdev->vtc);

	clk_disable_unprepare(fbdev->pclk);

}



static const struct of_device_id vdmafb_of_match_table[] = {

	{ .compatible = "xilinx,vdmafb", },

	{ /* end of table */ },

};

MODULE_DEVICE_TABLE(of, vdmafb_of_match_table);



static struct platform_driver xilinx_vdmafb_driver = {

	.probe    = vdmafb_probe,

	.remove   = vdmafb_remove,

	.shutdown = vdmafb_shutdown,

	.driver = {

		.name           = "xilinx-vdmafb",

		.of_match_table = vdmafb_of_match_table,

	},

};



module_platform_driver(xilinx_vdmafb_driver);



MODULE_DESCRIPTION("Framebuffer driver based on Xilinx VDMA IP Core.");

MODULE_AUTHOR("GGber, Inc.");

MODULE_LICENSE("GPL v2");

由于用的是正点原子的内核,内核默认LCD驱动是开着的,不放心的可以自己确定一下。剩下的就可以参考正点原子的流程来做了,最终我这边实现效果如下:

 目前只有显示,还没加触摸屏驱动,下一章节更新~~~

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Zynq-7000系列之linux开发学习笔记是一系列关于在Zynq7030数据采集板上进行Linux开发的文章。在这些文章中,作者提供了关于编译Linux内核、制作设备树、安装NFS等方面的指导和经验。在其中一篇文章中,作者遇到了在挂载NFS时出现的问题,提示"wrong fs type, bad option, bad superblock"等错误信息。作者还提供了Linux内核源码的下载链接以及开发环境的相关信息。整个学习笔记的目标是让开发板能够连接外网,并通过NFS挂载到虚拟机上运行一个helloworld程序。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *3* [Zynq-7000系列之linux开发学习笔记:NFS配置与开发板联网(七)](https://blog.csdn.net/Claudedy/article/details/94591622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Zynq-7000系列之linux开发学习笔记:编译Linux内核和制作设备树(六)](https://blog.csdn.net/Claudedy/article/details/90760085)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值