驱动开发学习

这篇具有很好参考价值的文章主要介绍了驱动开发学习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

驱动

1、驱动开发环境

完成系统移植的三步:u-boot启动引导程序、内核镜像、文件系统,u-boot启动引导程序最好固化到开发板上,内核镜像通过tftp服务从ubuntu下载,文件系统通过nfs服务从ubuntu共享到开发板,开发板启动计数时按任意键进入u-boot命令模式设置bootcmd和bootargs

# setenv serverip 192.168.3.120
# setenv ipaddr 192.168.3.233
# setenv bootcmd tftp 41000000 uImage\;tftp 42000000 exynos4412-fs4412.dtb\;bootm 41000000 – 42000000\;
#setenv bootargs root=/dev/nfs\; nfsroot=192.168.3.120:/source/rootfs rw console=ttySAC2,115200  init=/linuxrc  ip=192.168.3.233
# saveenv

注意:192.168.3.120 对应Ubuntu的ip

192.168.3.233 对应板子的ip

这两个ip应该根据自己的实际情况适当修改

重启开发板进入自启动模式自动加载内核和文件系统

2、驱动开发工具使用source insight软件和vim工具,当然如果不想频繁地从Windows复制到ubuntu可以使用共享文档,这样就可以在Windows上写好代码在ubuntu中直接编译。

设置共享文档步骤:

  1. 打开VMware,选择虚拟机设置选择选项选择共享文件夹,点击总是启用,点击添加就可以设置共享文件夹了

  2. 设置完成后可以在ls /mnt/hgfs查看共享目录是否挂载

  3. 如果没有挂载可以通过vmware-hgfsclient查看共享文件夹

  4. 挂载共享文件夹命令vmhgfs-fuse .host:/my /mnt/hgfs其中my是查看共享文件夹时显示的名字,/mnt/hgfs是挂载路径,挂载路径必须是空的文件夹否则可能失败

