From aa9dc72a99ad6ecbb5f482b0870c57dcae8af68b Mon Sep 17 00:00:00 2001 From: Tido Klaassen Date: Tue, 7 Jul 2015 21:20:20 +0200 Subject: [PATCH] - initial commit from private repository --- kernel/atomkernel.c | 11 +- ports/cortex-m/Makefile | 291 ++++++++++++++++++ ports/cortex-m/README.md | 1 + ports/cortex-m/atomport-asm.S | 176 +++++++++++ ports/cortex-m/atomport-private.h | 117 +++++++ ports/cortex-m/atomport-tests.h | 47 +++ ports/cortex-m/atomport.c | 200 ++++++++++++ ports/cortex-m/atomport.h | 63 ++++ ports/cortex-m/boards/ek-lm4f120xl/Makefile | 16 + .../boards/ek-lm4f120xl/board_setup.c | 134 ++++++++ ports/cortex-m/boards/nucleo-f103rb/Makefile | 15 + .../boards/nucleo-f103rb/board_setup.c | 131 ++++++++ ports/cortex-m/boards/nucleo-f411re/Makefile | 15 + .../boards/nucleo-f411re/board_setup.c | 129 ++++++++ ports/cortex-m/common/lm4f_con.c | 93 ++++++ ports/cortex-m/common/stm32_con.c | 92 ++++++ ports/cortex-m/common/stubs.c | 110 +++++++ ports/cortex-m/linker/lm4f120xl.ld | 10 + ports/cortex-m/linker/stm32f103rb.ld | 10 + ports/cortex-m/linker/stm32f411re.ld | 10 + ports/cortex-m/tests-main.c | 274 +++++++++++++++++ 21 files changed, 1944 insertions(+), 1 deletion(-) create mode 100644 ports/cortex-m/Makefile create mode 100644 ports/cortex-m/README.md create mode 100644 ports/cortex-m/atomport-asm.S create mode 100644 ports/cortex-m/atomport-private.h create mode 100644 ports/cortex-m/atomport-tests.h create mode 100644 ports/cortex-m/atomport.c create mode 100644 ports/cortex-m/atomport.h create mode 100644 ports/cortex-m/boards/ek-lm4f120xl/Makefile create mode 100644 ports/cortex-m/boards/ek-lm4f120xl/board_setup.c create mode 100644 ports/cortex-m/boards/nucleo-f103rb/Makefile create mode 100644 ports/cortex-m/boards/nucleo-f103rb/board_setup.c create mode 100644 ports/cortex-m/boards/nucleo-f411re/Makefile create mode 100644 ports/cortex-m/boards/nucleo-f411re/board_setup.c create mode 100644 ports/cortex-m/common/lm4f_con.c create mode 100644 ports/cortex-m/common/stm32_con.c create mode 100644 ports/cortex-m/common/stubs.c create mode 100644 ports/cortex-m/linker/lm4f120xl.ld create mode 100644 ports/cortex-m/linker/stm32f103rb.ld create mode 100644 ports/cortex-m/linker/stm32f411re.ld create mode 100644 ports/cortex-m/tests-main.c diff --git a/kernel/atomkernel.c b/kernel/atomkernel.c index 7521c70..5f71fa9 100755 --- a/kernel/atomkernel.c +++ b/kernel/atomkernel.c @@ -342,6 +342,9 @@ static void atomThreadSwitch(ATOM_TCB *old_tcb, ATOM_TCB *new_tcb) /* Set the new currently-running thread pointer */ curr_tcb = new_tcb; + /* TKL: If the thread is being scheduled in, it can not be suspended */ + curr_tcb->suspended = FALSE; + /* Call the architecture-specific context switch */ archContextSwitch (old_tcb, new_tcb); } @@ -351,7 +354,13 @@ static void atomThreadSwitch(ATOM_TCB *old_tcb, ATOM_TCB *new_tcb) * we get back here, we are running in old_tcb context again. Clear its * suspend status now that we're back. */ - old_tcb->suspended = FALSE; + + /** + * TKL: does not work on Cortex-M because of the delayed context switching + * via pend_sv_handler and also the separate thread and exception stacks + * being used. + */ + // old_tcb->suspended = FALSE; } diff --git a/ports/cortex-m/Makefile b/ports/cortex-m/Makefile new file mode 100644 index 0000000..d4521ad --- /dev/null +++ b/ports/cortex-m/Makefile @@ -0,0 +1,291 @@ +################################################ +# Toplevel makefile for all libopencm3 targets # +################################################ + +ifeq ($(V),) + Q := @ + # Do not print "Entering directory ...". + MAKEFLAGS += --no-print-directory +endif + +# Build directory +ifdef O + build_dir=$(shell readlink -f $(O)) +else + build_dir=$(CURDIR)/build +endif + +# Source directory +src_dir=$(CURDIR) + +# Clean object list before including board makefile +objs := + +# set default board if none is given +ifeq ($(BOARD),) + BOARD = nucleo-f103rb +endif + +include $(src_dir)/boards/$(BOARD)/Makefile + +# Make sure target MCU is set +ifndef TARGET + $(error TARGET undefined) +endif + +# Configure toolchain +CROSS_COMPILE ?= arm-none-eabi- + +CC := $(CROSS_COMPILE)gcc +CXX := $(CROSS_COMPILE)g++ +LD := $(CROSS_COMPILE)gcc +AR := $(CROSS_COMPILE)ar +AS := $(CROSS_COMPILE)as +OBJCOPY := $(CROSS_COMPILE)objcopy +OBJDUMP := $(CROSS_COMPILE)objdump +GDB := $(CROSS_COMPILE)gdb +STFLASH = $(shell which st-flash) + +LDSCRIPT ?= linker/$(TARGET).ld + +# Enable stack-checking. WARNING: the full automated test suite currently +# requires a little over 1KB RAM with stack-checking enabled. If you are +# using a device with 1KB internal SRAM and no external SRAM then you +# must disable stack-checking to run all of the automated tests. +#STACK_CHECK=true + +# Location of atomthreads sources +board_dir=$(src_dir)/boards/$(BOARD) +common_dir=$(src_dir)/common +kernel_dir=$(src_dir)/../../kernel +tests_dir=$(src_dir)/../../tests + +# Object files +objs += atomport.o +objs += atomport-asm.o + +# Kernel object files +objs += atomkernel.o +objs += atomsem.o +objs += atommutex.o +objs += atomtimer.o +objs += atomqueue.o + +objs += tests-main.o + +# Collection of built objects (excluding test applications) +build_objs = $(foreach obj,$(objs),$(build_dir)/$(obj)) + +# Target application filenames .elf for each test object +tobjs = $(notdir $(patsubst %.c,%.o,$(wildcard $(tests_dir)/*.c))) +telfs = $(patsubst %.o,%.elf,$(tobjs)) +tbins = $(patsubst %.o,%.bin,$(tobjs)) +thexs = $(patsubst %.o,%.hex,$(tobjs)) +build_tobjs = $(foreach tobj,$(tobjs),$(build_dir)/$(tobj)) +build_telfs = $(foreach telf,$(telfs),$(build_dir)/$(telf)) +build_tbins = $(foreach tbin,$(tbins),$(build_dir)/$(tbin)) +build_thexs = $(foreach thex,$(thexs),$(build_dir)/$(thex)) + +# Check if user wants to use external opencm3 lib or if we have to build +# it ourselves +ifeq ($(OPENCM3_DIR),) + OPENCM3_DIR = $(src_dir)/libopencm3 + lib_needed = build_lib +endif + +ifneq ($(V),) + $(info Using $(OPENCM3_DIR) as path to opencm3 library) +endif + +# Set up search paths for libopencm3 +INCLUDE_DIR = $(OPENCM3_DIR)/include +LIB_DIR = $(OPENCM3_DIR)/lib +SCRIPT_DIR = $(OPENCM3_DIR)/scripts + +# GCC flags +CFLAGS = -Os -g +CFLAGS += -Wall -Wshadow -Wimplicit-function-declaration +CFLAGS += -Wredundant-decls -Wstrict-prototypes +CFLAGS += -fno-common -ffunction-sections -fdata-sections + +# Enable stack-checking (disable if not required) +ifeq ($(STACK_CHECK),true) +CFLAGS += -DATOM_STACK_CHECKING -DTESTS_LOG_STACK_USAGE +endif + +# C & C++ preprocessor common flags +CPPFLAGS += -MD +CPPFLAGS += -Wall -Wundef +CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS) +CPPFLAGS += -I$(board_dir) -I$(common_dir) -I$(src_dir) -I$(kernel_dir) -I$(tests_dir) + +# Linker flags +LDFLAGS += --static -nostartfiles +LDFLAGS += -L$(LIB_DIR) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(build_dir)/$(*).map +LDFLAGS += -Wl,--gc-sections +ifeq ($(V),99) +LDFLAGS += -Wl,--print-gc-sections +endif + +## Used libraries +# Target specific version libopencm3 +LDLIBS += -l$(LIBNAME) + +## Flags for newlibc. +# This uses the version of newlib optimised for size and without libnosys. +# This is the configuration you want to use unless you really know what +# you are doing. +LDLIBS += -Wl,--start-group -lc_nano -lgcc -Wl,--end-group + +# This is the fully bloated version of newlib optimized for speed. +#LDLIBS += -Wl,--start-group -lc -lgcc -Wl,--end-group + +# Use small newlib with libnosys if you do not want to use the provided stubs. +# Be advised that heap management will probaly break in interesting ways +# because libnosys' standard _sbrk() expects the stack to start at the top +# end of memory while the threads' stacks are positioned inside the BSS. +#LDLIBS += -Wl,--start-group -lc_nano -lgcc -lnosys -Wl,--end-group + +# All +.PHONY: all +all: $(LIB_DIR)/lib$(LIBNAME).a $(build_tbins) $(build_thexs) $(build_telfs) $(build_tobjs) $(build_objs) Makefile + +# add build dependency for local libopencm3 if no external libopencm3 is used +$(LIB_DIR)/lib$(LIBNAME).a: $(lib_needed) + +.PHONY: build_lib +build_lib: + $(Q)if [ ! -d libopencm3 ] ; then \ + printf "######## ERROR ########\n"; \ + printf "\tlibopencm3 is not initialized.\n"; \ + printf "\tPlease run:\n"; \ + printf "\t$$ git submodule add https://github.com/libopencm3/libopencm3.git\n"; \ + printf "\t$$ git submodule init\n"; \ + printf "\t$$ git submodule update\n"; \ + printf "\tbefore running make.\n"; \ + printf "######## ERROR ########\n"; \ + exit 1; \ + fi + $(Q)$(MAKE) -C libopencm3 + +flash: $(BINARY).flash + +$(build_dir)/%.bin: $(build_dir)/%.elf + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (OBJCOPY) $(subst $(build_dir)/,,$@)") + $(Q)$(OBJCOPY) -O binary $< $@ + +$(build_dir)/%.hex: $(build_dir)/%.elf + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (OBJCOPY) $(subst $(build_dir)/,,$@)") + $(Q)$(OBJCOPY) -O ihex $< $@ + +$(build_dir)/%.srec: $(build_dir)/%.elf + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (OBJCOPY) $(subst $(build_dir)/,,$@)") + $(Q)$(OBJCOPY) -O srec $< $@ + +$(build_dir)/%.list: $(build_dir)/%.elf + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (OBJDUMP) $(subst $(build_dir)/,,$@)") + $(Q)$(OBJDUMP) -S $< > $@ + +$(build_dir)/%.elf $(build_dir)/%.map: $(build_dir)/%.o $(build_objs) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (ELF) $(subst $(build_dir)/,,$@)") + $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(build_objs) $(build_dir)/$(*).o $(LDLIBS) -o $@ + +$(build_dir)/%.o: $(src_dir)/%.S + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (AS) $(subst $(build_dir)/,,$@)") + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -D__ASSEMBLY__ -I`dirname $<` -c $< -o $@ + +$(build_dir)/%.o: $(src_dir)/%.c + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)") + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@ + +$(build_dir)/%.o: $(board_dir)/%.c + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)") + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@ + +$(build_dir)/%.o: $(common_dir)/%.c + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)") + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@ + +$(build_dir)/%.o: $(kernel_dir)/%.c + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)") + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@ + +$(build_dir)/%.o: $(tests_dir)/%.c + $(Q)mkdir -p `dirname $@` + $(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)") + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@ + +# Clean +.PHONY: clean +clean: + rm -rf doxygen-kernel + rm -rf doxygen-opencm3 + rm -rf $(build_dir) +ifneq ($(lib_needed),) + $(Q)$(MAKE) -C libopencm3 V=$(V) clean +endif + +# Docs +.PHONY: doxygen +doxygen: + doxygen $(kernel_dir)/Doxyfile + doxygen ./Doxyfile + +%.stlink-flash: $(build_dir)/%.bin + @printf " FLASH $<\n" + $(Q)$(STFLASH) write $(build_dir)/$(*).bin 0x8000000 + +ifeq ($(STLINK_PORT),) +ifeq ($(BMP_PORT),) +ifeq ($(OOCD_SERIAL),) +%.flash: $(build_dir)/%.hex + @printf " FLASH $<\n" + @# IMPORTANT: Don't use "resume", only "reset" will work correctly! + -$(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \ + -f board/$(OOCD_BOARD).cfg \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(build_dir)/$(*).hex" \ + -c "reset" \ + -c "shutdown" $(NULL) +else +%.flash: $(build_dir)/%.hex + @printf " FLASH $<\n" + @# IMPORTANT: Don't use "resume", only "reset" will work correctly! + -$(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \ + -f board/$(OOCD_BOARD).cfg \ + -c "ft2232_serial $(OOCD_SERIAL)" \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(build_dir)/$(*).hex" \ + -c "reset" \ + -c "shutdown" $(NULL) +endif +else +%.flash: $(build_dir)/%.elf + @printf " GDB $(build_dir)/$(*).elf (flash)\n" + $(Q)$(GDB) --batch \ + -ex 'target extended-remote $(BMP_PORT)' \ + -x $(SCRIPT_DIR)/black_magic_probe_flash.scr \ + $(build_dir)/$(*).elf +endif +else +%.flash: $(build_dir)/%.elf + @printf " GDB $(build_dir)/$(*).elf (flash)\n" + $(Q)$(GDB) --batch \ + -ex 'target extended-remote $(STLINK_PORT)' \ + -x $(SCRIPT_DIR)/stlink_flash.scr \ + $(build_dir)/$(*).elf +endif + + diff --git a/ports/cortex-m/README.md b/ports/cortex-m/README.md new file mode 100644 index 0000000..2114a47 --- /dev/null +++ b/ports/cortex-m/README.md @@ -0,0 +1 @@ +# Comming soon... \ No newline at end of file diff --git a/ports/cortex-m/atomport-asm.S b/ports/cortex-m/atomport-asm.S new file mode 100644 index 0000000..b270b3b --- /dev/null +++ b/ports/cortex-m/atomport-asm.S @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +.syntax unified + +.extern CTX_SW_NFO +.extern _stack +.extern vector_table + +.equ FPU_USED, 0x00000010 + +.text + +.global archFirstThreadRestore +.func archFirstThreadRestore +.type archFirstThreadRestore,%function +.thumb_func +archFirstThreadRestore: + /** + * Disable interrupts. They should be disabled anyways, but just + * to make sure... + */ + mov r1, #1 + msr PRIMASK, r1 + + /** + * Reset main stack pointer to initial value, which is the first entry + * in the vector table. + */ + ldr r1, = vector_table + ldr r1, [r1, #0] + msr MSP, r1 + + /* Update ctx_switch_info, set this thread as both running and next */ + ldr r1, = CTX_SW_NFO + str r0, [r1, #0] + str r0, [r1, #4] + + /* Get thread stack pointer from tcb. Conveniently the first element */ + ldr r2, [r0, #0] + + /* Discard dummy thread stack frame */ + add r2, r2, #36 + + /** + * New threads can't have used the FPU, so no need to check for + * FPU stack frame here + */ + + /** + * Load exception stack frame to registers r3-r10. xPSR ends up in r10, + * pc in r9 + */ + ldmia r2!, {r3-r10} + + /* initialise xPSR and store store adjusted stack pointer in PSP */ + msr APSR_nzcvq, r10 + msr PSP, r2 + + /* set bit #1 in CONTROL. Causes switch to PSP */ + mrs r1, CONTROL + orr r1, r1, #2 + msr CONTROL, r1 + + /* enable interrupts */ + mov r1, #0 + msr PRIMASK, r1 + + /* branch to thread entry point */ + bx r9 + nop +.size archFirstThreadRestore, . - archFirstThreadRestore +.endfunc + +.global pend_sv_handler +.func pend_sv_handler +.type pend_sv_handler,%function +.thumb_func +pend_sv_handler: + /** + * Disable interrupts. No need to check if they were enabled because, + * well, we're an interrupt handler. Duh... + */ + mov r0, #1 + msr PRIMASK, r0 + + /* Get running thread's stack pointer*/ + mrs r3, PSP + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + /* Check if FPU was used by thread and store registers if necessary */ + tst lr, FPU_USED + it eq + vstmdbeq r3!, {s16-s31} + + /** + * TODO: Defer stacking FPU context by disabling FPU and using a + * fault handler to store the FPU registers if another thread + * tries using it + */ +#endif + + /* Push running thread's remaining registers on stack */ + stmdb r3!, {r4-r11, lr} + + /* Fetch running thread's TCB and store its current stack pointer */ + ldr r2, = CTX_SW_NFO + ldr r1, [r2, #0] + str r3, [r1, #0] + + /** + * Fetch pointer to next thread's tcb from ctx_switch_info.next_tcb and + * use it to update ctx_switch_info.running_tcb. + */ + ldr r1, [r2, #4] + str r1, [r2, #0] + + /** + * Fetch next thread's stack pointer from its TCB and restore + * the thread's register context. + */ + ldr r3, [r1, #0] + ldmia r3!, {r4-r11, lr} + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + /** + * Check if FPU was used by new thread and restore registers if necessary. + */ + tst lr, FPU_USED + it eq + vldmiaeq r3!, {s16-s31} + + /** + * TODO: only restore FPU registers if FPU was used by another thread + * between this thread being scheduled out and now. + */ +#endif + + /* Restore process stack pointer */ + msr PSP, r3 + + /* Re-enable interrupts */ + mov r0, #0 + msr PRIMASK, r0 + + /* Return to new thread */ + bx lr + nop +.size pend_sv_handler, . - pend_sv_handler +.endfunc diff --git a/ports/cortex-m/atomport-private.h b/ports/cortex-m/atomport-private.h new file mode 100644 index 0000000..09cc58d --- /dev/null +++ b/ports/cortex-m/atomport-private.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOMPORT_PRIVATE_H_ +#define __ATOMPORT_PRIVATE_H_ + +#include "atomport.h" +#include "atom.h" + +/** + * context saved automagically by exception entry + */ +struct isr_stack { + 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 isr_fpu_stack { + uint32_t s0; + uint32_t s1; + uint32_t s2; + uint32_t s3; + uint32_t s4; + uint32_t s5; + uint32_t s6; + uint32_t s7; + uint32_t s8; + uint32_t s9; + uint32_t s10; + uint32_t s11; + uint32_t s12; + uint32_t s13; + uint32_t s14; + uint32_t s15; + uint32_t fpscr; +}; + +/** + * remaining context saved by task switch ISR + */ +struct task_stack { + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t lr; +}; + +struct task_fpu_stack { + uint32_t s16; + uint32_t s17; + uint32_t s18; + uint32_t s19; + uint32_t s20; + uint32_t s21; + uint32_t s22; + uint32_t s23; + uint32_t s24; + uint32_t s25; + uint32_t s26; + uint32_t s27; + uint32_t s28; + uint32_t s29; + uint32_t s30; + uint32_t s31; +}; + +/** + * Info needed by pend_sv_handler used for delayed task switching. + * Running_tcb is a pointer to the TCB currently running (gosh, really?!) + * next_tcb is a pointer to a TCB that should be running. + * archContextSwitch() will update next_tcb and trigger a pend_sv. The + * pend_sv_handler will be called as soon as all other ISRs have returned, + * do the real context switch and update running_tcb. + */ +struct task_switch_info { + volatile struct atom_tcb *running_tcb; + volatile struct atom_tcb *next_tcb; +}; + +#endif /* __ATOMPORT_PRIVATE_H_ */ diff --git a/ports/cortex-m/atomport-tests.h b/ports/cortex-m/atomport-tests.h new file mode 100644 index 0000000..0bc7152 --- /dev/null +++ b/ports/cortex-m/atomport-tests.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOM_PORT_TESTS_H +#define __ATOM_PORT_TESTS_H + +/* Include Atomthreads kernel API */ +#include +#include "atom.h" + +/* Default thread stack size (in bytes) */ +#define TEST_THREAD_STACK_SIZE 1024 + +/* Uncomment to enable logging of stack usage to UART */ +/* #define TESTS_LOG_STACK_USAGE */ + +#define ATOMLOG printf +#define _STR + +#endif /* __ATOM_PORT_TESTS_H */ + diff --git a/ports/cortex-m/atomport.c b/ports/cortex-m/atomport.c new file mode 100644 index 0000000..4dc612a --- /dev/null +++ b/ports/cortex-m/atomport.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "atomport.h" +#include "atomport-private.h" + +static void thread_shell(void); + +/** + * + */ +struct task_switch_info ctx_switch_info asm("CTX_SW_NFO") = +{ + .running_tcb = NULL, + .next_tcb = NULL, +}; + +/** + * We do not perform the context switch directly. Instead we mark the new tcb + * as should-be-running in ctx_switch_info and trigger a PendSv-interrupt. + * The pend_sv_handler will be called when all other pending exceptions have + * returned and perform the actual context switch. + * This way we do not have to worry if we are being called from task or + * interrupt context, which would mean messing with either main or thread + * stack format. + * + * One difference to the other architectures is that execution flow will + * actually continue in the old thread context until interrupts are enabled + * again. From a thread context this should make no difference, as the context + * switch will be performed as soon as the execution flow would return to the + * calling thread. Unless, of course, the thread called atomSched() with + * disabled interrupts, which it should not do anyways... + */ +void __attribute__((noinline)) +archContextSwitch(ATOM_TCB *old_tcb_ptr __maybe_unused, ATOM_TCB *new_tcb_ptr) +{ + if(likely(ctx_switch_info.running_tcb != NULL)){ + ctx_switch_info.next_tcb = new_tcb_ptr; + + __dmb(); + + SCB_ICSR = SCB_ICSR_PENDSVSET; + } +} + +void sys_tick_handler(void) +{ + /* Call the interrupt entry routine */ + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); +} + +/** + * Put chip into infinite loop if NMI or hard fault occurs + */ +void nmi_handler(void) +{ + while(1) + ; +} + +void hard_fault_handler(void) +{ + while(1) + ; +} + + +/** + * This function is called when a new thread is scheduled in for the first + * time. It will simply call the threads entry point function. + */ +static void thread_shell(void) +{ + ATOM_TCB *task_ptr; + + /** + * We "return" to here after being scheduled in by the pend_sv_handler. + * We get a pointer to our TCB from atomCurrentContext() + */ + task_ptr = atomCurrentContext(); + + /** + * Our thread entry point and parameter are stored in the TCB. + * Call it if it is valid + */ + if(task_ptr && task_ptr->entry_point){ + task_ptr->entry_point(task_ptr->entry_param); + } + + /** + * Thread returned or entry point was not valid. + * Should never happen... Maybe we should switch MCU into debug mode here + */ + while(1) + ; +} + +/** + * Initialise a threads stack so it can be scheduled in by + * archFirstThreadRestore or the pend_sv_handler. + */ +void archThreadContextInit(ATOM_TCB *tcb_ptr, void *stack_top, + void (*entry_point)(uint32_t), uint32_t entry_param) +{ + struct isr_stack *isr_ctx; + struct task_stack *tsk_ctx; + + /** + * New threads will be scheduled from an exception handler, so we have to + * set up an exception stack frame as well as task stack frame + */ + isr_ctx = stack_top - sizeof(*isr_ctx); + tsk_ctx = stack_top - sizeof(*isr_ctx) - sizeof(*tsk_ctx); + +#if 0 + printf("[%s] tcb_ptr: %p stack_top: %p isr_ctx: %p tsk_ctx: %p entry_point: %p, entry_param: 0x%x\n", + __func__, tcb_ptr, stack_top, isr_ctx, tsk_ctx, entry_point, entry_param); + printf("[%s] isr_ctx->r0: %p isr_ctx->psr: %p tsk_ctx->r4: %p tsk_ctx->lr: %p\n", + __func__, &isr_ctx->r0, &isr_ctx->psr, &tsk_ctx->r4, &tsk_ctx->lr); +#endif + /** + * We use the exception return mechanism to jump to our thread_shell() + * function and initialise the PSR to the default value (thumb state + * flag set and nothing else) + */ + isr_ctx->psr = 0x01000000; + isr_ctx->pc = (uint32_t) thread_shell; + + /* initialise unused registers to silly value */ + isr_ctx->lr = 0xDEADBEEF; + isr_ctx->r12 = 0xDEADBEEF; + isr_ctx->r3 = 0xDEADBEEF; + isr_ctx->r2 = 0xDEADBEEF; + isr_ctx->r1 = 0xDEADBEEF; + isr_ctx->r0 = 0xDEADBEEF; + + /** + * We use this special EXC_RETURN code to switch from main stack to our + * thread stack on exception return + */ + tsk_ctx->lr = 0xFFFFFFFD; + + /* initialise unused registers to silly value */ + tsk_ctx->r11 = 0xDEADBEEF; + tsk_ctx->r10 = 0xDEADBEEF; + tsk_ctx->r9 = 0xDEADBEEF; + tsk_ctx->r8 = 0xDEADBEEF; + tsk_ctx->r7 = 0xDEADBEEF; + tsk_ctx->r6 = 0xDEADBEEF; + tsk_ctx->r5 = 0xDEADBEEF; + tsk_ctx->r4 = 0xDEADBEEF; + + /** + * Stack frames have been initialised, save it to the TCB. Also set + * the thread's real entry point and param, so the thread shell knows + * what function to call. + */ + tcb_ptr->sp_save_ptr = tsk_ctx; + tcb_ptr->entry_point = entry_point; + tcb_ptr->entry_param = entry_param; +} + diff --git a/ports/cortex-m/atomport.h b/ports/cortex-m/atomport.h new file mode 100644 index 0000000..1aba5c0 --- /dev/null +++ b/ports/cortex-m/atomport.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOM_PORT_H +#define __ATOM_PORT_H + +#include +#include +#include + +/* Required number of system ticks per second (normally 100 for 10ms tick) */ +#define SYSTEM_TICKS_PER_SEC 100 + +/* Size of each stack entry / stack alignment size (4 bytes on Cortex-M without FPU) */ +#define STACK_ALIGN_SIZE sizeof(uint32_t) + +#define POINTER void * +#define UINT32 uint32_t + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#define __maybe_unused __attribute__((unused)) + +/** + * Critical region protection: this should disable interrupts + * to protect OS data structures during modification. It must + * allow nested calls, which means that interrupts should only + * be re-enabled when the outer CRITICAL_END() is reached. + */ +#define CRITICAL_STORE bool __irq_flags +#define CRITICAL_START() __irq_flags = cm_mask_interrupts(true) +#define CRITICAL_END() (void) cm_mask_interrupts(__irq_flags) + +/* Uncomment to enable stack-checking */ +/* #define ATOM_STACK_CHECKING */ + +#endif /* __ATOM_PORT_H */ diff --git a/ports/cortex-m/boards/ek-lm4f120xl/Makefile b/ports/cortex-m/boards/ek-lm4f120xl/Makefile new file mode 100644 index 0000000..37581c9 --- /dev/null +++ b/ports/cortex-m/boards/ek-lm4f120xl/Makefile @@ -0,0 +1,16 @@ +TARGET := lm4f120xl + +LIBNAME = opencm3_lm4f +DEFS = -DLM4F +DEFS += -DSTD_CON=UART0 +DEFS += -DMST_SIZE=0x400 + +FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 +ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS) + +OOCD ?= openocd +OOCD_INTERFACE ?= ti-icdi +OOCD_BOARD ?= ek-lm4f120xl + +objs += board_setup.o +objs += stubs.o lm4f_con.o \ No newline at end of file diff --git a/ports/cortex-m/boards/ek-lm4f120xl/board_setup.c b/ports/cortex-m/boards/ek-lm4f120xl/board_setup.c new file mode 100644 index 0000000..03ded27 --- /dev/null +++ b/ports/cortex-m/boards/ek-lm4f120xl/board_setup.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "atomport.h" + +static void uart_setup(uint32_t baud) +{ + periph_clock_enable(RCC_GPIOA); + gpio_set_af(GPIOA, 1, GPIO0 | GPIO1); + + periph_clock_enable(RCC_UART0); + + /* We need a brief delay before we can access UART config registers */ + __asm__("nop"); + + /* Disable the UART while we mess with its setings */ + uart_disable(UART0); + + /* Configure the UART clock source as precision internal oscillator */ + uart_clock_from_piosc(UART0); + + /* Set communication parameters */ + uart_set_baudrate(UART0, baud); + uart_set_databits(UART0, 8); + uart_set_parity(UART0, UART_PARITY_NONE); + uart_set_stopbits(UART0, 1); + + /* Now that we're done messing with the settings, enable the UART */ + uart_enable(UART0); +} + +/** + * initialise and start SysTick counter. This will trigger the + * sys_tick_handler() periodically once interrupts have been enabled + * by archFirstThreadRestore() + */ +static void systick_setup(void) +{ + systick_set_frequency(SYSTEM_TICKS_PER_SEC, 80000000); + + systick_interrupt_enable(); + + systick_counter_enable(); +} + +/** + * Set up the core clock to something other than the internal 16MHz PIOSC. + * Make sure that you use the same clock frequency in systick_setup(). + */ +static void clock_setup(void) +{ + /** + * set up 400MHz PLL from 16MHz crystal and divide by 5 to get 80MHz + * system clock + */ + rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, 5); +} + +/** + * Set up user LED and provide function for toggling it. This is for + * use by the test suit programs + */ +static void test_led_setup(void) +{ + /* LED is connected to GPIO1 on port F */ + periph_clock_enable(RCC_GPIOF); + gpio_mode_setup(GPIOF, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO1); + gpio_set_output_config(GPIOF, GPIO_OTYPE_PP, GPIO_DRIVE_2MA, GPIO1); + + gpio_set(GPIOF, GPIO1); +} + +void test_led_toggle(void) +{ + gpio_toggle(GPIOF, GPIO1); +} + +/** + * Callback from your main program to set up the board's hardware before + * the kernel is started. + */ +int board_setup(void) +{ + /* Disable interrupts. This makes sure that the sys_tick_handler will + * not be called before the first thread has been started. + * Interrupts will be enabled by archFirstThreadRestore(). + */ + cm_mask_interrupts(true); + + /* configure system clock, user LED and UART */ + gpio_enable_ahb_aperture(); + clock_setup(); + test_led_setup(); + uart_setup(115200); + + /* initialise SysTick counter */ + systick_setup(); + + return 0; +} diff --git a/ports/cortex-m/boards/nucleo-f103rb/Makefile b/ports/cortex-m/boards/nucleo-f103rb/Makefile new file mode 100644 index 0000000..f18e8c6 --- /dev/null +++ b/ports/cortex-m/boards/nucleo-f103rb/Makefile @@ -0,0 +1,15 @@ +TARGET := stm32f103rb +LIBNAME = opencm3_stm32f1 +DEFS = -DSTM32F1 +DEFS += -DSTD_CON=USART2 +DEFS += -DMST_SIZE=0x400 + +FP_FLAGS ?= -msoft-float +ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd + +OOCD ?= openocd +OOCD_INTERFACE ?= stlink-v2-1 +OOCD_BOARD ?= st_nucleo_f103rb + +objs += board_setup.o +objs += stubs.o stm32_con.o diff --git a/ports/cortex-m/boards/nucleo-f103rb/board_setup.c b/ports/cortex-m/boards/nucleo-f103rb/board_setup.c new file mode 100644 index 0000000..05a1818 --- /dev/null +++ b/ports/cortex-m/boards/nucleo-f103rb/board_setup.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "atomport.h" + +/** + * Set up USART2. + * This one is connected via the virtual serial port on the Nucleo Board + */ +static void usart_setup(uint32_t baud) +{ + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_AFIO); + rcc_periph_clock_enable(RCC_USART2); + + usart_disable(USART2); + + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, + GPIO_USART2_TX | GPIO_USART2_RX); + + usart_set_baudrate(USART2, baud); + usart_set_databits(USART2, 8); + usart_set_stopbits(USART2, USART_STOPBITS_1); + usart_set_parity(USART2, USART_PARITY_NONE); + usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); + usart_set_mode(USART2, USART_MODE_TX_RX); + + usart_enable(USART2); +} + +/** + * initialise and start SysTick counter. This will trigger the + * sys_tick_handler() periodically once interrupts have been enabled + * by archFirstThreadRestore() + */ +static void systick_setup(void) +{ + systick_set_frequency(SYSTEM_TICKS_PER_SEC, 72000000); + + systick_interrupt_enable(); + + systick_counter_enable(); +} + +/** + * Set up the core clock to something other than the internal 16MHz PIOSC. + * Make sure that you use the same clock frequency in systick_setup(). + */ +static void clock_setup(void) +{ + /* set core clock to 72MHz, generated from external 8MHz crystal */ + rcc_clock_setup_in_hse_8mhz_out_72mhz(); +} + +/** + * Set up user LED and provide function for toggling it. This is for + * use by the test suit programs + */ +static void test_led_setup(void) +{ + /* LED is connected to GPIO5 on port A */ + rcc_periph_clock_enable(RCC_GPIOA); + + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO5); + + gpio_set(GPIOA, GPIO5); +} + +void test_led_toggle(void) +{ + gpio_toggle(GPIOA, GPIO5); +} + +/** + * Callback from your main program to set up the board's hardware before + * the kernel is started. + */ +int board_setup(void) +{ + /* Disable interrupts. This makes sure that the sys_tick_handler will + * not be called before the first thread has been started. + * Interrupts will be enabled by archFirstThreadRestore(). + */ + cm_mask_interrupts(true); + + /* configure system clock, user LED and UART */ + clock_setup(); + test_led_setup(); + usart_setup(115200); + + /* initialise SysTick counter */ + systick_setup(); + + return 0; +} + diff --git a/ports/cortex-m/boards/nucleo-f411re/Makefile b/ports/cortex-m/boards/nucleo-f411re/Makefile new file mode 100644 index 0000000..546cbe0 --- /dev/null +++ b/ports/cortex-m/boards/nucleo-f411re/Makefile @@ -0,0 +1,15 @@ +TARGET := stm32f411re +LIBNAME = opencm3_stm32f4 +DEFS = -DSTM32F4 +DEFS += -DSTD_CON=USART2 +DEFS += -DMST_SIZE=0x400 + +FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 +ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS) + +OOCD ?= openocd +OOCD_INTERFACE ?= stlink-v2-1 +OOCD_BOARD ?= st_nucleo_f4 + +objs += board_setup.o +objs += stubs.o stm32_con.o diff --git a/ports/cortex-m/boards/nucleo-f411re/board_setup.c b/ports/cortex-m/boards/nucleo-f411re/board_setup.c new file mode 100644 index 0000000..49cca22 --- /dev/null +++ b/ports/cortex-m/boards/nucleo-f411re/board_setup.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "atomport.h" + +/** + * Set up USART2. + * This one is connected via the virtual serial port on the Nucleo Board + */ +static void usart_setup(uint32_t baud) +{ + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_USART2); + + usart_disable(USART2); + + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3); + gpio_set_af(GPIOA, GPIO_AF7, GPIO2); + + usart_set_baudrate(USART2, baud); + usart_set_databits(USART2, 8); + usart_set_stopbits(USART2, USART_STOPBITS_1); + usart_set_parity(USART2, USART_PARITY_NONE); + usart_set_mode(USART2, USART_MODE_TX_RX); + usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); + + usart_enable(USART2); +} + +/** + * initialise and start SysTick counter. This will trigger the + * sys_tick_handler() periodically once interrupts have been enabled + * by archFirstThreadRestore() + */ +static void systick_setup(void) +{ + systick_set_frequency(SYSTEM_TICKS_PER_SEC, 16000000); + + systick_interrupt_enable(); + + systick_counter_enable(); +} + +/** + * Set up the core clock to something other than the internal 16MHz PIOSC. + * Make sure that you use the same clock frequency in systick_setup(). + */ +static void clock_setup(void) +{ + /** + * Clock setting for stm32f4 is currently broken in libopencm3. + * Leave at internal 16MHz + */ + // rcc_clock_setup_hse_3v3(CLOCK_3V3_48MHZ); +} + +/** + * Set up user LED and provide function for toggling it. This is for + * use by the test suit programs + */ +static void test_led_setup(void) +{ + /* LED is connected to GPIO5 on port A */ + rcc_periph_clock_enable(RCC_GPIOA); + gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO5); + gpio_set(GPIOA, GPIO5); +} + +void test_led_toggle(void) +{ + gpio_toggle(GPIOA, GPIO5); +} + +/** + * Callback from your main program to set up the board's hardware before + * the kernel is started. + */ +int board_setup(void) +{ + /* Disable interrupts. This makes sure that the sys_tick_handler will + * not be called before the first thread has been started. + * Interrupts will be enabled by archFirstThreadRestore(). + */ + cm_mask_interrupts(true); + + /* configure system clock, user LED and UART */ + clock_setup(); + test_led_setup(); + usart_setup(115200); + + /* initialise SysTick counter */ + systick_setup(); + + return 0; +} diff --git a/ports/cortex-m/common/lm4f_con.c b/ports/cortex-m/common/lm4f_con.c new file mode 100644 index 0000000..23a7407 --- /dev/null +++ b/ports/cortex-m/common/lm4f_con.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +/** + * _read and _write for LM4F + * + * _read and _write are used by newlib's I/O routines (think printf, etc.) + * If you want to use this code in your binary, you will have to initialise + * the UART in your board's setup code and define STD_CON to your UART's + * name in your board's Makefile + */ +int _read(int fd, void *buf, size_t count) +{ + int rcvd; + char *ptr; + + if(fd <= 2){ + ptr = (char *) buf; + rcvd = 0; + + while(count > 0){ + *ptr = uart_recv_blocking(STD_CON); + if(*ptr == '\r'){ + *ptr = '\n'; + } + + ++rcvd; + --count; + } + }else{ + rcvd = -1; + errno = EIO; + } + + return rcvd; +} + +int _write(int fd, const void *buf, size_t count) +{ + int sent; + char *ptr; + + if(fd <= 2){ + sent = count; + ptr = (char *) buf; + + while(count > 0){ + if(*ptr == '\n'){ + uart_send_blocking(STD_CON, '\r'); + } + uart_send_blocking(STD_CON, *ptr++); + + ++sent; + --count; + } + }else{ + errno = EIO; + sent = -1; + } + + return sent; +} diff --git a/ports/cortex-m/common/stm32_con.c b/ports/cortex-m/common/stm32_con.c new file mode 100644 index 0000000..ffc5f27 --- /dev/null +++ b/ports/cortex-m/common/stm32_con.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +/** + * _read and _write for STM32 + * + * _read and _write are used by newlib's I/O routines (think printf, etc.) + * If you want to use this code in your binary, you will have to initialise + * the UART in your board's setup code and define STD_CON to your UART's + * name in your board's Makefile + */ +int _read(int fd, void *buf, size_t count) +{ + int rcvd; + char *ptr; + + if(fd <= 2){ + ptr = (char *) buf; + rcvd = 0; + while(count > 0){ + *ptr = usart_recv_blocking(STD_CON); + if(*ptr == '\r'){ + *ptr = '\n'; + } + ++rcvd; + --count; + } + }else{ + rcvd = -1; + errno = EIO; + } + + return rcvd; +} + +int _write(int fd, const void *buf, size_t count) +{ + int sent; + char *ptr; + + if(fd <= 2){ + sent = count; + ptr = (char *) buf; + + while(count > 0){ + if(*ptr == '\n'){ + usart_send_blocking(STD_CON, '\r'); + } + usart_send_blocking(STD_CON, *ptr++); + ++sent; + --count; + } + + }else{ + errno = EIO; + sent = -1; + } + + return sent; +} + diff --git a/ports/cortex-m/common/stubs.c b/ports/cortex-m/common/stubs.c new file mode 100644 index 0000000..06bdbf2 --- /dev/null +++ b/ports/cortex-m/common/stubs.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015, Tido Klaassen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +/** + * _sbrk is needed by newlib for heap management. + * The main stack usually starts at the top of RAM and grows downwards, + * while the heap starts at the bottom and grows upwards. To prevent + * the heap from colliding with the main stack, we reserve a certain amount + * of memory and check that growing the heap won't touch that region. + * The size of the protected area is set via the define MST_SIZE in the + * board Makefile + */ + +#ifndef MST_SIZE +#error Main stack size not defined. Please define MST_SIZE in board Makefile +#endif + +/** + * The vector table is provided by libopencm3/cm3/vector.h and contains + * the initial main stack pointer value + */ +extern vector_table_t vector_table; + +/** + * The linker provides the start address of the unused system memory. + * It is exported via the symbol 'end' and will be used as the bottom + * of the heap + */ +extern char end; + +static char *heap_end = 0; +caddr_t _sbrk(int incr) +{ + char *prev_end; + + if(heap_end == 0){ + heap_end = &end; + } + + prev_end = heap_end; + + if(heap_end + incr + MST_SIZE > (char *) vector_table.initial_sp_value){ + /* new heap size would collide with main stack area*/ + return (caddr_t) 0; + } + + heap_end += incr; + + return (caddr_t) prev_end; +} + +/** + * dummy stubs needed by newlib when not linked with libnosys + */ +int _close(int file) +{ + return -1; +} + +int _fstat(int file, struct stat *st) +{ + st->st_mode = S_IFCHR; + + return 0; +} + +int _isatty(int file) +{ + return 1; +} + +int _lseek(int file, int ptr, int dir) +{ + return 0; +} + +int _open(const char *name, int flags, int mode) +{ + return -1; +} diff --git a/ports/cortex-m/linker/lm4f120xl.ld b/ports/cortex-m/linker/lm4f120xl.ld new file mode 100644 index 0000000..2675012 --- /dev/null +++ b/ports/cortex-m/linker/lm4f120xl.ld @@ -0,0 +1,10 @@ +/* Memory regions for TI Stellaris EX-LM4F120XL evaluation board. */ + +MEMORY +{ + rom (rx) : ORIGIN = 0x00000000, LENGTH = 256K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* Include main opencm3 linker script */ +INCLUDE libopencm3_lm4f.ld diff --git a/ports/cortex-m/linker/stm32f103rb.ld b/ports/cortex-m/linker/stm32f103rb.ld new file mode 100644 index 0000000..86078f9 --- /dev/null +++ b/ports/cortex-m/linker/stm32f103rb.ld @@ -0,0 +1,10 @@ +/* Memory regions for STM32F103RB, 128K flash, 20K RAM. */ + +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include main opencm3 linker script */ +INCLUDE libopencm3_stm32f1.ld diff --git a/ports/cortex-m/linker/stm32f411re.ld b/ports/cortex-m/linker/stm32f411re.ld new file mode 100644 index 0000000..3c61d05 --- /dev/null +++ b/ports/cortex-m/linker/stm32f411re.ld @@ -0,0 +1,10 @@ +/* Memory regions for STM32F411RE, 512K flash, 128K RAM. */ + +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +/* Include main opencm3 linker script */ +INCLUDE libopencm3_stm32f4.ld diff --git a/ports/cortex-m/tests-main.c b/ports/cortex-m/tests-main.c new file mode 100644 index 0000000..225ee49 --- /dev/null +++ b/ports/cortex-m/tests-main.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2010, Kelvin Lawson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "atom.h" +#include "atomport-private.h" +#include "atomtests.h" +#include "atomtimer.h" + + +/* Constants */ + +/* + * Idle thread stack size + * + * This needs to be large enough to handle any interrupt handlers + * and callbacks called by interrupt handlers (e.g. user-created + * timer callbacks) as well as the saving of all context when + * switching away from this thread. + * + * In this case, the idle stack is allocated on the BSS via the + * idle_thread_stack[] byte array. + */ +#define IDLE_STACK_SIZE_BYTES 512 + + +/* + * Main thread stack size + * + * Note that this is not a required OS kernel thread - you will replace + * this with your own application thread. + * + * In this case the Main thread is responsible for calling out to the + * test routines. Once a test routine has finished, the test status is + * printed out on the UART and the thread remains running in a loop + * flashing a LED. + * + * The Main thread stack generally needs to be larger than the idle + * thread stack, as not only does it need to store interrupt handler + * stack saves and context switch saves, but the application main thread + * will generally be carrying out more nested function calls and require + * stack for application code local variables etc. + * + * With all OS tests implemented to date on the AVR, the Main thread + * stack has not exceeded 201 bytes. To allow all tests to run we set + * a minimum main thread stack size of 204 bytes. This may increase in + * future as the codebase changes but for the time being is enough to + * cope with all of the automated tests. + */ +#define MAIN_STACK_SIZE_BYTES 1024 + + +/* + * Startup code stack + * + * Some stack space is required at initial startup for running the main() + * routine. This stack space is only temporarily required at first bootup + * and is no longer required as soon as the OS is started. By default + * GCC sets this to the top of RAM (RAMEND) and it grows down from there. + * Because we only need this temporarily, though, it would be wasteful to + * set aside a region at the top of RAM which is not used during runtime. + * + * What we do here is to reuse part of the idle thread's stack during + * initial startup. As soon as we enter the main() routine we move the + * stack pointer to half-way down the idle thread's stack. This is used + * temporarily while calls are made to atomOSInit(), atomThreadCreate() + * and atomOSStart(). Once the OS is started this stack area is no + * longer required, and can be used for its original purpose (for the + * idle thread's stack). + * + * This does mean, however, that we cannot monitor the stack usage of the + * idle thread. Stack usage is monitored by prefilling the stack with a + * known value, and we are obliterating some of that prefilled area by + * using it as our startup stack, so we cannot use the stack-checking API + * to get a true picture of idle thread stack usage. If you wish to + * monitor idle thread stack usage for your applications then you are + * free to use a different region for the startup stack (e.g. set aside + * an area permanently, or place it somewhere you know you can reuse + * later in the application). For the time being, this method gives us a + * simple way of reducing the memory consumption without having to add + * any special AVR-specific considerations to the automated test + * applications. + * + * This optimisation was required to allow some of the larger automated + * test modules to run on devices with 1KB of RAM. You should avoid doing + * this if you can afford to set aside 64 bytes or so, or if you are + * writing your own applications in which you have further control over + * where data is located. + */ + + +/* Local data */ + +/* Application threads' TCBs */ +static ATOM_TCB main_tcb; + +/* Main thread's stack area */ +static uint8_t main_thread_stack[MAIN_STACK_SIZE_BYTES]; + +/* Idle thread's stack area */ +static uint8_t idle_thread_stack[IDLE_STACK_SIZE_BYTES]; + +/* Forward declarations */ +static void main_thread_func (uint32_t data); + + +/** + * \b main + * + * Program entry point. + * + * Sets up the AVR hardware resources (system tick timer interrupt) necessary + * for the OS to be started. Creates an application thread and starts the OS. + */ +extern int board_setup(void); +int main ( void ) +{ + int8_t status; + + + /** + * Note: to protect OS structures and data during initialisation, + * interrupts must remain disabled until the first thread + * has been restored. They are reenabled at the very end of + * the first thread restore, at which point it is safe for a + * reschedule to take place. + */ + board_setup(); + + /** + * Initialise the OS before creating our threads. + * + * Note that we cannot enable stack-checking on the idle thread on + * this platform because we are already using part of the idle + * thread's stack now as our startup stack. Prefilling for stack + * checking would overwrite our current stack. + * + * If you are not reusing the idle thread's stack during startup then + * you are free to enable stack-checking here. + */ + status = atomOSInit(&idle_thread_stack[0], IDLE_STACK_SIZE_BYTES, FALSE); + if (status == ATOM_OK) + { + + /* Create an application thread */ + status = atomThreadCreate(&main_tcb, + TEST_THREAD_PRIO, main_thread_func, 0, + &main_thread_stack[0], + MAIN_STACK_SIZE_BYTES, + TRUE); + if (status == ATOM_OK) + { + /** + * First application thread successfully created. It is + * now possible to start the OS. Execution will not return + * from atomOSStart(), which will restore the context of + * our application thread and start executing it. + * + * Note that interrupts are still disabled at this point. + * They will be enabled as we restore and execute our first + * thread in archFirstThreadRestore(). + */ + atomOSStart(); + } + } + + while (1) + ; + + /* There was an error starting the OS if we reach here */ + return (0); +} + + +/** + * \b main_thread_func + * + * Entry point for main application thread. + * + * This is the first thread that will be executed when the OS is started. + * + * @param[in] data Unused (optional thread entry parameter) + * + * @return None + */ +extern void test_led_toggle(void); +static void main_thread_func (uint32_t data) +{ + uint32_t test_status; + int sleep_ticks; + + + /* Put a message out on the UART */ + printf("Go\n"); + + /* Start test. All tests use the same start API. */ + test_status = test_start(); + + /* Check main thread stack usage (if enabled) */ +#ifdef ATOM_STACK_CHECKING + if (test_status == 0) + { + uint32_t used_bytes, free_bytes; + + /* Check idle thread stack usage */ + if (atomThreadStackCheck (&main_tcb, &used_bytes, &free_bytes) == ATOM_OK) + { + /* Check the thread did not use up to the end of stack */ + if (free_bytes == 0) + { + printf("Main stack overflow\n"); + test_status++; + } + + /* Log the stack usage */ +#ifdef TESTS_LOG_STACK_USAGE + printf("MainUse: %lu\n", used_bytes); +#endif + } + + } +#endif + + /* Log final status */ + if (test_status == 0) + { + printf("Pass\n"); + } + else + { + printf("Fail(%lu)\n", test_status); + } + + /* Flash LED once per second if passed, very quickly if failed */ + sleep_ticks = (test_status == 0) ? SYSTEM_TICKS_PER_SEC : (SYSTEM_TICKS_PER_SEC/8); + + /* Test finished, flash slowly for pass, fast for fail */ + while (1) + { + /* Toggle a LED (STK500-specific) */ + test_led_toggle(); + + /* Sleep then toggle LED again */ + atomTimerDelay (sleep_ticks); + } + +}