简介:

  本次测试了zephyr的中断驱动方式(GPIOTE),在这可以去看zephyr的官方文档对zephyr的中断定义,连接如下,Interrupts — Zephyr Project Documentation (nordicsemi.com) ;版本可能不对应,但是原理是一致的,今天记录的就是其中的零延迟中断,就是减少中断时间,让来自外部的中断能快速响应,进入到我们的中断服务程序中进行快速执行(也就是ISR)。

根据文档,就作者理解来如下,如有更好的理解可以进行指正,有些时候在执行某些线程时对时间有要求或者在临界区进行操作时,不能够被外部中断(ISQ)打断,可以禁止(中断服务程序)ISR的执行。通过IRQ禁止达到在处理某些线程时不会被打断,但是会让中断处理被延迟,但这时候又出现一个矛盾,有些中断是我想要及时处理的,那么我们需要不被屏蔽掉,就是这个中断是比前面列举的线程执行更重要的事,那么怎么办,可以直接使用零延迟中断进行定义,让这些中断直接得到响应,在零延迟中断中又分为两种:一是常规的ISR,二是直接的ISR(某些情况下比常规的更快),常规的ISR可能还是会被打断,导致一下开销产生,具体在zephyr中有4点列举:

如果某个任务完全不想要被打断,快速的执行,那么就可以使用直接ISR(direct ISR)。在作者看来正常情况下(没有其余中断打断的情况下),他们两的时间应该是一致的。具体可以点击上面链接,直接看官方描述。

本次使用的是在开发之前默认你已经配置好开发环境,如果是第一次开发,建议去安装下面给出官方环境参考文档,或者去比例比例观看环境搭建的学习视频(VS code),也可以参看我文章中的关于9160开机测试的文章。官方连接如下:开发你的第一个nRF Connect SDK(NCS)/Zephyr应用程序 - iini - 博客园 (cnblogs.com)

参考资料:

  nordic的官方讲解视频,可以在哔哩哔哩上搜索nordic半导体去看关于其中一个视频:zephyr的设备驱动程序模型,中断和电源管理视频,中文讲解( https://www.bilibili.com/video/BV1MU4y177Zhis_story_h5=false&p=1&share_from=ugc&share_medium=android&share_plat=android&share_session_id=c0145896-48dc-4bbf-b938f1f4b3a4644a&share_source=WEIXIN&share_tag=s_i×tamp=1668583626&unique_k=29oQkX4),或者直接参看zephyr的官方。

本次测试环境:VS code、NCS

一、建立工程

建立一个zephyr的工程,如果你有NCS,并且已经安装好相关可以进行开发的环境,那么可以打开一个hello Word的工程进行添加,如果没可以zephyr的SDK,可以依据nordic官方NCS进行开发,它也有如STM32等芯片底层文件,因为nordic只是在zephyr的SDK中加入了自己的产品形成了NCS包,其余zephyr原本有的并没有删减,所以你可以在NCS中建立如STM32芯片的工程进行开发,且上层的驱动都是抽象的,只是对应余硬件的定义换成了具体的芯片定义,我们只用管APP开发,所以一套代码,可以建立成不同芯片的工程,并且在编译下载后依然可以运行,不止局限于nordic的开发。

1、zephyr工程建立

对于zephyr可以直接建立一个文件夹,然后再里面包含如下的几个文件就可以进行编译开发了,

1)、其中src中放置我们的.c文件(APP),便于管理;

2)、CMakeLists.txt是工程创建的直接根本文件,具体内容可以是如下:

#这是cmake的版本
cmake_minimum_required(VERSION 3.20.0) #添加的库
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) #建立的工程名字(本次为hello_world,可以改为GPIOTE等)
project(hello_world) #添加.c文件,稍后在src中建立一个main.c
target_sources(app PRIVATE src/main.c)

3)、prj.conf为配置文件,很多时候还需要一个overlay文件,可以进行设备树驱动的更改,有一个默认的,如果需要定义更改,就用overlay文件进行实现

由于本次我使用的是nordic的SDK,NCS,我可以在VS code上安装好相关插件然后直接镜像创建一个工程在其余文件中(根据自己选择,但是保证和NCS处于同一个磁盘中),如果不会请参看前面提到的教学文档与视频,在看后,你就可以理解为什么只是这几个文件就可以建立一个工程了。

