利用platform编写驱动控制树莓派4B io口


我观看讯为视频写的,其链接: link

1.平台总线模型简介

1.什么是平台总线模型

平台总线模型也叫platform总线模型。是linux内核虚拟出来的一条总线,不是真实的导线。
平台总线模型就是把原来的驱动C文件给分成了俩个C文件,一个是device.c,一个是driver.c
把稳定不变的放在driver,c里面,需要变的就放在device,c里。

2.平台总线优缺点

(1).可以提高代码的重用性
(2).减少重复性代码
设备 总线(连接设备和驱动) 驱动
device.c driver.c

3.怎么编写以平台总线模型设计的驱动?

一个是device.c ,一个是driver.c,然后分别注册device.c和driver.c。
平台总线就是以名字来匹配,实际上就是字符串比较。

2.平台总线注册一个device

device.c里面写的是硬件资源,这里的硬件资源是指寄存器的地址,中断号,时钟等硬件资源。
device,c代码

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

void led_release(struct device *dev)
{
	printk("led_release \n");
}

struct resource led_res[] = {
	[0] = {
		.start = 0xfe200000,
		.end = 0xfe200003,
		.flags = IORESOURCE_MEM,
		.name = "GPIO1_IO4DIR",
	},
	[1] = {
		.start = 0xfe20001c,
		.end = 0xfe20001f,
		.flags = IORESOURCE_MEM,
		.name = "GPIO1_IO4H"
	},
	[2] = {
		.start = 0xfe200028,
		.end = 0xfe20002b,
		.flags = IORESOURCE_MEM,
		.name = "GPIO1_IO4L"
	},
};

struct platform_device led_device = {
	.name = "led_test",
	.id = -1,
	.resource = led_res,
	.num_resources = ARRAY_SIZE(led_res),
	.dev={
		.release = led_release,
	},

};

static int device_init(void)
{
	platform_device_register(&led_device);
	printk("platform_device_register ok \n");
	
	return 0;
}

static void device_exit(void)
{
	platform_device_unregister(&led_device);

	printk("goodbye! \n");
}

module_init(device_init);
module_exit(device_exit);

MODULE_LICENSE("GPL");

3.平台总线注册driver

driver.c代码

#include <linux/init.h>  
#include <linux/module.h> 
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h> //注册杂项设备头文件
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/io.h>

unsigned int *vir_gpio4_dr=NULL;
unsigned int *vir_gpio4_h=NULL;
unsigned int *vir_gpio4_l=NULL;

struct resource *gpio4_dir;
struct resource *gpio4_h;
struct resource *gpio4_l;

struct resource *leddir_mem_test;
struct resource *ledh_mem_test;
struct resource *ledl_mem_test;

ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{
	char kbuf[64] = {0};
	if ( copy_from_user( kbuf, ubuf, size) != 0)
	{
		printk( "copy_from_user error\n ");
		return -1;
	}
	printk( "kbuf is %s\n ", kbuf);
	*vir_gpio4_dr |= (001<<(3*4));
	if( kbuf[0] == 1)
	{
		
		*vir_gpio4_h |=(1<<4);
	}
	else if( kbuf[0]==0)
	{
		*vir_gpio4_l |=(1<<4);
	}
	return 0;
}

int misc_release( struct inode *inode, struct file *file)
{
	printk( "hello misc_relaease bye bye \n ");
	return 0;
}

int misc_open( struct inode *inode, struct file *file)
{
	printk( "hello misc_open\n ");
	return 0;
}
//文件操作集
struct file_operations misc_fops = {
		.owner = THIS_MODULE, 
		.open = misc_open,
		.release = misc_release,
		.write = misc_write,
		};
//miscdevice 结构体
struct miscdevice misc_dev = {
	.minor = MISC_DYNAMIC_MINOR, 
	.name = "hello_misc",
	.fops = &misc_fops,
};


int led_probe( struct platform_device *pdev)
{
	
	int ret;

	printk( "led_probe\n");
	ret = misc_register( &misc_dev); //注册杂项设备
	if (ret < 0)
	{
		printk( "misc registe is error \n");
	}
	printk( "misc registe is succeed \n");

	gpio4_dir = platform_get_resource( pdev, IORESOURCE_MEM, 0);
	gpio4_h   = platform_get_resource( pdev, IORESOURCE_MEM, 1);
	gpio4_l   = platform_get_resource( pdev, IORESOURCE_MEM, 2);

	vir_gpio4_dr = ioremap( gpio4_dir->start,4);
	if( vir_gpio4_dr== NULL )
	{
		printk( "gpio4dr ioremap error\n");
		return EBUSY;
	}
	
	vir_gpio4_h = ioremap( gpio4_h->start,4);
	if( vir_gpio4_h== NULL)
	{
		printk( "gpio4h ioremap error\n");
		return EBUSY;
	}

	vir_gpio4_l = ioremap( gpio4_l->start,4);
	if( vir_gpio4_l == NULL)
	{
		printk( "gpio4l ioremap error\n");
		return EBUSY;
	}
	printk( "gpio ioremap success\n");

	return 0;
#if 0
	leddir_mem_test = request_mem_region( gpio4_dir->start, gpio4_dir->end - gpio4_dir->start +1, "led_dir");
	if( leddir_mem_test == NULL){
		printk( "platform_get_resource iserror \n");
		goto errdir_region;
	}
	
	ledh_mem_test = request_mem_region( gpio4_dir->start, gpio4_dir->end - gpio4_dir->start +1, "led_dir");
	if( ledh_mem_test == NULL){
		printk( "platform_get_resource iserror \n");
		goto errh_region;	
	}
	
	ledl_mem_test = request_mem_region( gpio4_dir->start, gpio4_dir->end - gpio4_dir->start +1, "led_dir");
	if( ledl_mem_test == NULL){
		printk( "platform_get_resource iserror \n");
		goto errl_region;
	}
	return 0;

errdir_region:
	release_mem_region( gpio4_dir->start, gpio4_dir->end - gpio4_dir->start +1);

	return -EBUSY;
errh_region:
	release_mem_region( gpio4_h->start, gpio4_h->end - gpio4_h->start +1);

	return -EBUSY;	
errl_region:
	release_mem_region(gpio4_l->start, gpio4_l->end - gpio4_l->start +1);

	return -EBUSY;
#endif
}

