您好,欢迎来到61ic! | [登录] [注册] 忘记密码 | 设为首页 帮助
 . 网站首页 . 业界新闻 . 设计中心 . 移动技术 . TI专栏 . ADI专栏 . FPGA专栏 . 代码工厂 . 官方商城 . 
 . 活动专区 . 新品快递 . 解决方案 . 前沿科技 . TI资源 . ADI资源 . FPGA资源 . 下载中心 . 产品展示 . 
加入收藏
付款方式
联系我们
您现在的位置: 61IC电子在线 >> TI专栏 >> TI C6000 DSP和ARM >> OMAP-L1x处理器 >> 正文
  [组图]ICETEK-OMAPL138 LED设备驱动           ★★★ 【字体:
ICETEK-OMAPL138 LED设备驱动
作者:tandesir    文章来源:tandesir    点击数:    更新时间:2013-10-6    

目标板  ICETEKOMAPL138

编译工具arm-none-linux-gnueabi-gcc(4.3.3)

 

硬件解析

      如图1所示,ICETEKOMAPL138 LED分别连接至EMIFA_D12

EMIFA_D13EMIFA_D14EMIFA_D15,且为低电平有效。

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

  

1 LED连接

      如图2所示,查阅数据手册 OMAP-L138 Low-Power Applications Processor》,知EMIFA_D12D15分别与GP34]-GP37]复用。

 

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

 

2 EMIFA引脚

      如图3所示,查阅数据手册《OMAP-L138 Applications Processor System》,EMIFA_D12D15系统配置引脚为PINMUX8,当PINMUX815-12bit配置为8h时,EMIFA_D12配置为GP34];当PINMUX811-8bit配置为8h时,EMIFA_D13配置为GP35];当PINMUX87-4bit配置为8h时,EMIFA_D14配置为GP36];当PINMUX83-0bit配置为8h时,EMIFA_D15配置为GP37]。

 

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

 

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

 

3 EMIFA配置

对应代码

#define PINMUX_BASE_ADDR                   0x01c14120

#define PINMUX_3_LED                             8

#define PINMUX_OFFSET_3_LED_D4        12

#define PINMUX_OFFSET_3_LED_D5        8

#define PINMUX_OFFSET_3_LED_D6        4

#define PINMUX_OFFSET_3_LED_D7        0

#define PINMUX_MODE_3_LED                0x8

 

      如图4所示,查阅数据手册《OMAP-L138 Low-Power Applications Processor》知,PINMUX的基地址为0x01C1420,地址空间为20×4bitPINMUX8的地址为0x01C1420+8×4bit

 

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

 

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

 

4 PINMUX地址分配

对应代码

int pinmux_setup(unsigned char pinmux_num,unsigned char pinmux_mode)

void __iomem *pinmux_base_virt = ioremap(PINMUX_BASE_ADDR, 20);

void __iomem *pinmux_virt = pinmux_base_virt + pinmux_num * 4;

… …

val &= ~((0xf<<PINMUX_OFFSET_3_LED_D4)|(0xf<<PINMUX_OFFSET_3_LED_D5)|(0xf<<PINMUX_OFFSET_3_LED_D6)|(0xf<<PINMUX_OFFSET_3_LED_D7));

      val |=((pinmux_mode<<PINMUX_OFFSET_3_LED_D4)|(pinmux_mode<<PINMUX_OFFSET_3_LED_D5)|(pinmux_mode<<PINMUX_OFFSET_3_LED_D6)|(pinmux_mode<<PINMUX_OFFSET_3_LED_D7));

 

其中 pinmux_num PINMUX_3_LED pinmux_modePINMUX_MODE_3_LED

 

      如图5所示,查阅数据手册《OMAP-L138 Low-Power Applications Processor》知,GPIO的基地址为0x01E26000,GPIO9bank,每个bank占用10×4bitBank3的基地址为0x01E26000+0x10(GPIO Bank0&1之前的空间)+10×4bit(GPIO Bank0&1所占用的空间)DIR23相对Bank3的偏移量为0OUT_DATA23相对Bank3的偏移量为4

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

  

5 GPIO地址分配

对应代码

#define GPIO_BASE_ADDR                   0x01e26000

#define GPIO_BANK01_OFFSET                 0x10   //First GPIO REG at 0x10 offset

#define GPIO_REGS_PER_BANKSET               10

#define GPIO_BANKS_PER_BANKSET            2

