Еще вопросы.
Значит, написал вот такой код:
main.c:Код
#define TASK_STK_SIZE 2048
uint32_t task1_stk[TASK_STK_SIZE];
void task1(void* x)
{
while(1)
{
led_toggle(led);
//printf("@ task1\n");
}
}
int main(void)
{
configure_clocks();
led = led_create(GPIOE, 6);
os_add_task("task1", task1, (void*) 0x555, task1_stk, TASK_STK_SIZE);
os_start();
while(1);
}
scheduler.c:Код
typedef struct task_descriptor
{
uint32_t* stk_ptr;
uint16_t stk_size;
task_handler handler;
void* args;
task_state state;
char* name;
} task_descriptor;
static uint8_t tasks_used = 0;
static task_descriptor* tasks[MAX_TASKS];
__asm void _run_process(uint32_t* stk_ptr)
{
LDR R4, [R0, #(4*14)]
ADD R0, R0, #(4*16)
MSR PSP, R0
MOV R0, #2
MSR CONTROL, R0
CPSIE I
BX R4
}
void os_add_task(char* name, task_handler task, void *args, uint32_t* stk_ptr, uint32_t stk_size)
{
tasks[tasks_used]->name = name;
tasks[tasks_used]->handler = task;
tasks[tasks_used]->args = args;
tasks[tasks_used]->stk_size = stk_size;
tasks[tasks_used]->state = RUN;
tasks[tasks_used]->stk_ptr = (uint32_t*) ((uintptr_t) stk_ptr & 0xFFFFFFF8);
*(--tasks[tasks_used]->stk_ptr) = 0x01000000L;
*(--tasks[tasks_used]->stk_ptr) = (uint32_t)(task);
tasks[tasks_used]->stk_ptr -= 14;
//init_stack(task, &stk_ptr[stk_size-1]);
if(tasks_used < MAX_TASKS) tasks_used++;
printf("# created task: %s\n", name);
}
void os_start(void)
{
printf("# starting OS...\n");
_run_process(tasks[0]->stk_ptr);
}
Инициализацию стека задачи и ассемблерный код пока взял из scmrtos (спасибо за наводку!).
Мои вопросы вот в чем:
1. Правильно ли я понимаю: стек задачи - это просто область памяти (в моем случае task1_stk), конец которой заполняется таким образом, чтобы получить в ней значения регистров процессора как при переключении контекста (среди прочего там сидит и указатель на задачу). А далее асмовым (как правило) кодом из этого куска памяти значения тупо переписываются в регистры, после чего все как бы указывает на нужную нам задачу.
2. Приведенный выше код вроде как работает - в задачу task1 входит и крутится в ней. Но если раскомментировать printf в задаче task1, то проц уходит в MemFault (MemManage_Handler) сразу же в самой первой команде printf'а (судя по дизассемблеру). Почему так?
3. Не очень понятна запись
tasks[tasks_used]->stk_ptr = (uint32_t*) ((uintptr_t) stk_ptr & 0xFFFFFFF8);. Для чего нужно выравнивание по 8 байтам?