openwrt通过字符驱动的方式控制LED灯光 (四-- 二)_一只青木呀的博客-程序员秘密

技术标签: 字符驱动  openwrt  

1、概述

通过在openwrt源码目录下(或者SDK包的openwrt的目录下)编写gpio的字符驱动生成ipk包,发送到开发板上insmod加载驱动,然后通过编写APP来进行测试。

2、在源码目录的 ./package/kernel下创建gpio_control_driver文件夹

mkdir gpio_control_driver

在这里插入图片描述

3、在gpio_control_driver文件夹下创建Makefile和src文件夹

mkdir src
touch Makefile

4、编写Makefile

include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
 
PKG_NAME:=gpio_control_driver
PKG_RELEASE:=1

include $(INCLUDE_DIR)/package.mk
 
define KernelPackage/$(PKG_NAME)
  SUBMENU:=Other modules
  DEPENDS:=@GPIO_SUPPORT
  TITLE:=Driver for FA156 gpios control
  FILES:=$(PKG_BUILD_DIR)/gpio_control_driver.ko
  AUTOLOAD:=$(call AutoLoad,30,gpio_control_driver)
endef
 
define KernelPackage/$(PKG_NAME)/description
 Kernel module to control gpios for  FA156
endef
 
 
define Build/Prepare
	mkdir -p $(PKG_BUILD_DIR)
	cp -rf  ./src/* $(PKG_BUILD_DIR)/
endef
 
define Build/Compile
	$(MAKE) -C "$(LINUX_DIR)" \
		CROSS_COMPILE="$(TARGET_CROSS)" \
		ARCH="$(LINUX_KARCH)" \
		SUBDIRS="$(PKG_BUILD_DIR)" \
		EXTRA_CFLAGS="$(BUILDFLAGS)" \
		$(EXTRA_KCONFIG) \
		modules
endef

$(eval $(call KernelPackage,$(PKG_NAME)))

makefile注释在https://editor.csdn.net/md/?articleId=109803571这篇文章里,我详细注释了。

5、进入src目录下创建gpio_control_driver.c 、 Makefile

touch gpio_control_driver.c 
touch Makefile

在这里插入图片描述

6、编写gpio_control_driver.c 、Makefile

Makefile:

obj-m := gpio_control_driver.o

gpio_control_driver.c:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define NEWCHRLED_CNT			1		  	
#define NEWCHRLED_NAME			"gpio_control"	
#define GPIO_CONTROL_SET_OUT			0x01
#define GPIO_CONTROL_SET_IN			    0x02
//#define GPIO_CONTROL_GET_DIRECTION	0x03
#define GPIO_CONTROL_SET_VALUE			0x04
#define GPIO_CONTROL_GET_VALUE			0x05
#define GPIO_CONTROL_REQUEST_GPIO		0x06
#define GPIO_CONTROL_FREE_GPIO			0x07
#define GET_GPIO_NUM(arg1)	        (unsigned char)((arg1 >> 24) & 0xff)
#define GET_GPIO_VALUE(arg1)	    (unsigned char)((arg1 >> 16) & 0xff)



struct  gpio_control_dev{
    
	dev_t devid;			
	struct cdev cdev;		
	struct class *class;		
	struct device *device;	
	int major;				
	int minor;				
};
struct  gpio_control_dev  gpio_control;

static int gpio_control_open(struct inode *pinode, struct file *pfile)
{
    
        printk("***%s***\n",__func__);

        return 0;
}

static int gpio_control_release(struct inode *pinode, struct file *pfile)
{
    
        printk("***%s***\n",__func__);

        return 0;
}
static long gpio_control_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{
    
	int ret;
	unsigned char gpio_number;
	unsigned char gpio_value;
 
 
	gpio_number = GET_GPIO_NUM(arg);
	gpio_value  = GET_GPIO_VALUE(arg);
 
	switch (cmd){
    
	case GPIO_CONTROL_SET_OUT:
		ret = gpio_direction_output(gpio_number, gpio_value);
		if (ret < 0){
    
			return -1;
		}
		break;
 
	case GPIO_CONTROL_SET_IN:
		ret = gpio_direction_input(gpio_number);
		if (ret < 0){
    
			return -1;
		}
		break;
	case GPIO_CONTROL_SET_VALUE:
		gpio_set_value(gpio_number, gpio_value);
		break;
 
	case GPIO_CONTROL_GET_VALUE:
		ret = gpio_get_value(gpio_number);
		if (ret < 0){
    
			return -1;
		}
		break;
 
	case GPIO_CONTROL_REQUEST_GPIO:
		if (0 > gpio_request(gpio_number, "gpio_ctrl")){
    
			return -1;
		}
		break;
 
	case GPIO_CONTROL_FREE_GPIO:
		gpio_free(gpio_number);
		break;
 
	default:
		printk("***Unknown command:0x%02X\n***\n", cmd);
		break;
 
	}
 
	return 0;
}

static const struct file_operations gpio_control_ops = {
    
                .owner                  = THIS_MODULE,
                .open                   = gpio_control_open,
                .release                = gpio_control_release,
                .unlocked_ioctl         = gpio_control_ioctl,
};

static int __init led_init(void)
{
    
    unsigned int ret = 0;

    /*1. register chrdev*/
    if (gpio_control.major) {
    		
		gpio_control.devid = MKDEV(gpio_control.major, 0);
		ret =register_chrdev_region(gpio_control.devid, NEWCHRLED_CNT, NEWCHRLED_NAME);
	} else {
    						
		ret = alloc_chrdev_region(&gpio_control.devid, 0, NEWCHRLED_CNT, NEWCHRLED_NAME);	
	}
    if(ret < 0 )
    {
    
        goto faial_alloc_chrdeev;
    }

    /* 2. init chrdev*/
    gpio_control.cdev.owner = THIS_MODULE;
	cdev_init(&gpio_control.cdev, &gpio_control_ops);
    
    /* 3. add chrdev */
    ret = cdev_add(&gpio_control.cdev, gpio_control.devid, NEWCHRLED_CNT);
    if (ret < 0)
    {
    
        goto faial_add_chrdeev;
    }
    /* 4. create class */
    gpio_control.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
	if (IS_ERR(gpio_control.class)) {
    
        goto  faial_create_class;
	}
    
    /* 5. create device */
    gpio_control.device = device_create(gpio_control.class, NULL, gpio_control.devid, NULL, NEWCHRLED_NAME);
	if (IS_ERR(gpio_control.device)) {
    
		goto faial_create_device;
	}

    return 0;

