FreeRTOS_基本概念、内存管理_学习笔记

0 FreeRTOS源码概述

该STM32F103Z开发板提供了一个freertos.c文件,由STM32CubeMX软件生成,其结构如下:

/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle; // 声明任务句柄
const osThreadAttr_t defaultTask_attributes = { // 定义任务属性
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
void StartDefaultTask(void *argument); // 声明默认任务入口
void MX_FREERTOS_Init(void); // 初始化函数
void MX_FREERTOS_Init(void) {
  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes); // 创建任务
  }
void StartDefaultTask(void *argument){ // 定义默认任务
  LCD_Init();
  LCD_Clear();
  
  for(;;)
  {
  }
}

后续的程序开发,都会在这个模板上进行修改

1 基本概念

对于整个单片机程序,称其为程序(application)。我们可以在程序中创建多个任务(task)或称为线程(thread)
以一个同时要做喂饭和回信息两件事的人举例:

  1. 任务状态(State):
    ◼ 当前正在喂饭,它是 running 状态;另一个"回信息"的任务就是"not running"状态
    ◼ "not running"状态还可以细分:
    ◆ ready:就绪,随时可以运行
    ◆ blocked:阻塞,卡住了,母亲在等待同事回信息
    ◆ suspended:挂起,同事废话太多,不管他了
  2. 优先级(Priority)
    ◼ 我工作生活兼顾:喂饭、回信息优先级一样,轮流做
    ◼ 我忙里偷闲:还有空闲任务,休息一下
    ◼ 厨房着火了,什么都别说了,先灭火:优先级更高
  3. 栈(Stack)
    ◼ 喂小孩时,我要记得上一口喂了米饭,这口要喂青菜了
    ◼ 回信息时,我要记得刚才聊的是啥
    ◼ 做不同的任务,这些细节不一样,对于人来说,当然是记在脑子里,对于程序,是记在栈里。每个任务有自己的栈
  4. 事件驱动
    ◼ 孩子吃饭太慢:先休息一会,等他咽下去了、等他提醒我了,再喂下一口
  5. 协助式调度(Co-operative Scheduling)
    ◼ 你在给同事回信息
    ◆ 同事说:好了,你先去给小孩喂一口饭吧,你才能离开
    ◆ 同事不放你走,即使孩子哭了你也不能走
    ◼ 你好不容易可以给孩子喂饭了
    ◆ 孩子说:好了,妈妈你去处理一下工作吧,你才能离开
    ◆ 孩子不放你走,即使同事连发信息你也不能走

2 内存管理

2.1 栈

栈(stack):一个内存空间,CPU的SP寄存器指向它,可以用于函数调用、局部变量、多任务系统里面保存现场。
以下代码,用于理解栈。与FreeRTOS的使用无关

int g_cnt = 0;
void b_func(int a)
{
	a += 2;
	return a; 
}
void c_func(int a)
{
	a += 3;
	return a; 
}
void a_func(int a)
{
	g_cnt = b_func(a);
	g_cnt = c_func(g_cnt);
}
int main(void)
{
	int i = 99;
	a_func();
}

以上代码,main调用函数a,函数a先后调用函数b和c。调用其他函数的本质是使用BL汇编指令,实现

LR = 返回地址(下一条指令的地址)
PC = 函数地址。往PC寄存器存地址,就会跳过去执行那段代码

每次调用函数,都会执行一次BL,即LR和PC经过一次上述的变化,就有以下问题:

  1. LR是否被覆盖了,怎么会事呢?
  2. 局部变量在栈中分配,如何分配?
  3. 为何每个RTOS任务都有自己的栈?

解答:

  1. 编译器会在函数入口自动PUSH保存LR以及一些必要的寄存器 到里,从而避免上一个函数被覆盖。函数执行完后,栈区会被POP回收。
  2. 局部变量优先分配到寄存器中,空间不足了(或用volatile指定)再放栈里
  3. 切换任务时,会保存当前函数的现场,恢复目标函数的现场。保存线程时,将所有寄存器(除了SP)压到到当前函数对应的栈里,并且记录SP;恢复现场时,先找到SP,POP寄存器信息。各个任务使用各自的栈,方便内存管理和现场恢复。

2.2 堆

堆(heap):一块空闲的内存。可以从里面分配一块空间用作栈
malloc:从堆中画出一块空间给程序用。
free:释放他
在这里插入图片描述

2.3 FreeRTOS的内存管理方法

内存管理函数为pvPortMalloc, vPortFree,对应C中的malloc和free
源码中默认提供了5个文件,对应内存管理的5种方法

文件优点缺点
heap_1.c分配简单,时间确定只分配不回收
heap_2.c动态分配,最佳分配碎片,时间不定
heap_3.c调用标准库速度慢,时间不定
heap_4.c相邻空闲内存可合并可解决碎片问题,时间不定
heap_5.c在heap_4基础上支持分隔的内存块可解决碎片问题,时间不定

一般不用heap_3,heap_4和heap_5常用。heap_5可以通过链表沟通片内和片外RAM
以下列举了一些内存管理

void * pvPortMalloc(size_t xWantedSize); //分配内存,如果失败则返回NULL
void vPortFree(void * pv); //释放内存
size_t xPortGetFreeHeapSize(void); //返回空闲内存容量。heap3无法用
size_t xPortGetMinimumEverFreeHeapSize(void); //返回程序运行过程中空闲内存容量的最小值。只有heap4,5能用

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值