下载 FreeRTOS
 

出色的 RTOS & 嵌入式软件

内核
最新资讯
简化任何设备的身份验证云连接。
利用 CoAP 设计节能型云连接 IoT 解决方案。
11.0.0 版 FreeRTOS 内核简介:
FreeRTOS 路线图和代码贡献流程。
使用 FreeRTOS 实现 OPC-UA over TSN。

RTOS 流缓冲区
[流缓冲区和消息缓冲区]


本页面包含:
  1. 简介
  2. 入门
  3. 阻塞读取和触发级别
  4. 阻塞写入
  5. 发送和接收完整宏(用于多核)


简介

通过流缓冲区,可以将字节流从中断服务程序传递到任务, 或者从一个任务传递到另一个。 字节流可以是任意长度, 且并不一定具有开头或结尾。 可以一次写入任意数量的字节, 也可以一次读取任意数量的字节。 数据通过拷贝传递,发送方将数据复制到缓冲区中, 读取方将数据复制出缓冲区。

与大多数其他 FreeRTOS 通信原语不同, 流缓冲区针对单读取器单写入器场景进行了优化, 例如将数据从中断服务程序传递到任务, 或从双核 CPU 上的一个微控制器内核传递到另一个微控制器内核。

通过将 FreeRTOS/source/stream_buffer.c 源文件 包含在项目中来启用流缓冲区功能。

流缓冲区实施采 直达任务通知。 因此,流缓冲区 API 将调用的任务置于“阻塞”状态, 调用该 API 可以改变该调用任务的 通知状态和通知值。

重要提示: 在 FreeRTOS 对象中独一无二的是, 流缓冲区实现( 消息缓冲区 构建在流缓冲区之上,所以消息缓冲区实现也是如此)假设只有一个任务或 中断会写入缓冲区(写入者), 并且只有一个任务或中断将从缓冲区读取(读取者)。 写入者和读取者可以是不同的任务或中断,这样是安全的, 但不同于 其他 FreeRTOS 对象,具有多个写入者或读取者 并不安全。 如果有多个不同的写入者, 则应用程序编写者必须将每个 写入 API 函数的调用(如 xStreamBufferSend())放在一个临界区中, 并以 “0” 为发送阻塞时间。 同样, 如果存在多个不同的读取者,那么应用程序编写者必须将 每个读取 API 函数的调用(如 xStreamBufferReceive()) 放在临界区中,并以 “0” 为接收阻塞时间。


入门指南

FreeRTOS/Demo/Common/Minimal/StreamBufferInterrupt.c 源文件 提供了如何使用流缓冲区将数据 从中断服务程序传递到任务的大量注释的示例。

请参阅流缓冲区部分 获取流缓冲区相关 API 函数的列表, 在许多示例中, 包括演示所使用函数的代码片段。


阻塞读取和触发级别

xStreamBufferReceive() 用于读取 来自 RTOS 任务的流缓冲区的数据。 xStreamBufferReceiveFromISR()) 用于 从中断服务程序 (ISR) 的流缓冲区中读出数据。

xStreamBufferReceive() 允许指定阻塞时间。 如果在任务使用 xStreamBufferReceive() 读取 恰好为空的流缓冲区时 指定了非零阻塞时间, 则该任务 将进入阻塞状态(因此不消耗任何 CPU 时间,并且其他任务可以 运行) ,直到流缓冲区中有指定数量的数据可用, 或者阻塞时间到期。 在等待数据的任务从阻塞状态移除之前, 流缓冲区中必须包含的数据量称为流缓冲区的 触发等级。 例如:

  • 如果任务在读取触发级别为 1 的空流缓冲区时被阻塞, 则向缓冲区写入单个字节或任务的阻塞时间到期时, 该任务将被解除阻塞。

  • 如果任务在读取触发级别为 10 的空流缓冲区时被阻塞, 则在流缓冲区至少包含 10 个字节或任务的阻塞时间到期之前, 该任务将不会被解除阻塞。
如果读取任务的阻塞时间 在达到触发级别之前到期, 则该任务仍将接收实际可用的字节数。

