Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2409710
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: LINUX

2011-03-24 13:12:00

13mini2440led灯驱动

 

注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方

1.本文所介绍的程序平台

开发板:arm9-mini2440

虚拟机为:Red Hat Enterprise Linux 5

开发板上系统内核版本:linux-2.6.32.2

上拉/下拉

 

上拉是将不确定的信号通过一个电阻与电源相连,固定在高电平。下拉是将不确定 的信号通过一个电阻与地相连,固定在低电平。上拉是对器件注入电流,下拉是输出电流。当一个接有上拉电阻的I/O端口设为输入状态时,它的常态为高电平,可用于检测低电平的输入。

 

S3c2440 I/O端口

 

S3C2440包含GPA GPB ....GPJ 九组I/O端口。它们的寄存器是相似的:GPxCON用于设置端口功能(00  示输入、01  示输出、10示特殊功能、11保留不用)GPxDAT用于读/写数据,GPxUP 用于决定是否使用内部上拉电阻 (某位为0时,相应引脚无内部上拉;为1时,相应引脚使用内部上拉 )

 

2.程序清单

本次实验程序为网络代码,本人作了改动和较为详细的注释,如有错误请指出。

 

官方手册上写,mini2440的四个LED与CPU的GPIO相连,LED1, LED2, LED3, LED4分别对应的

是GPB5, GPB6, GPB7, GPB8。那什么是GPIO呢?

 

GPIO是通用输入输出口的简称,只需要设置相应的CPU寄存器,就可以改变引脚的用途。

控制硬件,其实就是控制对应的寄存器。

 

四个LED的采用GPBCON寄存器上的4组2bit位来配置对应引脚的状态。4组2bit位的功能都

一样:00表示输入,01表示输出,10为特殊功能,11是保留的。

LED1对应的是GPB5, GPB5使用[11:10]位

LED2对应的是GPB6, GPB6使用[12:13]位

LED3对应的是GPB7, GPB7使用[14:15]位

LED4对应的是GPB8, GPB8使用[16:17]位

驱动需要先设置LED为输出状态,也就是要把对应的GPBX设置为01。

 

四个LED采用CPBDAT寄存器来对应4个LED的数值状态,GPBDAT5就对应GPB5,GPBDAT6就对

应GPB6,以此类推。手册上写低电平有效,就是说当GPBDAT寄存器位置为0时,LED就发光。

 

在三星官方的手册S3C2440.pdf中有寄存器状态描述

 

mini2440_leds.h

 

#ifndef _LEDDEV_H_

#define _LEDDEV_H_

 

#include

 

/* 定义幻数 */

#define LEDDEV_IOC_MAGIC  'k'

 

/* 定义命令 */

#define LEDDEV_IOCON   _IO(LEDDEV_IOC_MAGIC, 1)

#define LEDDEV_IOCOFF _IO(LEDDEV_IOC_MAGIC, 2)

 

#define LEDDEV_IOC_MAXNR 2

 

#endif /* _LEDDEV_H_ */

 

mini2440_leds.c

 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#include "mini2440_leds.h"

 

#define DEVICE_NAME "my_leds"

 

/* GPBX */

 

static unsigned long led_table [] = {

    S3C2410_GPB(5),

    S3C2410_GPB(6),

    S3C2410_GPB(7),

    S3C2410_GPB(8),

};

 

/* GPBX的输出状态 */

static unsigned int led_cfg_table [] = {

    S3C2410_GPIO_OUTPUT,

    S3C2410_GPIO_OUTPUT,

    S3C2410_GPIO_OUTPUT,

    S3C2410_GPIO_OUTPUT,

};

 

 

/* 驱动接口函数

* ioctl的内核空间版本和用户控件的版本不同

* 内核版为:

* int (*ioctl)( struct inode *inode, struct file *file, unsigned int

* cmd, unsigned long arg);

* */

 

static int sbc2440_leds_ioctl(

    struct inode *inode,

    struct file *file,

    unsigned int cmd,

    unsigned long arg)

{

    int i;

       /* 检测命令的有效性 */

      if (_IOC_TYPE(cmd) != LEDDEV_IOC_MAGIC)

          return -EINVAL;

      if (_IOC_NR(cmd) > LEDDEV_IOC_MAXNR)

          return -EINVAL;

 

    /*

    switch(cmd) {

    case 0:

    case 1:

        if (arg > 4) {

            return -EINVAL;

        }

       

          // 设置数据寄存器GPBDAT

          //低电平有效,用户程序传来的cmd取反

        s3c2410_gpio_setpin(led_table[arg], !cmd);

 

         

        return 0;

    default:

        return -EINVAL;

    }*/

     /* 根据命令,执行相应的操作 */

     switch(cmd) {

     case LEDDEV_IOCOFF:

      /*灯全灭*/

      cmd = 1;

      for(i=0; i<4; i++)

       s3c2410_gpio_setpin(led_table[i], cmd);

      return 0;

     

     case LEDDEV_IOCON:

      /*灯全亮*/

      for(i=0; i<4; i++)

       s3c2410_gpio_setpin(led_table[i], !cmd);

      return 0;

     default:

      return -EINVAL;

     }

 

}

 

/* 接口对象 */

static struct file_operations dev_fops = {

    .owner  =   THIS_MODULE,

    .ioctl  =   sbc2440_leds_ioctl,

};

 

 

/* 设备对象 */

static struct miscdevice misc = {

    .minor = MISC_DYNAMIC_MINOR,/* 动态设备号 */

    .name = DEVICE_NAME,/* 将在/dev目录生成led设备 */

    .fops = &dev_fops,/* 驱动接口 */

};

 

static int __init dev_init(void)

{

    int ret;

    int i;

   

   

    for (i = 0; i < 4; i++) {

        /*设置GPIO对应的配置寄存器GPIOCON为输出状态*/

        s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

 

        /*设置GPIO对应的数据寄存器GPIODAT为低电平

       *在模块加载结束后,四个LED应该是全部都是发光状态*/

        s3c2410_gpio_setpin(led_table[i], 0);

    }

 

    /* 注册设备 */

    ret = misc_register(&misc);

 

    printk (DEVICE_NAME"\tinitialized\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("FriendlyARM Inc.");

 

leds_app.c

 

#include

#include

#include

 

#include       // open() close()

#include      // read() write()

#include "mini2440_leds.h"

//define LED STATUS

#define LED_ON  0

#define LED_OFF 1

//------------------------------------- main ---------------------------------------------

int main(void)

{

       int fd;

       int ret;

       char *i;

 

       fd = open("/dev/my_leds", 0);

 

       if (fd < 0)

        {

                printf("open device %s error\n", "my_leds");

        }

        else

        {

        while(1)

        {

           ioctl(fd,LEDDEV_IOCOFF);

           sleep(1);//等待1秒再做下一步操作

           printf("led is off\n");

           ioctl(fd,LEDDEV_IOCON);

           sleep(1);

           printf("led is on\n");

       }

           close(fd);

      }

           return 0;

}

 

Arm平台LED实验:

[root@FriendlyARM test]# insmod mini2440_leds.ko

my_leds initialized //全亮

[root@FriendlyARM test]# ./leds_app

led is off

led is on

led is off

led is on

led is off

led is on

led is off

^C

[root@FriendlyARM test]#

阅读(1578) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~