led和蜂鸣器驱动(广州龙芯中科1B开发板)培训讲学_第1页
led和蜂鸣器驱动(广州龙芯中科1B开发板)培训讲学_第2页
led和蜂鸣器驱动(广州龙芯中科1B开发板)培训讲学_第3页
led和蜂鸣器驱动(广州龙芯中科1B开发板)培训讲学_第4页
led和蜂鸣器驱动(广州龙芯中科1B开发板)培训讲学_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Good is good, but better carries it.精益求精,善益求善。led和蜂鸣器驱动(广州龙芯中科1B开发板)TOCo1-3huHYPERLINKl_Toc46311.前言PAGEREF_Toc46313HYPERLINKl_Toc30862.硬件电路PAGEREF_Toc30863HYPERLINKl_Toc142852.1.LED引脚PAGEREF_Toc142853HYPERLINKl_Toc5332.2.LED原理分析PAGEREF_Toc5334HYPERLINKl_Toc111042.3.蜂鸣器引脚PAGEREF_Toc111045HYPERLINKl_T

2、oc12862.4.蜂鸣器原理分析PAGEREF_Toc12865HYPERLINKl_Toc280773.GPIO相关分析PAGEREF_Toc280776HYPERLINKl_Toc123833.1.阅读CPU手册PAGEREF_Toc123836HYPERLINKl_Toc66633.2.Linux内核源码分析PAGEREF_Toc66636HYPERLINKl_Toc42964.点亮一个ledPAGEREF_Toc42969HYPERLINKl_Toc303504.1.源码PAGEREF_Toc303509HYPERLINKl_Toc306064.2.运行结果PAGEREF_Toc30

3、60613HYPERLINKl_Toc277155.手动指定那个led亮PAGEREF_Toc2771513HYPERLINKl_Toc150945.1.源码PAGEREF_Toc1509413HYPERLINKl_Toc196055.2.运行结果PAGEREF_Toc1960519HYPERLINKl_Toc209986.蜂鸣器驱动PAGEREF_Toc2099820HYPERLINKl_Toc144586.1.源码PAGEREF_Toc1445820HYPERLINKl_Toc285997.参考资料PAGEREF_Toc2859920修订历史版本号更新日期更新内容V1.02013.9.13

4、创建前言由于龙芯资料较少,现在又有点时间,写了两句,仅供初学者入门时参考,还望高手多多指教。硬件电路LED引脚先把电路图贴出来我们选择LED9作为本次实验的对象。LED9接到龙芯1B的引脚T12再查龙芯1B处理器的用户手册v1.9如下图即CAN0_RX为GPIO38.,同理可得Led6接GPIO39;led7接GPIO40;led8接GPIO41。如原理图所示注意:这里有GPIO0,GPIO1,。GPIO38,GPIO39。到底表示什么意思啊?个人认为第一列的GPIO1,GPIO2,为原理图中的编号,而第三列的GPIO38,GPIO39为CPU引脚编号,可以再CPU手册中找到。如前面的led9

5、所示。这几个引脚可以在源码中定义为宏,详细请见后面代码,这里只贴出相关部分。LED原理分析LED又叫发光二极管,有正负两个极,只要在正负两极之间接上合适的正电压,LED就导通,并发光。这里只需要让CPU的GPIO引脚输出低电平,对应的LED就被点亮。比如GPIO38输出低电平,即可点亮LED9。蜂鸣器引脚LED7接在CAN1_RX上,CAN1_RX经过电阻后接蜂鸣器,如下图所示所以LED7和蜂鸣器共用一个引脚GPIO40。蜂鸣器原理分析蜂鸣器通过NPN三极管提供所需的大电流,当GPIO40输出低电平时,NPN三极管截止,蜂鸣器不响;当输出高电平时,NPN三极管导通,蜂鸣器响。由于LED7和蜂鸣

6、器共用同一个引脚,并且为了开机后蜂鸣器不响(想起来烦人,哈哈)。所以引脚GPIO40必须输出低电平,恰好低电平使LED导通,所以LED7在开机后一直亮着。GPIO相关分析阅读CPU手册首先看龙芯1B处理器的手册,其中对GPIO相关的寄存器有:配置寄存器,输入使能寄存器,输入寄存器,配置输出寄存器,MUX寄存器。根据经验,一般都是先配置GPIO为输入还是输出,然后读输入寄存器或者写输出寄存器实现输入输出功能。V1.9版的手册中写得还不是很清楚,我们这里也只能猜了。贴上手册中的截图作为对比参考,我把其它CPU的截图也贴上相比较而言,龙芯1B处理器手册写得太简单了,以至于没有说清楚。Linux内核源