source insight---查看和编写代码工具

  1. 将ubuntu中的linux内核代码复制到Windows中

  2. 在source insight中新建项目

    在第一个对话框中,第一个文本框(行编辑器),输入工程的名字

    在第二个对话框中,第一个本文框中选择刚解压的Linux内核源码目录(顶层linux-3.14),点击ok

    在第三个对话框中,在对话框中选择要查看的目录/文件 需要选择的目录文件: include init kernel arch/arm/kernel arch/arm/include/asm driver/base driver/char driver/i2c driver/spi fs/char_dev.c 点击close关闭

    重新选择project---->open project ​ 选择刚才创建的工程名 ​ ok ​ 如果提示同步,则选择确认进行同步

  3. 开始编写驱动代码

    驱动代码必须包含四部分:

    a.头文件

    #include <linux/init.h>
    #include <linux/module.h>

    b.加载和卸载时的函数定义

    static int __init hello_init(void)
    {
        return 0;
    }
    ​
    static void __exit hello_exit(void)
    {
    ​
    }

    c.加载和卸载的入口声明

    module_init(hello_init);//当使用insmod 驱动名称.ko 加载驱动时执行函数hello_init()
    module_exit(hello_exit);//当使用remod 驱动名称 卸载驱动时执行函数hello_exit()

    d.协议选择GPL

    MODULE_LICENSE("GPL");

    3、驱动操作

    a.加载驱动使用命令

    insmod 驱动程序路径.ko

    b.加载好驱动后可以通过命令查看驱动

    lsmod

    c.卸载驱动命令(不用加.ko)

    rmmod 驱动程序名

    字符设备驱动创建框架

    1、申请设备号

    int register_chrdev(unsigned int major,const char *name,const struct file_operations *fops)
    参数1:unsigned int major------大于0则是申请对应的主设备号;等于0则是由内核分配主设备号
    参数2:const char *name------是注册时的名字
    参数3:const struct file_operations *fops------是用来关联文件IO接口的结构体
    返回值:当参数1大于0时,正确返回0,失败返回负数
           当参数1等于0时,正确返回主设备号,失败返回负数

    2、创建设备节点(生成对应的驱动文件)

    1. 创建文件信息结构体

      struct class * class_create(owner,name);
      参数1:owner-----拥有者,一般THIS_MODULE
      参数2:name-----字符串,描述信息
      返回值:struct class *------信息结构体       
    2. 创建字符驱动设备文件(节点),一般默认建在/dev下,但是可以在任意目录下创建

      struct device *device_create(   struct class *class,struct device *parent,dev_t devt,void *drvdata,const char *fmt, ...)
      参数1:struct class *class--------class结构体,创建的设备文件的信息内容,通过 class_create()函数创建
      参数2:struct device *parent--------表示父类对象,一般直接写NULL,结构体地址
      参数3:dev_t devt--------设备号可以有函数MKDEV(ma, mi)获得,ma------主设备号, mi------次设备号,也可以由主设备号左移20位或上一个数字得到这个数字不能大于2^20,例:major<<20|0
      参数4:void *drvdata-------私有数据,一般填NULL
      参数5:const char *fmt, ...--------设备文件名字符串首地址
      返回值:struct device *---------设备节点对象(设备文件描述),成功返回地址,失败返回NULL
    3. 文件IO接口层实现,应用程序调用文件io时,驱动程序也调用对应的文件io接口函数 在结构体 struct file_operations 每一个成员变量都代表绑定一个系统调用(文件io)函数,只要对结构体中的成员赋值,就代表值绑定上一个文件io函数

      struct file_operations {
      		struct module *owner;
      		loff_t (*llseek) (struct file *, loff_t, int);
      		ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
      		ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
      		ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
      		ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
      		int (*iterate) (struct file *, struct dir_context *);
      		unsigned int (*poll) (struct file *, struct poll_table_struct *);
      		long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
      		long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
      		int (*mmap) (struct file *, struct vm_area_struct *);
      		int (*open) (struct inode *, struct file *);
      		int (*flush) (struct file *, fl_owner_t id);
      		int (*release) (struct inode *, struct file *);
      		int (*fsync) (struct file *, loff_t, loff_t, int datasync);
      		int (*aio_fsync) (struct kiocb *, int datasync);
      		int (*fasync) (int, struct file *, int);
      		int (*lock) (struct file *, int, struct file_lock *);
      		ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
      		unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
      		int (*check_flags)(int);
      		int (*flock) (struct file *, int, struct file_lock *);
      		ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
      		ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
      		int (*setlease)(struct file *, long, struct file_lock **);
      		long (*fallocate)(struct file *file, int mode, loff_t offset,
      			  loff_t len);
      		int (*show_fdinfo)(struct seq_file *m, struct file *f);
      	};//函数指针的集合,
    4. 驱动控制硬件,控制外设,其实就是控制地址,通过地址往寄存器写入、读出控制 内核驱动是通过虚拟地址操作 初始化硬件

      地址映射:
      void * ioremap(cookie,size);
      参数1:cookie-----物理地址
      参数2:size-----映射内容大小,字节
      返回值:返回映射成功后的虚拟内存地址
      操作虚拟内存地址中的内容就是操作对应的物理地址空间内容

    字符设备驱动卸载时需要的函数

    在卸载入口中实现,清除 与初始化逆序过程进行卸载

    //1、映射释放(中断释放)
    iounmap(映射的虚拟内存地址);----释放映射地址
    //2、释放设备文件
    void device_destroy(struct class * class,dev_t devt);
    //3、释放设备文件结构体
    void class_destroy(struct class * cls)
    //4、释放设备号
    void unregister_chrdev(unsigned int major,const char * name)

    字符驱动模型举例:

    通过字符设备驱动控制一颗LED灯

    //头文件包含
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <asm/io.h>
    
    #include <asm/uaccess.h>
    //使用结构体表示一个驱动对象(面向对象的编程思想)
    struct Led_Dev
    {
    unsigned int *gpx1con;
    unsigned int *gpx1dat;
    struct class * class;
    struct device * dev;
    unsigned int major;
    unsigned int dev_no;
    };
    struct Led_Dev led;
    //4、文件IO功能与设备功能实现绑定
    ssize_t led_read (struct file * flie, char __user * data, size_t size, loff_t * ops)
    {
            return 0;
    }
    ssize_t led_write (struct file * file, const char __user * data, size_t size, loff_t * ops)
    {
            //data是应用程序传递的数据的地址,size 传递的大小
            int num;
            copy_from_user(&num,data,size);//从应用程序获取数据存到num中
           
            if(num==1)
            {
                    *(led.gpx1dat) |= 1;
            }
            else
            {
                    *(led.gpx1dat) &= ~1;
            }
    
            return 0;
    }
    int led_open (struct inode * inode, struct file * file)
    {
            printk("open ok\n");
            return 0;
    }
    int led_close (struct inode * inode, struct file * file)
    {
            printk("close ok\n");
            return 0;
    }
    
    
    const struct file_operations fops=
    {
    	.open = led_open,
    	.release = led_close,
    	.write = led_write
    
    };
    
    //驱动加载与卸载函数实现
    static int __init led_init(void)
    {
    	led.major = 250;
    	led.dev_no = led.major<<20|0;
    //1、申请设备号
    	
    	
    	int res = register_chrdev(led.major,"led_dev",&fops);
    	if(res !=0 )
    	{
    		printk("register dev error\n");
    		goto err_1;
    		//return -1;
    	}
    //2、创建设备文件
    	led.class = class_create(THIS_MODULE,"led_cls");
    	if (IS_ERR(led.class))
    	{
    		printk("class create error\n");
    		goto err_2;
    		//unregister_chrdev(major,name);
    		//return -1;
    	}		
    	led.dev = device_create(led.class, NULL, led.dev_no,NULL,"led");
    	if(IS_ERR(led.dev))
    	{
    		printk("device create error\n");
    		goto err_3;
    		//class_destroy(class);
    		//unregister_chrdev(major,name);
    		//return -1;
    	}
    //3、驱动设备控制硬件
    	//硬件寄存器地址映射
    	led.gpx1con = ioremap(0x11000c20, 4);
    	if(led.gpx1con==NULL)
    	{
    		printk("gpx1con ioremap error\n");
    		goto err_4;
    		//device_destroy(class, dev_no);
    		//class_destroy(class);
    		//unregister_chrdev(major,name);
    		//return -1;
    	}
    	led.gpx1dat = ioremap(0x11000c24, 4);
    	if(led.gpx1dat==NULL)
    	{
    		printk("gpx1dat ioremap error\n");
    		goto err_5;
    		//iounmap(gpx1con);
    		//device_destroy(class, dev_no);
    		//class_destroy(class);
    		//unregister_chrdev(major,name);
    		//return -1;
    	}
    	//硬件初始化
    	*(led.gpx1con) = *(led.gpx1con) & ~0xf | 1;
    	*(led.gpx1dat) |= 1;
    	return 0;
     //出错处理的代码   
    err_5:
    	//1、映射地址释放
    	iounmap(led.gpx1con);
    	
    err_4:	//2、设备文件释放
    	device_destroy(led.class,led.dev_no);//释放设备文件
    
    err_3:
    	class_destroy(led.class);//释放文件信息结构体
    	
    err_2:	//3、驱动设备号注销
    	unregister_chrdev(led.major,"led_dev");
    	
    err_1:
    	return -1;
    }
    
    
    static void __exit led_exit(void)
    {
    	//卸载驱动,与初始化逆序
    	//1、映射地址释放
    	iounmap(led.gpx1con);
    	iounmap(led.gpx1dat);
    	//2、设备文件释放
    		
    	device_destroy(led.class, led.dev_no);//释放设备文件
    	class_destroy(led.class);//释放文件信息结构体
    
    	//3、驱动设备号注销
    	
    	unregister_chrdev(led.major,"led_dev");
    	
    }
    
    //驱动加载与卸载
    module_init(led_init);
    module_exit(led_exit);
    
    //协议包含GPL
    MODULE_LICENSE("GPL");

    驱动中实现中断

    中断驱动---检测外部中断 获取外设的数据内容,通过中断信号进行获取 在驱动中设置外设为中断模式:当外设产生设定的特定信号(就是中断) 在驱动中实现中断处理操作(函数)

    本文以按键中断为例

    需要使用按键设备,需要先在设备树中说明使用的按键是一个中断设备,我使用的板子是Samsung的Exynos系列,按键使用的是KEY3

    驱动开发学习

     

