分享
分销 收藏 举报 申诉 / 5
播放页_导航下方通栏广告

类型led驱动详解.doc

  • 上传人:w****g
  • 文档编号:3560685
  • 上传时间:2024-07-09
  • 格式:DOC
  • 页数:5
  • 大小:37.50KB
  • 下载积分:6 金币
  • 播放页_非在线预览资源立即下载上方广告
    配套讲稿:

    如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。

    特殊限制:

    部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。

    关 键  词:
    led 驱动 详解
    资源描述:
    #include <linux/module.h> #include <linux/init.h>//头文件:module_init、module_exit等宏定义。 #include <linux/fs.h>////struct file_operations #include <asm/irq.h> #include <mach/regs-gpio.h>// S3C2410 GPIO寄存器定义 #include <mach/hardware.h>// s3c2410_gpio_setpin, s3c2410_gpio_cfgpin等 #include <linux/device.h>//class_create device_create(注意,有些2.6.27以前是的可能是class_device_create,如果出现implicate 错误时,看一下这个头问题里边是哪一个),udev,自动在/dev下创建设备节点 #include <linux/cdev.h>//字符设备节点注册,函数有cdev_init,cdev_add,cdev_del等早期的办法是register_chrdev,unregister_chrdev这种方法应避免使用。 #define DEVICE_NAME "leds" #define LED_MAJOR 231 #define IOCTL_LED_ON 1#define IOCTL_LED_OFF 0 static unsigned long led_table [] ={S3C2410_GPB5, S3C2410_GPB6, S3C2410_GPB7, S3C2410_GPB8,} static unsigned int led_cfg_table [] ={ S3C2410_GPB5_OUTP,S3C2410_GPB6_OUTP,S3C2410_GPB7_OUTP, S3C2410_GPB8_OUTP,}; struct leds_type { struct cdev cdev; }; struct leds_type *my_leds_dev; static int EmbedSky_leds_open(struct inode *inode, struct file *file) { int i; for (i = 0; i < 4; i++) { // 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能 s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); } return 0;} static int EmbedSky_leds_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { if (arg > 4) { return -EINVAL; } switch(cmd) { case IOCTL_LED_ON:// 设置指定引脚的输出电平为0 s3c2410_gpio_setpin(led_table[arg], 0); return 0; case IOCTL_LED_OFF: // 设置指定引脚的输出电平为1 s3c2410_gpio_setpin(led_table[arg],1); return 0; default: return -EINVAL; } } static struct file_operations EmbedSky_leds_fops ={ .owner = THIS_MODULE, .open = EmbedSky_leds_open, .ioctl = EmbedSky_leds_ioctl,}; static char __initdata banner[] = "TQ2440/SKY2440 LEDS, (c) 2008,\n";static struct class *led_class; static int __init EmbedSky_leds_init(void){ int ret;dev_t devno=MKDE(LED_MAJOR,0); printk("init led\n"); printk(banner); if(!my_leds_dev) { ret=-ENOMEM; goto fail_malloc; } memset(my_leds_dev,0,sizeof(struct leds_type)); cdev_init(&(my_leds_dev->cdev),&EmbedSky_leds_fops); ret=cdev_add(&(my_leds_dev->cdev),devno,1); if(ret)printk(KERN_NOTICE"ERROR %d",ret); //注册一个类,使mdev可以在"/dev/"目录下面建立设备节点 led_class = class_create(THIS_MODULE, DEVICE_NAME); if(IS_ERR(led_class)) { printk("Err: failed in EmbedSky-leds class.\n"); return -1; } //创建一个设备节点,节点名为DEVICE_NAME device_create(led_class, NULL, MKDEV(LED_MAJOR, 0), NULL, DEVICE_NAME); printk(DEVICE_NAME " initialized\n"); return 0; fail_malloc: unregister_chrdev_region(devno,1); return ret;} static void __exit EmbedSky_leds_exit(void){ unregister_chrdev(LED_MAJOR, DEVICE_NAME); device_destroy(led_class, MKDEV(LED_MAJOR, 0));//删掉设备节点 class_destroy(led_class); //注销类} module_init(EmbedSky_leds_init);module_exit(EmbedSky_leds_exit); MODULE_AUTHOR(""); // 驱动程序的作者 MODULE_DESCRIPTION("TQ2440/SKY2440 LED Driver"); // 一些描述信息 MODULE_LICENSE("GPL"); // 遵循的协议 上面代码中,led_table数组相当于对应了GPB的四个IO口的索引,通过这四个值,对这四个IO口进行相关操作。例如: S3C2410_GPB5 = S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5) = S3C2410_GPIO_BANKB + 5 = 32*1 + 5 在s3c2410_gpio_setpin(S3C2410_GPB5,0)中,该函数首先通过S3C2410_GPB5获得GPB的虚拟地址和偏移地址,再对GPB5的GPBDAT寄存器进行操作,具体 void s3c2410_gpio_setpin(unsigned int pin, unsigned int to){ void __iomem *base = S3C2410_GPIO_BASE(pin); unsigned long offs = S3C2410_GPIO_OFFSET(pin); unsigned long flags;unsigned long dat;local_irq_save(flags); dat = __raw_readl(base + 0x04);//读取GPIO的DAT数据到dat dat &= ~(1 << offs); //先将要设置的IO口拉低 dat |= to << offs; //再将形参的to值赋给dat __raw_writel(dat, base + 0x04);//最后将DAT值写进GPIO的DAT local_irq_restore(flags);} 上面的 函数调用了两个子函数,具体定义如下 #define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO) #define S3C2410_GPIO_OFFSET(pin) ((pin) & 31) 其中S3C24XX_VA_GPIO定义如下: #define S3C24XX_VA_GPIO S3C2410_ADDR(0x00E00000) #define S3C2410_ADDR(x) (0xF0000000 + (x)) 这里S3C2410_ADDR的基地址为0xF0000000(??),也即2440所有寄存器的虚拟地址的基地址。0x00E00000表示2440的GPIO的偏移地址,也就是说其GPIO的虚拟地址首地址为0xF0E00000。 再看看S3C2410_GPIO_BASE(pin)的定义,我们不仿把S3C2410_GPB5的值放进去计算,可以得到(S3C2410_GPB5&~31)=32。其目的就是去掉GPB的偏移值,然后再右移一位,和GPIO的虚拟地址首地址相加。因此,S3C2410_GPIO_BASE(pin)只代表了对应GPIO组的虚拟地址,如GPB的虚拟地址为10000(B)+0xF0E00000=0xF0E00010。依此类推,可以得到所有GPIO的偏移地址,具体如下表: S3C2410_GPIO_OFFSET用于获得具体GPIO的偏移地址。如GPB5,则S3C2410_GPIO_OFFSET(pin) = (pin)&31 = (32*1 + 5) & 31 = 5。有了*base和off,就可以操作具体的寄存器了。 函数s3c2410_gpio_cfgpin()用于配置GPCON寄存器。具体代码 void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function){ void __iomem *base = S3C2410_GPIO_BASE(pin); unsigned long mask; unsigned long con; unsigned long flags; if (pin < S3C2410_GPIO_BANKB) { mask = 1 << S3C2410_GPIO_OFFSET(pin);//GPA的寄存器只占一位 } else { mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;//非GPA的寄存器占两位 } local_irq_save(flags); con = __raw_readl(base + 0x00);//先保留GPCON的值 con &= ~mask; //再将要设置的管脚的CON值清零 con |= function; //然后将形参传进来的配置赋给CON __raw_writel(con, base + 0x00); //最后将CON值写进GPCON寄存器 local_irq_restore(flags);} 上面的LED驱动程序中,led_cfg_table数组给出了GPB相应管脚的属性设置,调用上面的函数后即设置为Output。 到此为止,整个S3C2440的IO口操作,应该就一目了然了 #define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v)) # define __chk_io_ptr(x) (void)0 __chk_io_ptr()是编译器为了更细致地检查参数的属性,用于调试,正常编译时没有作用。 volatile为了防止Compiler优化。 内核中,对所有的地址都是通过虚拟地址进行访问的.因此,不能直接访问0x56000010的物理地址,如果要对0x56000010的物理地址进行访问(一般是外设寄存器),那么需要把0x56000010的物理地址映射为虚拟地址,然后对该虚拟地址进行访问就是对实际的物理地址进行访问了。 需要注意的是:在进行映射时,该虚拟地址需要disable cache和Write Buffer, 否则就是加了volatile也是没有用的 这个IOREMAP的实现过程中 offset = phys_addr &~ PAGE_MASK; phys_addrs &= PAGE_MASK; size = PAGE_ALIGN(last_addr) - phys_addrs; 下面是通过vmlist中查找以size大小的空闲块,所以从这里可以看出,已经做过了页的对齐,只以映射的大小 杂项设备(misc device) 杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在 Linux 内核的include\linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。 也就是说,misc设备其实也就是特殊的字符设备。 字符设备(char device) 使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时,如果有多个设备使用该函数注册驱动程序,LED_MAJOR不能相同,否则几个设备都无法注册(我已验证)。如果模块使用该方式注册并且 LED_MAJOR为0(自动分配主设备号 ),使用insmod命令加载模块时会在终端显示分配的主设备号和次设备号,在/dev目录下建立该节点,比如设备leds,如果加载该模块时分配的主设备号和次设备号为253和0,则建立节点:mknod leds c 253 0。使用register_chrdev (LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时都要手动建立节点 ,否则在应用程序无法打开该设备。 __raw_readl和__raw_writel Linux对I/O的操作都定义在asm/io.h中,相应的在arm平台下,就在asm-arm/io.h中。 #define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v)) #define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)) #define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))在include\linux\compiler.h中: #ifdef __CHECKER__…… extern void __chk_io_ptr(void __iomem *); #else…… # define __chk_io_ptr(x) (void)0…… #endif __raw_readl(a)展开是:((void)0, *(volatile unsigned int _force *)(a))。在定义了__CHECKER__的时候先调用__chk_io_ptr检查该地址,否则__chk_io_ptr什么也不做,*(volatile unsigned int _force *)(a)就是返回地址为a处的值。(void)xx的做法有时候是有用的,例如编译器打开了检查未使用的参数的时候需要将没有用到的参数这么弄一下才能编译通过。 CPU对I/O的物理地址的编程方式有两种:一种是I/O映射,一种是内存映射。__raw_readl和__raw_writel等是原始的操作I/O的方法,由此派生出来的操作方法有:inb、outb、_memcpy_fromio、readb、writeb、ioread8、iowrite8等。 本文来自CSDN博客,转载请标明出处:
    展开阅读全文
    提示  咨信网温馨提示:
    1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
    2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
    3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
    4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
    5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
    6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

    开通VIP折扣优惠下载文档

    自信AI创作助手
    关于本文
    本文标题:led驱动详解.doc
    链接地址:https://www.zixin.com.cn/doc/3560685.html
    页脚通栏广告

    Copyright ©2010-2026   All Rights Reserved  宁波自信网络信息技术有限公司 版权所有   |  客服电话:0574-28810668    微信客服:咨信网客服    投诉电话:18658249818   

    违法和不良信息举报邮箱:help@zixin.com.cn    文档合作和网站合作邮箱:fuwu@zixin.com.cn    意见反馈和侵权处理邮箱:1219186828@qq.com   | 证照中心

    12321jubao.png12321网络举报中心 电话:010-12321  jubao.png中国互联网举报中心 电话:12377   gongan.png浙公网安备33021202000488号  icp.png浙ICP备2021020529号-1 浙B2-20240490   


    关注我们 :微信公众号  抖音  微博  LOFTER               

    自信网络  |  ZixinNetwork