7、码分析现在我们来看一下linux内核中GPIO相关代码。源码路径“linux内核根目录/arch/mips/loongson/ls1x/gpio.c”。我们想实现的功能就是简单的在GPIO口输出高低电平。源文件gpio.c中有个函数ls1b_gpio_direction_output(),从函数名字上看好像能实现这个功能。具体分析一下。/*函数功能:直接在某个GPIO输出高电平或者低电平入参:structgpio_chip*chip可以为空指针unsignedgpioGPIO的序号intlevel电平值。1-高电平;0-低电平*/intls1b_gpio_direction_output(st

8、ructgpio_chip*chip,unsignedgpio,intlevel)u32temp;u32mask;/入参检查:判断是否超过最大的GPIO个数,即GPIO的合法性检查if(gpio=STLS1B_N_GPIO)return-EINVAL;/把高低电平值写到输出寄存器中gpio_set_value(gpio,level);/由于寄存器是32位的,一个寄存器最多可以控制32个GPIO/就比如:配置寄存器,就有配置寄存器0和配置寄存器1/所以这里分开处理if(gpio=32)/获取锁,执行原子操作spin_lock(&gpio_lock);mask=1(gpio-32);/配置GPIO

9、引脚为GPIO功能temp=LOONGSON_GPIOCFG1;temp|=mask;LOONGSON_GPIOCFG1=temp;/配置GPIO引脚为输出temp=LOONGSON_GPIOIE1;temp&=(mask);LOONGSON_GPIOIE1=temp;/释放锁spin_unlock(&gpio_lock);elsespin_lock(&gpio_lock);mask=1=STLS1B_N_GPIO)_gpio_set_value(gpio,state);return;/对不同GPIO操作不同的寄存器if(gpio=32)mask=1(gpio-32);/获取锁spin_loc

10、k(&gpio_lock);/把高低电平值写到输出寄存器中val=LOONGSON_GPIOOUT1;if(state)val|=mask;elseval&=(mask);LOONGSON_GPIOOUT1=val;/释放锁spin_unlock(&gpio_lock);elsemask=1gpio;spin_lock(&gpio_lock);val=LOONGSON_GPIOOUT0;if(state)val|=mask;elseval&=mask;LOONGSON_GPIOOUT0=val;spin_unlock(&gpio_lock);经过以上分析,要让GPIO输出高低电平,首先写输出寄

11、存器,然后把引脚配置为GPIO,最后设置为输出。点亮一个led源码源码包含一个驱动源程序、一个应用源程序和一个Makefile。rootlocalhostled#catMakefile#ifKERNELRELEASEisdefined,wevebeeninvokedfromthe#kernelbuildsystemandcanuseitslanguage.ifneq($(KERNELRELEASE),)obj-m:=ls1b_led_driver.o#otherwisewewerecalleddirectlyfromthecommand#line;invokethekernelbuildsys

12、tem.elseKERNELDIR=/home/dev/develop/1b-linux-3.0-d8b47bbPWD:=$(shellpwd)default:$(MAKE)-C$(KERNELDIR)M=$(PWD)modulescp./ls1b_led_driver.ko/nfsramdisk/LS1Brootfs/testmipsel-linux-gccls1b_led_app.c-ols1b_led_appcpls1b_led_app/nfsramdisk/LS1Brootfs/testclean:rm*.o*.mod.c*.order*.symvers*.koendif这个Makef

13、ile是参考linuxdevicedriver修改的。也是比较通用的,只需要修改一个linux内核路径和驱动模块文件名就可以了。这里把应用程序的编译也放在了一起。这样执行make时,驱动和应用一起编译。rootlocalhostled#catls1b_led_driver.c#include#include#include#include#include#include#include#include#include#include#include#include#defineLS1B_LED_1_ON(0)#defineLS1B_LED_1_OFF(1)intls1b_led_major=0

14、;intls1b_led_minor=0;structcdevls1b_led_devs;intls1b_led_open(structinode*inode,structfile*filp)printk(KERN_DEBUG%s:openn,_FUNCTION_);return0;intls1b_led_release(structinode*inode,structfile*file)printk(KERN_DEBUG%s:closen,_FUNCTION_);return0;ssize_tls1b_led_set(structfile*filp,constchar_user*buff,s

15、ize_tcount,loff_t*offp)ls1b_gpio_direction_output(NULL,38,0);printk(KERN_DEBUG%s:led9onn,_FUNCTION_);return0;structfile_operationsls1b_led_ops=.owner=THIS_MODULE,.open=ls1b_led_open,.release=ls1b_led_release,.write=ls1b_led_set,;MODULE_AUTHOR(caogoscaogos);MODULE_LICENSE(DualBSD/GPL);intls1b_led_ini

