我正在开发一种使用网守任务来访问共享资源的设计.我现在的基本设计是网守任务正在接收的单个队列以及将请求放入其中的多个任务.
这是一个内存有限的系统,我正在使用FreeRTOS(Cortex M3端口).
问题如下:异步处理这些请求非常简单.请求任务将其请求排队并进行业务,轮询,处理或等待其他事件.为了同步处理这些请求,我需要一种机制让请求任务阻塞,这样一旦处理了请求,网守就可以唤醒调用该请求的任务.
我能想到的最简单的设计是在每个请求中包含一个信号量,但考虑到内存限制和FreeRTOS中信号量的相当大的大小,这是不切实际的.
我想到的是使用任务挂起和任务恢复功能来手动阻止任务,将句柄传递给网守,当请求完成时,它可以恢复任务.暂停/恢复有一些问题,我真的想避免它们.单个恢复调用将唤醒任务,无论其被多少次被其他调用暂停,这可能会产生不良行为.
一些简单的伪C来演示suspend/resume方法.
void gatekeeper_blocking_request(void)
{
put_request_in_queue(request);
task_suspend(this_task);
}
void gatekeeper_request_complete_callback(request)
{
task_resume(request->task);
}
Run Code Online (Sandbox Code Playgroud)
我计划在此期间使用的解决方法是使用异步调用并在每个请求任务中完全实现阻塞.当操作完成时,网守将执行提供的回调,然后可以发布到任务的主队列或特定信号量,或任何需要的信号.对请求进行阻塞调用本质上是一个便利功能,因此每个请求任务都不需要实现此功能.
Pseudo-C用于演示特定于任务的阻塞,但这需要在每个任务中实现.
void requesting_task(void)
{
while(1)
{
gatekeeper_async_request(callback);
pend_on_sempahore(sem);
}
}
void callback(request)
{
post_to_semaphore(sem);
}
Run Code Online (Sandbox Code Playgroud)
也许最好的解决方案就是不在网守和API中实现阻塞,并强制每个任务来处理它.但是,这将增加每个任务流程的复杂性,我希望我能避免它.在大多数情况下,所有调用都将阻止,直到操作完成.
是否有一些我缺少的构造,或者甚至只是一个更好的术语来解决这类问题?在我的搜索中,我没有遇到过这样的事情.
附加说明 - 网守任务的两个原因:
需要大堆栈空间.网守可以拥有一个只需要所有内存的堆栈,而不是将这个要求添加到每个任务中.
资源并不总是可以在CPU中访问.它不仅可以同步CPU中的任务,还可以同步CPU外部的任务.
我已经FreeRTOS
在一些嵌入式项目中使用了一年时间,到目前为止它工作得非常完美。FreeRTOS
目前我面临着一个与使用高速中断移植到相关的难题PIC24H
,希望大家能帮助我解决这个问题。提前致谢
我创建了一个小型演示项目以方便测试:
两个任务:
// Task 1
if (xTaskCreate(RTOSTask_1, (signed char) "[T1]", configMINIMAL_STACK_SIZE2, NULL, tskIDLE_PRIORITY + 1, &hTask1) == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{
LREP("\r\nCannot create Task 1.");
Display_Error(1000);
}
// Task 2
if (xTaskCreate(RTOSTask_2, (signed char) "[T2]", configMINIMAL_STACK_SIZE2, NULL, tskIDLE_PRIORITY + 2, &hTask2) == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{
LREP("\r\nCannot create Task 2.");
Display_Error(1000);
}
Run Code Online (Sandbox Code Playgroud)
任务落实:
void RTOSTask_1(void* pvParameter)
{
while(1)
{
if (xSemaphoreTake(hTask1Semaphore, portMAX_DELAY) == pdTRUE)
{
putchar1('1');
}
}
}
void RTOSTask_2(void* pvParameter)
{
while(1)
{
if (xSemaphoreTake(hTask2Semaphore, …
Run Code Online (Sandbox Code Playgroud) 我可以做这样的事情吗:
#ifdef FREERTOS
#define malloc(size) pvPortMalloc(size)
#define free(ptr) pvPortFree(ptr)
#endif
Run Code Online (Sandbox Code Playgroud)
并期望它总是调用pvPortMalloc()
而不是malloc()
?
另外,把它放在之前/之后会有什么区别#include <stdlib.h>
?
我有一些代码想要在 FreeRTOS 内和外运行,我想将所有调用替换为使用 FreeRTOS 时的malloc()
调用pvPortMalloc()
。
在configMINIMAL_STACK_SIZE
Cortex M0 MCU 上 FreeRTOS 的一些演示中设置为 60,而在其他一些演示中设置为 70。使用 STM32Cube 软件时设置为 128。
我的问题是实际上最小堆栈大小是多少?
查看STM32 Cortex-M0编程手册,我看到处理器寄存器是R0-R12、MSP、PSP、LR、PC、PSR、ASPR、IPSR、EPSR、PRIMASK、CONTROL。这不是意味着 MINIMAL 堆栈大小只有 23 个字吗?或者是否需要为上下文切换保存更多信息?
解决方案是关闭初始化模块中的 I2C 时钟。尽管 STM 可以处理它,但 LCD 的数据表表明它只能处理高达 10kHz 的频率。
对于 DMA,必须在 CubeMX 软件中启用和设置一个 IRQ,以启用 DMA TX/RX 线。
我正在使用带有 freeRTOS 的 STM32 - Nucleo-F401RE 板。我最近使用过 freeRTOS,但我从未真正使用过 I2C。
尝试使用 CubeMX 生成的 I2C 驱动程序设置一个简单的LCD 显示器。
到目前为止,它只发送了我请求发送的数据的一半左右。我已经使用简单的“show firmware”命令对其进行了测试,并且可以正常工作。所以我可以验证 I2C 实例是否设置正确。
/* I2C1 init function */
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{ …
Run Code Online (Sandbox Code Playgroud) 我有一个简单的 FreeRTOS 程序,基本上我需要计算运行不同次数的迭代所需的时间。问题是它只是冻结并且不再执行,尽管迭代尚未完成,我需要它成功地到达 vTaskEndScheduler() 以终止,以便我可以正确计算时间。可能是什么原因? 冻结屏幕截图
void Task1() {
for (int i = 0; i < 100; i++)
{
printf("This is task 1 ");
printf("Iteration number ");
printf("%d", i);
printf("\n");
vTaskDelay(100);
}
vTaskEndScheduler();
};
void Task2() {
for (int i = 0; i < 100; i++) {
printf("This is task 2 ");
printf("Iteration number ");
printf("%d", i);
printf("\n");
vTaskDelay(100);
}
vTaskEndScheduler();
};
void main_blinky(void)
{
enableFlushAfterPrintf();
xTaskCreate(Task1, (signed char*) "t1", 100, NULL, 1, NULL);
xTaskCreate(Task2, (signed char*) "t2", 100, NULL, …
Run Code Online (Sandbox Code Playgroud) 我使用 ESP-32 并且需要std::shared_ptr
使用 FreeRTOS 队列通过。然而,它失去了一个链接。我认为这是问题的根源:
#include <iostream>
#include <memory>
#define PRINT_USE_COUNT(p) std::cout << "Use count: " << p.use_count() << std::endl;
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
}
class testClass {
public:
testClass() {
std::cout << "Class is constructed" << std::endl;
};
virtual ~testClass() {
std::cout << "Class is destructed" << std::endl;
};
};
struct container {
std::shared_ptr<testClass> field;
};
extern "C" void app_main(void) {
auto queue = xQueueCreate(1, sizeof(container));
auto p = std::make_shared<testClass>();
PRINT_USE_COUNT(p); // …
Run Code Online (Sandbox Code Playgroud) 我正在 Xilinx UltraScale+ ZCU102 设备上为 RPU 编写一个应用程序,需要在 FreeRTOS 中运行一些任务。我的应用程序首先创建一个“启动”任务,然后创建其余的任务。成功创建启动任务并调用 vTaskStartScheduler() 后,启动任务未运行。
我注意到 FreeRTOS 常见问题解答页面 ( http://www.freertos.org/FAQHelp.html ) 说:
如果您创建的项目正在编译,并且至少执行到调度程序启动为止,但在调用 vTaskStartScheduler() 后只有一个任务正在执行或根本没有任务正在执行,那么很可能是中断向量表不正确。
所以我首先检查以确保中断向量表是正确的。我使用的是 FreeRTOS 10.0,它是作为 ZCU102 BSP 的一部分构建的。
在使用 BSP 创建的文件“port_asm_vectors.S”中,我有
// port_asm_vectors.S
...
.section .vectors,"a"
_vector_table:
ldr pc,=_boot
ldr pc,=Undefined
ldr pc, _swi
ldr pc,=PrefetchAbortHandler
ldr pc,=DataAbortHandler
NOP /* Placeholder for address exception vector*/
ldr pc, _irq
ldr pc,=FIQHandler
_irq: .word FreeRTOS_IRQ_Handler
_swi: .word FreeRTOS_SWI_Handler
...
Run Code Online (Sandbox Code Playgroud)
在我的应用程序的链接描述文件中,我有以下内容
// lscript.ld
...
SECTIONS
{
.vectors : {
KEEP (*(.vectors))
*(.boot)
} > …
Run Code Online (Sandbox Code Playgroud) 我正在用 ESP32 制作一盏灯,我选择的 HomeKit 库使用我不熟悉的 FreeRTOS 和 esp-idf。
目前,我有一个函数,每当需要更改灯光颜色时就会调用该函数,这只会一步步更改它。我想让它在颜色之间淡入淡出,这需要一个运行一两秒的函数。将此块作为程序的主要执行显然会使其非常无响应,因此我需要将其作为任务运行。
我面临的问题是,我只想一次运行一个淡入淡出函数的副本,如果在完成之前第二次调用它,则第一个副本应该在之前退出(无需等待完整的淡入淡出时间)开始第二个副本。
我发现vTaskDelete
,但如果我在任意点终止淡入淡出功能,一些变量和 LED 本身将处于未知状态。为了解决这个问题,我想到使用“kill flag”全局变量,淡入淡出函数将检查其每个循环。
这是我正在考虑的伪代码:
update_light {
kill_flag = true
wait_for_fade_to_die
xTaskCreate fade
}
fade {
kill_flag = false
loop_1000_times {
(fading code involving local and global variables)
.
.
if kill_flag, vTaskDelete(NULL)
vTaskDelay(2 / portTICK_RATE_MS)
}
}
Run Code Online (Sandbox Code Playgroud)
我的主要问题是:
wait_for_fade_to_die
?我没有通过简短的浏览找到任何东西,但我是 FreeRTOS 的新手。PendSV和SVCall都是由软件调用的——SVCall是通过调用svc指令来调用的,PendSV是通过设置Cortex-M的特定寄存器来调用的。PendSV 用于上下文切换,SVCall 用于访问操作系统内核功能和设备驱动程序。
我想知道的不仅仅是“PendSV 用于上下文切换,SVCall 用于启用调度程序”。我找不到更多信息。
干杯