NRF52832学习笔记(41)——添加串口库libuarte

一、背景

由于板子上不支持硬件流控,在使用 app_uart_fifo 库接收串口大数据时,频繁报 APP_UART_COMMUNICATION_ERROR 错误,多次重新初始化后,串口也不再产生中断了。查看官方论坛后决定使用串口异步库 libuarte

二、简介

Libuarte 是一个 UARTE 库,由以下层组成:

  • nrf_libuarte_drv:一个低级 UARTE 驱动程序,具有扩展功能,如连续计算接收的字节、双缓冲、启动和停止接收器的可选事件,以及可在接收器启动和停止时触发的可选任务。
  • nrf_libuarte_async:适用于接收和传输异步数据包的库。它管理接收缓冲区并实现接收器非活动超时。库正在使用 nrf_libuarte。它旨在用于典型的 UART 用例,其中交易对手异步发送可变长度的数据包。在这种情况下,用户会在数据包边界(即超时)和 DMA 缓冲区已满时收到事件。

2.1 nrf_libuarte_drv

nrf_libuarte_drv 使用 EasyDMA 双缓冲功能和 PPI 连接来确保可靠的接收。连续接收由 STARTRX 任务建立,连接到 ENDRX 事件。STARTRX 任务启动后,将生成 RXSTARTED 事件。

在 RXSTARTED 事件中:

  • EasyDMA 已配置为传输,并且可以配置为下一次传输。
  • Configuration registers 被锁存。

使用这种方法时,系统延迟取决于所使用的缓冲区的大小。如果缓冲区足够大,系统可以确保完全接收,而无需流控制,延迟为数毫秒。这个最小延迟可以覆盖 SoftDevice 或任何其他更高优先级的中断和 flash 操作(包括 flash 页面擦除)。

此外,计数器模式下的专用 TIMER 外设用于跟踪接收到的字节数。

nrf_libuarte_drv 可以配置硬件事件来启动和停止接收器。例如,此选项可用于构建具有请求和响应引脚的低功耗 UART 协议,该协议仅在传输期间启用接收器。所有硬件任务和事件都与 PPI 连接,这允许不依赖于中断处理时间的自主操作。

nrf_libuarte_drv 正在使用以下硬件资源:

  • UARTE 实例
  • TIMER 实例
  • PPI 通道:
    • 如果未使用可选任务和事件,则至少 2 个 PPI 通道(在最多 255 次 EasyDMA 传输的设备上为 3 个)。
    • 如果使用可选任务和事件,则最多 9 个 PPI 通道和 2 个 PPI 组。

2.2 nrf_libuarte_async

nrf_libuarte_async 库构建在 lib_libuarte_drv 驱动程序之上。它实现了接收器非活动超时,这会导致一个包含接收数据量的事件。

该库具有用于接收的专用缓冲区,并处理来自驱动程序 (NRF_LIBUARTE_DRV_EVT_RX_BUF_REQ) 的缓冲区请求事件。

您可以使用以下选项之一实现接收器不活动超时,具体取决于可用资源:

  • 专用的 TIMER 外围设备
  • 专用 RTC 外设
  • 一个 app_timer 实例

TIMER/RTC 外设
TIMER 或 RTC 外设与 TIMER/RTC 外设中的字节边界事件 (RXDRDY) 和任务 CLEAR 之间的 PPI 连接一起使用。

TIMER/RTC 的配置方式是在 compare 事件上触发中断。当任务 CLEAR 未按时触发时,将触发中断。

configurable 中的超时和 resolution 等于所用外设的 tick length。

app_timer实例
除了 TIMER/RTC 外设 之外,还可以使用 app_timer 实例进行超时实现。此方法需要按指定的时间间隔定期生成 app_timer 事件。

超时时,app_timer 事件处理程序检查收到的字节数是否已更改。根据此检查,处理程序报告数据包边界。

与 TIMER/RTC 外设相比,超时分辨率较低,等于可以设置的最短app_timer超时。

nrf_libuarte_async 正在使用以下硬件资源:

  • UARTE 实例
  • TIMER 实例
  • 2 或 3 个 PPI 通道
  • 如果 TIMER 或 RTC 外围设备用于接收器非活动超时,则使用以下附加资源:
    • RTC 或 TIMER 实例
    • 2 个 PPI 通道