16、t(void)intresult;dev_tdevno;structcdev*dev=&ls1b_led_devs;structfile_operations*fops=&ls1b_led_ops;result=alloc_chrdev_region(&devno,0,1,ls1b_led);if(0result)printk(KERN_WARNINGls1b_led:unabletogetamjorn);returnresult;ls1b_led_major=MAJOR(devno);printk(KERN_DEBUGls1b_led:major=%dn,ls1b_led_major);cd

17、ev_init(dev,fops);dev-ops=fops;result=cdev_add(dev,devno,1);if(result)printk(KERN_NOTICEError%daddingls1b_led,result);returnresult;printk(KERN_DEBUGls1b_leddeviceinstalled.withmajor%dn,ls1b_led_major);return0;voidls1b_led_exit(void)cdev_del(&ls1b_led_devs);unregister_chrdev_region(MKDEV(ls1b_led_maj

18、or,0),1);printk(ls1b_leddeviceuninstalledn);module_init(ls1b_led_init);module_exit(ls1b_led_exit);这个驱动程序必linuxdevicedriver中的HelloWorldModule要稍微复杂点。不过已经是非常简单的字符设备驱动了。这个驱动程序的核心就是函数ls1b_led_set()。其中的ls1b_gpio_direction_output(NULL,38,0);的功能是让GPIO38输出低电平。然后把函数ls1b_led_set()作为该驱动structfile_operationsls1b

19、_led_ops的写函数,即应用程序中调用write()函数,就会对应调用驱动的函数ls1b_led_set()。注意:函数ls1b_led_set()没有对入参进行分别处理,只要应用程序调用write()函数,不管write什么内容,都执行GPIO38输出低电平的操作。rootlocalhostled#catls1b_led_app.c#include#include#include#include#include#include#includeintmain(void)intdev_fd;charbuff2=0;dev_fd=open(/dev/led,O_RDWR|O_NONBLOCK)

20、;if(-1=dev_fd)printf(Canntopenfile/dev/ledn);return-1;write(dev_fd,buff,1);close(dev_fd);return0;这个应用程序简单来说就是打开设备文件,并执行写操作。即调用驱动中的函数ls1b_led_set()点亮LED。友情提示:内核顶层配置中*Enableloadablemodulesupport一定要选上。运行结果/test#lsls1b_led_appls1b_led_driver.ko/test#echo8/proc/sys/kernel/printk/test#insmodls1b_led_drive

21、r.kols1b_led:major=253ls1b_leddeviceinstalled.withmajor253/test#mknod/dev/ledc2530/test#./ls1b_led_appls1b_led_open:openls1b_led_set:led9onls1b_led_release:close/test#当然开发板上的LED9肯定被点亮。经过前面分析可知,打印信息“ls1b_led_set:led9on”为驱动程序打印出来的。命令“echo8/proc/sys/kernel/printk”是将内核打印级别调到最低。为了能把所有驱动中的printk打印信息打印出来。命

22、令“mknod/dev/ledc2530”新建设备节点。否则,应用中open()会失败。253为主设备号,根据前面的打印“ls1b_leddeviceinstalled.withmajor253”获得的。手动指定那个led亮源码在前面led驱动的基础上改进了一下,现在可以手动输入led序号,然后制定序号的led被点亮。驱动程序源码ls1b_led_driver.c#include#include#include#include#include#include#include#include#include#include#include#include/led正极接3.3v,负极接cpu引脚/

23、cpu输出低电平,led导通,亮#defineLS1B_LED_ON(0)/cpu输出高电平,led截止,灭#defineLS1B_LED_OFF(1)/led引脚#defineLS1B_PIN_LED_9(38)/gpio38#defineLS1B_PIN_LED_6(39)/gpio39#defineLS1B_PIN_LED_7(40)/gpio40#defineLS1B_PIN_LED_8(41)/gpio41/led主次设备号,动态申请intls1b_led_major=0;intls1b_led_minor=0;structcdevls1b_led_devs;intls1b_led_

