驱动模块分离概念

发布者:闪耀的星空最新更新时间:2024-08-14 来源: cnblogs关键字:驱动模块 手机看文章 扫描二维码
随时随地手机看文章

    还记得以前刚开始学习编写程序的时候,无论再多的代码,再多的功能都是使劲的往同一个.C文件中塞,最后导致的直接结果就是,代码多,功能复杂,严重的妨碍了我们代码可移植性甚至良好的阅读性,接下来,我们开始来学习将一个驱动程序进行拆分,根据各种代码的性质或者功能来写入不同的.C文件中,此处,我们来尝试使用平台设备来实现IMX257蜂鸣器的驱动分离代码。

    前面我们实现了beep驱动,博客地址http://www.cnblogs.com/lihaiyan/p/4298105.html

    在本实验中,我们根据beep的性质,分为设备,驱动两个模块分别编写驱动程序,在设备的.C文件中,负责定义驱动的设备IO地址等可变的信息,而在驱动的.C文件中负责统一的内存地址IOREMAP映射,注册设备等不变的代码。这样,当我们程序要修改时,比如说如果我们要将beep修改为led的话,那么就只需要将设备的.C文件中的地址修改过来就可以了,大大的增强了代码的可移植性。

    接下来,我么开始步入正题:

一、设备beep_dev.c的实现

1.定义平台设备结构体

如图所示,在平台设备结构体,需要注意两个地方,

 

第一个是.name,它是用于保存在设备链中,利用它在驱动链中进行匹配,找到相应的驱动程序。

 

第二个是.resources,它是一个资源结构体,用于保存我们IMX257板子的内存IO地址,当我们要更改硬件是,只需要修改资源结构体中的数据即可。简单的说,资源结构体主要的功能就是传递参数,将板子的内存地址传入beep_drv.c中,beep_drv.c只要通过platform_get_resource函数即可得到资源中保存的数据。

2.定义资源结构体

如图所示:

在资源结构体数组中,

数组0中存储了IMX257的IOMUX的基地址

数组1中存储了IMX257的GPIO1的基地址,此处我们的beep为GPIO1_26

数组2中存储了IMX257的beep在GPIO1地址的偏移

在beep_drv.c将这些数据获取,然后分别ioremap进行地址映射

3.接下来就是在分别在入口函数中申请平台设备,在出口函数中注销平台设备

 

总结一下,可以发现我们的设备beep_dev.C文件中只做了一件事,那就是保存IMX257的地址,所以,如果我们以后要移植 驱动程序的话,只需要修改地址就够了。当然,蜂鸣器有点简单,在以后的程序可能就没这么简单了,不过总体的框架都是这样,实现了驱动模块分离。

 

二、驱动beep_drv.c的实现

1.平台驱动支持

    和上面差不多,此处我们先实现一个平台驱动的支持,也就是

①定义平台驱动结构体

②在入口函数中注册平台驱动

③在出口函数中卸载平台驱动

此处就不再详细将这个,见下图:

 

2.平台驱动探测函数probe实现

接下来,重点来了,我们此处驱动程序的核心就是在probe这个函数。

当我们的驱动和设备匹配成功之后,就会调用probe函数,在此函数中可以干任何我们想干的事。

所以,我们呢,就利用此函数完成我们的硬件设备初始化的工作。

①得到前面设备beep_dev.c文件中的资源结构体的资源

②将前面的资源中的地址,通过ioremap函数分别映射地址

③注册字符设备驱动,创建类,然后再类下面创建设备节点

如下图所示:

 

3.平台驱动释放函数remove实现

在remove函数中,自然就是将前面我们映射的地址取消映射,卸载字符设备驱动程序

如图所示:

 

4.实现file_opration结构体

前面注册字符设备时,需要一个file_operation结构体,用于制定读写函数,如下图所示:

 

