下载 FreeRTOS
 

出色的 RTOS & 嵌入式软件

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

中断驱动的零拷贝传输模式

[FreeRTOS-Plus-IO 传输模式]

数据方向

中断驱动的零拷贝传输模式可以与 FreeRTOS_write() 一起使用。


说明

ioconfigUSE_ZERO_COPY_TX 必须在 FreeRTOSIOConfig.h 中设置为 1, 以使零拷贝传输模式可用。 另外, 其必须被明确启用于 相同配置文件中使用的 相同配置文件中使用的外围设备明确启用。

当选择零拷贝传输模式时,FreeRTOS_write() 不直接将字节写入外围设备。 相反,待写入的总字节数 和指向第一个字节的指针存储于 FreeRTOS-Plus-IO 驱动器内。 随后,外围设备的中断 服务程序使用这些值来执行实际写入操作。 字节从提供的缓冲区直接被拷贝到外围设备的 寄存器,而不存储在任何中间队列或缓冲区中。

FreeRTOS-Plus-IO 驱动器可以创建和管理互斥锁,以确保同时仅有 一项任务可以执行零拷贝写入。 必须 在任务能够开始零拷贝写入之前获取互斥锁。 互斥锁 可通过调用 FreeRTOS_ioctl() (使用 ioctlOBTAIN_WRITE_MUTEX 请求代码) 获取。 请务必检查 FreeRTOS_ioctl() 返回值, 确认是否已成功获取互斥锁,该检查步骤必须在调用 FreeRTOS_write() 前执行。 如果通过非互斥锁持有者的任务调用 FreeRTOS_write() ,调用将失败 。

零拷贝写入由 FreeRTOS-Plus-IO 中断服务程序执行。 在启动写入操作的 FreeRTOS_write() 调用返回后,中断服务程序可能会继续访问被写入的缓冲区一段时间。 直到中断服务程序完成写入操作前,不得重复使用缓冲区或以任何方式损坏缓冲区 。 FreeRTOS_ioctl()、 ioctlOBTAIN_WRITE_MUTEXioctlWAIT_PREVIOUS_WRITE_COMPLETE 请求代码可用于此用途。

一项持有互斥锁但不执行 FreeRTOS_WRITE() 的任务必须 通过使用请求代码调用 FreeRTOS_ioctl() 以手动释放互斥锁, 请求代码应设置为 ioctlRELEASE_WRITE_MUTEX。

中断服务程序和写入互斥锁 由 FreeRTOS-Plus-IO 代码提供,无需由 应用程序编写者提供。

中断驱动的零拷贝传输模式
优点 缺点
  • 自动将调用任务置于 阻塞状态,等待写入互斥锁 变为可用。这 确保了调用 FreeRTOS_write() 的任务 仅当它确实可以访问外围设备时才使用 CPU 时间 。
  • 对 FreeRTOS_write() 的调用可立即返回,允许 调用任务在传输过程中执行其他操作。 。
  • 通过中断服务程序,字节直接从提供的缓冲区中作为 FreeRTOS_write() 调用中的参数被传输至外围寄存器。 无需额外的 RAM,无需额外拷贝数据, 实为一非常高效的写入 方法。
  • 使用写入互斥锁表示双向互斥已被 内置于 FreeRTOS-Plus-IO 驱动器中。
  • 使用模型更复杂。

ioctlUSE_ZERO_COPY_TX 请求代码用于调用 FreeRTOS_ioctl() 以配置外围设备, 使用中断驱动的零拷贝传输模式进行写入。 请注意,此请求代码将导致外围设备的 中断被启用,且外围设备的中断优先级被设置为 可能的最低值。 可以使用 ioctlSET_INTERRUPT_PRIORITY 请求代码 在必要时提高外围设备的优先级。


示例用法

FreeRTOS_write() API 函数文档页面也提供了相关示例。


/* FreeRTOS-Plus-IO includes. */
#include "FreeRTOS_IO.h"

void vAFunction( void )
{
/* The Peripheral_Descriptor_t type is the FreeRTOS-Plus-IO equivalent of a descriptor. */
Peripheral_Descriptor_t xOpenedPort;
BaseType_t xReturned;
const uint32_t ulMaxBlock100ms = ( 100UL / portTICK_PERIOD_MS );

/* Open the SPI port identified in the board support package as using the
path string "/SPI2/". The second parameter is not currently used and can
be set to anything, although, for future compatibility, it is recommended
that it is set to NULL. */

xOpenedPort = FreeRTOS_open( "/SPI2/", NULL );

if( xOpenedPort != NULL )
{
/***************** Configure the port *********************************/

/* xOpenedPort now contains a valid descriptor that can be used with
other FreeRTOS-Plus-IO API functions.

Peripherals default to using Polled mode for both reads and writes.
Change from the default to use the interrupt driven zero copy transfer
mode for writing. The third FreeRTOS_ioctl() parameter is not used and
can take any value - although it is recommended to set the value to NULL
for future compatibility. A successful FreeRTOS_ioctl() call will return
pdPASS, for simplicity, this example does not show the return value being
checked. */

FreeRTOS_ioctl( xOpenedPort, ioctlUSE_ZERO_COPY_TX, NULL );


/***************** Use the port ***************************************/

/* As the zero copy transfer mode is being used, the write mutex must
be obtained before FreeRTOS_write() is called. The following call will
attempt to obtain the mutex. If the mutex is not immediately available,
then the calling task will be placed into the Blocked state to wait for
it, but the task will not wait longer than 100ms. If the task is
successful in obtaining the mutex in that time, FreeRTOS_ioctl() will
return pdPASS, otherwise FreeRTOS_ioctl() will return pdFAIL. */

xReturned = FreeRTOS_ioctl( xOpenedPort, ioctlOBTAIN_WRITE_MUTEX, ulMaxBlock100ms );

if( xReturned == pdTRUE )
{
/* The mutex was successfully obtained, now a FreeRTOS_write() can
be performed. This call will send 100 bytes from ucBuffer. ucBuffer
is assumed to be defined outside of this function. */

xReturned = FreeRTOS_write( xOpenedPort, ucBuffer, 100 );

if( xReturned == 100 )
{
/* The write was successful BUT will not yet have completed. The
peripheral's interrupt service routine will be accessing ucBuffer,
but this task is free to do anything else it needs to do at this
point - provided the data in ucBuffer is not changed. */

}
}

/* Some time later the task wants to update the data in ucBuffer, and
perform another write. First it must ensure the previous write has
completed. If it can successfully obtain the write mutex again then
it knows it is safe to access ucBuffer. Again, a maximum block time of
100ms is used. */

xReturned = FreeRTOS_ioctl( xOpenedPort, ioctlOBTAIN_WRITE_MUTEX, ulMaxBlock100ms );

if( xReturned == pdTRUE )
{
/* The mutex was obtained, so the task can go ahead and update the
buffer. In this example, all it is going to do is clear it to zero. */

memset( ucBuffer, 0, 100 );

/* The task already holds the mutex, so can perform the write now. */
xReturned = FreeRTOS_write( xOpenedPort, ucBuffer, 100 );

/* Again - if at this point xReturned == 100, the write was successful,
but will still be in progress. */

}

/* Before exiting the function, the task wants to ensure the write has
completed, but this time it does not want to perform another write itself,
so uses the ioctlWAIT_PREVIOUS_WRITE_COMPLETE request code in place of the
ioctlOBTAIN_WRITE_MUTEX request code in a call to FreeRTOS_ioctl(). */

FreeRTOS_ioctl( xOpenedPort, ioctlWAIT_PREVIOUS_WRITE_COMPLETE, ulMaxBlock100ms );
}
}

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