您的位置:首页 > 其它

Led驱动程序及应用程序编写

2016-08-14 15:20 363 查看
本来打算写一下NAND驱动和网卡驱动及USB驱动的,突然发现好长时间不写驱动,写驱动的套路都忘的差不多了,而且以前写的驱动程序都不够模块化,想复用的话还需要做些修改,所以,还是先写一下LED驱动,熟悉一下套路,顺便把程序模块化了,留着以后备用。

1.先看一下LED的硬件原理图





根据以上两张图片内容,可以列出如下表格:

LED-numberLED-netGPIO
LED1nLED_1GPB5
LED2nLED_2GPB6
LED3nLED_3GPB7
LED4nLED_4GPB8
根据电路的基本知识,IO口低电平时,LED亮,IO口高电平时,LED灭.

CMDSTATEGPIO-LEVEL
ON0
OFF1
用下列宏可以获得主设备号和次设备号

MAJOR(dev_t dev)

MANOR(dev_t dev)

用下列宏则可以通过主设备号和次设备号生成dev_t;

MKDEV(int major,int minor)

/**
Allocates a range of char device numbers.The major number will be chosen
dynamically ,and retured(along with the first minor number)in @dev.Returns zero or negative error code.
*/
int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name);
/*
This function will unregisters a range of @count device numbers,starting with @from,The
caller should normally be the one who allocated those numbers in the first place...
*/
void unregister_chrdev_region(dev_t from,unsigned count);


以上两个函数是动态分配设备号和注销设备号的函数,为了使函数可移植,使用上面两个函数处理设备号。

建立一个表格,列出成对出现的函数

TablesAreCool
ioremapiounmapxxx




led驱动程序-手动创建设备节点版本

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
static struct cdev led_cdev;
#define NAME "LED_GPIO_TEST"

#define GPBCON 0x56000010
#define GPBDAT 0x56000014
#define GPBUP  0x56000018

#define LED1 (1<<0) /*GPB5*/
#define LED2 (1<<1) /*GPB6*/
#define LED3 (1<<2) /*GPB7*/
#define LED4 (1<<3) /*GPB8*/

dev_t dev_id;
unsigned int *gpbcon;
unsigned int *gpbdat;
unsigned int *gpbup;

static int led_open(struct inode *inode,struct file *file)
{
return 0;
}

static int led_write(struct file *filp,const char __user *buff,size_t count,loff_t *offp)
{
unsigned char kernel_buf;
unsigned int data;
copy_from_user(&kernel_buf,buff,sizeof(unsigned char));
/*off*/
if ((kernel_buf & (1<<7)) == 0) {
switch (kernel_buf) {
case LED1:
data = readl(gpbdat);
data |= (1<<5);
writel(data,gpbdat);
break;
case LED2:
data = readl(gpbdat);
data |= (1<<6);
writel(data,gpbdat);
break;
case LED3:
data = readl(gpbdat);
data |= (1<<7);
writel(data,gpbdat);
break;
case LED4:
data = readl(gpbdat);
data |= (1<<8);
writel(data,gpbdat);
break;
default:
printk("led_write parameter is wrong!!!\n");
break;
}
} else {        /*on*/
kernel_buf &=(unsigned char)(~(1<<7));
switch (kernel_buf) {
case LED1:
data = readl(gpbdat);
data &= ~(1<<5);
writel(data,gpbdat);
break;
case LED2:
data = readl(gpbdat);
data &= ~(1<<6);
writel(data,gpbdat);
break;
case LED3:
data = readl(gpbdat);
data &= ~(1<<7);
writel(data,gpbdat);
break;
case LED4:
data = readl(gpbdat);
data &= ~(1<<8);
writel(data,gpbdat);
break;
default:
printk("on led_write parameter is wrong!!!\n");
break;
}
}
return 0;
}

static const struct file_operations led_fops =
{
.owner = THIS_MODULE,
.write = led_write,
.open = led_open
};
/**
* gpio level
* 0 - ON
* 1 - OFF
* */
static void led_gpio_init(void)
{
unsigned int data;
/*将IO地址空间映射到内核的虚拟地址空间上去,便于访问*/
gpbcon =(unsigned int *) ioremap(GPBCON,4);
gpbdat =(unsigned int *) ioremap(GPBDAT,4);
gpbup  =(unsigned int *) ioremap(GPBUP,4);
/*
*GPB8 [17:16]  00 = Input 01 = Output
*GPB7 [15:14]  00 = Input 01 = Output
*GPB6 [13:12]  00 = Input 01 = Output
*GPB5 [11:10]  00 = Input 01 = Output
*/
data = readl(gpbcon);
data &= ~(0x3 << 10 | 0x3 << 12 | 0x3 << 14|0x3 << 16);
data |= (1 << 10 | 1 << 12 | 1 << 14 | 1 << 16);
writel(data,gpbcon);

data = readl(gpbdat);
data &= ~((1<<5)| (1<<6)| (1<<7)| (1<<8));
data |= (1<<5)|(1<<6)|(1<<7)|(1<<8);
writel(data,gpbdat);
}
static int __init led_init(void)
{
int rc;
int error;
rc = alloc_chrdev_region(&dev_id,0,1,NAME);
if(rc < 0) {
printk("alloc_chrdev_region failed\n");
goto fail_alloc;
}
cdev_init(&led_cdev,&led_fops);
led_cdev.owner = THIS_MODULE;

error = cdev_add(&led_cdev,dev_id,1);
if (error) {
printk("Could not add cdev\n");
goto fail_with_cdev;
}
led_gpio_init();
return 0;
fail_with_cdev:
unregister_chrdev_region(dev_id,1);
fail_alloc:
return -1;
}

static void __exit led_exit(void)
{
cdev_del(&led_cdev);
unregister_chrdev_region(dev_id,1);
}

MODULE_LICENSE("GPL");
module_init(led_init);
module_exit(led_exit);


测试程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define PATHNAME "dev/LED_GPIO_TEST"

#define LED1 0
#define LED2 1
#define LED3 2
#define LED4 3

#define ON 11
#define OFF 22

static void led_cmd(int fd,int num,int cmd);
/**
*led control command
*@fd - file descrip
*@num - the led numbers
*@cmd - command the led become ON or OFF
*/
static void led_cmd(int fd,int num,int cmd)
{
unsigned char buf=0;
unsigned int ret;
/*the buf's 7th bit is 1 means ON,is 0 means OFF*/
if (cmd == ON)
buf |= (1<<7);
else if (cmd == OFF)
buf = 0;
buf |= (1<<num);
ret = write(fd,&buf,sizeof(buf));
if (ret == -1)
printf("the led_cmd func's write wrong!!!!!\n");
}

void led_poll(int fd)
{
led_cmd(fd,LED1,ON);
sleep(1);
led_cmd(fd,LED2,ON);
sleep(1);
led_cmd(fd,LED3,ON);
sleep(1);
led_cmd(fd,LED4,ON);
sleep(1);
led_cmd(fd,LED1,OFF);
sleep(1);
led_cmd(fd,LED2,OFF);
sleep(1);
led_cmd(fd,LED3,OFF);
sleep(1);
led_cmd(fd,LED4,OFF);
}
int main(void)
{
unsigned int fd;
unsigned char cmd;
fd = open(PATHNAME,O_WRONLY);
if( -1 == fd) {
printf("there is no dev node - %s\n",PATHNAME);
}
led_poll(fd);
close(fd);
return 0;
}


shell脚本

insmod led.ko
cat proc/devices
mknod dev/LED_GPIO_TEST c 252 0
ls dev/LED*
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息