#define GPIO_BANKS                                 9

#define GPIO_BANK_DIR_REG_OFFSET              0

#define GPIO_BANK_OUT_REG_OFFSET             0x4

 

#define GPIO_BANK_3_LED                 3

#define GPIO_BANK_PIN_4_LED_D1              4

#define GPIO_BANK_PIN_5_LED_D2              5

#define GPIO_BANK_PIN_6_LED_D3              6

#define GPIO_BANK_PIN_7_LED_D4              7

 

#define LED_D1_GPIO_PIN       (GPIO_BANK_3_LED*16 + GPIO_BANK_PIN_4_LED_D1)

 

 gpio_regs_base_virt = ioremap(GPIO_BASE_ADDR, GPIO_BANK01_OFFSET + 4 * GPIO_REGS_PER_BANKSET * (GPIO_BANKS / GPIO_BANKS_PER_BANKSET + GPIO_BANKS % GPIO_BANKS_PER_BANKSET));

 

      如图6所示,查阅数据手册《OMAP-L138 Low-Power Applications Processor》知,DIR23GPIO的方向控制寄存器,GP34-7]对应DIR2316bit偏移量47的位置。当对应的位写0时,方向设置为输出。

 

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

 

6 GPIO方向寄存器

对应代码

int gpio_setdir(unsigned char led_pin, unsigned char val)

{

… …

      led_reg_virt = gpio_regs_base_virt + GPIO_REGS_PER_BANKSET * (led_pin / 32) * 4 + GPIO_BANK01_OFFSET + GPIO_BANK_DIR_REG_OFFSET;

… …

       reg_val &= ~(0xf << (led_pin % 32));

 

}

其中led_pin LED_D1_GPIO_PIN,方向设置为输出。

 

 

      如图7所示,查阅数据手册《OMAP-L138 Low-Power Applications Processor》知,OUT_DATA23GPIO的数据输出寄存器。GP34-7]对应OUT_DATA2316bit偏移量47的位置。当对应的位写0时,输出低电平;对应位写1时,输出高电平。

 

【原创】ICETEK-OMAPL138 LED设备驱动 - tandesir - tandesir的博客

 

7 GPIO数据输出寄存器

对应代码

int led_output(unsigned char led_pin,unsigned char val)

