Firefly RK3308B LED灯实例(驱动)

通过驱动的方式,点亮LED灯,熟悉驱动开发的流程

参考链接:
https://www.cnblogs.com/downey-blog/p/10501709.html

(1)新建并编辑gpio_led_control.c

在目录/home/sgw/prj/Firefly-RK3308/kernel/drivers/test下,新建gpio_led_control.c

$ touch gpio_led_control.c
$ gedit gpio_led_conrtol.c

gpio_led_control.c内容
我的开发板是RCC-RK3308B-CC-PLUS,LED的端口号是10

#include <linux/init.h>  
#include <linux/module.h>
#include <linux/device.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/string.h>


MODULE_AUTHOR("Downey");
MODULE_LICENSE("GPL");

static int majorNumber = 0;
/*Class 名称,对应/sys/class/下的目录名称*/
static const char *CLASS_NAME = "led_control_class";
/*Device 名称,对应/dev下的目录名称*/
static const char *DEVICE_NAME = "led_control_demo";

static int led_control_open(struct inode *node, struct file *file);
static ssize_t led_control_read(struct file *file,char *buf, size_t len,loff_t *offset);
static ssize_t led_control_write(struct file *file,const char *buf,size_t len,loff_t* offset);
static int led_control_release(struct inode *node,struct file *file);

#define LED_PIN   10 
static int gpio_status;


static char recv_msg[20];

static struct class *led_control_class = NULL;
static struct device *led_control_device = NULL;

/*File opertion 结构体,我们通过这个结构体建立应用程序到内核之间操作的映射*/
static struct file_operations file_oprts = 
{
    .open = led_control_open,
    .read = led_control_read,
    .write = led_control_write,
    .release = led_control_release,
};


static void gpio_config(void)
{
    if(!gpio_is_valid(LED_PIN)){
        printk(KERN_ALERT "Error wrong gpio number\n");
        return ;
    }
    gpio_request(LED_PIN,"led_ctr");
    gpio_direction_output(LED_PIN,1);
    gpio_set_value(LED_PIN,1);
    gpio_status = 1;
}


static void gpio_deconfig(void)
{
    gpio_free(LED_PIN);
}

static int __init led_control_init(void)
{
    printk(KERN_ALERT "Driver init\r\n");
    /*注册一个新的字符设备,返回主设备号*/
    majorNumber = register_chrdev(0,DEVICE_NAME,&file_oprts);
    if(majorNumber < 0 ){
        printk(KERN_ALERT "Register failed!!\r\n");
        return majorNumber;
    }
    printk(KERN_ALERT "Registe success,major number is %d\r\n",majorNumber);

    /*以CLASS_NAME创建一个class结构,这个动作将会在/sys/class目录创建一个名为CLASS_NAME的目录*/
    led_control_class = class_create(THIS_MODULE,CLASS_NAME);
    if(IS_ERR(led_control_class))
    {
        unregister_chrdev(majorNumber,DEVICE_NAME);
        return PTR_ERR(led_control_class);
    }

    /*以DEVICE_NAME为名,参考/sys/class/CLASS_NAME在/dev目录下创建一个设备:/dev/DEVICE_NAME*/
    led_control_device = device_create(led_control_class,NULL,MKDEV(majorNumber,0),NULL,DEVICE_NAME);
    if(IS_ERR(led_control_device))
    {
        class_destroy(led_control_class);
        unregister_chrdev(majorNumber,DEVICE_NAME);
        return PTR_ERR(led_control_device);
    }
    printk(KERN_ALERT "led_control device init success!!\r\n");

    return 0;
}

/*当用户打开这个设备文件时,调用这个函数*/
static int led_control_open(struct inode *node, struct file *file)
{
    printk(KERN_ALERT "GPIO init \n");
    gpio_config();
    return 0;
}

/*当用户试图从设备空间读取数据时,调用这个函数*/
static ssize_t led_control_read(struct file *file,char *buf, size_t len,loff_t *offset)
{
    int cnt = 0;
    /*将内核空间的数据copy到用户空间*/
    cnt = copy_to_user(buf,&gpio_status,1);
    if(0 == cnt){
        return 0;
    }
    else{
        printk(KERN_ALERT "ERROR occur when reading!!\n");
        return -EFAULT;
    }
    return 1;
}

/*当用户往设备文件写数据时,调用这个函数*/
static ssize_t led_control_write(struct file *file,const char *buf,size_t len,loff_t *offset)
{
    /*将用户空间的数据copy到内核空间*/
    int cnt = copy_from_user(recv_msg,buf,len);
    if(0 == cnt){
        if(0 == memcmp(recv_msg,"on",2))
        {
            printk(KERN_INFO "LED ON!\n");
            gpio_set_value(LED_PIN,1);
            gpio_status = 1;
        }
        else
        {
            printk(KERN_INFO "LED OFF!\n");
            gpio_set_value(LED_PIN,0);
            gpio_status = 0;
        }
    }
    else{
        printk(KERN_ALERT "ERROR occur when writing!!\n");
        return -EFAULT;
    }
    return len;
}

/*当用户打开设备文件时,调用这个函数*/
static int led_control_release(struct inode *node,struct file *file)
{
    printk(KERN_INFO "Release!!\n");
    gpio_deconfig();
    return 0;
}

/*销毁注册的所有资源,卸载模块,这是保持linux内核稳定的重要一步*/
static void __exit led_control_exit(void)
{
    device_destroy(led_control_class,MKDEV(majorNumber,0));
    class_unregister(led_control_class);
    class_destroy(led_control_class);
    unregister_chrdev(majorNumber,DEVICE_NAME);
}

module_init(led_control_init);
module_exit(led_control_exit);

(2)编辑Makefile文件

$ gedit Makefile

Makefile内容

obj-m+=hello_world.o gpio_led_control.o
all:
	make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean

(3)编译生成.ko文件
回到/home/sgw/prj/Firefly-RK3308/kernel路径下

$ make

(4)adb推到开发板
回到/home/sgw/prj/Firefly-RK3308/kernel/drivers/test目录

$ adb push gpio_led_control.ko mnt/

(5)新建并编辑gpio_led_contro_user.c文件

$ touch gpio_led_contro_user.c
$ gedit gpio_led_control_user.c

gpio_led_control_user.c内容

#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
static char buf[256] = {1};
int main(int argc,char *argv[])
{
    int fd = open("/dev/led_control_demo",O_RDWR);
    if(fd < 0)
    {
        perror("Open file failed!!!\r\n");
        return -1;
    }
    while(1){
        printf("Please input <on> or <off>:\n");
        scanf("%s",buf);
        if(strlen(buf) > 3){
            printf("Ivalid input!\n");
        }
        else
        {
            int ret = write(fd,buf,strlen(buf));
            if(ret < 0){
                perror("Failed to write!!");
        }
    }
    }
    close(fd);
    return 0;
}

(6)交叉编译gpio_led_contro_user.c
根据Firefly官网介绍,Builroot的编译工具链是buildroot/output/firefly_rk3308_release/host/bin/aarch64-rockchip-linux-gnu-

$ /home/sgw/prj/Firefly-RK3308/buildroot/output/firefly_rk3308_release/host/bin/aarch64-rockchip-linux-gnu-gcc gpio_led_contro_user.c -o user

(7)adb推进开发板

$ adb push user mnt/

(8)adb进入开发板加载并执行

$ adb shell
/mnt # insmod gpio_led_control.ko
/mnt # ./user
Please input <on> or <off>:
on
Please input <on> or <off>:
off
Please input <on> or <off>:

可以看到开发板上的LED灯会亮灭。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值