开发板管脚

驱动开发学习

 

查看数据手册得到GPX1_2使用的中断是XEINT_10

驱动开发学习

 

驱动开发学习

 

在设备树中:arch/arm/boot/dts/exynos4x12-pinctrl.dtsi

	gpx1: gpx1 {
                    		gpio-controller;
                    		#gpio-cells = <2>;

                   		interrupt-controller;
                    		interrupt-parent = <&gic>;
                    		interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
                             		    	<0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
                    		#interrupt-cells = <2>;
           	 	};

	在设备树中添加自己的硬件设备信息---添加key3节点-----描述当前设备的的信息内容(中断号)
	arch/arm/boot/dts/exynos4412-fs4412.dts:实现硬件描述(中断号)
	
	key3_node {
                    		compatible = "key3";
                    		interrupt-parent = <&gpx1>;
                   		interrupts = <2 4>;//26
    		};

在驱动中申请中断,实现中断处理

a、获取到中断号
	获取设备树节点,返回值就是从设备树中找到的节点
	struct device_node *of_find_node_by_path(const char *path);

	从节点中获取到中断号,返回值就是中断号
	unsigned int irq_of_parse_and_map(struct device_node *dev,int index);

b、申请中断
	int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
	参数1:
		unsigned int irq:申请中断的中断号

	参数2:
		irqreturn_t (*)(int, void *)    ----   irq_handler_t
		irq_handler_t handler:函数指针,进行注册中断,当产生中断时调用对应的函数进行处理
	参数3:
		unsigned long flags:中断处理的触发方式
		#define IRQF_TRIGGER_NONE	0x00000000
		#define IRQF_TRIGGER_RISING	0x00000001
		#define IRQF_TRIGGER_FALLING	0x00000002
		#define IRQF_TRIGGER_HIGH	0x00000004
		#define IRQF_TRIGGER_LOW	0x00000008

	参数4:
		const char *name:字符串首地址,中断的描述信息
			/proc/inruppter
	参数5:
		void *dev:传递给参数2的函数进行自动调用的(作为参数2这个函数的参数)

	返回值:
		成功返回0,失败返回非0
	释放中断:
	void free_irq(unsigned int irq,void * dev_id)
	参数1:
		unsigned int irq
		中断号
	参数2:
		void * dev_id:与申请中断第五个参数保持一致

