这个简单的基于 ARM Cortex-M SysTick 的任务调度程序将无法工作。我应该自己管理抢占吗?

This simple ARM Cortex-M SysTick based task scheduler wont work. Should I manage preemption myself?

所以,我正在做一个基于 ARM Cortex M3 的非常简单的时间触发模式。 这个想法 is:when SysTick 得到服务,任务数组索引在 systick 处递增,指向任务的函数指针也是如此。 PendSV 处理程序被调用,并调用任务。我正在使用 Atmel ICE JTAG 对其进行调试。 发生的事情是它停留在第一个任务上,甚至没有增加计数器。它不会去任何地方。 代码模式:

#include <asf.h> // atmel software framework. cmsis and board support package.

#define NTASKS 3

typedef void (*TaskFunction)(void);
void task1(void);
void task2(void);
void task3(void);

TaskFunction run = NULL;

uint32_t count1 = 0; //counter for task1
uint32_t count2 = 0; // 2
uint32_t count3 = 0; // 3

TaskFunction tasks[NTASKS] = {task1, task2, task3};
volatile uint8_t tasknum = 0;

void task1(void)
{
    while(1)
    {
        count1++;
    }
}

void task2(void)
{
    while(1)
    {
        count2++;
    }
}

void task3(void)
{
    while(1)
    {
        count3++;
    }
}

void SysTick_Handler(void)
{
    tasknum = (tasknum == NTASKS-1) ? 0 : tasknum+1;
    run = tasks[tasknum];
    SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}

void PendSV_Handler(void)
{
    run();
}


int main(void)
{
    sysclk_init();
    board_init();
    pmc_enable_all_periph_clk();
    SysTick_Config(1000);
    while(1);
}

恐怕这种设计模式存在根本性缺陷。

在第一个 SysTick 事件中,task1() 将从 PendSV 处理程序 中调用 ,因此不会 return。进一步的 SysTick 事件将中断 PendSV 处理程序并再次设置 PendSV 位,但除非 运行ning 任务结束并且 PendSV 处理程序被允许 return 它不可能再次被调用。

好消息是 M3 上的适当上下文切换只需要少量的汇编语言——大概 10 行。您还需要进行一些设置,让用户模式代码使用进程堆栈指针等,并且您需要为每个任务设置一个堆栈,但这并不是全部。

如果您真的想在 SysTick 到达时取消 运行ning 任务并启动另一个,它们可以共享同一个堆栈;但如果这是进程堆栈,那么它的堆栈指针可以从 PendSV 中重置而不影响来自处理程序模式的 return 会容易得多。您还需要进行一些堆栈检查以说服 PendSV 'return' 开始您想要 运行.

的下一个任务