I.MX6U-驱动开发-2-LED驱动

1.地址映射

Linux驱动开发可以操作寄存器,但不能直接对寄存器物理地址进行读写(裸机可以),因为linux会使能MMU。

Linux下操作的是虚拟地址,需要先把物理地址转为虚拟地址,使用方法为:

ioremap:从物理地址转为虚拟地址  虚拟地址=ioremap(物理地址,大小)

iounmap:iounmap(虚拟地址)

2.led驱动框架搭建

包括注册函数,注销函数,file_operations结构体(owner,open,release,write)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define LED_MAJOR 200
#define LED_NAME "led"

static int led_open(struct inode *inode, struct file *filp)
{
    return 0;
}
static int led_release(struct inode *inode,struct file *filp)
{
    return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)
{
    return 0;
}


static const struct file_operations led_fops={
    .owner=THIS_MODULE,
    .write=led_write,
    .open=led_open,
    .release=led_release,
};

//注册
static int __init led_init(void)
{
    int ret=0;
    /*1.注册字符设备*/
    ret=register_chrdev(LED_MAJOR,LED_NAME,&led_fops);
    if(ret<0)
    {
        printk("register fail\r\n");
        return -EIO;
    }
    printk("led_init\r\n");
    return 0;
}
//卸载
static void __exit led_exit(void)
{
    /*注销字符设备*/
    unregister_chrdev(LED_MAJOR,LED_NAME);
    printk("led_exit\r\n");
}


/*注册驱动和卸载驱动*/
module_init(led_init);
module_exit(led_exit);
//license
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liujiasen");

3.驱动程序编写

1.初始化led的IO(使能时钟,IO复用,电气属性,输入输出设置)


#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#define LED_MAJOR 200
#define LED_NAME "led"

//寄存器物理地址
#define CCM_CCGR1_BASE         (0X020C406C)
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
#define GPIO1_DR_BASE          (0X0209C000)
#define GPIO1_GDIR_BASE        (0X0209C004)

//虚拟地址
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;


#define LEDOFF 0
#define LEDON 1

//led 打开和关闭
void led_switch(u8 sta)
{
    u32 val=0;
    if(sta==LEDON)
    {
        val=readl(GPIO1_DR);//读取寄存器的值
        val &=~(1<<3);//把bit3值为0 打开led
        writel(val,GPIO1_DR);   
    } 
    else
    {
        //close led
        val=readl(GPIO1_DR);//读取寄存器的值
        val |=(1<<3);//把bit3值为0 close led
        writel(val,GPIO1_DR);
    }
    
}

static int led_open(struct inode *inode, struct file *filp)
{
    return 0;
}
static int led_release(struct inode *inode,struct file *filp)
{
    return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)
{
    int retvalue;
    unsigned char databuf[1];

    retvalue=copy_from_user(databuf,buf,count);
    if(retvalue<0)
    {
        printk("kernel write fail\r\n");
        return -EFAULT;
    }
    //判断开灯还是关灯
    led_switch(databuf[0]);
    
    return 0;
}


static const struct file_operations led_fops={
    .owner=THIS_MODULE,
    .write=led_write,
    .open=led_open,
    .release=led_release,
};

//注册
static int __init led_init(void)
{
    int ret=0;
    unsigned int val=0;
    /*1.初始化LED灯 地址映射*/
    IMX6U_CCM_CCGR1=ioremap(CCM_CCGR1_BASE,4);
    SW_MUX_GPIO1_IO03=ioremap(SW_MUX_GPIO1_IO03_BASE,4);
    SW_PAD_GPIO1_IO03=ioremap(SW_PAD_GPIO1_IO03_BASE,4);
    GPIO1_DR=ioremap(GPIO1_DR_BASE,4);
    GPIO1_GDIR=ioremap(GPIO1_GDIR_BASE,4);
    /*2.初始化LED灯 时钟*/
    val=readl(IMX6U_CCM_CCGR1);//读取寄存器的值
    val &=~(3<<26);//把26,27值为0
    val |=3<<26;//把26,27值为1
    writel(val,IMX6U_CCM_CCGR1);//把值写入寄存器
    /*复用*/
    writel(5, SW_MUX_GPIO1_IO03);
    /*电器属性*/
    writel(0x10B0, SW_PAD_GPIO1_IO03);
    /*GPIO输入输出*/
	val = readl(GPIO1_GDIR);
	val &= ~(1 << 3);	/* 清除以前的设置 */
	val |= (1 << 3);	/* 设置为输出 */
	writel(val, GPIO1_GDIR);
    /*莫认为高点平输出点亮led*/
    val=readl(GPIO1_DR);//读取寄存器的值
    val &=~(1<<3);//把bit3值为0 打开led
    writel(val,GPIO1_DR);

    /*1.注册字符设备*/
    ret=register_chrdev(LED_MAJOR,LED_NAME,&led_fops);
    if(ret<0)
    {
        printk("register fail\r\n");
        return -EIO;
    }
    printk("led_init\r\n");
    return 0;
}
//卸载
static void __exit led_exit(void)
{
    unsigned int val=0;
    //close led
    val=readl(GPIO1_DR);//读取寄存器的值
    val |=(1<<3);//把bit3值为0 close led
    writel(val,GPIO1_DR);
    /*取消地址映射*/
	iounmap(IMX6U_CCM_CCGR1);
	iounmap(SW_MUX_GPIO1_IO03);
	iounmap(SW_PAD_GPIO1_IO03);
	iounmap(GPIO1_DR);
	iounmap(GPIO1_GDIR);
    /*注销字符设备*/
    unregister_chrdev(LED_MAJOR,LED_NAME);
    printk("led_exit\r\n");
}


/*注册驱动和卸载驱动*/
module_init(led_init);
module_exit(led_exit);
//license
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liujiasen");

2.进行测试

通过注册和注销点亮和关闭led

4.应用程序编写

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

/*
ledAPP <filename> <0:1> 1:open 2close


*/

//应用程序参数个数,传入的具体参数内容,格式为字符串
int main(int argc,char *argv[])
{
    int ret=0;
    int fd=0;
    unsigned char databuf[1];
    char *filename;
    char readbuf[100],writebuf[100];
    static char usrdata[]={"usr data!"};
    if(argc!=3)
    {
        printf("Eroor usage\r\n");
        return -1;
    }
      filename=argv[1];

  
    //RDWR具有读写
    fd=open(filename,O_RDWR);
    if(fd<0){
        printf("can't open file %s\r\n",filename);
        return -1;
    }

   databuf[0]=atoi(argv[2]);
   ret=write(fd,databuf,sizeof(databuf));
   if(ret<0)
   {
       printf("write fail\r\n");
       close(fd);
       return -1;
   }
   close(fd);



    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值