因此我们根据NCS中的hello_word建立一个镜像工程,并把该工程的文件夹名字命令为gpiote,且工程也建立为gpiote,,然后建立一个可以跑在nrf5340的应用核的工程,如下,该工程主要功能是,通过串口打印出,hello world+板子信息。

2、添加自定义.c文件

原本已经有一个.c文件了,该文件中主要就是串口打印信息,本次测试是需要测试中断,所以我们在定义一个名字为gpiote.c的文件,添加到我们工程,然后再进行代码编写,在src中加入一个gpiote.c文件,

然后把gpiote.c加入到工程,这就需要我们打开我们的CMakeLists.txt,添加如图所示代码:

然后点击全编译,我们就可以看到我们的工程下加入了gpiote.c文件:

全编译如下:

3、overlay文件加入

这里有一个隐藏的规则,如果你看了前面推荐的官网连接,那么应该知道,在工程目录下建立文件名和我们使用的板子一致时,可以不用在CMakeLists.txt中进行文件添加,编译器建立工程时可以识别这overlay文件,知道你要更改默认的devicetree定义,会把你加入进入,如果不知道请去看下前面给出的连接,那么zephyr第一那些板子呢,他们的名是什么,可以直接在vs code确看,就行是你建立工程时选择的板子名字:

由于我使用的是nrf5340,那么我就建立一个同名的overlay文件,最后我们工程目录如下,就看我框选部分,其余是建立hello_word镜像工程时产生的:

二、设备树更改

这里注意的是我使用了1.8的NCS,如果你使用高版本的NCS如2.1,那么overlay文件会有一点便跟,你可以参考其余工程。

主要是添加一个中断口定义,我们在nrf5340dk_nrf5340_cpuapp.overlay中进行处理,在添加前我们来看一下设备树文件zephyr.dts,建立编译工程后,可以在如下目录找到它:

可以看到已经有一个buttons的设备定义了,我想自己加一个自己的按键定义,作为中断触发源,我使用的是官方开发板,按键依然是那几个,但是我可以再定义一个,然后起一个其他名字,在overlay中添加如下代码:

/*参数加入devicetree的位置*/
/{
/*其别名,这主要给test_button其一个别名,然后可以在APP中通过别名gpiote定位到我们定义的按键*/
aliases {
gpiote = &test_button;
};
/*在原有的buttons下定义一个测试IO口,并且定位为GPIO0的0x17脚,即P0.23,名字为test_gpiote*/
buttons{
test_button: test_button {
gpios = < &gpio0 0x17 0x11 >;
label = "test_gpiote";
};
};
};

截图如下:

编译后可以在zephyr.dts中看到本次定义:

三、应用代码编写

1、常规方式:

在gpiote.c中的代码如下:

#include "device.h"
#include "irq.h"
#include <zephyr.h>
#include <sys/printk.h>
#include <sys/util.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#include <nrfx.h>
#include <dk_buttons_and_leds.h> #define PIN DT_GPIO_PIN(DT_ALIAS(gpiote), gpios)
/* 建立一个gpio引脚的类*/
struct gpio_pin {
const char * const port;
const uint8_t number;
};
/* 定义gpio_pin类型的变量,用于读取设备定义信息,这以数组的形式定义,
便于有多个按键时可以直接定义,ARRAY_SIZE用于计算大小*/
static const struct gpio_pin init_pin[] ={
{DT_GPIO_LABEL(DT_ALIAS(gpiote), gpios),
DT_GPIO_PIN(DT_ALIAS(gpiote), gpios)},
};
/* */
static const struct device * init_device[ARRAY_SIZE(init_pin)];
/* 回调的变量*/
static struct gpio_callback gpiote_cb; /*回调函数*/
void gpio_init_handle(const struct device *port,
struct gpio_callback *cb,
gpio_port_pins_t pins)
{
printk("run to gpiote test\n"); }
/*GPIOte程序*/
void gpiote_test(void)
{
/*如果时有多个按键可以增加数组个数*/
int err;
uint32_t pin_mask = 0; // gpio_flags_t flags = (IS_ENABLED(CONFIG_DK_LIBRARY_INVERT_BUTTONS) ?
// GPIO_PULL_UP : GPIO_PULL_DOWN);
/*获取设备*/
init_device[0]=device_get_binding(init_pin[0].port);
if (!init_device[0]) {
printk("Cannot bind gpio device");
}
/*配置gpio口,输入上拉*/
err = gpio_pin_configure(init_device[0], init_pin[0].number,
GPIO_INPUT | GPIO_PULL_UP);
if (err) {
printk("Cannot configure button gpio");
} /*中断配置*/
err = gpio_pin_interrupt_configure(init_device[0],
init_pin[0].number, GPIO_INT_DISABLE);
if (err) {
printk("Cannot disable callbacks()");
}
pin_mask |= BIT(init_pin[0].number);
/*回调设置*/ pin_mask |= BIT(init_pin[0].number);
/*回调设置*/
gpio_init_callback(&gpiote_cb, gpio_init_handle, pin_mask); /*将刚刚绑定的结构添加到向量表中*/
err = gpio_add_callback(init_device[0], &gpiote_cb);
if (err) {
printk("Cannot add callback");
}
/*将GPIO中断配置为下降沿触发,并启用它*/
err = gpio_pin_interrupt_configure(init_device[0],
init_pin[0].number, GPIO_INT_EDGE_FALLING);
if (err) {
printk("Cannot disable callbacks()");
}
printk("test start\n"); while(1)
{
}
} /*创建一个区别于main.c中的线程,用于初始haulgpiote功能 */
K_THREAD_DEFINE(gpiote_test_id,1024,gpiote_test,NULL,NULL,NULL,7,0,0);

