Led驱动代码完善与应用程序编写

发布时间:2023年12月26日

一.? 简介

前面几篇文章学习了 编写 Led驱动框架代码,Led的 IO初始化工作。文章地址如下:

LED驱动框架代码的实现-CSDN博客

Led驱动实验之Led灯初始化-CSDN博客

本文在之前实现的 Led驱动代码的基础上,完善代码。通过应用程序来实现 led灯的亮灭。

二.?? Led驱动代码完善

本文在前面 Led代码实现的基础上,进行完善。led.c源文件中,Led设备驱动卸载接口即 led_exit() 接口,去掉 关闭 Led灯的代码(即如下代码):

unsigned int value = 0;
printk("led_exit!\r\n");
value = readl(IMX6ULL_DR);  
value |= (1 << 3);         //bit3置1,关闭Led灯
writel(value, IMX6ULL_DR);

这里主要实现 led_write()接口实现,即对应应用层 write()函数。led.c文件的代码如下:

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

#define  LED_MAJOR   200   //Led的主设备号
#define  LED_NAME    "led" //Led灯的名字

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

#define  LED_OFF      0 //关闭Led灯
#define  LED_ON       1  //打开Led灯

//地址映射后的虚拟地址指针
static void __iomem *  IMX6ULL_CCM_CCGR1;
static void __iomem *  IMX6ULL_SW_MUX_GPIO1_IO03;
static void __iomem *  IMX6ULL_SW_PAD_GPIO01_IO03;
static void __iomem *  IMX6ULL_GDIR;
static void __iomem *  IMX6ULL_DR;

//开Led与关闭 Led
static void led_switch(unsigned char status)
{
    unsigned int value = 0;

    if(LED_ON == status) 
    {
        value = readl(IMX6ULL_DR);
        value &= ~(1 << 3);//bit3清零,低电平,打开Led
        writel(value, IMX6ULL_DR);
    }
    else if(LED_OFF == status) //bit3置1,高电平,关闭Led
    {
        value = readl(IMX6ULL_DR);
        value |= (1 << 3);
        writel(value, IMX6ULL_DR);
    }
}
 //打开Led设备
static int led_open(struct inode *inode, struct file *file)
{
    return 0;
}

// 向Led设备写数据
static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    int ret = 0;
    unsigned char data_buf[1] = {0};
    ret = copy_from_user(data_buf, buf, count);
    if(ret < 0)
    {
        printk("led_write failed!\r\n");
        return -EFAULT;
    }

    led_switch(data_buf[0]);
    
    return 0;
}

 //关闭/释放设备
static int led_release(struct inode *inode, struct file *file)
{
    return 0;
}

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

//Led驱动模块入口函数
static int __init led_init(void)
{  
    int ret = 0;
    unsigned int value = 0;
    printk("led_init!\r\n");

    /* Led灯的IO初始化 */
    //地址映射
    IMX6ULL_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
    IMX6ULL_SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
    IMX6ULL_SW_PAD_GPIO01_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
    IMX6ULL_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
    IMX6ULL_DR = ioremap(GPIO1_DR_BASE, 4);

    //使能 Led时钟
    value = readl(IMX6ULL_CCM_CCGR1);
    value &= ~(3 << 26);
    value |= (3 << 26);
    writel(value, IMX6ULL_CCM_CCGR1);

    //复用为 GPIO功能
    writel(0x05, IMX6ULL_SW_MUX_GPIO1_IO03);

    //配置电气属性
    writel(0X10B0, IMX6ULL_SW_PAD_GPIO01_IO03);

    //设置为输出功能
    value = readl(IMX6ULL_GDIR);
    value |= (1 << 3);
    writel(value, IMX6ULL_GDIR);

    //设置为低电平,打开 Led灯
    value = readl(IMX6ULL_DR);
    value &= ~(1 << 3);
    writel(value, IMX6ULL_DR);

    //注册字符设备
    ret = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
	if(ret < 0)
    {
        printk("led device register failed!\r\n");
        return -EIO;
    }		  
    return 0;
}

//Led驱动模块出口函数
static void __exit led_exit(void)
{
    printk("led_exit!\r\n");

    //取消地址映射
    iounmap(IMX6ULL_CCM_CCGR1);
    iounmap(IMX6ULL_SW_MUX_GPIO1_IO03);
    iounmap(IMX6ULL_SW_MUX_GPIO1_IO03);
    iounmap(IMX6ULL_GDIR);
    iounmap(IMX6ULL_DR);

    //卸载字符设备
    unregister_chrdev(LED_MAJOR, LED_NAME);
}

module_init(led_init); //入口
module_exit(led_exit); //出口

MODULE_LICENSE("GPL"); //模块 licence
MODULE_AUTHOR("lingxuewu"); //模块作者

二. 编写测试程序

这里编写的测试程序即 应用程序。应用程序通过写 关闭或打开 led的指令,传递给驱动。从而控制 led的亮灭。在 2_led工程中创建 应用程序文件 led_app.c。led_app.c文件中代码如下:

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

/*
* 打开/关闭 Led灯
* 参数:
* ./app_name /dev/led   0  //关闭Led灯
* ./app_name /dev/led   1  //打开Led灯
*/
int main(int argc, char* argv[])
{
    int fd = 0,count = 0;
    char * device_name = NULL;
    unsigned int led_value[1] = {0};

    if(argc != 3)
    {
        printf("main's param number error!\n");
        return -1;
    }

    device_name = argv[1];
    fd = open(device_name, O_RDWR);
    if(fd < 0)
    {
        printf("open led device failed!\n");
        return -1;
    }
    
    led_value[0] = atoi(argv[2]); //将字符转为数字
    count = write(fd, led_value, sizeof(led_value));
    if(count < 0)
    {
        printf("write data failed!\n");
        close(fd);

    }

    close(fd);
    return 0;
}

至此,Led驱动代码已完成,应用测试程序也已经完成,下一篇文章就是进行加载驱动模块以及测试。

文章来源:https://blog.csdn.net/wojiaxiaohuang2014/article/details/135189788
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。