tiny4412开发板LED灯驱动写法

简介

led灯成本很低,操控简单,在嵌入式产品中不可或缺,可以作为调试标识,状态指示等等,高级用法还可以作为呼吸灯进一步增强其美观性。本章介绍只控制led灯的亮灭,tiny4412开发板有四个LED灯在核心板上供用户操作,led灯亮灭靠cpu IO口输出电平,具体操控看实际电路。

电路图

在tiny4412开发板上,led灯电路如下:
tiny4412开发板LED灯驱动写法_第1张图片
与CPU连接如下:
这里写图片描述
可以看到CPU相应引脚输出相关电平,就可以控制灯的亮灭,cpu引脚输出低电平led灯亮,接下来就是操作相关寄存器,这些寄存器与GPM4相关,一个是控制寄存器,一个是数据寄存器。
命令寄存器
tiny4412开发板LED灯驱动写法_第2张图片
数据寄存器
tiny4412开发板LED灯驱动写法_第3张图片

驱动代码

//驱动代码
#include
#include
#include
#include 
#include 

#include
#include
#include
#include
#include //增加自动创建设备头文件
#include
//定义字符设备结构体
static struct cdev *leddriver_cdev;
//定义设备号(包含主次)
static dev_t leddriver_num=0;
//定义设备类
static struct class *leddriver_class;
//定义设备结构体
static struct device *leddriver_device;
//定义错误返回类型
static int  err;
//定义设备名称
#define LEDDRIVER_NAME "myled"

#define GPM4CON_ADDR 0x110002E0 
#define GPM4DAT_ADDR 0X110002E4

static volatile unsigned long *gpm4con=NULL;  
static volatile unsigned long *gpm4dat=NULL;

#define GPM4CON *gpm4con
#define GPM4DAT *gpm4dat


static

ssize_t leddriver_read(struct file *file, char __user *usr, size_t size, loff_t *loft)
{
    unsigned char LED_STATUE;


 copy_from_user(&LED_STATUE,usr,1);
 printk("leddriver read is %d\r\n",LED_STATUE);

  switch(LED_STATUE)
    {
 case 10:GPM4DAT |= (0x1<<0);break;
 case 11:GPM4DAT &=~(0X1<<0);break;
 case 20:GPM4DAT |= (0x1<<1);break;
 case 21:GPM4DAT &=~(0X1<<1);break;
 case 30:GPM4DAT |= (0x1<<2);break;
 case 31:GPM4DAT &=~(0X1<<2);break;
 case 40:GPM4DAT |= (0x1<<3);break;
 case 41:GPM4DAT &=~(0X1<<3);break;

  }

  return 0;
}

ssize_t leddriver_write (struct file *file, const char __user *usr, size_t size, loff_t *loft)
{
  printk("leddriver write is ok\r\n");
  return 0;
}

int leddriver_open (struct inode *node, struct file *file)
{
  printk("files open is success\r\n");
  return 0;
}

int leddriver_release (struct inode *node, struct file *file)
{
  printk("leddriver close is success\r\n");
  return 0;
}

//文件操作函数结构体
static struct file_operations leddriver_fops={
.owner=THIS_MODULE,
    .open=leddriver_open,
    .release=leddriver_release,
    .read=leddriver_read,
    .write=leddriver_write,
};

static __init int ldedriver_init(void)
{
//分配字符设备结构体,前面只是定义没有分配空间
leddriver_cdev=cdev_alloc();
//判断分配成功与否
if(leddriver_cdev==NULL)
{
  err=-ENOMEM;
  printk("leddriver alloc is err\r\n");
  goto err_leddriver_alloc;
}

//动态分配设备号
err=alloc_chrdev_region(&leddriver_num, 0, 1, LEDDRIVER_NAME);
//错误判断
if(err<0)
{
  printk("alloc leddriver num is err\r\n");
  goto err_alloc_chrdev_region;
}

//初始化结构体
cdev_init(leddriver_cdev,&leddriver_fops);

//驱动注册
err=cdev_add(leddriver_cdev,leddriver_num,1);
if(err<0)
{
  printk("cdev add is err\r\n");
  goto err_cdev_add;
}

//创建设备类
leddriver_class=class_create(THIS_MODULE,"led_class");
  err=PTR_ERR(leddriver_class);
  if(IS_ERR(leddriver_class))
    {
printk("leddriver creat class is err\r\n");
goto err_class_create;
  }


//创建设备
  leddriver_device=device_create(leddriver_class,NULL, leddriver_num,NULL, "leddevice");
 err=PTR_ERR(leddriver_device);
    if(IS_ERR(leddriver_device))
        {
printk("leddriver device creat is err \r\n");
goto err_device_create;
    }
//led灯寄存器配置
    gpm4con=ioremap(GPM4CON_ADDR, 4);
    gpm4dat=ioremap(GPM4DAT_ADDR, 4);

    GPM4CON &= ~(0XFFFF<<0);
    GPM4CON |= (0x1111<<0);
    GPM4DAT |= (0XF<<0);

printk("leddriver init is success\r\n");
return 0;

err_device_create:
class_destroy(leddriver_class);
err_class_create:
 cdev_del(leddriver_cdev);
err_cdev_add:
unregister_chrdev_region(leddriver_num, 1);

err_alloc_chrdev_region:
kfree(leddriver_cdev);

err_leddriver_alloc:
return err;

}

static __exit void leddriver_exit(void)
{
    //取消映射
    iounmap(gpm4con);
    iounmap(gpm4dat);

  device_destroy(leddriver_class,leddriver_num);
  class_destroy(leddriver_class);
  cdev_del(leddriver_cdev);
  unregister_chrdev_region(leddriver_num, 1);
  printk("leddriver is exit\r\n");
}


module_init(ldedriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");

app代码

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc,char *argv[])
{
  unsigned char LED_STATUE,shi;
  int ge;

  int led_fp;

  led_fp = open(argv[1],O_RDWR);
 // LED_STATUE=(unsigned char)atoi(argv[2]);
 while(1)
    {
  for(shi=1;shi<=4;shi++)
    {
      for(ge=1;ge>=0;ge--)
        {
      LED_STATUE=shi*10+ge;
      read(led_fp,&LED_STATUE,1);
      sleep(1);
    }
    }
    }
  close(led_fp);
}

Makefile

KERN_DIR = /zhangchao/linux3.5/linux-3.5
all:
    make -C $(KERN_DIR) M=`pwd` modules
cp:
    cp ./* /zhangchao/rootfs/zhangchao
clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
    rm -rf modules.order
obj-m += led.o

说明
虽然调用read write函数,来实现对灯的控制,并不符合函数操作规范,这里的led灯并不能看做是一个文件操作,并没有体现出linux一切皆文件,并不符合标准的文件操作方法,规范化写法将在后面给出。

你可能感兴趣的:(个人笔记,随笔,tiny4412,linux)