三、参考工程

libuarte 在 SDK v16.0 中得到了改进,它也从 Experimental 中移出并取代了串行库。

SDK\examples\peripheral\libuarte 中找到示例工程

四、添加组件库

基于 ble_app_uart 的工程,在 nRF_Drivers 文件夹和 nRF_Libraries 文件夹确认以下组件库是否存在,不存在则添加。

在 ble_app_uart 的工程中后三个文件没有,需要添加:

  1. 添加 nrfx_ppi.cnrfx_rtc.cnrfx_timer.c
    位于 SDK\modules\nrfx\drivers\src

  2. 添加 nrfx_libuarte_async.cnrfx_libuarte_drv.c
    位于 SDK\components\libraries\libuarte

  3. 添加 nrfx_queue.c
    位于 SDK\components\libraries\queue

  4. 添加上述编译文件路径

五、SDK配置

点击 sdk_config.h 文件

选择 Configuration Wizard

nRF_Drivers 中勾选PPI、RTC、TIMER相关选项

修改时钟配置,由于要移植的工程是ble_app_uart,其中蓝牙协议栈SoftDevice使用了RTC0和TIMER0,app_timer模块使用了RTC1,所以我们用于串口超时的时钟有RTC2、TIMER1和TIMER2等等。

nRF_Libraries 中勾选QUEUE相关选项

添加 NRF_LIBUARTE_ASYNC_WITH_APP_TIMERnrf_libuarte_drv 并勾选

// <q> NRF_LIBUARTE_ASYNC_WITH_APP_TIMER  - nrf_libuarte_async - libUARTE_async library#ifndef NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
#define NRF_LIBUARTE_ASYNC_WITH_APP_TIMER 1
#endif// <h> nrf_libuarte_drv - libUARTE library//==========================================================
// <q> NRF_LIBUARTE_DRV_HWFC_ENABLED  - Enable HWFC support in the driver#ifndef NRF_LIBUARTE_DRV_HWFC_ENABLED
#define NRF_LIBUARTE_DRV_HWFC_ENABLED 0
#endif// <q> NRF_LIBUARTE_DRV_UARTE0  - UARTE0 instance#ifndef NRF_LIBUARTE_DRV_UARTE0
#define NRF_LIBUARTE_DRV_UARTE0 1
#endif// <q> NRF_LIBUARTE_DRV_UARTE1  - UARTE1 instance#ifndef NRF_LIBUARTE_DRV_UARTE1
#define NRF_LIBUARTE_DRV_UARTE1 0
#endif// </h> 
//==========================================================

六、使用例子

1)添加头文件

#include "nrf_libuarte_async.h"

2)添加全局变量(SDK16.0以上 中 ble_peripheral 的 ble_app_uart 工程)

// 使用TIMER2作为计数,不使用RTC和TIMER用作超时(如果前两个都不使用,则使用app_timer作为超时)
NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 2, NRF_LIBUARTE_PERIPHERAL_NOT_USED, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3);
// 使用TIMER2作为计数,使用RTC2用作超时
//NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 2, 2, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3);static uint8_t text[] = "UART example started.\r\n Loopback:\r\n";
static uint8_t text_size = sizeof(text);
static volatile bool m_loopback_phase;typedef struct {uint8_t * p_data;uint32_t length;
} buffer_t;NRF_QUEUE_DEF(buffer_t, m_buf_queue, 10, NRF_QUEUE_MODE_NO_OVERFLOW);

第3,4,5参数分别是TIMER接口用作libuarte字节统计,RTC接口用作超时,TIMER接口用作超时,二者选其一即可,如果都不使用,则使用app_timer作为超时。

其中蓝牙协议栈SoftDevice使用了RTC0和TIMER0,app_timer模块使用了RTC1,所以我们用于串口超时的时钟有RTC2、TIMER1和TIMER2等等。

3)修改main函数
这里由于串口超时使用的是app_timer,而非RTC或TIMER,所以这里将uart_init()往后放。

/**@brief Application main function.*/
int main(void)
{bool erase_bonds;// Initialize.
//    uart_init();log_init();timers_init();uart_init();buttons_leds_init(&erase_bonds);power_management_init();ble_stack_init();gap_params_init();gatt_init();services_init();advertising_init();conn_params_init();// Start execution.
//    printf("\r\nUART started.\r\n");NRF_LOG_INFO("Debug logging for UART over RTT started.");advertising_start();// Enter main loop.for (;;){idle_state_handle();}
}