5.实现打开函数beep_open

    前面,我们的probe函数中已经实现了IO地址的映射,以及设备号的自动申请,自动创建设备节点。但是,单独只有这些是还不够的,由于我们IMX257芯片的IO引脚为复用IO,总共有七中模式,要想实现特定的功能,必须还得对IO引脚进行配置,

    所以,我们此处,在打开函数中实现引脚的配置。

①配置GPIO引脚为模式5

②配置GPIO引脚为上拉模式,电压1.8v,CMOS输出

③配置蜂鸣器的GPIO1_26为输出模式

④将蜂鸣器引脚电平清零。

经过前面几步,我们就实现了IMX257引脚的正确配置。

如下图所示:

 

6.实现写函数beep_write

通过前面的额正确配置GPIO,我们就已经可以正确的使用beep了,接下来,我们通过写函数来将我们的数据传入内核,从而相应的控制蜂鸣器的正确鸣叫与停止。

 

三 、应用程序beep_test.c的实现

在测试程序中,我们只需要实现以下几步

①打开设备

②判断用户输入的命令

③根据用户的命令来相应的控制

 

当我们用户输入

./beep_test on         蜂鸣器响

./beep_test off        蜂鸣器地址响

./beep_test on_off     鸣器响5声

 

 

四、驱动测试:

 

imx257板子上加载,如图所示:

 

移除驱动:

附 设备 beep_dev.c 程序:


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 #include

 8 

 9 #define DRIVER_NAME 'beep_dev'

10 #define DEVICE_NAME 'beep_dev'

11 #define IORESOURCE_IOMUX_BASE       0x00000200

12 #define IORESOURCE_GPIO1_BASE       0x00000400

13 #define IORESOURCE_BEEP_BIT         0x00000800

14 

15 

16 /* 定义资源结构体 */

17 static struct resource beep_resource[] = {

18     [0] =     {

19         .start     = 0x43FAC000,//IOMUX基地址

20         .end     = 0x43FAC000 + 0xFFF,

21         .flags = IORESOURCE_IOMUX_BASE,

22     },

23     [1] =     {

24         .start     = 0x53FCC000,//GPIO1基地址

25         .end     = 0x53FCC000 + 0xFFF,

26         .flags = IORESOURCE_GPIO1_BASE,

27     },

28     [2] = {

29         .start = 26,        //beep为GPIO1_26

30         .end = 26,

31         .flags = IORESOURCE_BEEP_BIT,

32     },

33 };

34 

35 static void beep_release(struct device *dev){

36 

37 }

38 

39 /*分配/设置/注册一个platform_device 结构体*/

40 static struct platform_device beep_dev = {

41     .name             = DEVICE_NAME,

42     .id                  = -1,

43     .num_resources     = ARRAY_SIZE(beep_resource),

44     .resource         = beep_resource,

45     .dev             = {

46         .release = beep_release,        

47     },

48 };

49 

50 //入口函数

51 static int beep_dev_init(void){

52         //注册一个平台设备

53     platform_device_register(&beep_dev);

54     return 0;

55 }

56 

57 //出口函数

58 static void beep_dev_exit(void){

59     platform_device_unregister(&beep_dev);

60 }

61 

62 module_init(beep_dev_init);

63 module_exit(beep_dev_exit);

64 

65 MODULE_AUTHOR('Lover雪儿');

66 MODULE_VERSION('0.1.0');

67 MODULE_LICENSE('GPL');


