王超的小站
认证:VIP会员
所在专题目录 查看专题
FreeRTOS移植详解2-滴答定时器实现(基于Microchip dsPIC33C系列芯片)
FreeRTOS移植详解3-内核裁剪(基于Microchip dsPIC33C系列芯片)
FreeRTOS移植详解4-中断配置(基于Microchip dsPIC33C系列芯片)
FreeRTOS移植详解5-临界段处理(基于Microchip dsPIC33C系列芯片)
FreeRTOS移植详解6-任务堆栈初始化和启动(基于Microchip dsPIC33C系列芯片)
FreeRTOS移植详解7-任务切换(基于Microchip dsPIC33C系列芯片)
作者动态 更多
PIC24 & dsPIC33 MCU Bootloader开发
2021-11-08 15:12
PIC16 & PIC18 MCU Bootloader开发
2021-11-08 15:00
Python开发环境搭建(for Bootloader)
2021-11-08 14:58
Python开发环境搭建 (for Control)
2021-01-27 18:43
MCU扩展CAN/CAN FD接口方案-MCU软件动手实验
2020-11-25 14:11

FreeRTOS移植详解6-任务堆栈初始化和启动(基于Microchip dsPIC33C系列芯片)

      在例程中我选择动态内存分配方式,configSUPPORT_DYNAMIC_ALLOCATION为1,相较静态内存分配方式使用更简单,但不好的地方就是用户不能明确分配各个任务内存。在动态内存分配方式,FreeRTOS首先需要有一个分配好的RAM空间——堆。堆的大小通过configTOTAL_HEAP_SIZE来指定。在例程中分配的是1024个字,也就是2048字节。实际项目中可以在调试阶段借助xPortGetFreeHeapSize()函数来判断堆的剩余空间,以便合理定义堆的大小。

      在动态分配方式下,当用户调用xTaskCreate()进行任务创建的时候,将自动在堆中分配任务堆栈和任务控制块,任务堆栈的大小在创建任务时由实参进行指定。同时,如队列、互斥信号量和计数型信号量等在创建后也需从堆中分配空间,堆的示意如下图。

      在任务创建过程中,经pxPortInitialiseStack()函数完成堆栈初始化后的任务堆栈情况如下图,这张图也是任务切换时压栈和出栈所操作的内容,务必清晰。

      堆栈初始化之后,我们看一下如何启动第一个任务,分析前必须了解如下基础知识。

1)程序指针PC(Program Counter):

      dsPIC33的PC为24位可寻址4M× 24位的程序空间,这个空间均等地划分为用户程序空间(0x000000~0x7FFFFF)和配置(或测试)存储空间(0x800000~0xFFFFFF)。因此用户可以仅用PC<22:0>即可访问任何用户程序空间。

      注意:堆栈初始化图中可以看到将任务函数的地址赋值给PC<15:0>,而PC<22:16>始终为0。这是因为dsPIC33系列MCU是16位的,虽然16位地址可以访问所有数据空间,但不能访问4M× 24位的程序空间,只能访问64K× 24位的程序空间。因此这里要提出跳转表的概念,当任务函数分配到大于64K× 24位的程序空间时编译器会链接出一个.handle的段,这个段中会定义一条GOTO指令,GOTO到实际的任务函数地址。所以才有堆栈初始化中PC<22:16>始终为0,而PC<15:0> = pxTaskCode的情况,因为若函数分配到了大于64K× 24位的程序空间,则pxTaskCode被链接为.handle段跳转表中的1条GOTO指令,借助该指令跳转到任务函数。

2)堆栈指针:

      dsPIC33堆栈指针就是W15,大家清晰即可。

3)汇编指令:

      为了真正的理解堆栈初始化及后续的任务切换过程,需要了解掌握如下的基本汇编语法。

      同时xTaskCreate()进行任务创建的时候还干了一件事,就是通过调用函数prvAddNewTaskToReadyList() 将新建任务添加到就绪列表中,并且会找到这些新建任务中优先级最高的任务。这些任务创建后,任务调度器将通过xPortStartScheduler() 启动第一个任务,函数如下。

      其中关键的portRESTORE_CONTEXT()的内容如下。首先看第一条指令,将所有任务中优先级最高任务的任务控制块TCB的第一个成员pxTopOfStack赋值给堆栈指针W15,接下来就比较简单,按照堆栈初始化的内容依次进行出栈,一直到SR寄存器出栈。

      回过头我们继续看一下xPortStartScheduler(),其在执行完portRESTORE_CONTEXT() 后调用了一条汇编return指令,这个return指令的结果便是将启动的第一个任务的任务函数pxTaskCode的地址赋值给PC指针,之后根据任务函数pxTaskCode在flash中的存储位置,采用直接运行任务函数或通过跳转表GOTO间接运行任务函数。至此FreeRTOS的任务顺利完成了启动工作。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 6
收藏 3
关注 40
成为作者 赚取收益
全部留言
0/200
  • 电子芯 2021-06-09 13:37
    比论文强一万倍
    回复
  • 星球居民-KFeNpETp 2020-11-12 08:55
    good
    回复