完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
freertos与STM32分析栈、堆、全局区、常量区、代码区、RAM、ROM,及如何分配堆栈空间
j结合资料: Code, RO-data,RW-data,ZI-data Code为程序代码部分 RO-data 表示 程序定义的常量const temp; RW-data 表示 已初始化的全局变量 ZI-data 表示 未初始化的全局变量 Program Size: Code=“18248” RO-data=320 RW-data=260 ZI-data=3952 Code, RO-data,RW-data …flash RW-data, ZIdata…RAM 猜测: #define configTOTAL_HEAP_SIZE ((size_t)(6*1024)) //系统所有总的堆大小 12480+1024=13504,只有ZI_Data改变了 #define configTOTAL_HEAP_SIZE ((size_t)(7*1024)) //系统所有总的堆大小 **-===========================================================** 13504+1024=14528,也只有ZI_Data改变了 FreeRTOS系统堆:设置为 8 1024* #define configTOTAL_HEAP_SIZE ((size_t)(8*1024)) //系统所有总的堆大小 系统堆栈: FreeRTOS系统堆:设置为 8 1024,不变* ZI_Data是不是就是上图的还未使用的heap空间,因为程序其他地方都没变,申请的堆再变大一个字节,也还是多余的,,, 当#define configTOTAL_HEAP_SIZE ((size_t)(8*1024)) //系统所有总的堆大小 系统堆栈,堆增加0x1000,其他增加一点点; 18624-14528=4096=0x1000,刚好增加这个数 任务栈空间设置: 为什么叫做系统所有堆的大小?不是叫堆栈或栈? 个人理解:这个系统堆指的是操作系统FreeRTOS使用的一段内存堆(在RAM中划过来的),每个任务有自己发任务堆栈,任务创建可以采用动态创建和静态创建,我使用的一般是动态创建任务的方式,如果静态创建,就和我们自己开辟的空间有关,通常静态创建任务用数组作为容器,但是通常静态创建的方式不使用,不管了。简称任务栈 系统栈空间设置: 系统栈空间, 任务栈不使用这里的栈空间,哪里使用这里的栈空间呢? 答案就在中断函数和中断嵌套。 由于 Cortex-M3 和 M4 内核具有双堆栈指针,MSP 主堆栈指针和 PSP 进程堆栈指针,或者叫 PSP任务堆栈指针也是可以的。在 FreeRTOS 操作系统中,主堆栈指针 MSP 是给系统栈空间使用的,进程堆栈指针 PSP 是给任务栈使用的。 也就是说,在 FreeRTOS 任务中,所有栈空间的使用都是通过PSP 指针进行指向的。 一旦进入了中断函数以及可能发生的中断嵌套都是用的 MSP 指针。 实际应用中系统栈空间分配多大,主要是看可能发生的中断嵌套层数,下面我们就按照最坏执行情况进行考虑,所有的寄存器都需要入栈,此时分为两种情况: 1:64 字节 对于 Cortex-M3 内核和未使用 FPU(浮点运算单元)功能的 Cortex-M4 内核在发生中断时需要将 16 个通用寄存器全部入栈,每个寄存器占用 4 个字节,也就是 16*4 = 64 字节的空间。可能发生几次中断嵌套就是要 64 乘以几即可。 当然,这种是最坏执行情况,也就是所有的寄存器都入栈。 (注:任务执行的过程中发生中断的话,有 8 个寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余寄存器入栈以及发生中断嵌套都是用的系统栈) 2:200 字节 对于具有 FPU(浮点运算单元)功能的 Cortex-M4 内核,如果在任务中进行了浮点运算,那么在发生中断的时候除了 16 个通用寄存器需要入栈,还有 34 个浮点寄存器也是要入栈的,也就是(16+34)*4 = 200 字节的空间。当然,这种是最坏执行情况,也就是所有的寄存器都入栈。(注:任务执行的过程中发送中断的话,有 8 个通用寄存器和 18 个浮点寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余通用寄存器和浮点寄存器入栈以及发生中断嵌套都是用的系统栈) 使用如下函数即可启动 FreeRTOS:vTaskStartScheduler(); 函数原型: void vTaskStartScheduler( void ); 函数描述: 函数 vTaskStartScheduler 用于启动 FreeRTOS 调度器,即启动 FreeRTOS 的多任务执行。 使用这个函数要注意以下几个问题: 空闲任务和可选的定时器任务是在调用这个函数后自动创建的。 正常情况下这个函数是不会返回的,运行到这里极有可能是用于定时器任务或者空闲任务的 heap 空间不足造成创建失败,此时需要加大 FreeRTOSConfig.h 文件中定义的 heap 大小: #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) 任务栈大小的确定 每个任务都需要自己的栈空间,应用不同,每个任务需要的栈大小不同的。 将如下的几个选项简单的累加就可以得到一个粗略的栈大小: 1, 函数的嵌套调用,针对每一级函数用到栈空间的有如下四项: 2,函数局部变量。 3,函数形参,一般情况下函数的形参是直接使用的 CPU 寄存器,不需要使用栈空间,但是这个函数中如果还嵌套了一个函数的话,这个存储了函数形参的 CPU 寄存器内容是要入栈的。 所以建议大家也把这部分算在栈大小中。 4, 函数返回地址,针对 M3 和 M4 内核的 MCU,一般函数的返回地址是专门保存到 LR(LinkRegister)寄存器里面的,如果这个函数里面还调用了一个函数的话,这个存储了函数返回地址的 LR 寄存器内容是要入栈的。 所以建议大家也把这部分算在栈大小中。 5, 函数内部的状态保存操作也需要额外的栈空间。 6, 任务切换,任务切换时所有的寄存器都需要入栈,对于带 FPU 浮点处理单元的 M4 内核 MCU 来说,FPU 寄存器也是需要入栈的。 7,针对 M3 内核和 M4 内核的 MCU 来说,在任务执行过程中,如果发生中断: M3 内核的 MCU 有 8 个寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余寄存器入栈以及发生中断嵌套都是用的系统栈。 M4 内核的 MCU 有 8 个通用寄存器和 18 个浮点寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余通用寄存器和浮点寄存器入栈以及发生中断嵌套都是用的系统栈。 8, 进入中断以后使用的局部变量以及可能发生的中断嵌套都是用的系统栈,这点要注意。 实际应用中将这些都加起来是一件非常麻烦的工作,上面这些栈空间加起来的总和只是栈的最小需求 实际分配的栈大小可以在最小栈需求的基础上乘以一个安全系数,一般取 1.5-2。上面的计算是我们用户可以确定的栈大小,项目应用中还存在无法确定的栈大小,比如调用printf函数就很难确定实际的栈消耗。又比如通过函数指针实现函数的间接调用,因为函数指针不是固定的指向一个函数进行调用,而是根据不同的程序设计可以指向不同的函数,使得栈大小的计算变得比较麻烦。 另外还要注意一点,建议不要编写递归代码,因为我们不知道递归的层数,栈的大小也是不好确定的。 一般来说,用户可以事先给任务分配一个大的栈空间,再采用的调试方法打印任务栈的 使用情况,运行一段时间就会有个大概的范围了,适当减小。这种方法比较简单且实用些。 函数栈大小确定 关于 MDK 生成的 map 和 htm 文件的使用,安富莱电子有出过一期视频教程,可以在这里查看: 看到其中一个人的结论: FreeRTOS中的堆栈,并没有占用系统启动文件中的堆栈空间大小。两者在空间分配上互不影响,需要单独设置。并且FreeRTOS有自己的内存申请函数pvPortMalloc()以及一系列的内存管理函数。 还有点不太明白,有FreeRTOS后,是不是stm32芯片的RAM=系统堆栈+FreeRTOS堆+其他?其中FreeRTOS堆里面创建任务划分了若干任务栈 要想正常成功并充分利用资源执行,任务栈和FreeRTOS堆空间要申请合适,创建任务的函数里面的值是以字为单位,需要乘以4变成字节,uxTaskGetStackHighWaterMark()返回值也是以字为单位 j结合资料: Code, RO-data,RW-data,ZI-data Code为程序代码部分 RO-data 表示 程序定义的常量const temp; RW-data 表示 已初始化的全局变量 ZI-data 表示 未初始化的全局变量 Program Size: Code=“18248” RO-data=320 RW-data=260 ZI-data=3952 Code, RO-data,RW-data …flash RW-data, ZIdata…RAM 猜测: #define configTOTAL_HEAP_SIZE ((size_t)(6*1024)) //系统所有总的堆大小 12480+1024=13504,只有ZI_Data改变了 #define configTOTAL_HEAP_SIZE ((size_t)(7*1024)) //系统所有总的堆大小 **-===========================================================** 13504+1024=14528,也只有ZI_Data改变了 FreeRTOS系统堆:设置为 8 1024* #define configTOTAL_HEAP_SIZE ((size_t)(8*1024)) //系统所有总的堆大小 系统堆栈: FreeRTOS系统堆:设置为 8 1024,不变* ZI_Data是不是就是上图的还未使用的heap空间,因为程序其他地方都没变,申请的堆再变大一个字节,也还是多余的,,, 当#define configTOTAL_HEAP_SIZE ((size_t)(8*1024)) //系统所有总的堆大小 系统堆栈,堆增加0x1000,其他增加一点点; 18624-14528=4096=0x1000,刚好增加这个数 任务栈空间设置: 为什么叫做系统所有堆的大小?不是叫堆栈或栈? 个人理解:这个系统堆指的是操作系统FreeRTOS使用的一段内存堆(在RAM中划过来的),每个任务有自己发任务堆栈,任务创建可以采用动态创建和静态创建,我使用的一般是动态创建任务的方式,如果静态创建,就和我们自己开辟的空间有关,通常静态创建任务用数组作为容器,但是通常静态创建的方式不使用,不管了。简称任务栈 系统栈空间设置: 系统栈空间, 任务栈不使用这里的栈空间,哪里使用这里的栈空间呢? 答案就在中断函数和中断嵌套。 由于 Cortex-M3 和 M4 内核具有双堆栈指针,MSP 主堆栈指针和 PSP 进程堆栈指针,或者叫 PSP 任务堆栈指针也是可以的。在 FreeRTOS 操作系统中,主堆栈指针 MSP 是给系统栈空间使用的,进 程堆栈指针 PSP 是给任务栈使用的。 也就是说,在 FreeRTOS 任务中,所有栈空间的使用都是通过 PSP 指针进行指向的。 一旦进入了中断函数以及可能发生的中断嵌套都是用的 MSP 指针。 实际应用中系统栈空间分配多大,主要是看可能发生的中断嵌套层数,下面我们就按照最坏执行情况 进行考虑,所有的寄存器都需要入栈,此时分为两种情况: 1:64 字节 对于 Cortex-M3 内核和未使用 FPU(浮点运算单元)功能的 Cortex-M4 内核在发生中断时需 要将 16 个通用寄存器全部入栈,每个寄存器占用 4 个字节,也就是 16*4 = 64 字节的空间。 可能发生几次中断嵌套就是要 64 乘以几即可。 当然,这种是最坏执行情况,也就是所有的寄存 器都入栈。 (注:任务执行的过程中发生中断的话,有 8 个寄存器是自动入栈的,这个栈是任务栈,进入中 断以后其余寄存器入栈以及发生中断嵌套都是用的系统栈) 2:200 字节 对于具有 FPU(浮点运算单元)功能的 Cortex-M4 内核,如果在任务中进行了浮点运算,那么 在发生中断的时候除了 16 个通用寄存器需要入栈,还有 34 个浮点寄存器也是要入栈的,也就是 (16+34)*4 = 200 字节的空间。当然,这种是最坏执行情况,也就是所有的寄存器都入栈。 (注:任务执行的过程中发送中断的话,有 8 个通用寄存器和 18 个浮点寄存器是自动入栈的, 这个栈是任务栈,进入中断以后其余通用寄存器和浮点寄存器入栈以及发生中断嵌套都是用的系 统栈) 使用如下函数即可启动 FreeRTOS: vTaskStartScheduler(); 函数原型: void vTaskStartScheduler( void ); 函数描述: 函数 vTaskStartScheduler 用于启动 FreeRTOS 调度器,即启动 FreeRTOS 的多任务执行。 使用这个函数要注意以下几个问题: 空闲任务和可选的定时器任务是在调用这个函数后自动创建的。 正常情况下这个函数是不会返回的,运行到这里极有可能是用于定时器任务或者空闲任务的 heap 空 间不足造成创建失败,此时需要加大 FreeRTOSConfig.h 文件中定义的 heap 大小: #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) 任务栈大小的确定 每个任务都需要自己的栈空间,应用不同,每个任务需要的栈大小不同的。 将如下的几个选项简单的累加就可以得到一个粗略的栈大小: 1, 函数的嵌套调用,针对每一级函数用到栈空间的有如下四项: 2,函数局部变量。 3,函数形参,一般情况下函数的形参是直接使用的 CPU 寄存器,不需要使用栈空间,但是这个函数中如果还嵌套了一个函数的话,这个存储了函数形参的 CPU 寄存器内容是要入栈的。 所以建议大家也把这部分算在栈大小中。 4, 函数返回地址,针对 M3 和 M4 内核的 MCU,一般函数的返回地址是专门保存到 LR(LinkRegister)寄存器里面的,如果这个函数里面还调用了一个函数的话,这个存储了函数返回地址的 LR 寄存器内容是要入栈的。 所以建议大家也把这部分算在栈大小中。 5, 函数内部的状态保存操作也需要额外的栈空间。 6, 任务切换,任务切换时所有的寄存器都需要入栈,对于带 FPU 浮点处理单元的 M4 内核 MCU 来说,FPU 寄存器也是需要入栈的。 7,针对 M3 内核和 M4 内核的 MCU 来说,在任务执行过程中,如果发生中断: M3 内核的 MCU 有 8 个寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余寄存器入栈以及发生中断嵌套都是用的系统栈。 M4 内核的 MCU 有 8 个通用寄存器和 18 个浮点寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余通用寄存器和浮点寄存器入栈以及发生中断嵌套都是用的系统栈。 8, 进入中断以后使用的局部变量以及可能发生的中断嵌套都是用的系统栈,这点要注意。 实际应用中将这些都加起来是一件非常麻烦的工作,上面这些栈空间加起来的总和只是栈的最小需求 实际分配的栈大小可以在最小栈需求的基础上乘以一个安全系数,一般取 1.5-2。上面的计算是我们用户可以确定的栈大小,项目应用中还存在无法确定的栈大小,比如调用printf函数就很难确定实际的栈消耗。又比如通过函数指针实现函数的间接调用,因为函数指针不是固定的指向一个函数进行调用,而是根据不同的程序设计可以指向不同的函数,使得栈大小的计算变得比较麻烦。 另外还要注意一点,建议不要编写递归代码,因为我们不知道递归的层数,栈的大小也是不好确定的。 一般来说,用户可以事先给任务分配一个大的栈空间,再采用的调试方法打印任务栈的 使用情况,运行一段时间就会有个大概的范围了,适当减小。这种方法比较简单且实用些。 函数栈大小确定 看到其中一个人的结论: FreeRTOS中的堆栈,并没有占用系统启动文件中的堆栈空间大小。两者在空间分配上互不影响,需要单独设置。并且FreeRTOS有自己的内存申请函数pvPortMalloc()以及一系列的内存管理函数。 还有点不太明白,有FreeRTOS后,是不是stm32芯片的RAM=系统堆栈+FreeRTOS堆+其他?其中FreeRTOS堆里面创建任务划分了若干任务栈 要想正常成功并充分利用资源执行,任务栈和FreeRTOS堆空间要申请合适,创建任务的函数里面的值是以字为单位,需要乘以4变成字节,uxTaskGetStackHighWaterMark()返回值也是以字为单位。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1570 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1515 浏览 1 评论
943 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
669 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1562 浏览 2 评论
1851浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
620浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
506浏览 3评论
511浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
492浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 12:09 , Processed in 0.508794 second(s), Total 43, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号