4)添加串口初始化函数
这里由于串口超时使用的是app_timer,而非RTC或TIMER,所以这里将串口中断优先级调整的app_timer优先级高,修改为 APP_IRQ_PRIORITY_LOW_MID 及以上。

/**@brief  Function for initializing the UART module.*/
/**@snippet [UART Initialization] */
static void uart_init(void)
{ret_code_t err_code;nrf_libuarte_async_config_t nrf_libuarte_async_config = {.tx_pin     = TX_PIN_NUMBER,.rx_pin     = RX_PIN_NUMBER,.baudrate   = NRF_UARTE_BAUDRATE_115200,.parity     = NRF_UARTE_PARITY_EXCLUDED,.hwfc       = NRF_UARTE_HWFC_DISABLED,.timeout_us = 100,.int_prio   = APP_IRQ_PRIORITY_LOW_MID};err_code = nrf_libuarte_async_init(&libuarte, &nrf_libuarte_async_config, uart_event_handler, (void *)&libuarte);APP_ERROR_CHECK(err_code);nrf_libuarte_async_enable(&libuarte);err_code = nrf_libuarte_async_tx(&libuarte, text, text_size);APP_ERROR_CHECK(err_code);
}
/**@snippet [UART Initialization] */

5)添加串口中断处理函数
每当 nrf_libuarte_drv 设置 EasyDMA 接收缓冲区时,都会生成缓冲区请求事件 (NRF_LIBUARTE_DRV_EVT_RX_BUF_REQ)。在这种情况下,请确保应用程序使用 nrf_libuarte_drv_rx_buf_rsp 进行响应并提供新的缓冲区。新的接收缓冲区必须在刚刚开始的传输结束之前提供,否则 UARTE 将开始覆盖活动缓冲区,因为接收会自主重新启动。

如果设备不支持 16 位长的 EasyDMA 传输,则使用 EasyDMA 双缓冲功能以及 ENDTX 事件和 STARTTX 任务之间的 PPI 连接来确保连续传输。传输完成后,将生成 NRF_LIBUARTE_DRV_EVT_TX_DONE 事件。

void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
{nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;ret_code_t ret;switch (p_evt->type){case NRF_LIBUARTE_ASYNC_EVT_ERROR:bsp_board_led_invert(0);break;case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:ret = nrf_libuarte_async_tx(p_libuarte,p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);if (ret == NRF_ERROR_BUSY){buffer_t buf = {.p_data = p_evt->data.rxtx.p_data,.length = p_evt->data.rxtx.length,};ret = nrf_queue_push(&m_buf_queue, &buf);APP_ERROR_CHECK(ret);}else{APP_ERROR_CHECK(ret);}bsp_board_led_invert(1);m_loopback_phase = true;break;case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:if (m_loopback_phase){nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);if (!nrf_queue_is_empty(&m_buf_queue)){buffer_t buf;ret = nrf_queue_pop(&m_buf_queue, &buf);APP_ERROR_CHECK(ret);UNUSED_RETURN_VALUE(nrf_libuarte_async_tx(p_libuarte, buf.p_data, buf.length));}}bsp_board_led_invert(2);break;default:break;}
}

6)串口接收
每次完成 EasyDMA 传输时,都会生成 NRF_LIBUARTE_DRV_EVT_RX_DATA 事件。事件结构包含指向数据和接收的数据量的指针。处理数据时,必须通过调用 nrf_libuarte_async_rx_free 用于释放接收到的缓冲区数据的函数。

上面串口中断处理函数是为了串口回环打印测试,实际应用可改为以下逻辑:

    case NRF_LIBUARTE_ASYNC_EVT_RX_DATA: {在此自定义串口处理(event->data.rxtx.p_data, event->data.rxtx.length)nrf_libuarte_async_rx_free(libuarte, event->data.rxtx.p_data, event->data.rxtx.length);} break;

7)串口发送
nrf_libuarte_async_tx 用于启动传输。
在传输完成时调用具有 NRF_LIBUARTE_ASYNC_EVT_TX_DONE 事件的事件处理程序。