中断分上下两部分:

上部分处理时间短、不费时间的中断处理

下部分处理一些费时间的中断

下部分就是将耗时操作延后处理,一般在上半部分的处理函数中调用

1、softirq:软中断,处理级别比较高,在内核机制中,需要修改内核源码功能 ​ 2、tasklet:实际上就是内部调用了softirq ​ 3、workqueue:工作队列

驱动中申请中断举例:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/wait.h>

#include <asm/io.h>
#include <asm/uaccess.h>

char c;

struct key_desc{
	unsigned int major;
	struct class * cls;
	dev_t devno;
	struct device * dev;
	}key;

irqreturn_t key_irq_handler(int i, void * j)
{
	c='q';
	printk("irqno : %d;input char %c\n",i,c);

	return IRQ_HANDLED;
}


//3、文件IO接口功能关联
ssize_t key_read (struct file * file, char __user * data, size_t size, loff_t * ops)
{
	
	printk("key read\n");
	int n = copy_to_user(data, &c, 1);
	c='w';
	return 0;
}
int key_open (struct inode * inode , struct file * file)
{
	printk("key open\n");
	return 0;
}

int key_release (struct inode * inode , struct file *file)
{
	printk("key close\n");
	return 0;
}

const struct file_operations fops = {
	.read = key_read,
	.release = key_release,
	.open = key_open
};

static int __init keydev_init(void)
{
	key.major = 252;
	//1、申请设备号
	int res = register_chrdev( key.major,"key", &fops);
	if(res<0)
	{
		goto err1;	
		
	}
	//2、设备文件
	key.cls = class_create(THIS_MODULE, "cls");
	if(IS_ERR(key.cls))
	{
		goto err2;	
		
	}
	key.devno = key.major << 20 | 0;
	key.dev = device_create(key.cls, NULL,key.devno ,NULL,"key_dev");
	if(IS_ERR(key.dev))
	{
		goto err3;	
		
	}
	//4、硬件初始化
	//a.获取中断号
	struct device_node * node = of_find_node_by_path("/key3");//查找设备树中节点为key_3
	if(IS_ERR(node))
	{
		goto err4;	
		
	}
	int irqno = irq_of_parse_and_map(node, 0);//申请中断号
	if(irqno<0)
	{
		goto err5;
	}
	//b.申请中断
	res = request_irq(irqno, key_irq_handler,IRQF_TRIGGER_FALLING,"key_in", NULL);
	if(res<0)
	{
		goto err6;
	}
	return 0;
err6:
	irqno = -1;

err5:
	node=NULL;

err4:
	device_destroy(key.cls, key.devno);

err3:
	class_destroy(key.cls);

err2:
	unregister_chrdev(key.major, "key");

err1:
	return -1;
}

static void __exit key_exit(void)
{

	device_destroy(key.cls, key.devno);
	class_destroy(key.cls);
	unregister_chrdev(key.major, "key");
}

module_init(keydev_init);
module_exit(key_exit);

MODULE_LICENSE("GPL");






测试程序

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>