faial_create_device:
    device_destroy(gpio_control.class, gpio_control.devid);
faial_create_class:
    class_destroy(gpio_control.class);
faial_add_chrdeev:
    cdev_del(&gpio_control.cdev);
faial_alloc_chrdeev:
    unregister_chrdev_region(gpio_control.devid, NEWCHRLED_CNT);

}

static void __exit led_exit(void)
{
    
    cdev_del(&gpio_control.cdev);
    unregister_chrdev_region(gpio_control.devid, NEWCHRLED_CNT);
    
    device_destroy(gpio_control.class, gpio_control.devid);
    class_destroy(gpio_control.class);
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("qingmu");

7、配置menuconfig

make  menuconfig

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8、编译

回到openwrt的根目录下

make ./package/kernel/gpio_control_driver/compile V=s

9、把生成的ipk包发送到板子上去

找到生成的ipk包
在这里插入图片描述
发送到板子上去

scp ./bin/ipq/packages/base/kmod-gpio_control_driver_4.4.60-1_ipq.ipk [email protected]:/root

10、安装ipk包

opkg install kmod-gpio_control_driver_4.4.60-1_ipq.ipk

11、加载驱动

在/lib/modules/4.19.57/下可以找到gpio_control_driver.ko,执行

insmod gpio_control_driver.ko

这样驱动就加载完成了,如果想卸载,可以执行

rmmod gpio_control_driver.ko

12、驱动测试

12.1、同样的方式把测试文件也打包成ipk包发送到板子上运行

  • 1、在openwrt的源码目录下(SDK包的openwrt的目录下)的./package目录下创建gpio_test目录,
mkdir gpio_test

在这里插入图片描述

  • 2、在gpio_test的目录下创建Makefile和src目录
touch Makefile
mkdir src

在这里插入图片描述

  • 3、编写Makefile
    makefile:
obj-m := gpio_control_driver.o


  • 4、在src的目录下创建gpiotest.c、gpio_test.h、Makefile
touch gpiotest.c
touch gpiotest.h
touch Makefile

在这里插入图片描述
gpio_test.c :

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include "gpio_test.h"
 
static unsigned char gpio_pin;//define GPIOs to be use
static int gpio_dev_fd;
 
void demo1_release(int signal_no)
{
    
	ioctl(gpio_dev_fd, GPIO_CONTROL_SET_IN, GPIO_IOCTL_PRAM(gpio_pin, 0));
	ioctl(gpio_dev_fd, GPIO_CONTROL_FREE_GPIO, GPIO_IOCTL_PRAM(gpio_pin, 0));
	exit(0);
}
 
 
//指定管脚拉高, 拉低
int set_gpio(unsigned char pin, int state)
{
       
 
    if(state == 1)
    {
    
        ioctl(gpio_dev_fd, GPIO_CONTROL_SET_VALUE, GPIO_IOCTL_PRAM(pin, 1));
    }
    else if(state == 0)
    {
    
        ioctl(gpio_dev_fd, GPIO_CONTROL_SET_VALUE, GPIO_IOCTL_PRAM(pin, 0));
    }
    else
    {
    
        printf("No such set\n");
        goto ERROR;
    }
 
    return 0;
 
    ERROR:
        return -1; 
}
 
int gpio_init(int pin)
{
    
    int ret;
 
    gpio_pin = pin;
 
    gpio_dev_fd = open(GPIO_CONTROL_DEVICE_PATH, O_RDWR);//open gpio device
    if (gpio_dev_fd < 0){
    
        printf("###open %s ERROR###\n", GPIO_CONTROL_DEVICE_PATH);
        goto ERROR;
    }else{
    
        printf("***open %s success***\n", GPIO_CONTROL_DEVICE_PATH);
    }
    
    ret = ioctl(gpio_dev_fd, GPIO_CONTROL_REQUEST_GPIO, GPIO_IOCTL_PRAM(pin, 0));
	if (ret < 0){
    
		printf("###request GPIO %d error###", pin);
		goto ERROR;
	}
	ret = ioctl(gpio_dev_fd, GPIO_CONTROL_SET_OUT, GPIO_IOCTL_PRAM(pin, 0));
	if (ret < 0){
    
		printf("###set GPIO %d output error###", pin);
		goto ERROR;
	}
 
	signal(SIGINT, demo1_release);//register terminal signal
 
    return 0;
 
    ERROR:
        return -1; 
}
 
 
int main()
{
    
    gpio_init(30);
    gpio_init(29);
   
    while(1)
    {
    
        set_gpio(30, 0);
        usleep(200000);
        set_gpio(30, 1);
        usleep(200000);
        set_gpio(29, 0);
        usleep(200000);
        set_gpio(29, 1);
        usleep(200000);
    }
	return 0;
}

注意:我这里的LED的灯的gpio口是GPIO30和GPIO29,大家个根据自己的GPIO口进行更改

gpio_test.h :

#ifndef GPIO_CONTROL_TEST_H_
#define GPIO_CONTROL_TEST_H_
 
#define GPIO_CONTROL_DEVICE_PATH		"/dev/gpio_control"
 
#define GPIO_IOCTL_PRAM(gpio_num, arg1) (((unsigned long)gpio_num << 24) + ((unsigned long)arg1 << 16))
#define GET_GPIO_NUM(arg1) (unsigned char)((arg1 >> 24) & 0xff)
#define GET_GPIO_VALUE(arg1) (unsigned char)((arg1 >> 16) & 0xff)
 
//IOCTRL CMDs
#define GPIO_CONTROL_SET_OUT			0x01
#define GPIO_CONTROL_SET_IN			0x02
//#define GPIO_CONTROL_GET_DIRECTION		0x03
#define GPIO_CONTROL_SET_VALUE			0x04
#define GPIO_CONTROL_GET_VALUE			0x05
#define GPIO_CONTROL_REQUEST_GPIO		0x06
#define GPIO_CONTROL_FREE_GPIO			0x07
 
int set_gpio(unsigned char pin, int state);
int gpio_init(int pin);
void delay_ms(int ms);
 
 
 
#endif

  • 5、回到openwrt根目录下编译
make ./package/gpio_test/compile V=s
  • 6、找到对应的ipk包并发送到板子上
find ./ -name gpio_te*.ipk

在这里插入图片描述
发送到对应的开发板,这里大家根据自己的实际情况来:

scp ./bin/ipq/packages/base/gpio_test_1-1.0_ipq.ipk [email protected]:/root
  • 6、安装goio_test的ipk包
opkg install gpio_test_1-1.0_ipq.ipk
  • 7、运行gpio_test应用程序
gpio_test

此时LED灯开始闪烁,大功告成

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_45309916/article/details/109811535

智能推荐

C语言结构体自动初始化实现,c语言结构体数组初始化_Apple Cook的博客-程序员秘密

最近看一段代码有所迷惑,先简单总结一下。有关结构体数组初始化的问题struct _m_usmart_nametab usmart_nametab[]=本文引用地址:http://www.eepw.com.cn/article/201611/322298.htm{#if USMART_USE_WRFUNS==1 //如果使能了读写操作(void*)read_addr,"u32 read_addr(u...

Python 之使用 celery 实现消息队列,异步函数_vv安的浅唱的博客-程序员秘密

关于celery 的实现消息队列,以及异步函数的使用有很多用途,比较常见的一个用途就是前端向后端发起一个请求,后端完成这个请求需要较长的时间,可以先向前端返回结果,然后将这个实现的过程存储,在后端慢慢实现。那么这个过程,就可以使用 celery 来实现。技术框架:在这里用到的 Python 的后端框架是 Django。celery 可以使用的中间件有 Redis,rabbitmq 等,这里...

抓取?callback=jQuery...形式的url_mabf的博客-程序员秘密

**抓取?callback=jQuery…形式的url最近爬取 遇到好些 这种 为 jsonp 动态加载方式 的 网站, 做个笔记记录下两种采集方式1 模拟浏览器 selenium + webdriver 采集 模拟人为滚动优点: 无需分析请求参数 节省配置时间缺点: 获取数据较慢, 浏览器一直往下滚 占用较大内存 易崩2 java || python get请求优点: 获取速度...

layui+flask前后端分离_layuimini +flask_weixin_43351935的博客-程序员秘密

目的:https://layui.itze.cn/demo/index.html 实现官网的数据table,对应的layui的资源已经下载好过程就不写了,后面直接放项目代码:数据来源:https://blog.csdn.net/yangjiabei_0301/article/details/78222174用flask作为后端:运行完整代码已经上传:传送门:https://github.com/jevy146/layui_flask_use...

IMX6ULL MMC: no card present_琰婧的博客-程序员秘密

报错 MMC: no card present 的, 一般是在移植 uboot 的时候配置有误, 排查的时候, 按照教程的操作步骤来进行检查。例如在 uboot 源码的./configs/mx6ull_alientek_emmc_defconfig 下。CONFIG_SYS_EXTRA_OPTIONS=“IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK”我就是因为这个配置中的 MX

创建Repo仓库_touowang的博客-程序员秘密

1. Repo的基本结构Repo包括几部分:Repo脚本, Repo库,Manifest库,Project库2. 从0开始创建repo仓库repo脚本:这是一个python脚本,用来下载repo和manifest这两个git库获取repo脚本,下载并修改权限curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o repochmod +x reporepo 库: repo工具本身也是一个git库,包含若干python脚本,每

随便推点

Android studio 打包签名 无法选择Signature Versions V1、V2_没有signature versions_木子帅的博客-程序员秘密

在android studio更新到3.0以上打包签名是会出现Signature Versions V1、V2的选项v1 v2的意思:android 7.0中引入了APK Signature Scheme v2,v1呢是jar Signature来自JDKV1:应该是通过ZIP条目进行验证,这样APK 签署后可进行许多修改 - 可以移动甚至重新压缩文件。V2:验证压缩文件的所有字节,而...

PHP使用curl替代file_get_contents_Mir_憨豆先生的博客-程序员秘密

http://www.ttlsa.com/php/curl-replace-ile_get_contents/初学php的朋友们,很容易翻一个错误,在写采集程序或者调用api接口总会有线考虑到使用file_get_contents函数来或许内容,程序的访问量不大倒是没什么影响,但是访问量提升了那非常的悲剧了,你会发现服务器负载飙升,最后服务器宕机.初入公司便遇到这个问题,遂使用cu

医院信息系统集成服务平台建设方案_医疗信息系统如何整合_找方案的博客-程序员秘密

医院信息集成平台概述以往医院的信息系统建设分期建设,造成系统操作上的割裂和数据之间通讯的割裂,严重的损坏了业务流程的连贯性,互联互通的核心是数据层面和应用层面的整合。具体来说,重点要解决医院信息系统的系统异构集成、数据共享和数据交换传输标准等关键性技术问题。全院各个应用系统均与医院信息平台互联,并通过医院信息平台实现相互之间的数据交换和应用服务的调用。医院信息集成平台就是实现医院信息系统应用整合。应用整合的首要需求是实现各医院应用系统之间的互联互通:从集成的层面上,需要考虑三个层面:数据层面...

模型压缩-剪枝/量化/蒸馏/AutoML_剪枝量化蒸馏那个压缩效果好_落难Coder的博客-程序员秘密

深度学习模型计算复杂度高,参数存在冗余。(1)线性或非线性量化。(2)结构或非结构剪枝。(3)网络结构搜索。(4)权重矩阵的低秩分解。(蒸馏)优化精度、性能、存储等,使得可以在一些场景和设备上进行相应模型的部署。(1)剪枝位置的判定一般根据权重。权重越小,证明该神经元的作用越小。(2)剪枝的方式:删去网络层上的权重的向量/整个神经元/单个像素(数据)。由于矩阵操作的并行化,减去单个像素或者向量并不能减少计算量。即有的硬件并不支持稀疏矩阵的运输,所以一般剪枝操作是直接减去整个神经元。(3)判别剪神经元的

PHP用socket连接SMTP服务器发送邮件_weixin_34112181的博客-程序员秘密

PHP用socket连接SMTP服务器发送邮件PHP用socket连接SMTP服务器发送邮件学习实验记录:分析与SMTP会话的一般流程1. HELO XXX \r\n //XXX就是自己起个名字,和服务器打个招呼返回 250 表示成功2. AUTH LOGIN \r\n //请求与服务器开始验证用户(登陆)返回 334 表示成功3. 用户名 \r...

oracle11g密码大小写敏感问题_huangyunzeng2008的博客-程序员秘密

密码大小写敏感是Oracle 11g数据库默认的一个新特性,数据库配置助手(DBCA)在创建数据库期间允许你将这个设置返回到11g以前的功能。 SEC_CASE_SENSITIVE_LOGON初始化参数控制密码大小写是否敏感,如果现有应用程序与11g的认证过程冲突,你可以使用ALTER SYSTEM命令将这一功能关闭。 ALTER SYSTEM SET SEC_CASE_SENSITI