{

      … …

      led_reg_virt = gpio_regs_base_virt + GPIO_REGS_PER_BANKSET * (led_pin / 32) * 4 + GPIO_BANK01_OFFSET + GPIO_BANK_OUT_REG_OFFSET;

      … …

      reg_val &= ~(0xf << (led_pin % 32));

      reg_val |= ~val << (led_pin % 32);

      … …

 


要点解析

1、操作要点

(1)  EMIFA_D12-D15配置为GPIO

(2)   GPIO设置为输出

(3)   GPIO数据寄存器OUT_DATA23写入数据

 

2API接口

(1)   write操作

char num;

num=1;                  //0x01=0000 0001

      write(fd,&num,sizeof(char));   //LED0被点亮

(2)   ioctl操作

ioctl(fd,0);                    //关闭所有LED

ioctl(fd,1);                    //打开所有LED

 

3、驱动编译

      在确保交叉编译工具安装正确,内核源码执行过一次make的前提下,将led.cled.hMakefile拷贝至内核源码自建目录driver/led,修改Makefile KERNELDIR为内核源码目录所在的路径。执行make modules

 

4、驱动的安装

      将生成的led.ko文件拷贝至开发板文件系统/目录,进入该目录并执行insmod led.ko,执行ls /dev/led查看驱动是否安装成功。执行rmmod led.ko可卸载驱动。


代码清单

led.c

#include <linux/init.h>

#include <linux/module.h>

 

#ifdef CONFIG_MODVERSIONS

#include <config/modversions.h>

#endif

 

#include <linux/types.h>  /* size_t */

#include <linux/stat.h>

#include <linux/unistd.h>

#include <linux/slab.h>   /* kmalloc() */

 

#include <linux/kernel.h> /* printk() */

#include <linux/fs.h>     /* everything... */

#include <linux/errno.h>  /* error codes */

#include <linux/fcntl.h>

#include <linux/cdev.h>

#include <linux/tty.h>

#include <linux/mm.h>

#include <asm/atomic.h>

#include <asm/io.h>

#include <linux/list.h>

#include <linux/sched.h>

#include <linux/device.h>

#include <linux/ioport.h>

#include <asm/uaccess.h>

 

#include "led.h"

 

#define DIM_LED_MAJOR 0

 

#define DEVICE_NAME "led"

 

static struct class *led_class;

 

int led_major = DIM_LED_MAJOR;

int led_minor = 0;

 

static int led_open (struct inode *inode, struct file *filp)

{

      printk (KERN_ALERT "Device led opened\n");

      return 0;

}

 

static int led_release (struct inode *inode, struct file *filp)

{

 

      printk (KERN_ALERT "Device led released\n");

      return 0;

}

 

static int led_read(struct file*f,char *dst,size_t size,loff_t*offset){

     return 0;

}

 

static int led_write(struct file*f,const char *src,size_t size,loff_t *offset){

 

     unsigned char num;

     __copy_from_user(&num,src,1);

#ifdef DEBUG

     printk("__copy_from_user:%d\n",num);

#endif

     if(num>=0 && num<=15)

          led_output(LED_D1_GPIO_PIN, num);

     else

          printk("unknown command\n");

     return 0;

}

 

static int led_ioctl (struct inode *inode,

                      struct file *filp,

                      unsigned int cmd,

                      unsigned long param)

{

      switch(cmd)

      {

      case LED_OFF:

           led_output(LED_D1_GPIO_PIN,0);

           break;

      case LED_ON:

           led_output(LED_D1_GPIO_PIN,15);

           break;

      default:;

      }

}

 

static struct file_operations led_fops = {

      .owner = THIS_MODULE,

      .open = led_open,

      .release = led_release,

      .read = led_read,

      .write = led_write,

      .ioctl = led_ioctl,

};

 

static int __init led_init(void)

{

      int ret;

 

#ifdef DEBUG

      printk(KERN_ALERT "led drive module loading ... \n");

#endif

     

      ret = pinmux_setup(PINMUX_3_LED,PINMUX_MODE_3_LED);  

      if(ret)

      {

           printk(KERN_ALERT "Failed to set led_d1 as a io-pin\n");

           return -EIO;

      }

 

      ret = gpio_setdir(LED_D1_GPIO_PIN, 0);

      if(ret)

      {

           printk(KERN_ALERT "Failed to set led_d1 as an output pin\n");

           return -EIO;

      }

 

      ret = led_output(LED_D1_GPIO_PIN, 15);

     

      led_major = register_chrdev(led_major, DEVICE_NAME, &led_fops);

      if (led_major<0)

      {

           printk(DEVICE_NAME " Can't register major number!\n");

           return -EIO;

      }

 

#ifdef DEBUG

      printk(KERN_ALERT "led drive module loaded. \n");

      printk(KERN_ALERT "led drive : device creating ...\n");

#endif

      led_class = class_create(THIS_MODULE, DEVICE_NAME);

      device_create(led_class, NULL, MKDEV(led_major, led_minor), NULL, DEVICE_NAME);

 

      return 0;

}

 

static void __exit led_clean(void)

{

#ifdef DEBUG

      printk(KERN_ALERT "led drive module unloading ... \n");

#endif

      device_destroy(led_class, MKDEV(led_major,led_minor));

      class_unregister(led_class);

      class_destroy(led_class);

      unregister_chrdev(led_major, DEVICE_NAME);

#ifdef DEBUG

      printk(KERN_ALERT "led drive module unloaded\n");

#endif

 

}

 

MODULE_LICENSE ("GPL");

MODULE_VERSION ("v0.1");

MODULE_AUTHOR ("RealtimeDSP");

MODULE_DESCRIPTION ("This module is the driver for LED on OMAPL138");

 

module_init(led_init);

module_exit(led_clean);


led.h

#ifndef __LED_H__

#define __LED_H__

 

 

#define PINMUX_BASE_ADDR             0x01c14120

//    The PINMUX occupied by LED_D1

#define PINMUX_3_LED                  8

#define PINMUX_OFFSET_3_LED_D4             12

#define PINMUX_OFFSET_3_LED_D5             8

#define PINMUX_OFFSET_3_LED_D6             4

#define PINMUX_OFFSET_3_LED_D7             0

 

#define PINMUX_MODE_3_LED                0x8

 

#define GPIO_BASE_ADDR                   0x01e26000

#define GPIO_BANK01_OFFSET                 0x10   //First GPIO REG at 0x10 offset

#define GPIO_REGS_PER_BANKSET               10

#define GPIO_BANKS_PER_BANKSET            2

#define GPIO_BANKS                      9

#define GPIO_BANK_DIR_REG_OFFSET         0

#define GPIO_BANK_OUT_REG_OFFSET       0x4

 

#define GPIO_BANK_3_LED                 3

#define GPIO_BANK_PIN_4_LED_D1              4

#define GPIO_BANK_PIN_5_LED_D2              5

#define GPIO_BANK_PIN_6_LED_D3              6

#define GPIO_BANK_PIN_7_LED_D4              7

 

#define LED_D1_GPIO_PIN       (GPIO_BANK_3_LED*16 + GPIO_BANK_PIN_4_LED_D1)

//#define LED_D2_GPIO_PIN     (GPIO_BANK_3_LED*16 + GPIO_BANK_PIN_5_LED_D2)

//#define LED_D3_GPIO_PIN     (GPIO_BANK_3_LED*16 + GPIO_BANK_PIN_6_LED_D3)

//#define LED_D4_GPIO_PIN     (GPIO_BANK_3_LED*16 + GPIO_BANK_PIN_7_LED_D3)

 

#define LED_ON                         1

#define LED_OFF                       0

 

#define DIM_CMD_MAGIC   'X'

 

#define DIM_CMD_IO(num)                   _IO(DIM_CMD_MAGIC,num)

#define LED_TURN_ON                   DIM_CMD_IO(1)

#define LED_TURN_OFF                 DIM_CMD_IO(2)

#define LED_TOGGLE                     DIM_CMD_IO(3)

 

int pinmux_setup(unsigned char pinmux_num,unsigned char pinmux_mode)

{

      void __iomem *pinmux_base_virt = ioremap(PINMUX_BASE_ADDR, 20);

      void __iomem *pinmux_virt = pinmux_base_virt + pinmux_num * 4;

      unsigned int val = ioread32(pinmux_virt);

      val &= ~((0xf<<PINMUX_OFFSET_3_LED_D4)|(0xf<<PINMUX_OFFSET_3_LED_D5)|(0xf<<PINMUX_OFFSET_3_LED_D6)|(0xf<<PINMUX_OFFSET_3_LED_D7));

      val |=((pinmux_mode<<PINMUX_OFFSET_3_LED_D4)|(pinmux_mode<<PINMUX_OFFSET_3_LED_D5)|(pinmux_mode<<PINMUX_OFFSET_3_LED_D6)|(pinmux_mode<<PINMUX_OFFSET_3_LED_D7));

 

#ifdef DEBUG

           printk("%s: pinmux_reg_phys is 0x%x\n", __FUNCTION__, PINMUX_BASE_ADDR + (unsigned int)pinmux_num * 4);

           printk("%s: pinmux_reg_virt is 0x%x\n", __FUNCTION__, (unsigned int)pinmux_virt);

           printk("%s: pinmux_reg_val is set as 0x%x\n", __FUNCTION__, val);

#endif

 

      iowrite32(val,pinmux_virt);

      iounmap(pinmux_base_virt);

      return 0;

}

 

int led_output(unsigned char led_pin,unsigned char val)

{

      void __iomem *gpio_regs_base_virt, *led_reg_virt;

      unsigned int reg_val;

     

      if(val>=0&&val<=15)

      {

           gpio_regs_base_virt = ioremap(GPIO_BASE_ADDR, GPIO_BANK01_OFFSET + 4 * GPIO_REGS_PER_BANKSET * (GPIO_BANKS / GPIO_BANKS_PER_BANKSET + GPIO_BANKS % GPIO_BANKS_PER_BANKSET));

           led_reg_virt = gpio_regs_base_virt + GPIO_REGS_PER_BANKSET * (led_pin / 32) * 4 + GPIO_BANK01_OFFSET + GPIO_BANK_OUT_REG_OFFSET;

           reg_val = ioread32(led_reg_virt);

           reg_val &= ~(0xf << (led_pin % 32));

           reg_val |= ~val << (led_pin % 32);

 

#ifdef DEBUG

           printk("%s: gpio_out_reg_phys is 0x%x\n", __FUNCTION__, GPIO_BASE_ADDR + GPIO_REGS_PER_BANKSET * (led_pin / 32) * 4 + GPIO_BANK01_OFFSET + GPIO_BANK_OUT_REG_OFFSET);

           printk("%s: gpio_out_reg_virt is 0x%x\n", __FUNCTION__, (unsigned int)led_reg_virt);

           printk("%s: gpio_out_reg_val is set as 0x%x\n", __FUNCTION__, reg_val);

#endif

           iowrite32(reg_val, led_reg_virt);

           iounmap(gpio_regs_base_virt);

      }

      return 0;

}

 

int gpio_setdir(unsigned char led_pin, unsigned char val)

{

        void __iomem *gpio_regs_base_virt, *led_reg_virt;

        unsigned int reg_val;

       

      if(val>=0&&val<=15)

      {

                gpio_regs_base_virt = ioremap(GPIO_BASE_ADDR, GPIO_BANK01_OFFSET + 4 * GPIO_REGS_PER_BANKSET * (GPIO_BANKS / GPIO_BANKS_PER_BANKSET + GPIO_BANKS % GPIO_BANKS_PER_BANKSET));

                led_reg_virt = gpio_regs_base_virt + GPIO_REGS_PER_BANKSET * (led_pin / 32) * 4 + GPIO_BANK01_OFFSET + GPIO_BANK_DIR_REG_OFFSET;

                reg_val = ioread32(led_reg_virt);

#ifdef DEBUG

           printk("%s: gpio_pin is %d\n", __FUNCTION__, led_pin);

           printk("%s: gpio_dir_reg_val is set as 0x%x\n", __FUNCTION__, reg_val);

#endif

                reg_val &= ~(0xf << (led_pin % 32));

#ifdef DEBUG

           printk("%s: gpio_dir_reg_val is set as 0x%x\n", __FUNCTION__, reg_val);

#endif

                reg_val |= val << (led_pin % 32);

#ifdef DEBUG

           printk("%s: gpio_dir_reg_val is set as 0x%x\n", __FUNCTION__, reg_val);

          

           printk("%s: gpio_dir_reg_phys is 0x%x\n", __FUNCTION__, GPIO_BASE_ADDR + GPIO_REGS_PER_BANKSET * (led_pin / 32) * 4 + GPIO_BANK01_OFFSET + GPIO_BANK_DIR_REG_OFFSET);

           printk("%s: gpio_dir_reg_virt is 0x%x\n", __FUNCTION__, (unsigned int)led_reg_virt);

#endif

                iowrite32(reg_val, led_reg_virt);

                iounmap(gpio_regs_base_virt);

        }

        return 0;

}

 

#endif
Makefile

# Comment/uncomment the following line to disable/enable debugging

DEBUG = n

 

# Add your debugging flag (or not) to CFLAGS

# "-O" is needed to expand inlines

ifeq ($(DEBUG),y)

  DEBFLAGS = -O -g -DDEBUG

else

  DEBFLAGS = -O2

endif

 

EXTRA_CFLAGS += $(DEBFLAGS)

#EXTRA_CFLAGS += -I$(LDDINC)

 

ifneq ($(KERNELRELEASE),)

# call from kernel build system

 

#scull-objs := main.o pipe.o access.o

 

      obj-m   := led.o

#    seed_led-objs := led.o

 

else

 

      KERNELDIR :=/home/realtimedsp/work/omapl138/linux-2.6.33-rc4-psp03.20.00.14.sdk

      PWD       := $(shell pwd)

 

modules:

      $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

 

clean:

      rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

 

depend .depend dep:

      $(CC) $(CFLAGS) -M *.c > .depend

 

 

ifeq (.depend,$(wildcard .depend))

include .depend

endif

 

endif

 


led_test.c(测试代码)

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/ioctl.h>

 

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/mman.h>

#include <fcntl.h>

#include <string.h>

 

int main()

{

    int fd = -1;

    int i;

    char num;

 

    fd = open("/dev/led", O_RDWR);  // 打开设备

    if (fd < 0) {

        printf("Can't open /dev/led\n");

        return -1;

    }

       

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

    {

      num=i;

      write(fd,&num,sizeof(char));

      sleep(1);

    }

   

     num=2;

    do

   {

      ioctl(fd,0);

      sleep(1);

      ioctl(fd,1);

     }while(num--);

 

    close(fd);

    return 0;

}

 

 

 

 

转载请标明出处,欢迎转载,请勿用于商业目的!

Copyrignt @ tandesir.blog.163.com

文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章: 没有了
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    没有相关文章
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    站长:61 湘ICP备13001086号-2