13、nRF52xx蓝牙学习(GPIOTE组件方式的任务配置)

下面再来探讨下驱动库如何实现任务的配置,驱动库的实现步骤应该和寄存器方式对应,关
键点就是如何调用驱动库的函数。
本例里同样的对比寄存器方式编写两路的 GPOITE 任务输出,一路配置为输出翻转,一路设
置为输出低电平。和 GPIOTE 事件相反,初始化任务应该是输出,同时需要使能任务和触发任务的 驱动库函数。下面介绍下如下三个组件库函数:
(1)nrfx_gpiote_out_init 函数
nrfx_err_t nrfx_gpiote_out_init(nrfx_gpiote_pin_t                pin,nrfx_gpiote_out_config_t const * p_config)
{NRFX_ASSERT(nrf_gpio_pin_present_check(pin));NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);NRFX_ASSERT(p_config);nrfx_err_t err_code = NRFX_SUCCESS;if (pin_in_use(pin)){err_code = NRFX_ERROR_INVALID_STATE;}else{if (p_config->task_pin){int8_t channel = channel_port_alloc(pin, NULL, true);if (channel != NO_CHANNELS){nrf_gpiote_task_configure((uint32_t)channel,pin,p_config->action,p_config->init_state);}else{err_code = NRFX_ERROR_NO_MEM;}}else{pin_in_use_set(pin);}if (err_code == NRFX_SUCCESS){if (p_config->init_state == NRF_GPIOTE_INITIAL_VALUE_HIGH){nrf_gpio_pin_set(pin);}else{nrf_gpio_pin_clear(pin);}nrf_gpio_cfg_output(pin);pin_configured_set(pin);}}NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));return err_code;
}

nrfx_gpiote_out_init 函数的主要作用是初始化一个 GPIO 引脚作为 GPIOTE(通用外设中断和事件)的输出引脚。它接收一个引脚编号和一个配置结构体指针作为参数,根据配置对引脚进行相应的初始化设置,并返回初始化结果的错误码。

函数参数 • nrfx_gpiote_pin_t pin:要初始化的 GPIO 引脚编号。

• nrfx_gpiote_out_config_t const * p_config:指向 GPIO 输出配置结构体的指针,该结构体包含了引脚的各种配置信息,如是否作为任务引脚、引脚动作、初始状态等。

nrfx_gpiote_out_config_结构体定义如下 :

typedef struct
{nrf_gpiote_polarity_t action;     /**< Configuration of the pin task. */nrf_gpiote_outinit_t  init_state; /**< Initial state of the output pin. */bool                  task_pin;   /**< True if the pin is controlled by a GPIOTE task. */
} nrfx_gpiote_out_config_t;

其中nrf_gpiote_outinit_t是枚举类型,其定义如下 :

typedef enum
{NRF_GPIOTE_INITIAL_VALUE_LOW  = GPIOTE_CONFIG_OUTINIT_Low,       ///<  Low to high.NRF_GPIOTE_INITIAL_VALUE_HIGH = GPIOTE_CONFIG_OUTINIT_High       ///<  High to low.
} nrf_gpiote_outinit_t;

NRFX_ASSERT(nrf_gpio_pin_present_check(pin));
    NRFX_ASSERT(m_cb.state == NRFX_DRV_STATE_INITIALIZED);
    NRFX_ASSERT(p_config);


NRFX_ASSERT 是一个断言宏,用于在开发和调试阶段检查某些条件是否满足。如果条件不满足,程序会触发断言失败,帮助开发者快速定位问题。

nrf_gpio_pin_present_check(pin) 检查指定的引脚是否存在

 m_cb.state == NRFX_DRV_STATE_INITIALIZED 检查 GPIOTE 驱动的状态是否已经初始化。

 p_config 检查配置结构体指针是否有效。


if (pin_in_use(pin))
    {
        err_code = NRFX_ERROR_INVALID_STATE;
    }


pin_in_use(pin) 函数检查指定的引脚是否已经被使用。如果该引脚已经被使用,则将错误码设置为 NRFX_ERROR_INVALID_STATE,表示状态无效。