int main()
{


	char buf;
	int num;
	int fd = open("/dev/key_dev",O_RDONLY);
	while(1)
	{
		
		num=0;
		num = read(fd,&buf,1);
		printf("%d%c\n",num,buf);
	}
	return 0;
}

Makefile

#编译驱动代码
KERNEL_PATH = /home/ubuntu/code/kernel/linux-3.14
#APP=beep_test#测试程序的名字不包括后缀
MODULES_PATH = $(shell pwd)
obj-m += key_int.o #把.c编译为.o文件注意.o前的名字与驱动文件名字一致

#编译为驱动程序.ko 要借助已经编译过的内核
all:
	make modules -C $(KERNEL_PATH) M=$(MODULES_PATH)
#	arm-none-linux-gnueabi-gcc $(APP).c -o $(APP)

install:
#	cp *.ko $(APP) /home/ubuntu/rootfs
	cp *.ko /home/ubuntu/rootfs

驱动中的阻塞IO与非阻塞IO实现

驱动中实现阻塞: 要创建等待队列头: wait_queue_head_t head; init_waitqueue_head(&head);

	1、在需要等待的位置(没有数据),就阻塞等待
		
		wait_event_interruptible(wq,condition)-----根据参数是否进行阻塞等待,完成阻塞等待

		参数1:
			wq:等待队列头,把当前进程加入到哪个等待队列中

		参数2:
			condition:是否执行阻塞等待的条件

			condition:真---不进行阻塞
			condition:假---进行阻塞

	2、合适位置进行阻塞唤醒
		wake_up_interruptible(&head);

非阻塞:在进行读写操作时,如果没有数据,就立即返回,如果有数据读取数据然后立即返回 应用程序:设置为非阻塞打开 int fd = open("/dev/key3",O_RDONLY | O_NONBLOCK);

	驱动文件中在阻塞前面添加:
	if((file->f_flags & O_NONBLOCK != 0) && (condition == 0))
		return -1;

驱动总线模型: 驱动框架: 0、声明实现入口函数(module_init、module_exit) 1、申请设备号(register_chrdev) 2、创建设备节点(class_create、device_create) 3、硬件初始化 ioremap地址映射 中断申请 4、实现文件IO接口

总线模型: 总线bus 驱动driver 设备device

总线bus: struct bus_type:总线对象,描述一条总线,管理device、driver,进行匹配

struct bus_type
{
	const char		*name;:总线名字
	int (*match)(struct device *dev, struct device_driver *drv);总线调用匹配设备和驱动,返回值就表示匹配成功与否
};

注册总线: ​ int bus_register(struct bus_type * bus); ​ 参数: ​ struct bus_type * bus:总线对象 ​ 注销总线: ​ void bus_unregister(struct bus_type * bus);

驱动driver: struct device_driver :驱动对象,描述一个驱动,对驱动进行说明

struct device_driver { ​ const char *name;:驱动的名字 ​ struct bus_type bus;总线对象,表示要把驱动注册到哪条总线 ​ int (probe) (struct device dev);如果匹配成功,则调用该驱动的probe函数,创建驱动(申请设备号。。。) ​ int (remove) (struct device *dev);当设备对象和驱动对象移除总线时会调用 ​ } ​ 注册驱动到总线: ​ int driver_register(struct device_driver * drv); ​ 从总线上注销: ​ void driver_unregister(struct device_driver * drv);