int led_remove( struct platform_device *pdev)
{
	printk("led_remove\n");
	return 0;
}
struct platform_driver led_driver ={
	.probe = led_probe,
	.remove = led_remove,
	.driver = {
		.owner = THIS_MODULE,
		.name = "led_test"
	},
};

static int led_driver_init( void)
{
	int ret =0;
	ret = platform_driver_register( &led_driver);
	if( ret<0)
	{
		printk( "platform_driver_register error \n");
	}
	printk( "platform_driver_register ok \n");
	return 0;
}

static void led_driver_exit(void)
{
	misc_deregister( &misc_dev); //卸载杂项设备
	printk( "misc gooodbye! \n");
	iounmap( vir_gpio4_dr);
	iounmap( vir_gpio4_h);
	iounmap( vir_gpio4_l);

	// platform 驱动卸载
	platform_driver_unregister( &led_driver);
	printk( "goodbye! \n");
}

module_init( led_driver_init);
module_exit( led_driver_exit);

MODULE_LICENSE( "GPL");

4.Makefile

在使用我写的Makefile的时候记得改下KDIR,和ARCH,

 obj-m +=device.o
 obj-m +=driver.o
 KDIR:=/home/kun/build_new/linux_kernel
 PWD?=$(shell pwd)
 all:
 	make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -C $(KDIR) M=$(PWD) modules
 clean:
 	rm *.mod.c *.order *.ko *.o *.mod *.symvers

5.app

编译指令arm-linux-gnueabihf-gcc app.c -o app -static

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
	int fd;
	fd = open("/dev/hello_misc",O_RDWR);//打开设备节点
	if(fd < 0)
	{
		perror("open error \n");
		return fd;
	}
	buf[0]=atoi(argv[1]);
	write(fd,buf,sizeof(buf)); //向内核层写数据
	close(fd);
	return 0;
}

5.编译运行

1.执行make,然后将生成的driver.ko、device.ko以及app可执行文件移到树莓派

2.先sudo dmesg -C 将内核杂志清楚

3.sudo insmod driver.ko

4.sudo insmod device.ko

5. dmesg可以查看打印信息

6.sudo ./app 1

在这里插入图片描述

7. sudo ./app 0

在这里插入图片描述

6 总结

platform总线给我的感觉就是把硬件的信息放在一个文件,让后另一个文件去获取该文件的硬件信息,感觉就相当于一个.c文件,一个.h文件,.c文件去写实现功能,.h去定义需要的文件,然后app可执行文件相当于main函数,去调用。(本人小白,刚学习驱动开发,个人愚见,如果不对的话,麻烦各位大佬提出,不胜感激)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在树莓派4B驱动USB摄像头,你可以按照以下步骤进行操作: 1. 首先,使用命令`lsusb`查看已连接的USB设备,确保摄像头被正确识别。 2. 安装Motion软件,可以使用以下命令进行安装:`sudo apt-get install motion`。安装完成后,需要修改Motion的配置文件。 3. 修改Motion的配置文件motion.conf,可以使用以下命令进行编辑:`sudo nano /etc/motion/motion.conf`。在文件中找到并修改以下参数: - 修改分辨率:将capture_width和capture_height设置为所需的分辨率,例如640 x 480。 - 修改访问地址和端号:将stream_localhost设置为off,将stream_port设置为8081。 - 可选:如果你遇到摄像头卡顿的问题,可以尝试调整framerate参数来提高帧率。 4. 保存并关闭文件,然后重新启动Motion服务:`sudo systemctl restart motion`。 5. 接下来,你可以通过访问`http://[树莓派地址]:8081`来查看实时监控视频。默认的用户名是admin,密码为空。 6. 如果你希望将摄像头接入到Home Assistant中,你需要修改Home Assistant的配置文件configuration.yaml,添加以下内容: ``` camera: - platform: generic name: 摄像头 still_image_url: http://{树莓派地址}:8081/picture/1/current/ username: admin framerate: 30 binary_sensor: - platform: ffmpeg_motion input: http://{树莓派地址}:8081/ name: 移动侦测 ``` 保存并关闭文件,然后重新启动Home Assistant。 这样,你就可以通过树莓派4B驱动USB摄像头并进行监控了。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值