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

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

//经典的单片机程序
void main()
{
 while(1)
  {
    喂一口饭();
    回复一个信息();
  }
}

单片机程序任务

//RTOS程序
喂饭()
{
    while(1)
      {
       喂一口饭();
      }
}

回复信息()
{
    while(1)
      {
       回复一个信息();
      }
}
void main()
{
  creste_task(喂饭);
  creste_task(回信息);
  star_scheduler();
      while(1)
      {
             sleep();
      }
}

RTOS程序任务

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

二.什么叫任务?

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

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

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

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

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

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

void add_val(int *pa,int *pb)
{  
   volatile int tmp;
   tmp = *pa;
   tmp = tmp +*pb;
   *pa = tmp;
}
int main(void)
{
  int a =1;
  int b =2;
  add_value(&a,&b);
  prvSetupHardware();

  xTaskCreate(vTask1,"Task1",1000,NULL,0,NULL);
  xTaskCreate(vTask1,"Task1",1000,NULL,0,NULL);
  xTaskCreate(vTask1,"Task1",1000,NULL,0,NULL);
  
  /*启动调度器*/
  vTaskStartScheduler();
}

四.认识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是怎么保存中断前的数据的呢?具体保存什么数据?保存在哪里?

猜你喜欢

转载自blog.csdn.net/weixin_44651073/article/details/127611557