unpriviledged sleep wip

master
tcsullivan 6 years ago
parent c66410f631
commit 34684b28a4

@ -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 <https://www.gnu.org/licenses/>.
#
openocd -f /usr/share/openocd/scripts/board/st_nucleo_l476rg.cfg &
sleep 1
gdb-multiarch -ex "target remote localhost:3333" main.elf
pkill openocd

@ -19,6 +19,7 @@
*/
#include "clock.h"
#include "task.h"
#include <arch/stm/stm32l476xx.h>
// 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;

@ -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

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

@ -18,8 +18,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "task.h"
#include "clock.h"
#include "heap.h"
#include "task.h"
#include <arch/stm/stm32l476xx.h>
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));
}

@ -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.

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

Loading…
Cancel
Save