Linux2.6.33 自己动手写驱动 LinuxF#网络应用C#C++
Linux2.6.33 自己动手写驱动
一、GPIO驱动编写和测试
1、GPIO的这点事儿
GPIO(General-Purpose IO ports),通用的IO端口。一般的微处理器芯片都提供通用的可编程IO端口,用户可以通过配置寄存器将其配置成输入、输出或者其他特殊功能模式。
通用IO端口一般都可以实现按位操作,即用户可以针对IO端口的每一位(以下简称IO位)进行操作。
GPIO端口输出的高低电平可以通过控制一组LED发光二极管来加以验证,这里,我们截取TE2440-DEV-I教学板中的四个发光二极管做实验。
应用S3C2440的GPF4-GPF7共四个IO位,各自控制一个发光二极管,分别对应D1-D4,硬件原理如图6.1所示。
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="图片_x0020_1" o:spid="_x0000_i1026" type="#_x0000_t75" o:bordertopcolor="black" o:borderleftcolor="black" o:borderbottomcolor="black" o:borderrightcolor="black" style="visibility: visible; width: 371.25pt; height: 137.25pt; mso-wrap-style: square"><font size="3"><imagedata src="file:///C:/DOCUME~1/IBM/LOCALS~1/Temp/msohtmlclip1/01/clip_image001.emz" o:title="" gain="192753f" grayscale="t" bilevel="t"></imagedata><bordertop type="single" width="4"></bordertop><borderleft type="single" width="4"></borderleft><borderbottom type="single" width="4"></borderbottom><borderright type="single" width="4"></borderright></font></shape>
图6.1 IO控制LED原理图
原理图分析:
(1) 四个发光二极管采用共阳极的连接方法,即四个发光二极管的阳极连接在一起,并连接到3.3V电源。
(2) 发光二极管的负极各自连接一个1K限流电阻,再分别连接到S3C2440的GPF4-GPF7。
思考:为什么要接一个1K的限流电阻呢?
顾名思义,串接限流电阻就是为了显示通过发光二极管的电流,从而达到减少功耗或者满足端口对最大电流的限制。
一般发光二极管的点亮电流为5mA~10mA。TE2440采用贴片发光二极管,1K限流电阻,驱动电压为3.3V,发光二极管压降为1.6V,那么发光二极管的电流大约为1.7mA。发光二极管已经能点亮了,如果希望更亮一些,可以将限流电阻减小,但是二极管的电流不能超多ARM芯片IO口的最大驱动电流。
(3) 根据电路原理可知,当GPF4-GPF7输出低电平时,由于发光二极管两端加上电压,则发光二极管点亮;当GPF4-GPF7输出高电平只,由于发光二极管两端压差为0,则发光二极管熄灭。
思考:发光二极管为什么会亮呢?
发光二极管在其两端的电压差超出其导通压降时开始工作,普通发光二极管的导通压降一般为1.6V~2.1V,同时,工作电流要满足该二极管的工作电流。满足电压和电流的要求,该二极管就可以发光了。
二极管的正负极可以用万用表的二极管档量出来,如果表上有了一点多的读数,红表笔接的发光二极管的正极,黑表笔接的就是发光二极管的负极。
(4) 我们可以通过程序控制GPF4-GPF7有规律的输出高低电平,则实现发光二极管有规律的亮灭。
2、驱动怎样编写
了解的硬件的概念以后,我们开始我们的驱动编写工作。
然后再在内核源码的“drivers/char/”目录下新建一个名为“TopElec_GPIO.c”的文件,作为我们的驱动文件。内容如下:
/*************************************
NAME:TopElec_GPIO.c
COPYRIGHT:www.top-elec.com
Ver1.00 2010/05/19
*************************************/
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <linux/gpio.h>
#define DEVICE_NAME "GPIO-Control"
#define S3C2410_GPFCON S3C2410_GPIOREG(0x50)
#define S3C2410_GPFDAT S3C2410_GPIOREG(0x54)
#define S3C2410_GPFUP S3C2410_GPIOREG(0x58)
#define S3C2410_GPF4 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 4)
#define S3C2410_GPF5 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 5)
#define S3C2410_GPF6 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 6)
#define S3C2410_GPF7 S3C2410_GPIONO(S3C2410_GPIO_BANKF, 7)
#define S3C2410_GPF4_OUTP (0x01 << 8)
#define S3C2410_GPF5_OUTP (0x01 << 10)
#define S3C2410_GPF6_OUTP (0x01 << 12)
#define S3C2410_GPF7_OUTP (0x01 << 14)
/* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
#define IOCTL_GPIO_ON 1
#define IOCTL_GPIO_OFF 0
/* 用来指定LED所用的GPIO引脚 */
static unsigned long gpio_table [] =
{
S3C2410_GPF(4),
S3C2410_GPF(5),
S3C2410_GPF(6),
S3C2410_GPF(7),
};
/* 用来指定GPIO引脚的功能:输出 */
static unsigned int gpio_cfg_table [] =
{
//由于2.6.33内核中没有定义GPIO的动作,所以我在上面自己定义了一下。
S3C2410_GPF4_OUTP,
S3C2410_GPF5_OUTP,
S3C2410_GPF6_OUTP,
S3C2410_GPF7_OUTP,
};
static int te2440_gpio_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
if (arg > 4)
{
return -EINVAL;
}
switch(cmd)
{
case IOCTL_GPIO_ON:
// 设置指定引脚的输出电平为0
s3c2410_gpio_setpin(gpio_table[arg], 0);
return 0;
case IOCTL_GPIO_OFF:
// 设置指定引脚的输出电平为1
s3c2410_gpio_setpin(gpio_table[arg], 1);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = te2440_gpio_ioctl,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{
int ret;
int i;
for (i = 0; i < 4; i++)
{
s3c2410_gpio_cfgpin(gpio_table[i], gpio_cfg_table[i]);
s3c2410_gpio_setpin(gpio_table[i], 0);
}
ret = misc_register(&misc);
printk (DEVICE_NAME" initialized/n");
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("www.top-elec.com");
MODULE_DESCRIPTION("GPIO control for Topelec TE2440DEV_I Board");
3、让驱动到内核里混一下
在内核源码中添加对LED 灯驱动的支持,修改同目录下的Kconfig文件,添加如下内容:
config TE2440_GPIO_TEST tristate "TE2440DEV-I Board GPIO Test(LED TEST)" depends on ARCH_S3C2440 default y if ARCH_S3C2440 help GPIO control for TE2440DEV-I Board. |
同样的道理,修改同目录下的Makefile文件,修改的内容如下:
obj-$(CONFIG_TE2440_GPIO_TEST) += TopElec_GPIO.o |
4、配置和编译内核
进入内核目录,键入make menuconfig命令,进入内核配置菜单,如下图所示:
图
Diver->chacarter device-> TE2440DEV-I Board GPIO Test 的支持,当然,你也可以选择<M>将驱动编译成模块。
好了,OK,大胆的make吧!
当然可能有错误,因为内核的版本不一致,或是编译器的问题,总之,Linux虽然玩起来和带劲,但是问题也会很多,要有越挫越勇的精神才能成为真正的高手哦!
至于,怎么把内核搞到板子上不在这里就不说了。
5、编写测试程序
/*************************************
NAME:GPIO_TEST.c
COPYRIGHT:www.top-elec.com
*************************************/
#include <stdio.h> /*定义函数要用到的头文件*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv) /*运行时参数传递,开或关哪个LED*/
{
int on; /*定义led状态变量,1表示灯亮,2表示灯灭*/
int led_no; /*定义led变量--哪个led*/
int fd; /*定义led设备文件描述符的变量*/
if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||
on < 0 || on > 1 || led_no < 1 || led_no > 4) /*判断命令输入参数个数*/
{
fprintf(stderr, "Usage: Please enter led number and led status,For example GPIO_TEST 1 0 /n");
exit(1);
}
fd = open("/dev/GPIO-Control", 0); /*为只读打开GPIO-Control设备文件,取出文件描述符*/
if (fd < 0) {
perror("open device /dev/GPIO-Control"); /*如果打开led文件出错,拿不到文件描述符,用perror宏输出错原因及信息*/
exit(1);
}
ioctl(fd, on, (led_no-1)); /*用ioctl()函数控制LED,其中fd--是前面打开的LED文件描述符,on--是开关命令0和1,led_no--是哪个LED*/
close(fd);
return 0;
}
顺便这个Makefile文件,看起来专业点:
CROSS=arm-softfloat-linux-gnu- all:GPIO_TEST GPIO_TEST:GPIO_TEST.c $(CROSS)gcc GPIO_TEST.c -o GPIO_TEST $(CROSS)strip GPIO_TEST clean: @rm -vf GPIO_TEST *.o *~ |
有了上面的两个 make就可以了
最后把测试程序搞的开发板上运行一下:
bash-3.2# ./GPIO_TEST 1 1 意思是D1被点亮
很多资料来源于网络,谢谢网络的上的无私奉献大侠们!
华清远见-嵌入式领域著名讲师 O(∩_∩)O 牛牛猛
点击链接加我好友!
http://student.csdn.net/invite.php?u=111047&c=758a60d66d3a92d1
欢迎大家去我CSDN博客上踩踩