设备device: struct device { struct kobject kobj;//所有对象的父类 const char *init_name;设备名 struct bus_type *bus;总线对象,表示要把设备注册到哪条总线 void platform_data;自定义数据,指向任意类型,可以存储设备信息 void (release)(struct device *dev);设备对象从总线移除时会调用 }; 注册设备到总线: int device_register(struct device * dev); 从总线上注销: void device_unregister(struct device * dev);文章来源地址https://www.toymoban.com/news/detail-454714.html

到了这里,关于驱动开发学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 1.1 Windows驱动开发:配置驱动开发环境

    在进行驱动开发之前,您需要先安装适当的开发环境和工具。首先,您需要安装Windows驱动开发工具包(WDK),这是一组驱动开发所需的工具、库、示例和文档。然后,您需要安装Visual Studio开发环境,以便编写和调试驱动程序。在安装WDK和Visual Studio之后,您还需要配置适当的

    2024年02月03日
    浏览(45)
  • 【IMX6ULL驱动开发学习】02.IMX6ULL烧写Linux系统

    由于我买的是正点原子的IMX6ULL阿尔法开发板,但是我是看韦东山老师视频学习的驱动 所以这里我烧录的方法是按照韦东山老师的课程来的 这里给出烧写Linux系统用到的工具 链接:https://pan.baidu.com/s/1bD-xxn3K8xQAVkJSaJmTzQ 提取码:af6w 下载解压后,可以看到烧写工具 烧写Linux系统

    2024年02月13日
    浏览(58)
  • 【inBuilder 低代码开发实验室】使用inbuilder完成商户表单UBML低代码开发-mac环境

    本次开放原子训练营开启inBuilder低代码实验室,包含5次课程,基于浪潮nBuilder低代码开发平台社区版(基于UBML开源项目的一个可以广泛使用的发行版),体验向导式、可视化、拖拽式开发方式,实现数字化转型中的场景应用。参与者通过训练营的学习和实践,掌握低代码开发的

    2024年02月10日
    浏览(38)
  • 一天时间完成Python入坑(开发环境搭建、excel解析、exe打包三步走)

            早就知道Python好,Python妙,Python用起来呱呱叫。工作上一直没有什么用得上Python的必要性,就一直没有接触,本次终于来了机会: 【图新地球桌面端要对外开放Python API】 ,开放图新地球的三维场景构建能力给到用户,用户可以在图新地球现有功能的基础上专注于做

    2024年02月10日
    浏览(42)
  • linux驱动开发环境搭建

    使用的是parallel 创建的ubuntu 16.04 ubuntu20.04虚拟机 在编译的时候把虚拟机分配8核,8G内存,开发的时候2核,4G内存就够了 https://blog.csdn.net/inf4inf/article/details/110272531 https://blog.csdn.net/yaoxinJJJ/article/details/115433638 https://zhuanlan.zhihu.com/p/409007775?utm_id=0

    2024年02月06日
    浏览(40)
  • 【IMX6ULL驱动开发学习】08.IMX6ULL通过GPIO子系统函数点亮LED

    通过GPIO子系统函数点亮LED 1、GPIO子系统函数 1.1 确定 led 的GPIO标号,查看内核中的gpiochip 查看 gpiochip ,以正点原子的IMX6ULL阿尔法开发板为例 查看原理图,发现led接的引脚是 GPIO1_IO3,对应 /sys/kernel/debug/gpio 中的 gpiochip0 组,gpiochip0 组从0开始算起, 所以 GPIO1_IO3 对应的标号就

    2024年02月10日
    浏览(77)
  • 树莓派驱动开发--搭建环境篇(保姆级)

            1.1、 虚拟机环境搭建 下载虚拟机vm,然后建立一个虚拟机,我这边用的ubantu版本是16.04,正点原子的,很稳定这个版本,推荐! 链接:https://pan.baidu.com/s/1r6NEANYDDbs7bg_lmPMeXA?pwd=hsw1  提取码:hsw1         1.2、 ssh、nfs、ftp搭建 使用命令搭建ssh 按步骤使用命令搭建nfs 

    2024年04月29日
    浏览(42)
  • (三)(Driver)驱动开发之双机调试环境搭建及内核驱动的运行

    请参考另一篇:https://blog.csdn.net/qq_41273999/article/details/133341733 请参考另一篇:https://blog.csdn.net/qq_41273999/article/details/133376458 准备好安装包,勾选将VMware Workstation控制台工具添加到系统PATH。 输入秘钥:ZF71R-DMX85-08DQY-8YMNC-PPHV8,如果失效,勾选试用30天。 下载完成后, 以管理员身份

    2024年02月06日
    浏览(38)
  • 【IMX6ULL驱动开发学习】10.设置uboot,通过tftp服务器加载内核与设备树,通过nfs挂载根文件系统

    首先根据这篇博客,保证自己的开发板与Ubuntu主机处于同一个网段,并且可以ping通 【IMX6ULL驱动开发学习】03.设置IMX6ULL开发板与虚拟机在同一网段 1. 在uboot中设置网络 首先启动自己的板子进入Linux系统,使用 ifconfig 命令或者 ifconfig -a 命令查看自己网卡的地址 我的网卡地址是

    2024年02月05日
    浏览(49)
  • 全志V3S嵌入式驱动开发(开发环境再升级)

    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】         前面我们陆陆续续开发了差不多有10个驱动,涉及到网口、串口、音频和视频等几个方面。但是整个开发的效率还是比较低的。每次开发调试的时候都很麻烦,譬如说,如果是驱动代码

    2024年02月08日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包