else
    {
        if (p_config->task_pin)
        {
            int8_t channel = channel_port_alloc(pin, NULL, true);

            if (channel != NO_CHANNELS)
            {
                nrf_gpiote_task_configure((uint32_t)channel,
                                          pin,
                                          p_config->action,
                                          p_config->init_state);
            }
            else
            {
                err_code = NRFX_ERROR_NO_MEM;
            }
        }


如果引脚未被使用,检查配置结构体中的 task_pin 字段。

如果 task_pin 为真,表示该引脚要作为任务引脚使用。

channel_port_alloc(pin, NULL, true) 函数尝试为该引脚分配一个 GPIOTE 通道。如果分配成功,返回通道编号;如果没有可用通道,返回 NO_CHANNELS。

如果通道分配成功,调用 nrf_gpiote_task_configure 函数对该通道进行配置,传入通道编号、引脚编号、引脚动作和初始状态等参数。

如果通道分配失败,将错误码设置为 NRFX_ERROR_NO_MEM,表示内存不足(这里实际是没有可用的 GPIOTE 通道)。


channel_port_alloc函数代码如下:
static int8_t channel_port_alloc(uint32_t pin, nrfx_gpiote_evt_handler_t handler, bool channel)
{int8_t   channel_id = NO_CHANNELS;uint32_t i;uint32_t start_idx = channel ? 0 : GPIOTE_CH_NUM;uint32_t end_idx   =channel ? GPIOTE_CH_NUM : (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS);// critical sectionfor (i = start_idx; i < end_idx; i++){if (m_cb.handlers[i] == FORBIDDEN_HANDLER_ADDRESS){pin_in_use_by_te_set(pin, i, handler, channel);channel_id = i;break;}}// critical sectionreturn channel_id;
}

代码解释如下 :

函数概述 channel_port_alloc 是一个静态函数,其作用是为指定的引脚分配一个通道。

该函数会在特定的通道范围内查找可用通道,若找到,就将该通道分配给指定引脚,并返回通道编号;若未找到,就返回 NO_CHANNELS。

函数参数

• pin:类型为 uint32_t,代表要分配通道的引脚编号。

• handler:类型为 nrfx_gpiote_evt_handler_t,是一个事件处理函数指针,当该引脚发生事件时会调用此函数。

• channel:类型为 bool,用于确定通道分配的范围。若为 true,就在普通通道范围内分配;若为 false,就在低功耗事件通道范围内分配。  

若成功分配通道,返回通道编号;若未找到可用通道,返回 NO_CHANNELS。

代码详细解释


static int8_t channel_port_alloc(uint32_t pin, nrfx_gpiote_evt_handler_t handler, bool channel)
{
    int8_t   channel_id = NO_CHANNELS;
    uint32_t i;

    


根据 channel 参数确定通道分配的起始和结束索引

uint32_t start_idx = channel ? 0 : GPIOTE_CH_NUM; 这行代码的作用是根据 channel 的值来确定通道分配范围的起始索引。

• 若 channel 为 true(非零),则 start_idx 被赋值为 0。这意味着通道分配从编号为 0 的通道开始。

• 若 channel 为 false(零),则 start_idx 被赋值为 GPIOTE_CH_NUM。这表明通道分配从编号为 GPIOTE_CH_NUM 的通道开始。

uint32_t end_idx = channel ? GPIOTE_CH_NUM : (GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS);

这行代码的作用是根据 channel 的值来确定通道分配范围的结束索引。

• 若 channel 为 true(非零),则 end_idx 被赋值为 GPIOTE_CH_NUM。这意味着通道分配的范围是从 0 到 GPIOTE_CH_NUM - 1。

• 若 channel 为 false(零),则 end_idx 被赋值为 GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS。这表明通道分配的范围是从 GPIOTE_CH_NUM 到 GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - 1。

总结 这两行代码的目的是根据 channel 的值选择不同的通道分配范围:

• 当 channel 为 true 时,通道分配范围是从 0 到 GPIOTE_CH_NUM - 1,通常代表普通通道的范围。

• 当 channel 为 false 时,通道分配范围是从 GPIOTE_CH_NUM 到 GPIOTE_CH_NUM + NRFX_GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - 1,一般代表低功耗事件通道的范围。



    

    // 进入临界区,这里代码注释表示是临界区,但代码中未实际体现临界区的保护代码
    // 临界区用于确保在多线程或多任务环境下,对共享资源的操作是原子的

    // 遍历指定范围的通道
    for (i = start_idx; i < end_idx; i++)
    {
        // 检查当前通道的处理函数地址是否为禁止使用的地址
        if (m_cb.handlers[i] == FORBIDDEN_HANDLER_ADDRESS)
        {
            // 如果是,调用 pin_in_use_by_te_set 函数将该引脚标记为已使用,并关联处理函数
            pin_in_use_by_te_set(pin, i, handler, channel);
            // 将通道编号赋值给 channel_id
            channel_id = i;
            // 找到可用通道后,跳出循环
            break;
        }
    }
    // 退出临界区,同样这里代码注释表示是临界区,但未实际体现临界区的保护代码

    // 返回通道编号,如果未找到可用通道,返回 NO_CHANNELS
    return channel_id;
}
   代码逻辑总结

1. 把 channel_id 初始化为 NO_CHANNELS,这意味着默认情况下未找到可用通道。

2. 依据 channel 参数确定通道分配的起始和结束索引。

3. 进入临界区(代码注释表明是临界区,但未实际实现临界区保护),以此保证在多线程或多任务环境下对共享资源的操作是原子的。

4. 遍历指定范围的通道,检查每个通道的处理函数地址是否为禁止使用的地址。

5. 若找到可用通道,调用 pin_in_use_by_te_set 函数将该引脚标记为已使用,并关联处理函数,然后将通道编号赋值给 channel_id,接着跳出循环。

6. 退出临界区(代码注释表明是临界区,但未实际实现临界区保护)。

7. 返回通道编号,若未找到可用通道,返回 NO_CHANNELS。        


nrf_gpiote_task_configure函数代码如下

__STATIC_INLINE void nrf_gpiote_task_configure(uint32_t idx, uint32_t pin,nrf_gpiote_polarity_t polarity,nrf_gpiote_outinit_t  init_val)
{NRF_GPIOTE->CONFIG[idx] &= ~(GPIOTE_CONFIG_PORT_PIN_Msk |GPIOTE_CONFIG_POLARITY_Msk |GPIOTE_CONFIG_OUTINIT_Msk);NRF_GPIOTE->CONFIG[idx] |= ((pin << GPIOTE_CONFIG_PSEL_Pos) & GPIOTE_CONFIG_PORT_PIN_Msk) |((polarity << GPIOTE_CONFIG_POLARITY_Pos) & GPIOTE_CONFIG_POLARITY_Msk) |((init_val << GPIOTE_CONFIG_OUTINIT_Pos) & GPIOTE_CONFIG_OUTINIT_Msk);
}

 nrf_gpiote_task_configure 是一个静态内联函数,其用途是对 nRF GPIOTE(通用引脚输入 / 输出任务和事件)模块的特定通道配置寄存器进行设置。借助该函数,你能够指定特定通道所关联的引脚、引脚极性以及初始输出值。

函数参数

• idx:uint32_t 类型,代表要配置的 GPIOTE 通道的索引。

• pin:uint32_t 类型,代表要关联到该通道的引脚编号。

• polarity:nrf_gpiote_polarity_t 类型,用于指定引脚的极性,例如高电平触发、低电平触发等。 • init_val:nrf_gpiote_outinit_t 类型,用于指定引脚的初始输出值。  


   
   代码逻辑步骤

1.  清除相关位:

 NRF_GPIOTE->CONFIG[idx] &= ~(GPIOTE_CONFIG_PORT_PIN_Msk |
                             GPIOTE_CONFIG_POLARITY_Msk |
                             GPIOTE_CONFIG_OUTINIT_Msk);
   
  NRF_GPIOTE->CONFIG[idx] 表示 GPIOTE 模块中第 idx 个通道的配置寄存器。  GPIOTE_CONFIG_PORT_PIN_Msk、GPIOTE_CONFIG_POLARITY_Msk 和 GPIOTE_CONFIG_OUTINIT_Msk 分别是用于选择引脚、极性和初始输出值的位掩码。

 ~ 是按位取反运算符,&= 是按位与赋值运算符。这行代码的作用是把配置寄存器中与引脚、极性和初始输出值相关的位清零,为后续设置新值做准备。  

2.  设置新值:

NRF_GPIOTE->CONFIG[idx] |= ((pin << GPIOTE_CONFIG_PSEL_Pos) & GPIOTE_CONFIG_PORT_PIN_Msk) |
                           ((polarity << GPIOTE_CONFIG_POLARITY_Pos) & GPIOTE_CONFIG_POLARITY_Msk) |
                           ((init_val << GPIOTE_CONFIG_OUTINIT_Pos) & GPIOTE_CONFIG_OUTINIT_Msk);
   
  << 是左移运算符,用于把 pin、polarity 和 init_val 移动到配置寄存器中对应的位置。

& 是按位与运算符,用于确保只有对应位掩码覆盖的位被设置。

| 是按位或运算符,|= 是按位或赋值运算符。这行代码的作用是将移动并掩码处理后的 pin、polarity 和 init_val 值设置到配置寄存器中。    

总结 此函数的主要功能是先清除 GPIOTE 通道配置寄存器中与引脚、极性和初始输出值相关的位,然后将新的引脚编号、极性和初始输出值设置到这些位上,从而完成对指定通道的配置。   

     


(2)nrfx_gpiote_out_task_enable函数

void nrfx_gpiote_out_task_enable(nrfx_gpiote_pin_t pin)
{NRFX_ASSERT(nrf_gpio_pin_present_check(pin));NRFX_ASSERT(pin_in_use(pin));NRFX_ASSERT(pin_in_use_by_te(pin));nrf_gpiote_task_enable((uint32_t)m_cb.pin_assignments[pin]);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/77588.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java的基本语法(1)

一、运算符和表达式 举例说明什么是运算符&#xff0c;什么是表达式&#xff1a; int a 1; int b 2; int c a b; 在这个例子当中&#xff0c;是运算符&#xff0c;并且是算术运算符 ab是表达式&#xff0c;因为是运算符&#xff0c;所以ab是算术表达式 1.1算术运算符 …

C++学习之密码学知识

目录 1.文档介绍 2.知识点概述 3.项目准备 4.序列化介绍 5.项目中基础组件介绍 6.基础模块在项目中作用 7.项目中其他模块介绍 8.加密三要素 9.对称加密和非堆成加密 10.对称和非对称加密特点 11.堆成加密算法des 12.des对称加密算法 13.对称加密算法aes 14.知识点…

安装vllm

ubuntu 22.04, RTX3080, cuda 12.1, cudnn 8.9.7&#xff0c;cuda和cudnn的安装参考&#xff1a;https://blog.csdn.net/m0_52111823/article/details/147154526?spm1001.2014.3001.5501。 查看版本对应关系&#xff0c;下载12.1对应的whl包&#xff0c;https://github.com/vl…

【WPF】自定义控件:ShellEditControl-同列单元格编辑支持文本框、下拉框和弹窗

需要实现表格同一列&#xff0c;单元格可以使用文本框直接输入编辑、下拉框选择和弹窗&#xff0c;文本框只能输入数字&#xff0c;弹窗中的数据是若干位的二进制值。 本文提供了两种实现单元格编辑状态下&#xff0c;不同编辑控件的方法&#xff1a; 1、DataTrigger控制控件的…

Gson、Fastjson 和 Jackson 对比解析

目录 1. Gson (Google) 基本介绍&#xff1a; 核心功能&#xff1a; 特点&#xff1a; 使用场景&#xff1a; 2. Fastjson (Alibaba) 基本介绍&#xff1a; 核心功能&#xff1a; 特点&#xff1a; 使用场景&#xff1a; 3. Jackson 基本介绍&#xff1a; 核心功能…

浅谈微信视频号推荐算法

这次可能会稍微有点干货&#xff0c;但保证不晦涩~ 一、算法推荐的本质&#xff1a;猜你喜欢 vs 社交绑架​ 视频号的推荐系统本质上在做两件事&#xff1a; ​预测你的兴趣​&#xff1a;通过你的浏览、点赞、评论、分享等行为&#xff0c;分析你的偏好。​满足社交需求​&…

halcon模板匹配(一)create_shape_model_xld

目录 一、提取刹车盘孔洞轮廓二、形状模板的创建-设置-训练-查找三、找到亮的圆孔四、获得匹配结果五、使用use_polarity进行模板匹配六、计算四个圆对应的矩形框七、创建四个圆对应的模板并查找一、提取刹车盘孔洞轮廓 小技巧总结,使用boundary 函数提取区域边界,在边界范围…

day26图像处理OpenCV

文章目录 一、OpenCV1.介绍2.下载3.图像的表示4.图像的基本操作4.1图片读取或创建4.1.1读取4.1.2创建 4.2创建窗口4.3显示图片4.3.1设置读取的图片4.3.2设置显示多久4.3.3释放 4.4.保存图片4.5图片切片&#xff08;剪裁&#xff09;4.6图片大小调节 5.在图像中绘值5.1绘制直线5…

零基础开始学习鸿蒙开发-智能家居APP离线版介绍

目录 1.我的小屋 2.查找设备 3.个人主页 前言 好久不发博文了&#xff0c;最近都忙于面试&#xff0c;忙于找工作&#xff0c;这段时间终于找到工作了。我对鸿蒙开发的激情依然没有减退&#xff0c;前几天做了一个鸿蒙的APP&#xff0c;现在给大家分享一下&#xff01; 具体…

C++的*了又*

先看下面一段代码 class HeapWord {friend class VMStructs;private:char *i; };主函数 #include "HeapWord.hpp" int main() {HeapWord *heapword new HeapWord();HeapWord *p new HeapWord();HeapWord **p1 new HeapWord *();heapword 3;*(HeapWord **)p he…

yolov8在windows系统的C++版本的onnxruntime部署方法

1.各个软件的的环境需要保持在统一的版本。 onnxruntime需要和cuda的版本对应上,版本号:onnxruntime-win-x64-gpu-1.18.1 ,链接: NVIDIA - CUDA | onnxruntime cuda:本机显卡支持的版本,cuda11.7,链接:CUDA Toolkit Archive | NVIDIA Developer cudnn:需要对应到cud…

js chrome 插件,下载微博视频

修改说明&#xff1a; 代码资源&#xff0c;免积分下载 起因&#xff0c; 目的: 最初是想下载微博上的NBA视频&#xff0c;因为在看网页上看视频很不方便&#xff0c;快进一次是10秒&#xff0c;而本地 VLC 播放器&#xff0c;快进一次是5秒。另外我还想做点视频剪辑。 对比…

【vue3】@click函数传动态变量参数

根据java的学习&#xff0c;摸索了一下vue3 函数传参的方式。以此作为记录。有更好的其它方式&#xff0c;可以评论区补充。 <script> const tmpref(); </script><button click"tmpFunction(传递参数:tmp)">按钮</button> // 直接【字符串…

jmeter 集成ZAP进行接口测试中的安全扫描 实现方案

以下是将 JMeter 集成 ZAP(OWASP Zed Attack Proxy)进行接口测试中安全扫描的实现方案: 1. 环境准备 JMeter 安装:从 JMeter 官方网站(https://jmeter.apache.org/download_jmeter.cgi)下载并安装 JMeter,确保其版本稳定。ZAP 安装:从 ZAP 官方网站(https://www.zapr…

全能格式转换器v16.3.0.159绿色便携版

前言 全能格式转换器具有音视频格式转换、合并视频、压缩视频、录制视频、下载视频、DVD刻录等功能。以超快的转换速度及强大的功能在国外名声大噪&#xff0c;转换速度是市面同类产品的30倍&#xff0c;操作简便&#xff0c;支持158种视频格式无损转换&#xff0c;批量转换高…

【基于开源insightface的人脸检测,人脸识别初步测试】

简介 InsightFace是一个基于深度学习的开源人脸识别项目,由蚂蚁金服的深度学习团队开发。该项目提供了人脸检测、人脸特征提取、人脸识别等功能,支持多种操作系统和深度学习框架。本文将详细介绍如何在Ubuntu系统上安装和实战InsightFace项目。 目前github有非常多的人脸识…

设计一个简单的权限管理系统

针对大规模服务器集群的权限管理系统设计&#xff0c;需结合 角色分层、最小权限原则 和 动态权限控制 来实现安全高效的权限管理。以下是分阶段设计方案&#xff1a; 一、核心设计思路 基于角色的访问控制&#xff08;RBAC&#xff09; 定义角色层级&#xff08;如董事长 >…

使用 nano 文本编辑器修改 ~/.bashrc 文件与一些快捷键

目录 使用 nano 编辑器保存并关闭文件使用 sed 命令直接修改文件验证更改 如果你正在使用 nano 文本编辑器来修改 ~/.bashrc 文件&#xff0c;以下是保存并关闭文件的具体步骤&#xff1a; 使用 nano 编辑器保存并关闭文件 打开 ~/.bashrc 文件 在终端中运行以下命令&#xf…

spm12_fMRI 2*4混合方差分析 Flexible factorial 对比矩阵

实验设计&#xff1a;2*4被试内设计 分析模型&#xff1a;spm 二阶分析中的 Flexible factorial 问题&#xff1a;Flexible factorial交互作用对比矩阵如何编写&#xff1f; 老师&#xff1a;deepseek老师【大神们看看这个矩阵是否可以如下编写&#xff1f;】 以下是来自de…

用Python修改字体字形与提取矢量数据:fontTools实战指南

字体设计与分析是NLP和视觉领域的交叉应用&#xff0c;而**fontTools** 是一款强大的Python库&#xff0c;可以让我们直接操作字体文件的底层结构。本文将通过两个实用函数&#xff0c;展示如何修改特定字形和提取所有字形的矢量数据&#xff0c;帮助开发者快速上手字体编辑与分…