Linux驱动开发之LED驱动

最近在学习嵌入式Linux驱动开发,大致了解了驱动的基本开发流程,本文主要针对字符设备驱动开发做一个简要介绍,也当作是对这几天工作的一个小小总结。

计算机系统是由软硬件相互协调共同完成工作的,作为专用计算机系统的嵌入式系统也不例外,既要有CPUSDRAMFLASHIO等硬件,同时也少不了操作系统和应用软件等软件的支持,而作为应用程序与硬件的桥梁——驱动程序,是整个嵌入式系统开发过程中的关键环节。驱动开发涉及底层,而了解底层作用机制对于整个系统的开发意义重大。

Linux内核中有60%以上是驱动程序,它不仅支持驱动以静态形式编译进内核,而且允许驱动以模块的形式动态加载进内核,大大减小了内核的大小,同时便于调试分析。

Linux将所有的设备当作文件进行处理,Linux系统的设备分为三类:字符设备、块设备和网络设备。字符设备的驱动有一个固定的模板,主要编写file_operations结构体中的成员函数,这些函数最终会在应用程序进行Linux的open()、write()、read()、ioctl()、close()等系统调用时被调用。

驱动开发作用在内核空间,应用程序开发作用在用户空间。下面以GPIO端口驱动LED亮灭为例。

1、查看开发板原理图和芯片数据手册;

   

从上图图中可以看出GPF4~GPF7 分别控制D12~D9,当GPF4~GPF7被配置为输出模式,同时向该引脚输出0时LED亮,输出1时LED灭。

从下图可以看出GPFCON控制寄存器对应的每个引脚由两位决定,01时表示输出,所以GPF7~GPF4为0101时,四个引脚配置为输出,所以GPFCON=0x55FF。GPFDAT的八位分别对应八个引脚,0表示输出0,1表示输出1,譬如要使D9~D12都亮,则GPFDAT=0x0F。GPFUP对应的八位为1时表示上拉失效,为0时对应位上拉。同时可以看出GPFCON、GPFDAT、GPFUP的物理地址分别是0x56000050、0x56000054、0x56000058。

2、在虚拟机的shell终端下,编写和编译驱动程序和测试程序,步骤如下图;

源码如下:

led.c

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/init.h>
#include<linux/delay.h>
#include<linux/device.h>
#include<linux/types.h>
#include<linux/ioctl.h>
#include<linux/cdev.h>
#include<linux/errno.h>

#include<asm/io.h>
#include<asm/hardware.h>
#include<asm/arch/regs-gpio.h>
#include<asm/arch-s3c2410/hardware.h>

#define S3C2410_GPFCON S3C2410_GPIOREG(0x50)
#define S3C2410_GPFDAT S3C2410_GPIOREG(0x54)
#define S3C2410_GPFUP S3C2410_GPIOREG(0x58)

#define GPFCON *(volatile unsigned int *)S3C2410_GPFCON
#define GPFDAT *(volatile unsigned int *)S3C2410_GPFDAT
#define GPFUP *(volatile unsigned int *)S3C2410_GPFUP

void delay_1(void)
{
	int i,j;
	for(i=0;i<1000;i++)
		for(j=0;j<10000;j++);
}

#define LED1_ON() (GPFDAT &=~0x8f)
#define LED2_ON() (GPFDAT &=~0x4f)
#define LED3_ON() (GPFDAT &=~0x2f)
#define LED4_ON() (GPFDAT &=~0x1f)
#define LED1_OFF() (GPFDAT |=0x80)
#define LED2_OFF() (GPFDAT |=0x40)
#define LED3_OFF() (GPFDAT |=0x20)
#define LED4_OFF() (GPFDAT |=0x10)

static int LedStatus;
void LedSet(int led)
{
	LedStatus = led;
	if(LedStatus&1)
		LED1_ON();
	else
		LED1_OFF();
	if(LedStatus&2)
		LED2_ON();
	else
		LED2_OFF();
	if(LedStatus&4)
		LED3_ON();
	else
		LED3_OFF();
	if(LedStatus&8)
		LED4_ON();
	else
		LED4_OFF();
}

void LedDisp(void)
{
	LedSet(0x08);
	delay_1();
	LedSet(0x04);
	delay_1();
	LedSet(0x02);
	delay_1();
	LedSet(0x01);
	delay_1();
	LedSet(0x02);
	delay_1();
	LedSet(0x04);
	delay_1();
	LedSet(0x08);
	delay_1();
}

#define DEVICE_NAME "led"
#define LED_MAJOR 220

static int led_open(struct inode *inode,struct file *file)
{
	GPFCON=0x5500;
	GPFUP=0xff;
	printk("LED Driver Open Called!\n");
	return 0;
}

static int led_release(struct inode *inode,struct file *file)
{
	printk("LED Driver Release Called\n");
	return 0;
}

static int led_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
	int err=0;
	if(cmd==1){
		while(arg--)
		{
			LedDisp();
			printk("....");
		}
		printk("\n");
		return 0;
	}
	return err;
}

static struct file_operations led_fops =
{
	.owner   = THIS_MODULE,
	.open    = led_open,
	.release = led_release,
	.ioctl   = led_ioctl,
};

static int __init led_init(void)
{
	int result=0;
	result=register_chrdev(LED_MAJOR,DEVICE_NAME,&led_fops);
	if(result < 0)
	{
		printk("failed to register!\n");
		return result;
	}
	printk("success to register\n");
	return 0;
}

static void __exit led_exit(void)
{
	printk("Led Driver Module Exit\n");
	unregister_chrdev(LED_MAJOR,DEVICE_NAME);
}

module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("njust_sxy");
MODULE_DESCRIPTIO
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值