• 嵌入式FreeRTOS学习六,FreeRTOS中CPU寄存器与RAM内存和Flash之间的数据传输,以及栈空间的作用


    一.经典的单片机程序和RTOS任务机制的区别

    1. //经典的单片机程序
    2. void main()
    3. {
    4. while(1)
    5. {
    6. 喂一口饭();
    7. 回复一个信息();
    8. }
    9. }

    单片机程序任务

    1. //RTOS程序
    2. 喂饭()
    3. {
    4. while(1)
    5. {
    6. 喂一口饭();
    7. }
    8. }
    9. 回复信息()
    10. {
    11. while(1)
    12. {
    13. 回复一个信息();
    14. }
    15. }
    16. void main()
    17. {
    18. creste_task(喂饭);
    19. creste_task(回信息);
    20. star_scheduler();
    21. while(1)
    22. {
    23. sleep();
    24. }
    25. }

    RTOS程序任务

    ========================================================================= 

    二.什么叫任务?

    任务就是运行起来的函数,没有运行的任务就是一份程序文件,保存在flssh中;任务构成要素有三个,第一是运行的代码,第二是代码运行的位置,第三是代码运行的环境,比如运行过程中需要系统保存的各种局部变量等,我们称之为运行环境。

    三.那么怎么暂停/恢复任务?

    第一是记住函数运行的位置;
    第二是任务暂停时刻变量的值不能被破坏;
    第三是其它一些东西

    如果任务只是一份代码,我们根本不需要保存它,因为代码保存在flash中,任务暂停/恢复等根本不会破坏flash中的代码。

    =========================================================================

    什么是函数运行环境?以下面的函数为例:

    1. void add_val(int *pa,int *pb)
    2. {
    3. volatile int tmp;
    4. tmp = *pa;
    5. tmp = tmp +*pb;
    6. *pa = tmp;
    7. }
    8. int main(void)
    9. {
    10. int a =1;
    11. int b =2;
    12. add_value(&a,&b);
    13. prvSetupHardware();
    14. xTaskCreate(vTask1,"Task1",1000,NULL,0,NULL);
    15. xTaskCreate(vTask1,"Task1",1000,NULL,0,NULL);
    16. xTaskCreate(vTask1,"Task1",1000,NULL,0,NULL);
    17. /*启动调度器*/
    18. vTaskStartScheduler();
    19. }

    四.认识ARM架构STM32F407

    要深入了解FreeRTOS操作系统,就要有汇编知识的基础和ARM架构的基础,补充ARM架构知识,以STM32F103芯片为例。

       STM32F103又被称之为SOC:systom on chip;

    1.SOC里有内存,有flash,还有UATR等各种模块,程序运行的时候,代码存储在flash中, 用J-link,ST-link专用烧写工具烧写,这样代码不会被轻易破坏,CPU从flash中读取指令进行执行,flash 能很好地保存程序的完整性。

    2.CPU和内存的关系,CPU可以把数据写进去,也可以把数据读出来,例如执行a=a+b这个运算关系时,会进行下面操作:

    •  把RAM内存中的数据a读取出来;
    •  把RAM内存中的数据b读取出来;
    • 在CPU中有计算单元,在里面执行a+b的计算操作;
    • 计算出来的结果写入到a的位置

    那么从内存中把a,b的值读出来,读到CPU里面的什么地方保存呢? 怎么从ARM 中读取数据值呢?这些需要我们对CPU的结构有一定的了解,以下是CPU的内部结构。

    CPU 里面有很多的寄存器组,用于保存从ARM中读取进来的值。此外 CPU 内还有一块 ROM,固化了一段启动代码,作用就是读取配置字节或 GPIO 状态确定启动哪些外设、搜索可用于启动的设备、从外设读出数据放到内存做第 1 阶段的引导。所以从ARM里面读取数据的流程为:

    1. 读flah,得到flah里面的指令代码;
    2. 执行指令,即上述的读ARM内存的过程;

    =========================================================================

    五.简单的汇编指令 

    深入了解RTOS操作系统的工作机制,必须知道任务中变量的赋值,变化,保存的机制,这就必须对寄存器和汇编语言有一定的了解掌握。

    上述的加法代码示例中涉及到的汇编指令有汇编加指令ADD,汇编读指令LDR,汇编写指令STR;
    从flash中读取代码后,就对ARM内存进行相应的读,写操作;LDR   RO  [addrA]为从addrA地址读取数据保存到R0寄存器中;addrA为源地址,RO为目标地址。

    CPU内部,有 R0,R1,R2,...,R13,R14,R15为CPU内部的寄存器组,其中R13别名SP,为CPU里的栈;R14别名LR,为返回地址;R13别名PC,为当前指令的返回地址;PUSH指令为入栈和POP指令为出栈。

    PUSH { R3,LR }写入内存,将寄存器的值写入到SP指定位置的RAM内存中 的位置上去;
    POP { R3,PC }读出内存,将SP指定位置的RAM内存上的值读到寄存器上去,注意,高位寄存器对应的地址为高地址,低位寄存器对应的地址为低地址;

    下面是加法程序转变的汇编程序代码

     PUSH { R3,LR },将高位寄存器LR放入SP指向的地址中,同时SP指针向下移动 4个字节,SP=SP-4,再将低位寄存器R3放入,SP=SP-4。

    POP { R3,PC }读出RAM内存中的值赋值给寄存器,将SP指向位置的值取出赋值给低位寄存器R3,同时指针往上移动四个字节,SP=SP+4,将视频指向位置的值赋值给高位寄存器PC

     汇编代码大致的处理过程如下:

    注意:

    1.第一个参数通常保存在R0中,第二个参数通常保存在R1中,依此类推;

    2.PUSH { R3,LR },将R3,LR寄存器入栈;LR等于下一条指令的地址

    3. LDR r2,[r0,#0x00]         等价于r2= r0+0=a=1

       STR r2,[sp,#0x00]         等价于tmp = sp=r2=a=1,因为SP指向的就是R3的地址,局部变量保存在栈中,SP指向的地址也就是局部变量的地址;这两句话的意思为去&a 的地址上读取数据,保存在r2里面,再将r2的值放入临时变量tmp中;

    4.CPU计算流程

     LDR  r2,[r1,0x00]          等价于r2= r1+0=b=2

      LDR   r3,[sp,0x00]         等价于r3= sp+0=tmp=1

      ADD  r2, r2, r3               等价于r2= r2+r3=2+1= 1    

      STR  r2, [sp,0x00]         等价于tmp=sp+0=r2=3

      LDR r2 [sp,0x00]           等价于r2= sp+0=tmp

      STR r2 [r0,ox00]           等价于r2= sp+0=a

    5.出栈的过程

    POP{r3,pc},这个过程就是读内存,然后把sp指向位置的值赋值给r3,pc 
    r3 = [ sp ],sp = sp +4
    pc = [sp ],sp = sp +4

    =========================================================================

    这就是加法函数在CPU寄存器和RAM内存中的执行过程,实现了a=a+b的功能,接下来我们可以假设函数在执行a=a+b的过程中发生了中断,中断任务结束后回到断点继续执行中断前的那个任务,那么freertos是怎么保存中断前的数据的呢?具体保存什么数据?保存在哪里?

  • 相关阅读:
    jdbc 数据源(DruidDataSourceFactory)连接池 —— druid
    docker-compose Wordpress遇到的很多问题
    触控笔哪个牌子好用?主动电容笔和被动电容笔的区别
    【无标题】
    《动手学深度学习 Pytorch版》 8.7 通过时间反向传播
    通俗易懂生成对抗网络GAN原理
    六、回归与聚类算法 - K-means算法
    第五章《类的继承》第4节:属性的屏蔽
    Groovy安装开发环境
    手把手带你体验一场属于Linux的学习之旅
  • 原文地址:https://blog.csdn.net/weixin_44651073/article/details/127611557