简体   繁体   English

抢占式调度算法

[英]Preemptive Scheduling Algorithm

Here is a small preemptive scheduling algorithm for MSP430G2553 Launchpad from @tonyp12 from https://forum.43oh.com/topic/9450-tiny-msp430-preemptive-multitasking-system/ 这是来自https://forum.43oh.com/topic/9450-tiny-msp430-preemptive-multitasking-system/的 @ tonyp12的MSP430G2553 Launchpad的小型抢占式调度算法

Even though I know the concept of contet switching, this program confuses me a little bit. 即使我知道竞争切换的概念,该程序也让我有些困惑。 Can someone explain what he is doing step by step specifically in the below snippets? 有人可以在下面的代码段中逐步解释他在做什么吗?

int* multistack = (int*) __get_SP_register();
  int i=0; while(i<tasks-1){
    int j = stacksize[i]; if (!j) j = 24;
    multistack -= j;  
    *(multistack) = (int) taskpnt[++i];         // prefill in PC 
    *(multistack-1) = GIE;                      // prefill in SR
    taskstackpnt[i] = (int) multistack-26;      // needs 12 dummy push words
  } 

and

#pragma vector = WDT_VECTOR 
__raw __interrupt void taskswitcher(void)
{
  asm ("push R15\n push R14\n push R13\n push R12\n"
       "push R11\n push R10\n push R9\n push R8\n"
       "push R7\n push R6\n push R5\n push R4");

  taskstackpnt[taskrun] = __get_SP_register();
  if (++taskrun == tasks) taskrun = 0;
  __set_SP_register(taskstackpnt[taskrun]);
  
  asm ("pop R4\n pop R5\n pop R6\n pop R7\n"
       "pop R8\n pop R9\n pop R10\n pop R11\n"
       "pop R12\n pop R13\n pop R14\n pop R15");
}

Thanks. 谢谢。 And here is the complete code: 这是完整的代码:

#include "msp430.h"
#include "common.h"

//=========================(C) Tony Philipsson 2016 =======================
funcpnt const taskpnt[]={ task1, task2, task3,  // <- PUT YOUR TASKS HERE
}; 
const int stacksize[tasks] = {28};              // a blank value defaults to 24 stack words
//=========================================================================
int taskstackpnt[tasks];
unsigned int taskdelay[tasks];
char taskrun;

int main( void )
{
  WDTCTL = WDTPW + WDTHOLD;                     // Stop watchdog timer 
  if (CALBC1_8MHZ != 0xff){               // erased by mistake?
    BCSCTL1 = CALBC1_8MHZ;                   // Set DCO to factory calibrate 1MHz  
    DCOCTL = CALDCO_8MHZ;
  } 
  int* multistack = (int*) __get_SP_register();
  int i=0; while(i<tasks-1){
    int j = stacksize[i]; if (!j) j = 24;
    multistack -= j;  
    *(multistack) = (int) taskpnt[++i];         // prefill in PC 
    *(multistack-1) = GIE;                      // prefill in SR
    taskstackpnt[i] = (int) multistack-26;      // needs 12 dummy push words
  }
  WDTCTL = WDTPW+WDTTMSEL+WDTCNTCL;             // 4ms interval at 8MHz smclk
  IE1 |= WDTIE;
  __bis_SR_register(GIE);
  asm ("br &taskpnt");                          // indirect jmp to first task
}

//============= TASK SWITCHER ISR =============
#pragma vector = WDT_VECTOR 
__raw __interrupt void taskswitcher(void)
{
  asm ("push R15\n push R14\n push R13\n push R12\n"
       "push R11\n push R10\n push R9\n push R8\n"
       "push R7\n push R6\n push R5\n push R4");

  taskstackpnt[taskrun] = __get_SP_register();
  if (++taskrun == tasks) taskrun = 0;
  __set_SP_register(taskstackpnt[taskrun]);

  asm ("pop R4\n pop R5\n pop R6\n pop R7\n"
       "pop R8\n pop R9\n pop R10\n pop R11\n"
       "pop R12\n pop R13\n pop R14\n pop R15");
} 
#include "msp430.h"
#include "common.h"

__task void task1(void){
  P1DIR |= BIT0;
  while(1){
    __delay_cycles(800000);
    P1OUT |= BIT0;
    __delay_cycles(800000);
    P1OUT &=~BIT0;        
  }
}
#include "msp430.h"
#include "common.h"

__task void task2(void){
  P1DIR |= BIT6;
  while(1){
    __delay_cycles(1200000);
    P1OUT |= BIT6;
    __delay_cycles(1200000);
    P1OUT &=~BIT6;        
  }
}
#include "msp430.h"
#include "common.h"
unsigned int fibo(int);

__task void task3(void){
  int temp = 0;
  while(1){
    fibo(++temp);
  }
}
unsigned int fibo(int n){
  if (n < 2)
    return n;
  else
    return (fibo(n-1) + fibo(n-2));
}
#ifndef COMMON_H_
#define COMMON_H_
#define  tasks (sizeof(taskpnt)/2)
__task void task1(void);
__task void task2(void);
__task void task3(void);
typedef __task void (*funcpnt)(void);
#endif

The first snipped of code initialize all the stacks for the various tasks. 代码的第一个片段初始化了各种任务的所有堆栈。

First saving the PC as the address of the task function (the first instruction): 首先将PC保存为任务功能的地址(第一条指令):

*(multistack) = (int) taskpnt[++i]; 

then it saves the status register with the GIE enabled (needed for correct task switch function): 然后在启用GIE的情况下保存状态寄存器(需要正确的任务切换功能):

*(multistack-1) = GIE;   

These two will be restored automatically by reti when the scheduler interrupt will end. 当调度程序中断结束时,这两个将由reti自动恢复。

Also the new stackpointer for the task is saved (including space for registries saving): 此外,还将保存任务的新堆栈指针(包括用于保存注册表的空间):

taskstackpnt[i] = (int) multistack-26;

The second snippet is the scheduler interrupt itself. 第二个片段是调度程序中断本身。

The PC and the SR are saved by hardware during interrupt calling automagically. 在中断自动调用期间,PC和SR由硬件保存。 In the interrupt code the registry are saved for current task: 在中断代码中,注册表被保存用于当前任务:

asm ("push R15\n push R14\n push R13\n push R12\n"
   "push R11\n push R10\n push R9\n push R8\n"
   "push R7\n push R6\n push R5\n push R4");

then the software saves the stack pointer for the current task: 然后软件将保存当前任务的堆栈指针:

taskstackpnt[taskrun] = __get_SP_register();

and get the next task stack pointer index: 并获取下一个任务堆栈指针索引:

if (++taskrun == tasks) taskrun = 0;

then restore the new task stack pointer: 然后恢复新的任务堆栈指针:

__set_SP_register(taskstackpnt[taskrun]);

and pop the registries saved in stack: 并弹出保存在堆栈中的注册表:

 asm ("pop R4\n pop R5\n pop R6\n pop R7\n"
   "pop R8\n pop R9\n pop R10\n pop R11\n"
   "pop R12\n pop R13\n pop R14\n pop R15");

The PC and SR for the new task are restored by interrupt's reti. 用于新任务的PC和SR通过中断的退出恢复。

The new task is ready to go! 新任务已准备就绪!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM