diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..a7efaa1 --- /dev/null +++ b/run.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# @file run.sh +# Starts openocd and connects gdb to the target, for programming/debugging +# +# Copyright (C) 2018 Clyne Sullivan +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +openocd -f /usr/share/openocd/scripts/board/st_nucleo_l476rg.cfg & +sleep 1 +gdb-multiarch -ex "target remote localhost:3333" main.elf +pkill openocd diff --git a/src/kernel/clock.c b/src/kernel/clock.c index 44b7722..5bfc93a 100644 --- a/src/kernel/clock.c +++ b/src/kernel/clock.c @@ -19,6 +19,7 @@ */ #include "clock.h" +#include "task.h" #include // ticks since init @@ -26,9 +27,16 @@ volatile uint32_t ticks = 0; volatile uint8_t tim2_finished = 1; +extern task_t *current; + void clock_svc(uint32_t *args) { - udelay(args[0]); + if (args[0] == 0) { + current->sleep = ticks + args[1]; + SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; + } else if (args[0] == 1) { + udelay(args[1]); + } } void clock_init(void) @@ -71,6 +79,11 @@ void clock_init(void) TIM2->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN; } +uint32_t millis(void) +{ + return ticks; +} + void delay(uint32_t count) { uint32_t target = ticks + count; diff --git a/src/kernel/clock.h b/src/kernel/clock.h index c3554f6..3ec7857 100644 --- a/src/kernel/clock.h +++ b/src/kernel/clock.h @@ -28,6 +28,8 @@ */ extern void clock_init(void); +uint32_t millis(void); + /** * Sleeps for given amount of milliseconds. * @param ms Number of milliseconds to sleep for diff --git a/src/kernel/init.c b/src/kernel/init.c index e4ac115..ca60c3e 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -27,6 +27,7 @@ extern uint8_t __bss_end__; extern void user_main(void); +void init_idle(void); int main(void) { @@ -46,7 +47,14 @@ int main(void) // enable FPU //SCB->CPACR |= (0xF << 20); - task_init(user_main); + task_init(init_idle, 512); while (1); } +void init_idle(void) +{ + task_start(user_main, 4096); + + while (1) + delay(100); +} diff --git a/src/kernel/task.c b/src/kernel/task.c index 1a1c16b..19fa5ea 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -18,8 +18,9 @@ * along with this program. If not, see . */ -#include "task.h" +#include "clock.h" #include "heap.h" +#include "task.h" #include task_t *current, *prev; @@ -71,7 +72,7 @@ void task_crt0(void) "); } -task_t *task_create(void (*code)(void), uint32_t stackSize) +task_t *task_create(void (*code)(void), uint16_t stackSize) { task_t *t = (task_t *)malloc(sizeof(task_t)); t->next = 0; @@ -95,15 +96,16 @@ task_t *task_create(void (*code)(void), uint32_t stackSize) t->sp[14] = (uint32_t)code; t->sp[15] = (uint32_t)task_crt0; t->sp[16] = 0x01000000; + t->sleep = 0; return t; } -void task_init(void (*init)(void)) +void task_init(void (*init)(void), uint16_t stackSize) { current = (task_t *)malloc(sizeof(task_t)); current->stack = 0; - task_t *init_task = task_create(init, 4096); + task_t *init_task = task_create(init, stackSize); prev = init_task; current->next = init_task; @@ -166,33 +168,29 @@ void PendSV_Handler(void) if (task_disable != 0) asm("bx lr"); - // TODO why, and what does this do // TODO get back to c, implement task sleeping + + // Save current stack pointer asm("\ mrs r0, psp; \ isb; \ - ldr r1, =current; \ - ldr r2, [r1]; \ stmdb r0!, {r4-r11, r14}; \ - str r0, [r2, #8]; \ - ldr r0, [r2, #0]; \ - ldr r3, =prev; \ - str r2, [r3]; \ - str r0, [r1]; \ - ldr r2, [r1]; \ - ldr r0, [r2, #8]; \ + mov %0, r0; \ + " : "=r" (current->sp)); + + // Load next task + uint32_t ticks = millis(); + do { + current = current->next; + } while (current->sleep > ticks); + current->sleep = 0; + + // Load stack pointer, return + asm("\ + mov r0, %0; \ ldmia r0!, {r4-r11, r14}; \ msr psp, r0; \ bx lr; \ - "); - // r1 = current - // r2 = *current - // r0 = sp - // *current.sp = sp - // r0 = current->next - // current = r0 - // r2 = *current - // r0 = *current.sp - // unpack + " :: "r" (current->sp)); } diff --git a/src/kernel/task.h b/src/kernel/task.h index 3d331ae..472e909 100644 --- a/src/kernel/task.h +++ b/src/kernel/task.h @@ -30,6 +30,7 @@ typedef struct { void *next; /**< pointer to the next task_t instance */ uint32_t *stack; /**< pointer to the task's stack */ uint32_t *sp; /**< pointer to the task's last sp register value */ + uint32_t sleep; /**< number of milliseconds task is sleeping for */ } task_t; /** @@ -37,7 +38,7 @@ typedef struct { * This task is given a 4kb stack. * @param init the initial thread to run */ -void task_init(void (*init)(void)); +void task_init(void (*init)(void), uint16_t stackSize); /** * Starts a new task. diff --git a/src/user/user.c b/src/user/user.c index fc51d29..0bb2607 100644 --- a/src/user/user.c +++ b/src/user/user.c @@ -5,7 +5,16 @@ void task1(void); void task2(void); +void user_delay(uint32_t ms) +{ + register uint32_t r1 asm("r1") = ms; + asm("\ + mov r0, 0; \ + mov r1, %0; \ + svc 2; \ + " :: "r" (r1)); +} void user_main(void) { @@ -14,22 +23,22 @@ void user_main(void) for (int i = 0; i < 8; i++) { gpio(GPIO_OUT, 5, !(i & 1)); - delay(200); + user_delay(200); } } void task1(void) { - delay(400); + user_delay(400); task_start(task2, 1024); } void task2(void) { int state = 0; - delay(2500); + user_delay(2500); while (1) { gpio(GPIO_OUT, 5, state ^= 1); - delay(500); + user_delay(500); } }