附 驱动 beep_drv.c 程序:


  1 #include

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 

 11 #define DRIVER_NAME 'beep_dev'

 12 #define DEVICE_NAME 'beep_dev'

 13 

 14 #define IORESOURCE_IOMUX_BASE        0x00000200

 15 #define IORESOURCE_GPIO1_BASE        0x00000400

 16 #define IORESOURCE_BEEP_BIT            0x00000800

 17 

 18 static int major;        //主设备号

 19 static struct class *beep_class;//创建类,在类下面创建设备

 20 //定义寄存器

 21 static unsigned long base_iomux;      //iomux基址 0X 43FA C000 -  0X 43FA FFFF

 22 static unsigned long base_gpio1;    //gpio3      0X 53FC C000 -  0X 53FC FFFF

 23 #define MUX_CTL      (*(volatile unsigned long *)(base_iomux + 0x011c))// MUX_CTL模式选择  配置寄存器

 24 #define PAD_CTL      (*(volatile unsigned long *)(base_iomux + 0x0314))// PAD_CTL GPIO常用功能设置

 25 #define DR_GPIO1     (*(volatile unsigned long *)(base_gpio1 + 0x0000))// GPIO DR   数据寄存器  DR

 26 #define GDIR_GPIO1     (*(volatile unsigned long *)(base_gpio1 + 0x0004))// GPIO GDIR 方向控制寄存器  GDIR

 27 static int beep_pin;//引脚的偏移

 28 

 29 

 30 static int beep_open(struct inode *inode, struct file *file)

 31 {

 32     printk('<0>function open!nn');

 33     //引脚配置

 34     //MUX_CTL

 35     MUX_CTL &= ~(0x07 << 0);    

 36     MUX_CTL |= (0X05 << 0);    //设置为ALT5  GPIO1_26 BEEP

 37     //PAD_CTL

 38     PAD_CTL &= ~(0x01<<13 | 0x01<<3 | 0x03<<1 | 0x01<<0);   //1.8v 不需要上拉下拉  CMOS输出 slew rate

 39     //GDIR_GPIO1    配置为输出模式

 40     GDIR_GPIO1 &= ~(0x01 << beep_pin);    

 41     GDIR_GPIO1 |= (0x01 << beep_pin);    //配置为输出模式    

 42 

 43     //DR_GPIO1        配置为输出0 点亮ERR_LED

 44     DR_GPIO1 &= ~(0x01 << beep_pin);        //将GPIO1_26清零

 45 

 46     return 0;

 47 }

 48 static ssize_t beep_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

 49 {

 50     int val;

 51     printk('<0>function write!nn');

 52     if(copy_from_user(&val,buf,count))

 53         printk('<0>copy_from_user error!n');        

 54     if(val == 1){    //响蜂鸣器

 55         DR_GPIO1 |= (0x01 << beep_pin);        //将GPIO1_26置1

 56     }else{            //停蜂鸣器

 57         DR_GPIO1 &= ~(0x01 << beep_pin);        //将GPIO1_26清零

 58     }

 59     return count;

 60 }

 61 

 62 //构造file_operation结构体

 63 static struct file_operations beep_fops = {

 64     .owner    = THIS_MODULE,    /*宏*/

 65     .open    = beep_open,

 66     .write    = beep_write,

 67 };

 68 

 69 

 70 

 71 //探测函数

 72 static int beep_probe(struct platform_device *pdev){

 73     struct resource *res;

 74     printk('<0> beep_probe,found beepnn');

 75     /* 根据platform的资源进行ioremap */

 76     //获取资源 IOMUX 的地址

 77     res = platform_get_resource(pdev,IORESOURCE_IOMUX_BASE,0);

 78     //映射IOMUX的内存地址

 79     base_iomux = (unsigned long)ioremap(res->start,res->end - res->start);

 80     

 81     //获取资源 GPIO1 的地址

 82     res = platform_get_resource(pdev,IORESOURCE_GPIO1_BASE,0);

 83     //映射GP1IO1的内存地址

 84     base_gpio1 = (unsigned long)ioremap(res->start,res->end - res->start);

 85     

 86     //获取资源 LED灯 的偏移地址

 87     res = platform_get_resource(pdev,IORESOURCE_BEEP_BIT,0);

[1] [2]
关键字:驱动模块 引用地址:驱动模块分离概念

上一篇:构建Linux下IMX257 开发环境
下一篇:NorFlash驱动

推荐阅读最新更新时间:2024-11-10 16:55

S3C2440 LCD液晶模块驱动设计
参数配置: 开发板型号TX2440; 一个像素点采用16位表示; LCD屏幕分辨率 480*272; 液晶模块型号:BL43014_SPEC;图像的内容以C语言数组的形式保存在bmp.c文件中。 /* *版权所有(C)2015,ZJU * *文件名称:lcd.c *内容摘要:关于lcd的配置 *其它说明:开发板型号: TX2440 * led显示尺寸 480 x 272 液晶模块型号:BL43014_SPEC *当前版本:V1.0 *作 者:Frank *完成日期:2015.12.20 * */ #define GPCCON (*(volatile unsigned long *)0x56000020)
[单片机]
S3C2440 LCD液晶<font color='red'>模块</font><font color='red'>驱动</font>设计
基于STM32CUBEMX驱动TOF模块VL53l0x(1)----单模块距离获取的最佳实践
概述 VL53L0X是新一代飞行时间(ToF)激光测距模块(不同于传统技术),采用目前市场上最小的封装,无论目标反射率如何,都能提供精确的距离测量。它可以测量2m的绝对距离,为测距性能等级设定了新的基准,为各种新应用打开了大门。 VL53L0X集成了一个领先的SPAD阵列(单光子雪崩二极管),并内嵌ST的第二代FlightSense™专利技术。 VL53L0X的940nm VCSEL发射器(垂直腔面发射激光器)完全不为人眼所见,加上内置的物理红外滤光片,使其测距距离更长,对环境光的免疫性更强,对盖片的光学串扰具有更好的稳定性。 ! 视频教学 样品申请 源码下载 ( 所有功能 ● 完全集成的小型化模块 ○ 940
[单片机]
基于STM32CUBEMX<font color='red'>驱动</font>TOF<font color='red'>模块</font>VL53l0x(1)----单<font color='red'>模块</font>距离获取的最佳实践
全新4.5 kV XHP™ 3 IGBT模块驱动器实现尺寸小型化和效率最大化
【 2023 年 12 月 2 5 日,德国慕尼黑讯】 许多应用都出现了采用更小IGBT模块,以及将复杂设计转移给产业链上游的明显趋势。为了顺应小型化和集成化的全球趋势, 英飞凌科技股份公司推出了4.5 kV XHP™ 3 IGBT模块,旨在从根本上改变采用两电平和三电平拓扑结构且使用2000 V至3300 V交流电压的中压变频器(MVD)与交通运输应用的格局 。这款新半导体器件将给诸多应用带来裨益,包括大型传送带、泵、高速列车、机车以及商用、工程和农用车辆(CAV)。 XHP3_IGBT XHP系列包括一款带有一个发射极控制续流二极管的TRENCHSTOP™ IGBT4450 A半桥IGBT模块,以及一款带有
[电源管理]
全新4.5 kV XHP™ 3 IGBT<font color='red'>模块</font>让<font color='red'>驱动</font>器实现尺寸小型化和效率最大化
STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块
ADXL345 ADXL345是一款常见的的3轴加速度计, Analog Device生产. 13位分辨率, ±16 g测量范围, 分辨率3.9 mg/LSB. 可通过SPI(3线或4线)或I2C接口访问. 主要用于倾斜检测, 静态重力加速度测量, 以及运动或冲击导致的动态加速度测量. 能够测量不到1.0°的倾斜角度变化. 可以对单击, 双击, 自由落体等情况设置中断. 模块与STC8H的接线 市面上的模块, 一般是8个pin脚, 在使用SPI接线方式的情况下, 与STC8H的接线方式如下. 除了SPI用到的CS, MISO, MOSI, SCLK以外, STC8H还需要提供两个中断输入, 因为INT0, INT1已经
[单片机]
STC8H开发(六): SPI<font color='red'>驱动</font>ADXL345三轴加速度检测<font color='red'>模块</font>
JSN-SR04T超声波模块驱动(模式一、STM32)
一、前期准备 单片机:STM32F103C8T6 开发环境:MDK5.14 库函数:标准库V3.5 JSN-SR04T模块:淘宝有售 二、实验效果 三、驱动原理 此模块分3中模式: (1)模式一:R27 = open,普通驱动模式; (2)模式二:R27 = 47K,串口模式,每隔100ms更新一次数据。 (3)模式三:R27 = 120K,串口模式,发0x55。 注意:次模块测试盲区20cm。 触发信号Tirig维持10Us以上的高电平即可等待Echo的返回,这里是用EXTI检测俩个跳变信号,去打开和关闭定时器,最后一次测量计算结果后清除定时器计时,并等待下一个循环开始。 需要完整工程或者有问题的请加QQ:100
[单片机]
JSN-SR04T超声波<font color='red'>模块</font><font color='red'>驱动</font>(模式一、STM32)
PI SCALE-iFlex 系列再添新家族,XLT驱动模块继续挑战功率密度极限
Power Integration(PI)日前宣布推出SCALE-iFlex XLT系列双通道即插即用型门极驱动器,适配单个LV100(三菱)、XHP 2(英飞凌)、HPnC(富士电机)以及耐压高达2300V的同等半导体功率模块,该模块适用于储能系统以及风电和光伏可再生能源应用。该款超紧凑单板驱动器可对逆变器模块进行主动温升管理,从而提高系统利用率,并简化物料清单(BOM)以提高逆变器系统的可靠性。 SCALE-iFlex门极驱动器系统的特点就是紧凑,支持业界标准的双管模块,具有隔离电压功能,且即插即用,因此非常适合空间紧凑的应用。 SCALE-iFlex解决方案由一个中央隔离主控制 (IMC) 和一到四个模组适配的门极驱
[电源管理]
PI SCALE-iFlex 系列再添新家族,XLT<font color='red'>驱动</font><font color='red'>模块</font>继续挑战功率密度极限
选择模块化LED驱动器的理由
LED驱动器规格书的内容通常是非常吸引人的,厂家会承诺在低价格的基础上,提供良好的性能和丰富的功能。然而,在实际应用中,有许多的潜在障碍在规格书中并未被提到,这样有可能会给开发者带来严重的问题。此外,LED驱动器的研发,测试和认证都很耗时且花费高昂,尤其是AC/DCLED驱动器。现成的并且经过测试的模块,节省了研发工作中所产生的高成本费用,这至少可以节约80%以上的设计成本。 模块化VS分立式:概述 传统观念认为分立式LED驱动器比模块化解决方案会更具有成本优势。然而,事实并非如此。如果价格对比只是基于BOM(物料清单)的成本,模块化驱动器的价格是要高于分立式LED驱动器。但这不是一个公平的对比方法,因为分立式方案的实际应用成
[嵌入式]
选择<font color='red'>模块</font>化LED<font color='red'>驱动</font>器的理由
基于STM32CUBEMX驱动TOF模块VL6180与VL6180X(1)----单模块距离获取的最佳实践
概述 VL6180X是基于ST FlightSense™专利技术的最新产品。作为一项突破性技术,它实现了独立于目标反射率的绝对距离测量。传统的测量方法通过测量反射光的光量来估算距离,然而这种方法存在一个主要缺点,即被测物体的颜色和表面特性对测量精度产生很大影响。VL6180X采用了一种全新的方法,它精确测量了光线从传感器照射到最近物体,并在反射回传感器所需的时间(即飞行时间),从而准确计算出两者之间的距离。 VL6180X模块集成了一个红外发射器、一个红外传感器和一个环境光传感器,全部封装在一个便于集成的三合一回流焊封装中。这种设计使终端产品制造商能够减少光学和机械设计的优化过程,并降低相关成本。 该模块具备低功耗操作的特点。
[单片机]
基于STM32CUBEMX<font color='red'>驱动</font>TOF<font color='red'>模块</font>VL6180与VL6180X(1)----单<font color='red'>模块</font>距离获取的最佳实践
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved