AcWing
  • 首页
  • 活动
  • 题库
  • 竞赛
  • 校园
  • 应用
  • 文章
    • 题解
    • 分享
    • 问答
  • 吐槽
  • 登录/注册

Linux 驱动开发基础---LED驱动程序

作者: 作者的头像   也许 ,  2022-05-14 14:54:08 ,  所有人可见 ,  阅读 31


0


思路:
LED驱动.png

代码实现基于imx6ull

驱动程序虽然可以操作硬件,但是也不能直接使用寄存器地址,要通过ioremap()函数映射为虚拟地址操作

驱动程序 leddrv.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>

static int major;
static struct class *led_class;

/* registers */
// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;

// GPIO5_GDIR 地址:0x020AC004
static volatile unsigned int *GPIO5_GDIR;

//GPIO5_DR 地址:0x020AC000
static volatile unsigned int *GPIO5_DR;

static ssize_t led_write(struct file *filp, const char __user *buf,
             size_t count, loff_t *ppos)
{
    char val;
    int ret;

    /* copy_from_user : get data from app */
    ret = copy_from_user(&val, buf, 1);

    /* to set gpio register: out 1/0 */
    if (val)
    {
        /* set gpio to let led on */
        *GPIO5_DR &= ~(1<<3);
    }
    else
    {

        /* set gpio to let led off */
        *GPIO5_DR |= (1<<3);
    }
    return 1;
}

static int led_open(struct inode *inode, struct file *filp)
{
    /* enable gpio5
     * configure gpio5_io3 as gpio
     * configure gpio5_io3 as output 
     */
    *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;
    *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;

    *GPIO5_GDIR |= (1<<3);

    return 0;
}

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

/* 入口函数 */
static int __init led_init(void)
{
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

    major = register_chrdev(0, "100ask_led", &led_fops);

    /* ioremap */
    // IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
    IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);

    // GPIO5_GDIR 地址:0x020AC004
    GPIO5_GDIR = ioremap(0x020AC004, 4);

    //GPIO5_DR 地址:0x020AC000
    GPIO5_DR  = ioremap(0x020AC000, 4);

    led_class = class_create(THIS_MODULE, "myled");
    device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); /* /dev/myled */

    return 0;
}

static void __exit led_exit(void)
{
    iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
    iounmap(GPIO5_GDIR);
    iounmap(GPIO5_DR);

    device_destroy(led_class, MKDEV(major, 0));
    class_destroy(led_class);

    unregister_chrdev(major, "100ask_led");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

测试程序

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


// ledtest /dev/myled on
// ledtest /dev/myled off

int main(int argc, char **argv)
{
    int fd;
    char status = 0;

    if (argc != 3)
    {
        printf("Usage: %s <dev> <on|off>\n", argv[0]);
        printf("  eg: %s /dev/myled on\n", argv[0]);
        printf("  eg: %s /dev/myled off\n", argv[0]);
        return -1;
    }
    // open
    fd = open(argv[1], O_RDWR);
    if (fd < 0)
    {
        printf("can not open %s\n", argv[0]);
        return -1;
    }

    // write
    if (strcmp(argv[2], "on") == 0)
    {
        status = 1;
    }

    write(fd, &status, 1);
    return 0;   
}

0 评论

你确定删除吗?
1024
x

© 2018-2022 AcWing 版权所有  |  京ICP备17053197号-1
用户协议  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标
请输入绑定的邮箱地址
请输入注册信息