七、工程代码

基于 nRF5_SDK_17.1.0_ddde560,仅用于移植文件添加参考。
百度网盘: https://pan.baidu.com/s/1yu34SDNoBl7Uy-WV18UO8A?pwd=999m 提取码: 999m


• 由 Leung 写于 2024 年 11 月 4 日

• 参考:nRF5 SDK v17.1.0: Libuarte - advanced UARTE driver (nordicsemi.com)
    nrf52840蓝牙开发之Libuarte外设移植

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

ORU 的 Open RAN 管理平面 (M 平面)

[TOC](ORU 的 Open RAN 管理平面 (M 平面)) ORU 的 Open RAN 管理平面 (M 平面) https://www.techplayon.com/open-ran-management-plane-m-plane-for-open-radio-unit/ ORU M 平面 在 ORAN 中&#xff0c;设置参数的 O-RU 管理功能是通过 M-Plane 完成的。管理功能包括 O-…

MQ的基础知识

一.什么是MQ 其实就是不同的程序之间的一种的通信方式,通过将消息发送到中间件里面然后中间件就会将这个消息发送给相应的服务进行一个消息的消费,这个时候就会进行一些的业务逻辑的处理,这个方式提高了整个系统的可靠性,拓展性以及灵活性.常见的类型为Aapache Kafaka&#xf…

蓝牙OPP协议详解及Android实现

文章目录 前言一、什么是蓝牙OPP协议&#xff1f;二、OPP协议工作流程1. 设备配对和连接2. 启动 OPP 服务3. 发送对象4. 传输对象5. 传输完成6. 断开连接 三、 Android OPP协议实现1. 启动 OPP 服务器&#xff08;接收方&#xff09;2. 发送文件&#xff08;发送方&#xff09;…

医学可视化之涟漪图

在医学领域&#xff0c;数据可视化能够帮助我们更直观地理解和分析复杂的信息。涟漪图作为一种独特的可视化工具&#xff0c;具有重要的作用、价值和广泛的使用场景。 一、涟漪图的特点 涟漪图是一种基于地理位置的可视化图表&#xff0c;它通过在地图上显示不同大小或颜色的…

定义宏将整数的二进制的奇数位和偶数位互换位置

假设这个数为n00000000 00000000 00000000 00001101——13 1.思路 1.1 奇数位&#xff1a;00000000 00000000 00000000 00000101 但是怎么获得奇数位呢&#xff1f;——进行按位与运算 不懂如何运算的可以看我主页的详解操作符-CSDN博客&#xff0c;该章详细写了各个操作符如何…

快要结束的大学时光

目录 大一 大一上学期 Java HTMLCSS 大一下学期 HTMLCSSJS JAVA python 大二 大二上学期 Java 原型 前端 大二下学期 前端 数据结构 Android BootStrap JavaWeb ios程序设计 软件测试​编辑 大三 大三上学期 小程序 大三下学期 JavaWeb 整理数据库 大…

高效实现MySQL数据集成的具体案例分享

MySQL数据集成案例分享&#xff1a;1–BI秉心-店铺信息表–store_z–>store 在数据驱动的业务环境中&#xff0c;如何高效、可靠地实现数据集成是每个企业面临的重要挑战。本文将聚焦于一个具体的系统对接集成案例&#xff1a;将MySQL中的店铺信息表store_z的数据集成到另一…