在此程序的基础上,你可以定义多个按键并放入设备模型数组,虽然我本次测试只使用了一个按键,如果你添加的是多个按键,记得初始化时用for循环,把每一个设备都添加一下,我这只有一个设备说以只使用了数组的第0位的设备(也只有一个)。

结果:

2、zephyr中的direct ISR(直接中断模式)

APP我们不用更改,只要把驱动中的IRQ_CONNECT();替换为IRQ_DIRECT_CONNECT();然后再加入zephy官方文档定义的代码:

你可以在工程的如下地方找到这个文件,然后更改原始定义,改部分代码已经更改:

可以直接替换代码:

#define CONFIG_direct_isr

#ifdef CONFIG_direct_isr
ISR_DIRECT_DECLARE(gpiote_event_handler_direct)
{
gpiote_event_handler();
ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */
return 1; /* We should check if scheduling decision should be made */
}
#endif
static int gpio_nrfx_init(const struct device *port)
{
static bool gpio_initialized; if (!gpio_initialized) {
gpio_initialized = true;
#ifdef CONFIG_direct_isr
IRQ_DIRECT_CONNECT(DT_IRQN(GPIOTE_NODE), DT_IRQ(GPIOTE_NODE, priority),
gpiote_event_handler_direct, 0); #else
IRQ_CONNECT(DT_IRQN(GPIOTE_NODE), DT_IRQ(GPIOTE_NODE, priority),
gpiote_event_handler, NULL, 0);
#endif
irq_enable(DT_IRQN(GPIOTE_NODE));
nrf_gpiote_int_enable(NRF_GPIOTE, NRF_GPIOTE_INT_PORT_MASK);
} return 0;
}

编译下载即可:

四、中断查看向量表参看

在如下目录可以看到我们的中断服务程序入口:其中21753就是本次中断ISR的如果地址:

在这个数组下还有中断向量表,可以自行查看:

GPIO测试到此结束。如有错漏欢迎评论指正。