24、open(structinode*inode,structfile*filp)printk(KERN_DEBUG%s:openn,_FUNCTION_);return0;intls1b_led_release(structinode*inode,structfile*file)printk(KERN_DEBUG%s:closen,_FUNCTION_);return0;/*功能:将led序号转换为对应的引脚入参:unsignedintled_indexled序号出参:无返回值:unsignedintled_gpioled引脚*/unsignedintls1b_led_index_to_pin(

25、unsignedintled_index)switch(led_index)case9:returnLS1B_PIN_LED_9;case6:returnLS1B_PIN_LED_6;case7:returnLS1B_PIN_LED_7;case8:returnLS1B_PIN_LED_8;default:return0;/*功能:熄灭指定led入参:unsignedintled_indexled序号出参:无返回值:无*/voidls1b_led_off(unsignedintled_index)ls1b_gpio_direction_output(NULL,ls1b_led_index_to

26、_pin(led_index),LS1B_LED_OFF);/*功能:点亮指定led入参:unsignedintled_indexled序号出参:无返回值:无*/voidls1b_led_on(unsignedintled_index)ls1b_gpio_direction_output(NULL,ls1b_led_index_to_pin(led_index),LS1B_LED_ON);/*功能:关闭所有led入参:无出参:无返回值:无*/voidls1b_led_off_all()ls1b_led_off(9);/关闭led9ls1b_led_off(6);ls1b_led_off(7);

27、ls1b_led_off(8);ssize_tls1b_led_set(structfile*filp,constchar_user*buff,size_tcount,loff_t*offp)charinputbuff10=0;unsignedintled_index=0;unsignedinttmp=0;/关闭所有ledls1b_led_off_all();/打开指定ledcopy_from_user(inputbuff,buff,1);/一次只处理一个ledled_index=(unsignedint)(inputbuff0);ls1b_led_on(led_index);printk(K

28、ERN_DEBUG%s:led%donn,_FUNCTION_,led_index);return0;structfile_operationsls1b_led_ops=.owner=THIS_MODULE,.open=ls1b_led_open,.release=ls1b_led_release,.write=ls1b_led_set,;MODULE_AUTHOR(caogoscaogos);MODULE_LICENSE(DualBSD/GPL);intls1b_led_init(void)intresult;dev_tdevno;structcdev*dev=&ls1b_led_devs;

29、structfile_operations*fops=&ls1b_led_ops;result=alloc_chrdev_region(&devno,0,1,ls1b_led);if(0result)printk(KERN_WARNINGls1b_led:unabletogetamjorn);returnresult;ls1b_led_major=MAJOR(devno);printk(KERN_DEBUGls1b_led:major=%dn,ls1b_led_major);cdev_init(dev,fops);dev-ops=fops;result=cdev_add(dev,devno,1

30、);if(result)printk(KERN_NOTICEError%daddingls1b_led,result);returnresult;printk(KERN_DEBUGls1b_leddeviceinstalled.withmajor%dn,ls1b_led_major);return0;voidls1b_led_exit(void)cdev_del(&ls1b_led_devs);unregister_chrdev_region(MKDEV(ls1b_led_major,0),1);printk(ls1b_leddeviceuninstalledn);module_init(ls

31、1b_led_init);module_exit(ls1b_led_exit);应用程序源码#include#include#include#include#include#include#includeintmain(void)intdev_fd;charbuff2=0;unsignedinttmp=0;dev_fd=open(/dev/led,O_RDWR|O_NONBLOCK);if(-1=dev_fd)printf(Canntopenfile/dev/ledn);return-1;/根据用户输入,点亮指定的ledbuff0=getchar()-0;write(dev_fd,buff,1

32、);/由于led7和蜂鸣器接在同一个引脚上/避免蜂鸣器一直响,最后把蜂鸣器关了sleep(1);buff0=7;write(dev_fd,buff,1);close(dev_fd);return0;Makefilerootlocalhostled#catMakefile#ifKERNELRELEASEisdefined,wevebeeninvokedfromthe#kernelbuildsystemandcanuseitslanguage.ifneq($(KERNELRELEASE),)obj-m:=ls1b_led_driver.o#otherwisewewerecalleddirectly

33、fromthecommand#line;invokethekernelbuildsystem.elseKERNELDIR=/home/dev/develop/1b-linux-3.0-d8b47bbPWD:=$(shellpwd)default:$(MAKE)-C$(KERNELDIR)M=$(PWD)modulescp./ls1b_led_driver.ko/nfsramdisk/LS1Brootfs/testmipsel-linux-gccls1b_led_app.c-ols1b_led_appcpls1b_led_app/nfsramdisk/LS1Brootfs/test/clean:rm*.o*.mod.c*.order*.symvers*.kols1b_led_appendifrootl

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论