IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 04.驱动学习复盘(原始架构) -> 正文阅读

[嵌入式]04.驱动学习复盘(原始架构)

1.在单片机和裸机中我们操作硬件,

//操作寄存器
unsigned int *p = 0x12345678;
*p = 0x87654321;

2.在Linux上使能了MMU,不能直接操作物理地址,需要把物理地址转换成虚拟地址。

3.内核提供了相关的函数:

ioremap:把物理地址转换成虚拟地址

iounmap:释放掉ioremap映射的地址

static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size)
参数:映射物理地址的起始地址,要映射多大的内存空间
返回值:成功返回虚拟地址的首地址,失败返回NULL

static inline void iounmap(void __iomem *addr)
参数:要取消映射的虚拟地址的首地址

注意:物理地址只能被映射一次,多次映射会失败

4.cat /proc/iomem 查看哪些物理地址被映射过了。

5.一个相对完整的驱动实践编写,以蜂鸣器为例,要先根据硬件原理图和数据手册确定相关的寄存器地址。还是直接上代码了。

app:

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

int main(int argc, char *argv[])
{
	int fd;

	char buf[64] = {0};

	fd = open("/dev/beep_drv",O_RDWR);

	if(fd < 0)
	{
		perror("open error\n");
		return fd;
	}
	
	//接收来自命令行的数据
	//atoi将字符串转换成整形
	buf[0] = atoi(argv[1]);

	write(fd,buf,sizeof(buf));

	close(fd);

	return 0;
}

驱动:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>

//物理地址
#define PWM 0xC0018000
//映射完的虚拟地址首地址
unsigned int *vir_pwm_dr;

int beep_open(struct inode * inode, struct file * file)
{
	printk("beep_open\n");

	return 0;
}

int beep_release (struct inode *inode, struct file *file)
{
	printk("beep_release\n");

	return 0;
}

ssize_t beep_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{
	char kbuf[64] = "hahaha";
	
	if(copy_to_user(ubuf, kbuf, strlen(kbuf)) != 0)
	{
		printk("copy_to_user error\n");
		return -1;
	}

	return 0;
}

ssize_t beep_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("beep_write\n");

	if(kbuf[0] == 1)
		//左移一位
		*vir_pwm_dr |= (1<<1);
	else if(kbuf[0] == 0)
		*vir_pwm_dr &= ~(1<<1);
		
	return 0;
}

struct file_operations beep_fops = {
	.owner = THIS_MODULE,
	.open = beep_open,
	.release = beep_release,
	.read = beep_read,
	.write = beep_write
};
	
struct miscdevice beep_dev = {

	.minor = MISC_DYNAMIC_MINOR,
	.name = "beep_drv",
	.fops = &beep_fops
};

static int __init beep_init(void)
{
	int ret;

	ret = misc_register(&beep_dev);

	if(ret < 0)
	{
		printk("beep register is error\n");
		return -1;
	}
	
	printk("beep_init\n");

	//映射虚拟地址(物理地址,要映射的大小)
	vir_pwm_dr = ioremap(PWM, 4);

	if(vir_pwm_dr == NULL)
	{
		printk("PWM ioremap error\n");
		//Linux标准错误
		return -EBUSY;
	}

	printk("PWM ioremap ok\n");

	return 0;
}

static void __exit beep_exit(void)
{
	misc_deregister(&beep_dev);

	//取消映射(映射完的虚拟地址的首地址)
	iounmap(vir_pwm_dr);
	
	printk("beep_exit\n");
}

module_init(beep_init);
module_exit(beep_exit);

MODULE_LICENSE("GPL");

6.驱动传参,例如安装驱动时:insmod beep.ko a=1

驱动传参的作用:

(1)设置驱动的相关参数,比如设置缓冲区的大小

(2)设置安全校验,防止我们写的驱动被别人盗用

7.驱动传参使用的函数,

(1)传递普通的参数,比如 char, int 类型的

//参数:参数名,类型,参数读写权限
module_param(name,type,perm);

(2)传递数组

//参数:参数名、类型、实际传入的个数、参数读写权限
module_param_array(name, type, nump, perm);

8.关于驱动传参的驱动代码:

//包含宏定义的头文件
#include <linux/init.h>
//包含初始化加载模块的头文件
#include <linux/module.h>

static int a;
static int b[5];
//实际传入的个数
static int count;

//int、char类型参数传递
//参数名、类型、读写权限
module_param(a, int, S_IRUSR);

//传递数组
//参数名、类型、实际传入的个数、参数读写权限
module_param_array(b, int, &count, S_IRUSR);

//装载卸载函数入口
static int __init hello_init(void)
{	
	int i;
	for(i=0;i<count;i++)
	{
		printk("b[%d] = %d \n",i,b[i]);
	}	
	printk("count = %d\n",count);
	printk("a = %d\n",a);
	return 0;
}

static void __exit hello_exit(void)
{
	printk("a = %d\n",a);
	printk("hello_exit\n");
}

//驱动模块装载卸载声明
module_init(hello_init);
module_exit(hello_exit);

//开源许可证GPL声明
MODULE_LICENSE("GPL");



  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-11-14 21:52:49  更:2021-11-14 21:53:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:59:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码