Openwrt内核模块-通过定时器timer修改GPIO电平并用示波器检测

一、题目

BSP模块验证初体验:测量A28timer模块的精度
测量方式简介:通过timer模块完成指定延时计数之后触发中断,在中断处理中修改gpio管脚输出的电平,然后在示波器上抓获gpio变化的时间点,测量出timer的实际延时值,与理论设计的延时值进行比较,从而标定timer延时的精度。

二、实现

小组设计了内核模块measure,用于实现以上功能,该测量模块的文件树如下图所示。
measure模块文件树
开发板上电启动后,会自动执行程序。measure.c实现了以下功能:调用了timer计时器,开始计时20ms,计时器计时结束后触发中断并执行回调函数,回调函数则输出“Time is over”的提示,并切换GPIO30管脚的电平输出,每次切换电平成功后会输出“==========Modify successfully==========30”的提示,30即为GPIO管脚号。随后计时器再次启动循环执行上述步骤,因此实现了每隔20ms的时间切换一次电平,可以向示波器输出周期为40ms的波形,测量结果如下图所示。
请添加图片描述

理论时延 = 20.00 m s 测量时延 = 60.40 m s − 39.60 m s = 20.80 m s 相对偏差 = ( 20.80 m s − 20.00 m s ) ÷ 20.00 m s = 4.00 % 精度 Δ X = 测量值 X O − 理论值 X A = 0.80 m s \begin{aligned} & 理论时延=20.00ms\\ & 测量时延=60.40ms-39.60ms=20.80ms\\ & 相对偏差=(20.80ms-20.00ms)÷20.00ms=4.00\%\\ & 精度ΔX=测量值XO-理论值XA=0.80ms \end{aligned} 理论时延=20.00ms测量时延=60.40ms39.60ms=20.80ms相对偏差=(20.80ms20.00ms)÷20.00ms=4.00%精度ΔX=测量值XO理论值XA=0.80ms

三、源码

measure.c

#include <linux/io.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>

#define MODULE_NAME "measure"
#define INTERVAL 10
#define GPIO_PIN 30
#define H_LEVEL 1
#define L_LEVEL 0

int level=0;//记录当前的电平

static struct timer_list measure_timer;

//回调函数,计时结束时触发中断后执行
static void measure_timer_callback(unsigned long data)
{
    printk(KERN_INFO "Time is over\n");
    //修改GPIO输出
    if(level==H_LEVEL){
    gpio_set_value(GPIO_PIN, L_LEVEL);
    level=0;
    }
    else{
    gpio_set_value(GPIO_PIN, H_LEVEL);
    level=1;
    }
    printk(KERN_ERR "==========Modify successfully========== %d\n", GPIO_PIN);
    mod_timer(&measure_timer, jiffies + msecs_to_jiffies(INTERVAL));//再次启动计时器
}

static int __init measure_init(void)
{
    // 初始化GPIO管脚
    if (gpio_request(GPIO_PIN, "my_gpio") < 0) {
        printk(KERN_ERR "Failed to request GPIO %d\n", GPIO_PIN);
        return -1;
    }
    // 设置GPIO管脚为输出模式
    if (gpio_direction_output(GPIO_PIN, L_LEVEL) < 0) {//一开始输出低电平
        printk(KERN_ERR "Failed to set GPIO direction\n");
        gpio_free(GPIO_PIN);
        return -1;
    }
    setup_timer(&measure_timer, measure_timer_callback, 0);//初始化定时器
    mod_timer(&measure_timer, jiffies + msecs_to_jiffies(INTERVAL));//设置定时器的触发时间
    printk(KERN_INFO "measure module loaded\n");
    return 0;
}

static void __exit measure_exit(void)
{
    // 释放GPIO管脚
    gpio_free(GPIO_PIN);
    del_timer(&measure_timer);
    printk(KERN_INFO "measure module unloaded\n");
}

module_init(measure_init);
module_exit(measure_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Group 4");
MODULE_DESCRIPTION("measure Module");

PS:代码电平切换部分其实可以通过反转的方式更快地实现。即~1=0~0=1

外部Makefile

#
# Copyright (C) 2008-2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk

PKG_NAME:=measure
PKG_RELEASE:=3
PKG_LICENSE:=GPL-2.0

include $(INCLUDE_DIR)/package.mk

define KernelPackage/measure
  SUBMENU:=Other modules
  TITLE:=Simple GPIO Button Hotplug driver
  FILES:=$(PKG_BUILD_DIR)/measure.ko
  AUTOLOAD:=$(call AutoLoad,30,measure,1)
  KCONFIG:=
endef

define KernelPackage/measure/description
 This is a replacement for the following in-kernel drivers:
 1) gpio_keys (KEYBOARD_GPIO)
 2) gpio_keys_polled (KEYBOARD_GPIO_POLLED)

 Instead of generating input events (like in-kernel drivers do) it generates
 uevent-s and broadcasts them. This allows disabling input subsystem which is
 an overkill for OpenWrt simple needs.
endef

define Build/Compile
	$(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules
endef

$(eval $(call KernelPackage,measure))

内部Makefile

obj-m += measure.o
OpenWrt内核模块是指在OpenWrt操作系统中用于扩展功能的模块。它可以通过ubox工具箱进行管理。内核模块管理使用kmodloader来管理,包括加载内核模块、移除内核模块以及查看已加载的内核模块状态。\[1\]在编译OpenWrt源码时,可以使用命令"make package/kernel/hello-kernel/compile V=s"来编译驱动模块,并在编译完成后的目录中找到生成的内核模块文件。\[2\]在软件包定义中,可以设置内核模块的一些变量,如SUBMENU、TITLE、FILES、AUTOLOAD和DEPENDS等,以便在make menuconfig中进行配置和管理。\[3\] #### 引用[.reference_title] - *1* [OpenWrt开发必备软件模块——ubox(内核模块、日志管理、UCI配置文件数据类型的验证)](https://blog.csdn.net/qq_41453285/article/details/102621904)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [超详细!手把手演示编译OpenWrt内核驱动模块](https://blog.csdn.net/qq_41453285/article/details/102760270)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值