aboutsummaryrefslogtreecommitdiff
path: root/apps/os1
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2016-01-02 21:13:31 +0100
committerTrygve Laugstøl <trygvis@inamo.no>2016-01-02 21:13:31 +0100
commitbaedda497d16c5096971eee83a0c467fe663fe6d (patch)
tree2f8925c68d94aed7d5fc7022462abbb359200b9e /apps/os1
parent9129af503c8211d713c8a160a3b6f3f86b328639 (diff)
downloadstm32f103-playground-baedda497d16c5096971eee83a0c467fe663fe6d.tar.gz
stm32f103-playground-baedda497d16c5096971eee83a0c467fe663fe6d.tar.bz2
stm32f103-playground-baedda497d16c5096971eee83a0c467fe663fe6d.tar.xz
stm32f103-playground-baedda497d16c5096971eee83a0c467fe663fe6d.zip
o Moving around a lot of files.
Diffstat (limited to 'apps/os1')
-rw-r--r--apps/os1/CMakeLists.txt23
-rw-r--r--apps/os1/os1.cpp285
-rw-r--r--apps/os1/os1_cm3.s56
3 files changed, 364 insertions, 0 deletions
diff --git a/apps/os1/CMakeLists.txt b/apps/os1/CMakeLists.txt
new file mode 100644
index 0000000..b6849b7
--- /dev/null
+++ b/apps/os1/CMakeLists.txt
@@ -0,0 +1,23 @@
+add_executable(os1.elf os1.cpp os1_cm3.s
+ ${PLAYGROUND_DIR}/src/init_low.s ${PLAYGROUND_DIR}/src/init_high.cpp ${PLAYGROUND_DIR}/include/init_high.h
+ ${PLAYGROUND_DIR}/include/playground.h
+ ${PLAYGROUND_DIR}/src/debug.cpp ${PLAYGROUND_DIR}/include/debug.h
+ ${PLAYGROUND_DIR}/include/stm32f10x_conf.h
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport/core_cm3.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/misc.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_rcc.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_usart.c
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c
+ )
+target_link_libraries(os1.elf tinyprintf)
+
+target_include_directories(os1.elf PUBLIC
+ ${PLAYGROUND_DIR}/include
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x
+ ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/inc)
+target_compile_definitions(os1.elf PUBLIC ${STM32F10X_STDPERIPH_DEFINES})
+
+set_target_properties(os1.elf PROPERTIES LINK_FLAGS "-nostartfiles -T${CMAKE_SOURCE_DIR}/cmake/stm32.ld")
+add_extra_commands(os1.elf)
diff --git a/apps/os1/os1.cpp b/apps/os1/os1.cpp
new file mode 100644
index 0000000..9c87a3d
--- /dev/null
+++ b/apps/os1/os1.cpp
@@ -0,0 +1,285 @@
+#include <stdint.h>
+#include <stm32f10x.h>
+#include <stm32f10x_rcc.h>
+#include <stm32f10x_gpio.h>
+
+#include "debug.h"
+#include "tinyprintf.h"
+#include "playground.h"
+
+extern "C"
+__attribute__((naked, used))
+void HardFault_Handler_C(uint32_t *hardfault_args) {
+ dbg_printf("r0 = 0x%08lx (%lu)\n", hardfault_args[0], hardfault_args[0]);
+ dbg_printf("r1 = 0x%08lx (%lu)\n", hardfault_args[1], hardfault_args[1]);
+ dbg_printf("r2 = 0x%08lx (%lu)\n", hardfault_args[2], hardfault_args[2]);
+ dbg_printf("r3 = 0x%08lx (%lu)\n", hardfault_args[3], hardfault_args[3]);
+ dbg_printf("r12 = 0x%08lx (%lu)\n", hardfault_args[4], hardfault_args[4]);
+ dbg_printf("lr = 0x%08lx (%lu)\n", hardfault_args[5], hardfault_args[5]);
+ dbg_printf("pc = 0x%08lx (%lu)\n", hardfault_args[6], hardfault_args[6]);
+ dbg_printf("psr = 0x%08lx (%lu)\n", hardfault_args[7], hardfault_args[7]);
+ dbg_printf("\n");
+
+ halt();
+}
+
+enum class exc_return_t : uint32_t {
+ RETURN_TO_HANDLER_MODE_USE_MSP = 0xFFFFFFF1,
+ RETURN_TO_THREAD_MODE_USE_MSP = 0xFFFFFFF9,
+ RETURN_TO_THREAD_MODE_USE_PSP = 0xFFFFFFFD,
+};
+
+// This is used from assembly so order is important
+struct task_t {
+ uint8_t *stack;
+ exc_return_t exc_return;
+ int flags;
+
+ void init(uint8_t *stack) {
+ this->stack = stack;
+ flags = 0x01;
+ set_ready();
+ }
+
+ void deinit() {
+ flags = 0;
+ }
+
+ bool is_ready() {
+ return (flags & 0x02) > 0;
+ }
+
+ void set_ready() {
+ flags |= 0x02;
+ }
+} __attribute__((packed));
+
+const int max_task_count = 3;
+const int stack_size = 100;
+
+task_t tasks[max_task_count];
+uint8_t stacks[max_task_count][stack_size];
+uint8_t task_count = 0;
+int current_task;
+
+const unsigned int SYSTICK_FREQUENCY_HZ = 10;
+
+struct hardware_frame_t {
+ uint32_t r0;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r12;
+ uint32_t lr;
+ uint32_t pc;
+ uint32_t psr;
+};
+
+struct software_frame_t {
+ uint32_t r4;
+ uint32_t r5;
+ uint32_t r6;
+ uint32_t r7;
+ uint32_t r8;
+ uint32_t r9;
+ uint32_t r10;
+ uint32_t r11;
+};
+
+extern "C"
+void SysTick_Handler() {
+ static bool on = true;
+
+ if (on) {
+ GPIO_SetBits(GPIOB, GPIO_Pin_7);
+ }
+ else {
+ GPIO_ResetBits(GPIOB, GPIO_Pin_7);
+ }
+
+ on = !on;
+
+ SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
+}
+
+void thread_end() {
+}
+
+volatile bool idle_task_run;
+
+void idle_task(const void *const) {
+ // trigger PendSV to run
+ SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
+
+ // wait for the PendSV handler to kick in. After the handler has completed it will do a context switch and
+ // this point shouldn't be reached.
+
+ idle_task_run = true;
+ while (idle_task_run) {
+ GPIOB->BSRR = GPIO_Pin_6;
+ GPIOB->BRR = GPIO_Pin_6;
+ }
+}
+
+static
+void os_create_thread(void (task)(void const *const), bool create_sw);
+
+void os_init() {
+ NVIC_SetPriority(SysTick_IRQn, 0xff);
+ NVIC_SetPriority(PendSV_IRQn, 0xff);
+
+ SysTick_Config(SystemCoreClock / SYSTICK_FREQUENCY_HZ);
+
+ GPIO_InitTypeDef init;
+ GPIO_StructInit(&init);
+ init.GPIO_Mode = GPIO_Mode_Out_PP;
+ init.GPIO_Pin = GPIO_Pin_6;
+ GPIO_Init(GPIOB, &init);
+ init.GPIO_Pin = GPIO_Pin_7;
+ GPIO_Init(GPIOB, &init);
+
+ for (int i = 0; i < max_task_count; i++) {
+ tasks[i].flags = 0;
+ }
+
+ os_create_thread(idle_task, false);
+ current_task = 0;
+}
+
+void os_create_thread(void (task)(void const *const)) {
+ os_create_thread(task, true);
+}
+
+static
+void os_create_thread(void (task)(void const *const), bool create_sw) {
+ uint8_t *s = stacks[task_count] + stack_size;
+
+ s -= sizeof(hardware_frame_t);
+ hardware_frame_t *hw = reinterpret_cast<hardware_frame_t *>(s);
+
+ hw->r0 = 0x00000000;
+ hw->r1 = 0x01010101;
+ hw->r2 = 0x02020202;
+ hw->r3 = 0x03030303;
+ hw->r12 = 0x0c0c0c0c;
+ hw->lr = reinterpret_cast<uint32_t>(thread_end);
+
+ hw->pc = reinterpret_cast<uint32_t>(task);
+ hw->psr = 0x01000000;
+
+ if (create_sw) {
+ s -= sizeof(software_frame_t);
+ software_frame_t *sw = reinterpret_cast<software_frame_t *>(s);
+
+ sw->r4 = 0x04040404;
+ sw->r5 = 0x05050505;
+ sw->r6 = 0x06060606;
+ sw->r7 = 0x07070707;
+ sw->r8 = 0x08080808;
+ sw->r9 = 0x09090909;
+ sw->r10 = 0x0a0a0a0a;
+ sw->r11 = 0x0b0b0b0b;
+ }
+
+ task_t *t = &tasks[task_count];
+ t->init(s);
+ t->exc_return = exc_return_t::RETURN_TO_THREAD_MODE_USE_PSP;
+
+ task_count++;
+}
+
+static
+int find_first_ready_task() {
+ task_t *t;
+ int idx = current_task + 1;
+ do {
+ if (idx == max_task_count) {
+ idx = 1;
+ } else if (idx == current_task) {
+ return 0;
+ }
+
+ t = &tasks[idx];
+ } while (!t->is_ready());
+
+ return idx;
+}
+
+__attribute__((used))
+task_t *select_next_task(uint8_t *current_stack) {
+
+ task_t *t = &tasks[current_task];
+ int new_task = find_first_ready_task();
+
+ if (new_task != current_task) {
+ t->stack = current_stack;
+ t = &tasks[new_task];
+ current_task = new_task;
+ }
+
+ return t;
+}
+
+volatile bool run;
+
+extern "C" void do_first_context_switch(uint8_t *user_stack, void (task)(const void *const arg));
+
+void os_start() {
+ run = true;
+
+ task_t &t = tasks[0];
+
+ do_first_context_switch(t.stack, idle_task);
+
+ while (run) {
+ }
+}
+
+
+volatile bool run1 = true;
+
+void job1(void const *const) {
+ while (run1) {
+ GPIO_SetBits(GPIOB, GPIO_Pin_8);
+ GPIO_ResetBits(GPIOB, GPIO_Pin_8);
+ }
+}
+
+volatile bool run2 = true;
+
+void job2(void const *const) {
+ while (run2) {
+ GPIO_SetBits(GPIOB, GPIO_Pin_5);
+ GPIO_ResetBits(GPIOB, GPIO_Pin_5);
+ }
+}
+
+int main(void) {
+ SystemInit();
+
+ init_printf(nullptr, dbg_putc);
+
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO
+ | RCC_APB2Periph_USART1
+ | RCC_APB2Periph_GPIOA
+ | RCC_APB2Periph_GPIOB
+ | RCC_APB2Periph_GPIOC,
+ ENABLE);
+
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, DISABLE);
+
+ // Make Port B's pin #5 the debug output pin
+ GPIO_InitTypeDef init;
+ GPIO_StructInit(&init);
+ init.GPIO_Mode = GPIO_Mode_Out_PP;
+ init.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_8;
+ GPIO_Init(GPIOB, &init);
+
+ os_init();
+ os_create_thread(job1);
+ os_create_thread(job2);
+ os_start();
+
+ return 0;
+}
diff --git a/apps/os1/os1_cm3.s b/apps/os1/os1_cm3.s
new file mode 100644
index 0000000..a9083dc
--- /dev/null
+++ b/apps/os1/os1_cm3.s
@@ -0,0 +1,56 @@
+.syntax unified
+.cpu cortex-m3
+.thumb
+
+.section .text
+
+/*
+
+User threads use the process stack (PSP register), kernel and exception code use the main stack (MSP register).
+
+*/
+
+.thumb_func
+.global do_first_context_switch
+// void do_first_context_switch(uint8_t *user_stack, void (task)(const void *arg));
+do_first_context_switch:
+ /* Set PSP to the user task's stack */
+ msr psp, r0
+
+ // Set CONTROL.SPSEL=1 so that we run with two stacks
+ mov r0, #2
+ msr control, r0
+ isb
+
+ // Restore the data from hardware_frame_t.
+ pop {r0 - r3, r12, lr}
+ // Pop PC and PSR. PSR is ignored, but we branch to the new PC
+ pop {r4, r5}
+ bx r4
+
+/*
+When this function is executed {r0-r3,r12,lr,pc} has been pushed to the stack pointed to by PSP. We push the rest of the
+registers to the PSP. The current stack pointer is the MSP.
+ */
+.thumb_func
+.global PendSV_Handler
+PendSV_Handler:
+ // Save the rest of the context to the current process' stack
+ mrs r0, psp
+ stmdb r0!, {r4 - r11}
+
+ // Call select_next_task_sp. after return, r0 points to a task_t
+ bl _Z16select_next_taskPh // task_t *select_next_task(uint8_t *current_stack)
+
+ // load task_t.stack and task_t.lr into r1 and lr
+ ldm r0, {r1, lr}
+
+ ldmia r1!, {r4 - r11}
+ msr psp, r1
+
+ // Return, let the CPU restore the hardware part of the context
+ bx lr
+.pool
+.size PendSV_Handler,.-PendSV_Handler
+
+.end