Этот простой планировщик задач на базе ARM Cortex-M SysTick работать не будет. Должен ли я сам управлять вытеснением? - PullRequest
0 голосов
/ 30 января 2020

Итак, я делаю очень простой шаблон, запускаемый по времени на основе ARM Cortex M3. Идея такова: когда SysTick обслуживается, индекс массива задач увеличивается на systick, как и указатель функции на задачу. Обработчик PendSV вызывается и вызывает задачу. Я использую Atmel ICE JTAG для его отладки. Что происходит, так это то, что он зависает при первом задании и даже не увеличивает счетчик. Это не go нигде. Кодовый шаблон:

#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);
}

1 Ответ

3 голосов
/ 30 января 2020

Боюсь, этот шаблон дизайна в корне ошибочен.

При первом событии SysTick task1() будет вызываться из обработчика PendSV , который, следовательно, не вернется , Дальнейшие события SysTick прервут обработчик PendSV и снова установят бит PendSV, но если запущенное задание не завершится и обработчику PendSV не будет разрешено вернуться, оно не может быть вызвано снова.

Хорошая новость заключается в том, что Правильное переключение контекста на M3 - это лишь небольшое количество ассемблера - возможно, 10 строк Вам также необходимо выполнить некоторую настройку, чтобы код пользовательского режима использовал указатель стека процессов и т. Д., И вам нужно настроить стек для каждой задачи, но на самом деле это еще не все.

Если вы если вы хотите отменить запущенную задачу, когда прибывает SysTick, и запустить другую, все они могут использовать один и тот же стек; но было бы намного проще, если бы это был стек процессов, чтобы его указатель стека мог быть сброшен изнутри PendSV, не влияя на возврат из режима обработчика. Вам также нужно будет сделать несколько стеков, чтобы убедить PendSV «вернуться» к началу следующей задачи, которую вы хотели запустить.

...