[Docker#3] LXC | 详解安装docker | docker的架构与生态

目录 1.LXC容器操作 安装LXC LXC容器操作步骤 2.理论 LXC 是什么&#xff1f; Docker 是什么 Docker 和虚拟机的区别 Docker 和 JVM 虚拟化的区别 Docker 版本 ⭕Docker 官方网站&#xff08;建议收藏&#xff09; Docker 架构 生活案例 Docker 生态 Docker 解决…

CAP相关的分布式技术

目录 一&#xff0c;CAP理论基础 1.1、一致性&#xff08;Consistency&#xff09; 1.2、可用性&#xff08;Availability&#xff09; 1.3、分区容忍性&#xff08;Partition Tolerance&#xff09; 1.4、CAP理论的核心观点 二&#xff0c;如何选C与A 2.1、网络分区情况…

【春秋云镜】CVE-2023-2130

目录 CVE-2023-2130漏洞利用漏洞检测防御措施 靶标介绍&#xff1a;解法一&#xff1a;解法二&#xff1a; CVE-2023-2130 漏洞详细信息 漏洞编号&#xff1a;CVE-2023-2130漏洞名称&#xff1a;SQL注入漏洞受影响的版本&#xff1a;SourceCodester采购订单管理系统1.0影响范…

Code::Blocks 24.10 全中文优化完整版

Code::Blocks&#xff08;或者叫做 CodeBlocks&#xff09;是一款开放源代码、跨平台的集成开发环境&#xff08;IDE&#xff09;&#xff0c;通过配置不同的编程语言编译器&#xff0c;可以用于多种编程语言程序开发。 网上有很多文章介绍 Code::Blocks 的安装&#xff0c;通…

二叉树-哈夫曼树的构造和应用

重点:哈夫曼树的构造和应用(编码) 选取完最小权值的两个节点后新结点的权值是二者之和,新节点可以和选取剩余的结点结合,也可以在剩余的里面选出最小两个结合后形成的新结点与第一个新结点结合(前提他们是最小的两个结点) 哈夫曼编码 哈夫曼编码优化 130为最小的带权路径长度 …

d3坐标轴系数角度变换-位置不对等问题

svg.append(text).attr(x, 100) // 文本 x 坐标.attr(y,200 ) // 文本 y 坐标// .attr(text-anchor, middle) // 文本居中.attr(fill, black) // 文本颜色.attr(transform, rotate(-90, 25, 30)) // 旋转 -90 度.attr(font-size, 9).text(你的文本); 有些老哥…

rosbag数据导出成pcd文件

目录 步骤 1&#xff1a;安装必要的 ROS 包步骤 2&#xff1a;播放 .bag 文件中的点云数据&#xff08;非必须&#xff09;步骤 3&#xff1a;使用 pcl_ros 提取并保存点云数据步骤 4&#xff1a;验证输出 要将 .bag 文件中的点云数据导出为 .pcd 文件&#xff0c;通常需要以…

基于 Spring Boot 和 Vue 的门票销售创新系统

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

推荐一款管道数据检索工具:Pipedata-Pro

Pipedata-Pro是一款专为设计石油、天然气、水和蒸汽管道及管道系统的工程师开发的应用程序。该应用程序提供了设计管道系统所需的工程数据&#xff0c;拥有一个全面的管道类型、配件和材料数据库。 软件特点&#xff1a; 1. 技术参数查询&#xff1a;Pipedata-Pro 提供关于管道…

使用 Umami 部署博客分析工具

Umami 简介 Umami 是一款开源且注重隐私的网站分析工具&#xff0c;可替代 Google Analytics。它提供网站流量和用户行为等见解&#xff0c;但不使用 Cookie 或收集个人数据&#xff0c;符合隐私法规。Umami 轻巧易用&#xff0c;可自行托管。 如果你有自己的博客&#xff0c;…

三菱QD77MS定位模块速度更改功能

速度更改功能” 是以任意时机将控制中的速度更改为新指定的速度的功能。更改后的速度直接设置到缓冲存储器中&#xff0c;并根据速度更改指令([cd.15速度更改请求)或者外部指令信号执行速度更改。 但是&#xff0c;机械原点复位的情况下&#xff0c;检测出近点狗 ON 并开始向蠕…

typescript 补充

文章目录 Pick<T, K> 从 T 中挑选部分属性构成新类型Partial<T>&#xff1a;将类型的所有属性变为可选Required<T>&#xff1a;将类型的属性变为必选。Omit<T, K>&#xff1a;从 T 中移除部分属性构成新类型。Readonly<T>&#xff1a;将类型的属…

运动【跑步 03】安踏冠军3的10KM和15KM*2体验(对比必迈PURE LIGHT)

这里写目录标题 1. 前言2. 两双鞋2.1 必迈 PURE LIGHT2.2 安踏 冠军 3 3. 主观对比4. 问题4.1 必迈 PURE LIGHT4.2 冠军 3 5. 总结 1. 前言 我是程序员&#xff0c;并不是专业的运动员&#xff0c;对跑步鞋的研究也不深&#xff0c;至今也就买过两双相对比较专业的跑鞋&#x…