宁波国际照明展
广州国际照明展览会(光亚展)

SOC8200下LED驱动

 虽然linux新内核下GPIO包括LED驱动有笼统接口架构。而选择自己实现。原本认为可以轻松搞定,但是这是可选择的为了能去理解LED这个驱动中的helloworld还是选择绕过linux复杂的架构。没想到还是呈现了一些小问题记录一下。硬件平台是天漠的SOC8200CPUam3517cortexa8
找到LED对应的引脚。首先看硬件原理图。
 可以看到LED2受HLED引脚控制。高电平时亮,当低电平时灭。继续跟踪HLED一直发现是引脚SYS_BOOT0
这时去am3517硬件手册查一下sys_boot0发现如下:
分别叫做GPIO1-6每组里32个gpio脚,32位寄存器的每一位都控制一个脚,所以gpio_2实际上是GPIO1,am3517下将gpio分为6个组。 可以看到sys_boot0其实也是gpio_2这里解释一下。而LED需要gpio驱动的所以我首先利用CONPCL_PA DCONF_SYS_NRESWA RM[31:16]这个寄存器配置成mode4具体见手册).
下面就应该是操作gpio寄存器了有几个对我目的比较重要。GPIO_DA TA OUT,GPIO_OE.GPIO_CLEA RDA TA OUT,GPIO_SETDA TA OUT
 GPIO_OE使能输出的所以我第二步就是将gpio_2设为输出使能。
 第三步就是对GPIO_DA TA OUT对应该gpio_2位写1或者0就相应的输出了低电平和高电平。
 这时会有人问那后两个寄存器有什么用?这个问题其实仔细看一下数据手册就知道了当时就是由于看的不仔细。置位,结果在这里浪费好多时间其实这两个寄存器是间接设置GPIO_DA TA 相应位的GPIO_CLEA RDA TA OUT相当于对该位置0GPIO_SETDA TA OUT相当于对该位置1而GPIO_DA TA OUT就是用顺序直接对该位写0或写1用间接设置寄存器一条指令就可以对特定位置0或1而直接写需要多条指令(先读取保存。再写入)
写的很粗糙也没有改。下面是驱动源码。
#includ<linux/module.h>
#includ<linux/kernel.h>
#includ<linux/init.h>
#includ<asm/delay.h>
#includ<asm/uaccess.h>
#includ<asm/io.h>
#includ<linux/types.h>
#includ<linux/cdev.h>
#includ<linux/fs.h>
#definGPIO1_BA SE  0x48310000        //这是GPIO1基址
下同 #definGPIO_OE     0x0034            //寄存器相对基址偏移量。
#definGPIO_DA TA OUT0x003C
#definGPIO_SETDA TA OUT0x0094
#definGPIO_CLEA RDA TA OUT0x0090
#definPA D_CONF    0x48002A 08        //这是用来将sys_boot0设成gpio_2寄存器
structcdev*dev;
intled_major;
structfile*filpintled_openstructinod*inode.{
 
 filp->private_data=inode->i_cdev;
 return0;
}
structfile*filpintled_releasstructinod*inode.{
 return0;
}
ssize_tled_writstructfile*filp.size_tcount,constchar__user*buff.loff_t*offp{
 
 u32l=0;
 unsigncharvalue;
 void __iomem*base;  //因为用了MMU所以要ioremap
 void__iomem*pad;
4096 bas=ioremapGPIO1_BA SE.;
256 pad=ioremapPA D_CONF.;
 ifcopy_from_user&value.1buff.{
  return-EFA ULT;
 }
//设成mode4
 l=__raw_readlpad;
 l=l|1<<18;
 l=l&~1<<17;
 l=l&~1<<16;
pad __raw_writell.;
 
//使能输出
 l=__raw_readlbase+GPIO_OE;
 l=l&~1<<2;
base+GPIO_OE __raw_writell.;
//向gpio_2写0或1控制LED亮灭
 l=__raw_readlbase+GPIO_DA TA OUT;
 ifvalu=='1'{
  l=l|1<<2;
base+GPIO_DA TA OUT __raw_writell.;
base+GPIO_SETDA TA OUT;可以看出来。用这个方法一条指令就够了 //或者直接用__raw_writel1<<2.>
 }els{
  l=l&~1<<2;
base+GPIO_DA TA OUT __raw_writell.;
base+GPIO_CLEA RDA TA OUT //或者iowrite321<<2.;
 }
 
 return1;
}
structfile_operled_fops={
.own=THIS_MODULE.>
.write=led_write.>
.open=led_open.>
.releas=led_release.>
};
statintled_initvoid{
 
 dev_tdevno;
 interr;
 
 ifalloc_chrdev_region&devno.1,0."led-zj"<0{
  return-1;
 }
 led_major=MA JORdevno;
 dev=cdev_alloc;
&led_fop cdev_initdev.;
 dev->op=&led_fops;
 dev->own=THIS_MODULE;
 err=cdev_adddev.1devno.;
 iferr<0
 printkKERN_NOTICE"Error";
 return1;
}
staticvoidled_exitvoid{
 
 cdev_deldev;
 unregister_chrdev_regionMKDEVled_major.10.;
}
module_initled_init;
module_exitled_exit;
MODULE_LICENSE"DualBSD/GPL";
 
遇到问题和总结:
对物理地址的读写用ioremap后才以用(如果启用了MMU
读写寄存器命令即可以用__raw_write8系列也可以用iowrite8系列函数(实际iowrit就是__raw_writ
查找硬件手册和原理图时要善用搜索功能(2700多页看手册说明仔细一些,免的走回头路。
本文来自网络。 授权转载请注明出处:http://www.ledjia.com/article/pid-2264.html

快速评论 发表新评论

您还未登录!登录后可以发表回复

文章评论 0人参与

联系我们

联系我们

137-9836-0047

在线咨询: QQ交谈

邮箱: admin@ledjia.com

工作时间:周一至周五,9:00-17:00,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部