- initial commit from private repository

This commit is contained in:
Tido Klaassen
2015-07-07 21:20:20 +02:00
parent 18477010d0
commit aa9dc72a99
21 changed files with 1944 additions and 1 deletions

View File

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

291
ports/cortex-m/Makefile Normal file
View File

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

1
ports/cortex-m/README.md Normal file
View File

@@ -0,0 +1 @@
# Comming soon...

View File

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

View File

@@ -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_ */

View File

@@ -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 <stdio.h>
#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 */

200
ports/cortex-m/atomport.c Normal file
View File

@@ -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 <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/sync.h>
#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;
}

63
ports/cortex-m/atomport.h Normal file
View File

@@ -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 <stdint.h>
#include <stddef.h>
#include <libopencm3/cm3/cortex.h>
/* 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 */

View File

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

View File

@@ -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 <stdbool.h>
#include <libopencm3/lm4f/rcc.h>
#include <libopencm3/lm4f/gpio.h>
#include <libopencm3/lm4f/uart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#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;
}

View File

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

View File

@@ -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 <stdbool.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#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;
}

View File

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

View File

@@ -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 <stdbool.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#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;
}

View File

@@ -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 <errno.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/lm4f/uart.h>
/**
* _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;
}

View File

@@ -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 <errno.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/stm32/usart.h>
/**
* _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;
}

View File

@@ -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 <sys/stat.h>
#include <libopencm3/cm3/vector.h>
/**
* _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;
}

View File

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

View File

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

View File

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

274
ports/cortex-m/tests-main.c Normal file
View File

@@ -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 <stdio.h>
#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);
}
}