注意:

  • 将触发器级别设置为 0 无效。 尝试设置 触发等级为 0 将导致使用 1 触发等级。

  • 指定的触发级别大于 流缓冲区的大小。

流缓冲器的触发级别最初 是在创建流缓冲区时设置的,然后可以 使用 xStreamBufferSetTriggerLevel() 函数 进行更改。


阻塞写入

xStreamBufferSend()) 用于 将数据从 RTOS 任务发送到流缓冲区。 xStreamBufferSendFromISR()) 用于 将数据从中断服务程序 (ISR) 发送到流缓冲区。

如果任务使用 xStreamBufferSend() 写入恰好已满的流缓冲区时指定了非零阻塞时间,则该任务 将进入阻塞状态(因此不消耗任何 CPU 时间,并且其他任务可以 运行),直到流缓冲区中出现可用空间,或者 阻塞时间到期。


发送和接收完整的回调

[另请参阅关于使用消息缓冲区进行双核心-核心间通信的博文。]

流缓冲区和消息缓冲区在每次发送和接收操作完成后 执行回调:

  • 使用 xStreamBufferCreate() 和 xMessageBufferCreate() API 函数 (及其静态分配的等效函数)创建的流缓冲区和消息缓冲区共享相同的回调函数,可使用 sbSEND_COMPLETED() 和 sbRECEIVE_COMPLETED() 宏定义这些回调函数。以下各节会详细介绍这些宏。
  • 使用 xStreamBufferCreateWithCallback() 和 xMessageBufferCreateWithCallback() API 函数 (及其静态分配的等效函数)创建的流缓冲区和消息缓冲区各自具有独特的回调函数。

sbSEND_COMPLETED()(和 sbSEND_COMPLETED_FROM_ISR())

sbSEND_COMPLETED() 是将数据写入流缓冲区时(在 FreeRTOS API 函数内部)调用的宏, 该流缓冲区使用 xStreamBufferCreate() 或 xStreamBufferCreateStatic() API 创建。 它需要一个参数,即已更新的流缓冲区的句柄。

默认情况下(即应用程序编写者未提供自己的宏实现), sbSEND_COMPLETED() 会检查流缓冲区上是否存在等待数据的阻塞任务; 如果存在,则将该任务从阻塞状态中移除。

应用程序编写者可以通过 在 FreeRTOSConfig.h 中提供自己的 sbSEND_COMPLETED() 实现来更改此默认行为。此操作非常适用于 使用流缓冲区在多核处理器上的核心之间传递数据。在 这种情况下,可以实现 sbSEND_COMPLETED() 以在其他 CPU 核心中生成中断, 然后中断服务程序可以使用 xStreamBufferSendCompletedFromISR() API 函数检查是否存在等待数据的任务, 并在必要时解除阻塞。

FreeRTOS/Demo/Common/Minimal/MessageBufferAMP.c 源文件提供了 详细说明该场景的示例。

如果您需要每个流缓冲区都有自己的“发送完成”行为, 请使用 xStreamBufferCreateStaticWithCallback() 或 xStreamBufferCreateStaticWithCallback() API 函数 创建流缓冲区。


sbRECEIVE_COMPLETED()(和 sbRECEIVE_COMPLETED_FROM_ISR())

sbRECEIVE_COMPLETED() 是 sbSEND_COMPLETED() 的接收等效函数。在 从流缓冲区读取数据时,会(在 FreeRTOS API 函数内部)调用此函数 。默认情况下(即应用程序编写者未提供自己的宏实现), 该宏会检查流缓冲区上是否存在等待缓冲区内空间可用的阻塞任务; 如果存在,则将该任务 从阻塞状态中移除。


与 sbSEND_COMPLETED() 一样,应用程序编写者 可以通过 在 FreeRTOSConfig.h 中提供替代实现来更改 sbRECEIVE_COMPLETED() 的默认行为。如果您需要每个流缓冲区都有自己的“接收完成”行为, 请使用 xStreamBufferCreateWithCallback() 或 xStreamBufferCreateStaticWithCallback() API 函数 创建流缓冲区。






Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.