zephyr的GPIOTE驱动开发记录——基于nordic的NCS的更多相关文章

  1. Linux GPIO键盘驱动开发记录_OMAPL138

    Linux GPIO键盘驱动开发记录_OMAPL138 Linux基本配置完毕了,这几天开始着手Linux驱动的开发,从一个最简单的键盘驱动开始,逐步的了解开发驱动的过程有哪些.看了一下Linux3. ...

  2. 驱动开发学习笔记. 0.02 基于EASYARM-IMX283 烧写uboot和linux系统

    驱动开发读书笔记. 0.02 基于EASYARM-IMX283 怎么烧写自己裁剪的linux内核?(非所有arm9通用) 手上有一块tq2440,但是不知道什么原因,没有办法烧boot进norflas ...

  3. 【转】基于V4L2的视频驱动开发

    编写基于V4L2视频驱动主要涉及到以下几个知识点:1> 摄像头方面的知识 要了解选用的摄像头的特性,包括访问控制方法.各种参数的配置方法.信号输出类型等.2> Camera解码器.控制器 ...

  4. linux驱动开发—基于Device tree机制的驱动编写

    前言Device Tree是一种用来描述硬件的数据结构,类似板级描述语言,起源于OpenFirmware(OF).在目前广泛使用的Linux kernel 2.6.x版本中,对于不同平台.不同硬件,往 ...

  5. 基于V4L2的视频驱动开发【转】

    转自:http://blog.chinaunix.net/uid-10747583-id-298573.html Tags:V4L2驱动框架.API.操作流程…… 原文地址:http://www.ee ...

  6. 《Linux设备驱动开发具体解释(第3版)》(即《Linux设备驱动开发具体解释:基于最新的Linux 4.0内核》)网购链接

    <Linux设备驱动开发具体解释:基于最新的Linux 4.0内核> china-pub   spm=a1z10.3-b.w4011-10017777404.30.kvceXB&i ...

  7. 基于DM642 RAW采集格式的视频驱动开发及应用

    摘 要:为解决C64X系列数字信号处理器(DSP)视频驱动不能应用于原始数据格式(RAW)采集格式的问题,设计了DM642和电耦合元件(CCD)高清传感器的数据传输接口,并分析.修改用于标准格式的视频 ...

  8. 基于335X平台Linux交换芯片驱动开发

    基于335X平台Linux交换芯片驱动开发   一.软硬件平台资料 1.开发板:创龙AM3359核心板,网口采用RMII形式. 2.Kernel版本:4.4.12,采用FDT 3.交换芯片MARVEL ...

  9. 基于ARM-contexA9-Linux驱动开发:如何获取板子上独有的ID号

    每个CPU,都有它固定的ID号,ID号就是这个CPU唯一的标识,它可能隐含着CPU的生产日期,版本号,型号等等,那么,在我们的这款友善之臂Tiny4412的板子上,我的这个CPU的ID又是多少呢?从我 ...

  10. Android字符设备驱动开发基于高通msm8916【原创 】

    本人才疏浅学,写一篇文档总结自己在msm8916平台上移植自己编写的简单的字符设备驱动开发的整个流程.这个小项目的主要功能是开发一个简单的APP,APP通过JNI去调用位于kernel的字符设备驱动. ...

随机推荐

  1. Tablesaw——Java统计、机器学习库

    资源 java二维数组处理可可视化库 https://github.com/jtablesaw/tablesaw plotly JS库的Java封装 https://github.com/jtable ...

  2. django_day07

    django_day07 django form组件 form组件的定义 class RegForm(forms.Form): user = forms.CharField(label='用户名') ...

  3. 第四篇:理解vue代码

    解释以下代码: 实现输入框中能够打字的功能 <el-input v-model="input" placeholder="在这打字"></el ...

  4. xtrabackup增量备份MySQL-5.7操作说明

    下载工具 本方法利用xtrabackup二进制包,版本是2.4.26 # 从官网下载二进制包:wget https://downloads.percona.com/downloads/Percona- ...

  5. 通过ftutilx 插件实现流版式文件全文检索

    Oracle 支持流版式文件的全文检索,而原生的PostgreSQL是不支持流版式文件全文检索的.KingbaseES 通过ftutilx 插件将流版式文件转换成文本文件,从而支持流版式文件全文检索. ...

  6. 对比es6class类和构造函数

    构造函数 在原来class 类这个语法糖没有出来之前 我们一般会把方法挂在prototype 上 为了防止过多的开辟内存 1 // 构造函数------------------------------ ...

  7. 使用Filebeat传送多行日志

    文章转载自:https://blog.csdn.net/UbuntuTouch/article/details/106272704 在解决应用程序问题时,多行日志为开发人员提供了宝贵的信息. 堆栈跟踪 ...

  8. 使用 Elastic Stack 分析地理空间数据 (一)

    文章转载自:https://blog.csdn.net/UbuntuTouch/article/details/106531939 随着人类在不断地探索空间,地理空间数据越来越多. 收集信息的速度以及 ...

  9. Python中dataclass库

    目录 dataclass语法 一. 简介 二. 装饰器参数 三. 数据属性 1. 参数 2. 使用示例 3. 注意事项 四. 其他 1. 常用函数 2. 继承 3. 总结 dataclass语法 一. ...

  10. scss的使用方法

    引用scss文件--看上一篇的less使用,里面的Koala,一样的原理!!! 方法一: scss: /**定义变量 */$width:404px;$color:green;$font-size:20 ...