mirror of
https://github.com/kelvinlawson/atomthreads.git
synced 2026-01-11 18:33:16 +01:00
Merge branch 'tidklaas-master'
This commit is contained in:
@@ -342,17 +342,16 @@ static void atomThreadSwitch(ATOM_TCB *old_tcb, ATOM_TCB *new_tcb)
|
||||
/* Set the new currently-running thread pointer */
|
||||
curr_tcb = new_tcb;
|
||||
|
||||
/**
|
||||
* The context switch will shift execution to a different thread. The
|
||||
* new thread is now ready to run so clear its suspend status in
|
||||
* preparation for it waking up.
|
||||
*/
|
||||
new_tcb->suspended = FALSE;
|
||||
|
||||
/* Call the architecture-specific context switch */
|
||||
archContextSwitch (old_tcb, new_tcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* The context switch shifted execution to a different thread. By the time
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
366
ports/cortex-m/Makefile
Normal file
366
ports/cortex-m/Makefile
Normal file
@@ -0,0 +1,366 @@
|
||||
################################################
|
||||
# Toplevel makefile for all Cortex-M 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 :=
|
||||
aobjs :=
|
||||
|
||||
# set default board if none is given
|
||||
ifeq ($(BOARD),)
|
||||
BOARD = nucleo-f103rb
|
||||
endif
|
||||
|
||||
include $(src_dir)/boards/$(BOARD)/Makefile.include
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
build_lib = true
|
||||
endif
|
||||
|
||||
ifneq ($(V),)
|
||||
$(info Using $(OPENCM3_DIR) as path to opencm3 library)
|
||||
endif
|
||||
|
||||
# Object files needed by all applications
|
||||
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
|
||||
|
||||
# Collection of built objects (excluding test applications)
|
||||
build_objs = $(foreach obj,$(objs),$(build_dir)/$(obj))
|
||||
|
||||
# Object needed by all test applications, but not user apps
|
||||
tmobjs = tests-main.o
|
||||
build_tmobjs = $(foreach obj,$(tmobjs),$(build_dir)/$(obj))
|
||||
build_tmobjs += $(build_objs)
|
||||
|
||||
# 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 -Werror
|
||||
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 -Werror
|
||||
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)
|
||||
|
||||
ifneq ($(BOARD),qemu)
|
||||
## Flags for newlibc.
|
||||
# This uses the version of newlib optimised for size and without libnosys.
|
||||
# This usually is the version of newlib you want to use, although it has some
|
||||
# limitations, like printf not having support for floating point vars.
|
||||
LDLIBS += -Wl,--start-group -lc_nano -lgcc -Wl,--end-group
|
||||
|
||||
# This is the fully bloated version of newlib. Adds about 20k compared to
|
||||
# libc_nano.
|
||||
#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.
|
||||
# This is 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
|
||||
else
|
||||
# Special LDLIBS for qemu target to enable semi-hosting.
|
||||
# TODO: Check if this is also useful for real hardware
|
||||
LDLIBS += -Wl,--start-group --specs=rdimon.specs -lc -lrdimon -lgcc -Wl,--end-group
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: build_all
|
||||
|
||||
# Generate a direct make target for a test application
|
||||
define build_test
|
||||
.PHONY: $(1)
|
||||
$(1): $(build_dir)/$(1).elf
|
||||
endef
|
||||
|
||||
# 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))
|
||||
|
||||
# Add a direct make target for every test app
|
||||
$(foreach test,$(patsubst %.o,%,$(tobjs)),$(eval $(call build_test,$(test))))
|
||||
|
||||
# Define an explicit target and linker rule for an application not in the
|
||||
# test suite. This will be a stand-alone applications located in the board
|
||||
# or common directory
|
||||
define build_app
|
||||
.PHONY: $(1)
|
||||
$(1): $(build_dir)/$(1).elf
|
||||
|
||||
$(build_dir)/$(1).elf $(build_dir)/$(1).map: $(LIB_DIR)/lib$(LIBNAME).a $(build_dir)/$(1).o $(build_objs) $(LDSCRIPT)
|
||||
$$(Q)mkdir -p `dirname $$@`
|
||||
$$(if $$(Q), @echo " (ELF) $$(subst $$(build_dir)/,,$$@)")
|
||||
$$(Q)$$(LD) $$(LDFLAGS) $$(ARCH_FLAGS) $$(build_objs) $$(build_dir)/$(1).o $(LDLIBS) -o $$@
|
||||
endef
|
||||
|
||||
# Target application filenames .elf for each user app object
|
||||
aelfs = $(patsubst %.o,%.elf,$(aobjs))
|
||||
abins = $(patsubst %.o,%.bin,$(aobjs))
|
||||
ahexs = $(patsubst %.o,%.hex,$(aobjs))
|
||||
build_aobjs = $(foreach aobj,$(aobjs),$(build_dir)/$(aobj))
|
||||
build_aelfs = $(foreach aelf,$(aelfs),$(build_dir)/$(aelf))
|
||||
build_abins = $(foreach abin,$(abins),$(build_dir)/$(abin))
|
||||
build_ahexs = $(foreach ahex,$(ahexs),$(build_dir)/$(ahex))
|
||||
|
||||
# add a direct make target for every standalone app
|
||||
$(foreach app,$(patsubst %.o,%,$(aobjs)),$(eval $(call build_app,$(app))))
|
||||
|
||||
# Build all test and user applications
|
||||
all_bins = $(build_tbins) $(build_abins)
|
||||
all_hexs = $(build_thexs) $(build_ahexs)
|
||||
all_elfs = $(build_telfs) $(build_aelfs)
|
||||
all_objs = $(build_tobjs) $(build_aobjs) $(build_tmobjs)
|
||||
|
||||
.PHONY: build_all
|
||||
build_all: $(LIB_DIR)/lib$(LIBNAME).a $(all_bins) $(all_hexs) $(all_elfs) $(all_objs) Makefile $(board_dir)/Makefile.include
|
||||
|
||||
# Add build dependency for local libopencm3 if no external libopencm3 is used
|
||||
ifeq ($(build_lib),true)
|
||||
$(LIB_DIR)/lib$(LIBNAME).a:
|
||||
$(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 V=$(V)
|
||||
endif
|
||||
|
||||
$(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 $< > $@
|
||||
|
||||
# This is the default rule for linking the test suite applications.
|
||||
# User applications defined in a board Makefile fragment are linked
|
||||
# by an explicitly generated rule.
|
||||
$(build_dir)/%.elf $(build_dir)/%.map: $(LIB_DIR)/lib$(LIBNAME).a $(build_dir)/%.o $(build_tmobjs) $(LDSCRIPT)
|
||||
$(Q)mkdir -p `dirname $@`
|
||||
$(if $(Q), @echo " (ELF) $(subst $(build_dir)/,,$@)")
|
||||
$(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(build_tmobjs) $(build_dir)/$(*).o $(LDLIBS) -o $@
|
||||
|
||||
$(build_dir)/%.o: $(src_dir)/%.S Makefile $(board_dir)/Makefile.include
|
||||
$(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 Makefile $(board_dir)/Makefile.include
|
||||
$(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)/%.S Makefile $(board_dir)/Makefile.include
|
||||
$(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: $(board_dir)/%.c Makefile $(board_dir)/Makefile.include
|
||||
$(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)/%.S Makefile $(board_dir)/Makefile.include
|
||||
$(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: $(common_dir)/%.c Makefile $(board_dir)/Makefile.include
|
||||
$(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 Makefile $(board_dir)/Makefile.include
|
||||
$(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 Makefile $(board_dir)/Makefile.include
|
||||
$(Q)mkdir -p `dirname $@`
|
||||
$(if $(Q), @echo " (CC) $(subst $(build_dir)/,,$@)")
|
||||
$(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -I`dirname $<` -c $< -o $@
|
||||
|
||||
# Clean. Remove only atomthread's object files and images
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf doxygen-kernel
|
||||
rm -rf doxygen-opencm3
|
||||
rm -rf $(build_dir)
|
||||
|
||||
# Real clean. Also clean libopencm3 if it was built in tree
|
||||
.PHONY: realclean
|
||||
realclean: clean
|
||||
ifeq ($(build_lib),true)
|
||||
$(Q)$(MAKE) -C libopencm3 V=$(V) clean
|
||||
endif
|
||||
|
||||
# Docs
|
||||
.PHONY: doxygen
|
||||
doxygen:
|
||||
doxygen $(kernel_dir)/Doxyfile
|
||||
ifeq ($(build_lib),true)
|
||||
$(Q)$(MAKE) -C libopencm3 V=$(V) doc
|
||||
endif
|
||||
|
||||
#################################################################################
|
||||
# Target flashing recipes "borrowed" from libopencm3-examples. Mostly untested. #
|
||||
#################################################################################
|
||||
|
||||
%.stlink-flash: $(build_dir)/%.bin
|
||||
$(if $(Q), @echo " (FLASH) $(subst $(build_dir)/,,$<)")
|
||||
$(Q)$(STFLASH) write $< 0x8000000
|
||||
|
||||
ifeq ($(STLINK_PORT),)
|
||||
ifeq ($(BMP_PORT),)
|
||||
ifeq ($(OOCD_SERIAL),)
|
||||
%.flash: $(build_dir)/%.hex
|
||||
$(if $(Q), @echo " (FLASH) $(subst $(build_dir)/,,$<)")
|
||||
@# 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 $<" \
|
||||
-c "reset" \
|
||||
-c "shutdown" $(NULL)
|
||||
else
|
||||
%.flash: $(build_dir)/%.hex
|
||||
$(if $(Q), @echo " (FLASH) $(subst $(build_dir)/,,$<)")
|
||||
@# 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 $<" \
|
||||
-c "reset" \
|
||||
-c "shutdown" $(NULL)
|
||||
endif
|
||||
else
|
||||
%.flash: $(build_dir)/%.elf
|
||||
$(if $(Q), @echo " (GDB) $(subst $(build_dir)/,,$<)")
|
||||
$(Q)$(GDB) --batch \
|
||||
-ex 'target extended-remote $(BMP_PORT)' \
|
||||
-x $(SCRIPT_DIR)/black_magic_probe_flash.scr \
|
||||
$<
|
||||
endif
|
||||
else
|
||||
%.flash: $(build_dir)/%.elf
|
||||
$(if $(Q), @echo " (GDB) $(subst $(build_dir)/,,$<)")
|
||||
$(Q)$(GDB) --batch \
|
||||
-ex 'target extended-remote $(STLINK_PORT)' \
|
||||
-x $(SCRIPT_DIR)/stlink_flash.scr \
|
||||
$<
|
||||
endif
|
||||
|
||||
# Include auto-generated dependencies
|
||||
-include $(all_objs:.o=.d)
|
||||
233
ports/cortex-m/README.md
Normal file
233
ports/cortex-m/README.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# ARM Cortex-M Port
|
||||
|
||||
Author: Tido Klaassen <tido@4gh.eu>
|
||||
|
||||
License: BSD Revised. Needs libopencm3, which is LGPLv3.
|
||||
|
||||
## Summary and Prerequisites
|
||||
This port should run on any Cortex-M0/3/4/4F (M0+ not tested).
|
||||
It uses RedHat's [newlib](https://sourceware.org/newlib/) and [libopencm3]
|
||||
(https://github.com/libopencm3/libopencm3). You will also need an ARM compiler
|
||||
toolchain. If you want to flash or debug your target, [openocd](http://openocd.org)
|
||||
is also a must. For STM32 targets [stlink](https://github.com/texane/stlink)
|
||||
might be helpful.
|
||||
|
||||
On Debian systems, compiler, newlib and openocd can easily be installed by the
|
||||
package manager (untested, not going to set up a new system just to test this):
|
||||
|
||||
```
|
||||
apt-get install gcc-arm-none-eabi binutils-arm-none-eabi
|
||||
apt-get install libnewlib-arm-none-eabi libnewlib-dev
|
||||
apt-get install openocd
|
||||
```
|
||||
|
||||
## Code Layout
|
||||
The "classic" port components (code needed for task set-up and context
|
||||
switching and the atomport{-private}.h headers) are residing in the
|
||||
top level port directory.
|
||||
|
||||
There are additional subdirectories:
|
||||
|
||||
* **boards** contains subdirectories for specific hardware. Each
|
||||
board needs at least a Makefile fragment, which defines certain variables
|
||||
describing the hardware used, as well as a list of extra object files needed.
|
||||
There will usually be at least a `board_setup.c`, which contains code to
|
||||
initialise the hardware properly (clocks, UART, systick timer, GPIOs, etc.).
|
||||
|
||||
* **common** contains code needed by multiple boards, such as
|
||||
stub functions for newlib or routines shared by multiple boards using the
|
||||
same family of target MCUs.
|
||||
|
||||
* **linker** contains linker script fragments for specific target MCUs. These
|
||||
just define the target's memory areas (RAM, Flash) and include libopencm3's
|
||||
main linker script for the appropriate chip family.
|
||||
|
||||
* **libopencm3** unless you compile and link against an external installation
|
||||
of libopencm3, this will be a Git submodule containing, surprise!, libopencm3.
|
||||
|
||||
* **build** this is a temporary directory where all object files end up in and
|
||||
which will be removed by `make clean`.
|
||||
|
||||
## Build Preparation
|
||||
Unless you decide to use an external installation of libopencm3, you will have
|
||||
to set up the libopencm3 sub-module:
|
||||
```
|
||||
git submodule add https://github.com/libopencm3/libopencm3.git
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
Optional: As of 2015-07-08 the libopencm3 API has not been declared stable. If
|
||||
future changes break the build, you can check out the older revision used while
|
||||
developing this port:
|
||||
```
|
||||
cd libopencm3
|
||||
git checkout a4bb8f7e240c9f238384cf86d009002ba42a25ed
|
||||
```
|
||||
|
||||
## Building and Flashing
|
||||
To build the test suite, run
|
||||
```
|
||||
make BOARD=*yourboard* all
|
||||
```
|
||||
where *yourboard* is the name of a directory in **boards**. If no BOARD is
|
||||
given, it defaults to nucleo-f103rb.
|
||||
|
||||
To build with an external libopencm3, run
|
||||
```
|
||||
make BOARD=*yourboard* OPENCM3_DIR=*/path/to/libopencm3* all
|
||||
```
|
||||
|
||||
Instead of building the whole test suite you can also just build a specific
|
||||
application image by giving its base name. If, for example, you only want
|
||||
to build the `queue2` test app, you can do that like this:
|
||||
```
|
||||
make BOARD=*yourboard* queue2
|
||||
```
|
||||
|
||||
If your board Makefile also sets up the necessary openocd variables, you can
|
||||
use it to flash the application image by appending `.flash` to its base name.
|
||||
```
|
||||
make BOARD=*yourboard* *yourimage*.flash
|
||||
```
|
||||
|
||||
N.B.: with the ek-lm4f120xl board openocd will report an error after flashing.
|
||||
I think it is because it can not handle the changed core clock after the
|
||||
application starts, but I simply can't be bothered to further investigate this.
|
||||
The application gets flashed and you can ignore the error.
|
||||
|
||||
## Adding New Boards
|
||||
To add support for a new board, you will have to provide at least two parts.
|
||||
First, a `Makefile.include` to be pulled in by the main Makefile. Second,
|
||||
some set-up code for your specific hardware. If there is no linker script for
|
||||
your MCU, you will have to add one, too.
|
||||
|
||||
### Board Makefile Fragment
|
||||
The main Makefile will include the Makefile.include located in the chosen
|
||||
board's sub-directory. This is where you set compile time options and additional
|
||||
source files to be used. Here is the one for the nucleo-f103rb:
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
* **TARGET** is the name for the actual MCU used on your board. It will be used
|
||||
to locate the linker script file in the `linker` directory by appending
|
||||
`.ld` to it.
|
||||
|
||||
* **LIBNAME** is the name of the opencm3 library to link your object files
|
||||
against.
|
||||
|
||||
* **DEFS** are flags that will be appended to the CPPFLAGS. You will at least
|
||||
have to define the opencm3 target family (STM32F1 here), so the build process
|
||||
will find the right header files to include. If you are using the stub and
|
||||
console functions provided in the common directory, you will also have to
|
||||
define the reserved main stack size (MST_SIZE) and which UART to use for stdio
|
||||
(STD_CON).
|
||||
|
||||
* **FP_FLAGS** which floating point format to use. For MCUs without hardware
|
||||
support for floating point (M0/3, sometimes 4), use `-msoft-float`,
|
||||
otherwise use `-mfloat-abi=hard -mfpu=fpv4-sp-d16`. You could add these
|
||||
directly to `ARCH_FLAGS`, but this way it is easily overridden from the
|
||||
make command line.
|
||||
|
||||
* **ARCH_FLAGS** specify the instruction (sub)set and CPU type to compile for,
|
||||
as well as any quirk tunings needed and the `FP_FLAGS`. These flags are
|
||||
handed to preprocessor, compiler, assembler and linker.
|
||||
|
||||
The following flags are only used for flashing the target with openocd:
|
||||
|
||||
* **OOCD** binary to call. Give full path if it is not in your PATH environment
|
||||
variable.
|
||||
|
||||
* **OOCD_INTERFACE** tells open which interface configuration to use
|
||||
|
||||
* **OOCD_BOARD** tells openocd which board configuration file to use.
|
||||
|
||||
* **objs** here you _append_ object files to include into _all_ binaries
|
||||
built for this board. The main Makefile will search for matching source files
|
||||
(*.c and *.S) in the main port directory, the board directory and the common
|
||||
directory. You will usually have at least a `board_setup.c` specific to
|
||||
your hardware and pull in the system and stdio stubs provided in the
|
||||
`common` directory.
|
||||
|
||||
* **aobjs** the build system will build one application for each object you
|
||||
add to this variable. It will do so by linking each of these objects with all
|
||||
of the kernel-, port- and board-objects (but none of the testsuite-objects).
|
||||
The source for the app-object should be located in either the board or
|
||||
common directory and must contain the application's `main()` function.
|
||||
The `helloworld.c` file in the common directory is provided as an example.
|
||||
|
||||
As you will probably know, variables assigned with the `?=` operator are
|
||||
only altered if they have not been already set. This way you can easily test
|
||||
different options for a build by providing the variables on the make command
|
||||
line.
|
||||
|
||||
### Board-Specific Set-up
|
||||
All hardware needs to be initialised to some degree before it is ready to run
|
||||
atomthread's kernel. At the very least you will have to
|
||||
|
||||
1. mask interrupts
|
||||
2. set up the main clock and configure the systick timer
|
||||
3. configure console UART
|
||||
4. configure GPIOs
|
||||
|
||||
(Steps 3. and 4. might be optional if you do not plan to let your board
|
||||
interact with the outside world in any way...)
|
||||
|
||||
The test suite programs expect your board set-up code to provide a function
|
||||
named `int board_setup(void)` to perform this tasks.
|
||||
|
||||
### Linker Script
|
||||
If you are using an hitherto unknown target MCU, you will have to provide a
|
||||
linker script for it in the `linker` directory. The script's name must
|
||||
be the same as given to the `TARGET` variable in your Makefile.include,
|
||||
with the extension `.ld` added. It is recommended that you just define
|
||||
your MCU's memory regions and include libopencm3's linker file for your
|
||||
target's product family. Please look at the provided linker files for examples
|
||||
on how to do this.
|
||||
|
||||
## Port Internals
|
||||
The Cortex-M port is different from the other architectures insofar as it makes
|
||||
use of two particular features. First, it uses separate stacks for thread and
|
||||
exception context. When the core enters exception mode, it first pushes xPSR,
|
||||
PC, LR, r0-r3 and r12 on the currently active stack (probably the thread stack
|
||||
in PSP) and then switches to the main stack stored in MSP. It also stores a
|
||||
special EXC_RETURN code in LR which, when loaded into the PC, will determine
|
||||
if on return program execution continues to use the MSP or switches over to
|
||||
the PSP and, on cores with an FPU, whether FPU registers need to be restored.
|
||||
The Cortex-M also implements a nested vectored interrupt controller (NVIC),
|
||||
which means that a running ISR may be pre-empted by an exception of higher
|
||||
priority.
|
||||
|
||||
The use of separate stacks for thread and exception context has the nice
|
||||
implication that you do not have to reserve space on every task's stack for
|
||||
possible use by ISRs. But it also means that it breaks atomthreads concept
|
||||
of simply swapping task stacks, regardless of if atomSched() was called from
|
||||
thread or interrupt context. We would have to implement different
|
||||
archContextSwitch() functions called from thread or exception context and
|
||||
also do messy stack manipulations depending on whether the task to be
|
||||
scheduled in was scheduled out in in the same context or not. Yuck!
|
||||
And don't get me started on nested exceptions calling atomIntExit()...
|
||||
|
||||
This is where the second feature comes handy, the PendSV mechanism.
|
||||
PendSV is an asynchronous exception with the lowest possible priority, which
|
||||
means that, when triggered, it will be called by the NVIC if there are no
|
||||
other exceptions pending or running. We use it by having archContextSwitch()
|
||||
set up a pointer to the TCB that should be scheduled in and then trigger the
|
||||
PendSv exception. As soon as program flow leaves the critical section or
|
||||
performs the outermost exception return, the pend_sv_handler() will be called
|
||||
and the thread context switch takes place.
|
||||
361
ports/cortex-m/atomport-asm.S
Normal file
361
ports/cortex-m/atomport-asm.S
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
/**
|
||||
* Create more readable defines for usable intruction set and FPU
|
||||
*/
|
||||
#undef THUMB_2
|
||||
#undef WITH_FPU
|
||||
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
#define THUMB_2
|
||||
#endif
|
||||
|
||||
#if defined(__VFP_FP__) && !defined(__SOFTFP__)
|
||||
#define WITH_FPU
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Extern variables needed for context switching and first thread restore
|
||||
*/
|
||||
.extern CTX_SW_NFO
|
||||
.extern vector_table
|
||||
|
||||
/**
|
||||
* Some bit masks and registers used
|
||||
*/
|
||||
.equ FPU_USED, 0x00000010
|
||||
.equ SCB_ICSR, 0xE000ED04
|
||||
.equ PENDSVCLR, 0x08000000
|
||||
|
||||
.text
|
||||
|
||||
.global archFirstThreadRestore
|
||||
.func archFirstThreadRestore
|
||||
.type archFirstThreadRestore,%function
|
||||
.thumb_func
|
||||
archFirstThreadRestore:
|
||||
/**
|
||||
* Disable interrupts. They should be disabled anyway, but just
|
||||
* to make sure...
|
||||
*/
|
||||
movs 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 r1, [r0, #0]
|
||||
msr PSP, r1
|
||||
|
||||
/**
|
||||
* Set bit #1 in CONTROL. Causes switch to PSP, so we can work directly
|
||||
* with SP now and use pop/push.
|
||||
*/
|
||||
movs r1, #2
|
||||
mrs r2, CONTROL
|
||||
orrs r2, r2, r1
|
||||
msr CONTROL, r2
|
||||
|
||||
/**
|
||||
* Initialise thread's register context from its stack frame. Since this
|
||||
* function gets called only once at system start up, execution time is
|
||||
* not critical. We can get away with using only Thumb-1 instructions that
|
||||
* will work on all Cortex-M devices.
|
||||
*
|
||||
* Initial stack looks like this:
|
||||
* xPSR
|
||||
* PC
|
||||
* lr
|
||||
* r12
|
||||
* r3
|
||||
* r2
|
||||
* r1
|
||||
* r0
|
||||
* exc_ret <- ignored here
|
||||
* r11
|
||||
* r10
|
||||
* r9
|
||||
* r8
|
||||
* r7
|
||||
* r6
|
||||
* r5
|
||||
* r4 <- thread's saved_sp points here
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Move SP to position of r8 and restore high registers by loading
|
||||
* them to r4-r7 before moving them to r8-r11
|
||||
*/
|
||||
add SP, #16
|
||||
pop {r4-r7}
|
||||
mov r8, r4
|
||||
mov r9, r5
|
||||
mov r10, r6
|
||||
mov r11, r7
|
||||
|
||||
/* move SP back to top of stack and load r4-r7 */
|
||||
sub SP, #32
|
||||
pop {r4-r7}
|
||||
|
||||
/*load r12, lr, pc and xpsr to r0-r3 and restore r12 and lr */
|
||||
add SP, #36
|
||||
pop {r0-r3}
|
||||
mov r12, r0
|
||||
mov lr, r1
|
||||
|
||||
/**
|
||||
* r2 contains the PC and r3 APSR, SP is now at the bottom of the stack. We
|
||||
* can't initialise APSR now because we will have to do a movs later when
|
||||
* enabling interrupts, so r3 must not be touched. We also need an extra
|
||||
* register holding the value that will be moved to PRIMASK. To do this,
|
||||
* we build a new stack containing only the initial values of r2, r3
|
||||
* and pc. In the end this will be directly popped into the registers,
|
||||
* finishing the thread restore and branching to the thread's entry point.
|
||||
*/
|
||||
|
||||
/* Save PC value */
|
||||
push {r2}
|
||||
|
||||
/* Move values for r2 and r3 to lie directly below value for pc */
|
||||
sub SP, #20
|
||||
pop {r1-r2}
|
||||
add SP, #12
|
||||
push {r1-r2}
|
||||
|
||||
/* Load values for r0 and r1 from stack */
|
||||
sub SP, #20
|
||||
pop {r0-r1}
|
||||
|
||||
/* Move SP to start of our new r2,r3,pc mini stack */
|
||||
add SP, #12
|
||||
|
||||
/* Restore xPSR and enable interrupts */
|
||||
movs r2, #0
|
||||
msr APSR_nzcvq, r3
|
||||
msr PRIMASK, r2
|
||||
|
||||
/* Pop r2,r3,pc from stack, thereby jumping to thread entry point */
|
||||
pop {r2,r3,pc}
|
||||
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...
|
||||
*/
|
||||
movs r0, #1
|
||||
msr PRIMASK, r0
|
||||
|
||||
/**
|
||||
* Clear PendSv pending bit. There seems to exist a hardware race condition
|
||||
* in the NVIC that can prevent automatic clearing of the PENDSVSET. See
|
||||
* http://embeddedgurus.com/state-space/2011/09/whats-the-state-of-your-cortex/
|
||||
*/
|
||||
ldr r0, = SCB_ICSR
|
||||
ldr r1, = PENDSVCLR
|
||||
str r1, [r0, #0]
|
||||
|
||||
/**
|
||||
* Check if running and next thread are really different.
|
||||
* From here on we have
|
||||
* r0 = &ctx_switch_info
|
||||
* r1 = ctx_switch_info.running_tcb
|
||||
* r2 = ctx_switch_info.next_tcb
|
||||
*
|
||||
* If r1 == r2 we can skip the context switch. This may theoretically
|
||||
* happen if the running thread gets scheduled out and in again by
|
||||
* multiple nested or tail-chained ISRs before the PendSv handler
|
||||
* gets called.
|
||||
*/
|
||||
ldr r0, = CTX_SW_NFO
|
||||
ldr r1, [r0, #0]
|
||||
ldr r2, [r0, #4]
|
||||
cmp r1, r2
|
||||
beq no_switch
|
||||
|
||||
/**
|
||||
* Copy running thread's process stack pointer to r3 and use it to push
|
||||
* */
|
||||
mrs r3, PSP
|
||||
|
||||
#if defined(THUMB_2)
|
||||
/**
|
||||
* Save old thread's context on Cortex-M[34]
|
||||
*/
|
||||
|
||||
#if defined(WITH_FPU)
|
||||
/* 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 // WITH_FPU
|
||||
|
||||
/* Push running thread's remaining registers on stack */
|
||||
stmdb r3!, {r4-r11, lr}
|
||||
|
||||
#else // !THUMB2
|
||||
|
||||
/**
|
||||
* Save old thread's register context on Cortex-M0.
|
||||
* Push running thread's remaining registers on stack.
|
||||
* Thumb-1 can only use stm on low registers, so we
|
||||
* have to do this in two steps.
|
||||
*/
|
||||
|
||||
/* Reserve space for r8-r11 + exc_return before storing r4-r7 */
|
||||
subs r3, r3, #36
|
||||
stmia r3!, {r4-r7}
|
||||
|
||||
/**
|
||||
* Move r8-r11 to low registers and use store multiple with automatic
|
||||
* post-increment to push them on the stack
|
||||
*/
|
||||
mov r4, r8
|
||||
mov r5, r9
|
||||
mov r6, r10
|
||||
mov r7, r11
|
||||
stmia r3!, {r4-r7}
|
||||
|
||||
/**
|
||||
* Move lr (contains the exc_return code) to low registers and store it
|
||||
* on the stack.
|
||||
*/
|
||||
mov r4, lr
|
||||
str r4, [r3, #0]
|
||||
|
||||
/* Re-adjust r3 to point at top of stack */
|
||||
subs r3, r3, #32
|
||||
#endif // !THUMB_2
|
||||
/**
|
||||
* Address of running TCB still in r1. Store threads current stack top
|
||||
* into its sp_save_ptr, which is the struct's first element
|
||||
*/
|
||||
str r3, [r1, #0]
|
||||
|
||||
/**
|
||||
* ctx_switch_info.next_tcb is going to become ctx_switch_info.running_tcb,
|
||||
* so we update the pointer.
|
||||
*/
|
||||
str r2, [r0, #0]
|
||||
|
||||
/**
|
||||
* Fetch next thread's stack pointer from its TCB's sp_save_ptr and restore
|
||||
* the thread's register context.
|
||||
*/
|
||||
ldr r3, [r2, #0]
|
||||
|
||||
#if defined(THUMB_2)
|
||||
|
||||
/* Cortex-M[34], restore thread's task stack frame */
|
||||
ldmia r3!, {r4-r11, lr}
|
||||
|
||||
#if defined(WITH_FPU)
|
||||
/**
|
||||
* 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 // WITH_FPU
|
||||
#else // !THUMB_2
|
||||
|
||||
/**
|
||||
* Thread restore for Cortex-M0
|
||||
* Restore thread's task stack frame. Because thumb 1 only supports
|
||||
* load multiple on low register, we have to do it in two steps and
|
||||
* adjust the stack pointer manually.
|
||||
*/
|
||||
|
||||
/* Restore high registers */
|
||||
adds r3, r3, #16
|
||||
ldmia r3!, {r4-r7}
|
||||
mov r8, r4
|
||||
mov r9, r5
|
||||
mov r10, r6
|
||||
mov r11, r7
|
||||
|
||||
/* Restore lr */
|
||||
ldr r4, [r3, #0]
|
||||
mov lr, r4
|
||||
subs r3, r3, #32
|
||||
|
||||
/**
|
||||
* Restore r4-r7 and adjust r3 to point at the top of the exception
|
||||
* stack frame.
|
||||
*/
|
||||
ldmia r3!, {r4-r7}
|
||||
adds r3, r3, #20
|
||||
#endif // !THUMB_2
|
||||
|
||||
/* Set process stack pointer to new thread's stack*/
|
||||
msr PSP, r3
|
||||
|
||||
no_switch:
|
||||
/* Re-enable interrupts */
|
||||
movs r0, #0
|
||||
msr PRIMASK, r0
|
||||
|
||||
/* Return to new thread */
|
||||
bx lr
|
||||
nop
|
||||
.size pend_sv_handler, . - pend_sv_handler
|
||||
.endfunc
|
||||
117
ports/cortex-m/atomport-private.h
Normal file
117
ports/cortex-m/atomport-private.h
Normal 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;
|
||||
} __attribute__((packed));
|
||||
|
||||
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;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* 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 exc_ret;
|
||||
} __attribute__((packed));
|
||||
|
||||
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;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* 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;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* __ATOMPORT_PRIVATE_H_ */
|
||||
47
ports/cortex-m/atomport-tests.h
Normal file
47
ports/cortex-m/atomport-tests.h
Normal 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 */
|
||||
|
||||
205
ports/cortex-m/atomport.c
Normal file
205
ports/cortex-m/atomport.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Enforce initial stack alignment
|
||||
*/
|
||||
stack_top = STACK_ALIGN(stack_top, STACK_ALIGN_SIZE);
|
||||
|
||||
/**
|
||||
* 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 = 0xEEEEEEEE;
|
||||
isr_ctx->r12 = 0xCCCCCCCC;
|
||||
isr_ctx->r3 = 0x33333333;
|
||||
isr_ctx->r2 = 0x22222222;
|
||||
isr_ctx->r1 = 0x11111111;
|
||||
isr_ctx->r0 = 0x00000000;
|
||||
|
||||
/**
|
||||
* We use this special EXC_RETURN code to switch from main stack to our
|
||||
* thread stack on exception return
|
||||
*/
|
||||
tsk_ctx->exc_ret = 0xFFFFFFFD;
|
||||
|
||||
/* initialise unused registers to silly value */
|
||||
tsk_ctx->r11 = 0xBBBBBBBB;
|
||||
tsk_ctx->r10 = 0xAAAAAAAA;
|
||||
tsk_ctx->r9 = 0x99999999;
|
||||
tsk_ctx->r8 = 0x88888888;
|
||||
tsk_ctx->r7 = 0x77777777;
|
||||
tsk_ctx->r6 = 0x66666666;
|
||||
tsk_ctx->r5 = 0x55555555;
|
||||
tsk_ctx->r4 = 0x44444444;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
67
ports/cortex-m/atomport.h
Normal file
67
ports/cortex-m/atomport.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 ALIGN(x, a) ((x + (typeof(x))(a) - 1) & ~((typeof(x))(a) - 1))
|
||||
#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((uint32_t)(p), (a)))
|
||||
#define STACK_ALIGN(p, a) (typeof(p))((typeof(a))(p) & ~((a) - 1))
|
||||
|
||||
#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 */
|
||||
17
ports/cortex-m/boards/ek-lm4f120xl/Makefile.include
Normal file
17
ports/cortex-m/boards/ek-lm4f120xl/Makefile.include
Normal file
@@ -0,0 +1,17 @@
|
||||
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
|
||||
# aobjs += helloworld.o
|
||||
141
ports/cortex-m/boards/ek-lm4f120xl/board_setup.c
Normal file
141
ports/cortex-m/boards/ek-lm4f120xl/board_setup.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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 <libopencm3/cm3/nvic.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 suite 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();
|
||||
|
||||
/* Set exception priority levels. Make PendSv the lowest priority and
|
||||
* SysTick the second to lowest
|
||||
*/
|
||||
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
|
||||
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
17
ports/cortex-m/boards/nucleo-f072rb/Makefile.include
Normal file
17
ports/cortex-m/boards/nucleo-f072rb/Makefile.include
Normal file
@@ -0,0 +1,17 @@
|
||||
TARGET ?= stm32f072rb
|
||||
|
||||
LIBNAME ?= opencm3_stm32f0
|
||||
DEFS ?= -DSTM32F0
|
||||
DEFS += -DSTD_CON=USART2
|
||||
DEFS += -DMST_SIZE=0x400
|
||||
|
||||
FP_FLAGS ?= -msoft-float
|
||||
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m0
|
||||
|
||||
OOCD ?= openocd
|
||||
OOCD_INTERFACE ?= stlink-v2-1
|
||||
OOCD_BOARD ?= st_nucleo_f0
|
||||
|
||||
objs += board_setup.o
|
||||
objs += stubs.o stm32_con.o
|
||||
# aobjs += helloworld.o
|
||||
134
ports/cortex-m/boards/nucleo-f072rb/board_setup.c
Normal file
134
ports/cortex-m/boards/nucleo-f072rb/board_setup.c
Normal 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/stm32/rcc.h>
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <libopencm3/stm32/usart.h>
|
||||
#include <libopencm3/cm3/systick.h>
|
||||
#include <libopencm3/cm3/cortex.h>
|
||||
#include <libopencm3/cm3/nvic.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_AF1, GPIO2 | GPIO3);
|
||||
|
||||
usart_set_baudrate(USART2, baud);
|
||||
usart_set_databits(USART2, 8);
|
||||
usart_set_parity(USART2, USART_PARITY_NONE);
|
||||
usart_set_stopbits(USART2, USART_CR2_STOP_1_0BIT);
|
||||
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, 48000000);
|
||||
|
||||
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 48MHz, generated from PIOSC */
|
||||
rcc_clock_setup_in_hsi_out_48mhz();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up user LED and provide function for toggling it. This is for
|
||||
* use by the test suite 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();
|
||||
|
||||
/* Set exception priority levels. Make PendSv the lowest priority and
|
||||
* SysTick the second to lowest
|
||||
*/
|
||||
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
|
||||
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
17
ports/cortex-m/boards/nucleo-f103rb/Makefile.include
Normal file
17
ports/cortex-m/boards/nucleo-f103rb/Makefile.include
Normal file
@@ -0,0 +1,17 @@
|
||||
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
|
||||
# aobjs += helloworld.o
|
||||
138
ports/cortex-m/boards/nucleo-f103rb/board_setup.c
Normal file
138
ports/cortex-m/boards/nucleo-f103rb/board_setup.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 <libopencm3/cm3/nvic.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 suite 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();
|
||||
|
||||
/* Set exception priority levels. Make PendSv the lowest priority and
|
||||
* SysTick the second to lowest
|
||||
*/
|
||||
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
|
||||
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
17
ports/cortex-m/boards/nucleo-f411re/Makefile.include
Normal file
17
ports/cortex-m/boards/nucleo-f411re/Makefile.include
Normal file
@@ -0,0 +1,17 @@
|
||||
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
|
||||
# aobjs += helloworld.o
|
||||
136
ports/cortex-m/boards/nucleo-f411re/board_setup.c
Normal file
136
ports/cortex-m/boards/nucleo-f411re/board_setup.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 <libopencm3/cm3/nvic.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 suite 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();
|
||||
|
||||
/* Set exception priority levels. Make PendSv the lowest priority and
|
||||
* SysTick the second to lowest
|
||||
*/
|
||||
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
|
||||
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
27
ports/cortex-m/boards/qemu/Makefile.include
Normal file
27
ports/cortex-m/boards/qemu/Makefile.include
Normal file
@@ -0,0 +1,27 @@
|
||||
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
|
||||
# aobjs += helloworld.o
|
||||
|
||||
# Special requirements for running automated tests with QEMU
|
||||
|
||||
QEMU ?= qemu-system-gnuarmeclipse
|
||||
.DEFAULT_GOAL := all
|
||||
.SECONDEXPANSION:
|
||||
|
||||
.PHONY: qemutests
|
||||
qemutests: $$(addsuffix .sim, $$(sort $$(build_telfs)))
|
||||
|
||||
%.sim: $$(basename $$@)
|
||||
boards/qemu/run_test.exp $(QEMU) $(*)
|
||||
31
ports/cortex-m/boards/qemu/README.md
Normal file
31
ports/cortex-m/boards/qemu/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
This board is a quick n' dirty copy of nucleo-f103rb, stripped down to run
|
||||
atomthread's test suite on qemu. Since it must be linked against newlib's
|
||||
librdimon to enable semi-hosting, the stubs provided in the common directory
|
||||
can not be used. Do not be surprised if malloc etc. do not work as expected.
|
||||
|
||||
The [GNU ARM Eclipse](http://gnuarmeclipse.livius.net/blog/) project maintains
|
||||
a fork of qemu that is able to emulate a Nucleo-F103RB board. Check out their
|
||||
gnuarmeclipse-dev branch from [here]
|
||||
(http://sourceforge.net/p/gnuarmeclipse/qemu/ci/gnuarmeclipse-dev/tree/).
|
||||
|
||||
At time of writing (2015-07-13), I had to run configure with
|
||||
`--disable-werror --target-list="gnuarmeclipse-softmmu"` to build
|
||||
a usable target.
|
||||
|
||||
After installing you can use it to run the test binaries like this:
|
||||
|
||||
```
|
||||
qemu-system-gnuarmeclipse -nographic -monitor null \
|
||||
-semihosting --machine NUCLEO-F103RB \
|
||||
--verbose --kernel build/kern1.elf
|
||||
```
|
||||
|
||||
The whole test suite can be run in an automatic way from the build system by
|
||||
using the tool `expect`.
|
||||
|
||||
```
|
||||
make BOARD=qemu QEMU=/path/to/your/qemu/binary qemutests
|
||||
```
|
||||
|
||||
If your qemu-binary is called `qemu-system-gnuarmeclipse` and is located
|
||||
in your search path, you can omit the `QEMU=...` part.
|
||||
119
ports/cortex-m/boards/qemu/board_setup.c
Normal file
119
ports/cortex-m/boards/qemu/board_setup.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 <libopencm3/cm3/nvic.h>
|
||||
|
||||
#include "atomport.h"
|
||||
|
||||
/**
|
||||
* initialise and start SysTick counter. This will trigger the
|
||||
* sys_tick_handler() periodically once interrupts have been enabled
|
||||
* by archFirstThreadRestore(). Since we did not change the clock source,
|
||||
* the MCU is still running from 16MHz PIOSC
|
||||
*/
|
||||
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().
|
||||
*/
|
||||
/**
|
||||
* Set up user LED and provide function for toggling it. This is for
|
||||
* use by the test suite 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)
|
||||
{
|
||||
static bool on = true;
|
||||
|
||||
/* qemu does not seem to know how to handle gpio_toggle() */
|
||||
if(on){
|
||||
gpio_clear(GPIOA, GPIO5);
|
||||
} else {
|
||||
gpio_set(GPIOA, GPIO5);
|
||||
}
|
||||
|
||||
on = !on;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from your main program to set up the board's hardware before
|
||||
* the kernel is started.
|
||||
*/
|
||||
extern void initialise_monitor_handles(void);
|
||||
int board_setup(void)
|
||||
{
|
||||
/* initialise semi-hosting */
|
||||
initialise_monitor_handles();
|
||||
|
||||
/* 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 user LED*/
|
||||
test_led_setup();
|
||||
|
||||
/* initialise SysTick counter */
|
||||
systick_setup();
|
||||
|
||||
/* Set exception priority levels. Make PendSv the lowest priority and
|
||||
* SysTick the second to lowest
|
||||
*/
|
||||
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
|
||||
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
40
ports/cortex-m/boards/qemu/run_test.exp
Executable file
40
ports/cortex-m/boards/qemu/run_test.exp
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env expect
|
||||
|
||||
# Expect script to run an automated test within the simulator (QEMU) and
|
||||
# check for successful completion.
|
||||
#
|
||||
# Arguments: <path_to_qemu> <test_elf_file>
|
||||
#
|
||||
# Returns 0 on successful test run within QEMU, 1 on failure
|
||||
|
||||
|
||||
# Start the test
|
||||
spawn [lindex $argv 0] -nographic -monitor null -semihosting \
|
||||
--machine NUCLEO-F103RB --kernel [lindex $argv 1]
|
||||
|
||||
# Expect to see the test starting within 10 seconds
|
||||
set timeout 10
|
||||
|
||||
# Wait for the test to start ("Go")
|
||||
expect {
|
||||
"Go" {
|
||||
puts "Test started"
|
||||
|
||||
# The test could take up to 3 minutes to complete once started
|
||||
set timeout 180
|
||||
|
||||
# Now expect to see "Pass" or "Fail" within 3 minutes
|
||||
expect {
|
||||
"Pass" { puts "Test passed"; exit 0 }
|
||||
"Fail" { puts "Test failed"; exit 1 }
|
||||
timeout { puts "Test timed out without completing"; exit 1 }
|
||||
}
|
||||
}
|
||||
|
||||
timeout {
|
||||
# Didn't receive "Go" within 10 seconds
|
||||
puts "Test failed to start ('Go' not seen)"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
100
ports/cortex-m/common/helloworld.c
Normal file
100
ports/cortex-m/common/helloworld.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#include "atom.h"
|
||||
#include "atomport-private.h"
|
||||
#include "atomtimer.h"
|
||||
|
||||
#define STACK_SIZE 1024
|
||||
#define THREAD_PRIO 42
|
||||
|
||||
static ATOM_TCB main_tcb;
|
||||
|
||||
static uint8_t thread_stacks[2][STACK_SIZE];
|
||||
|
||||
static void main_thread_func(uint32_t data);
|
||||
|
||||
/**
|
||||
* Example for a stand-alone board application
|
||||
*/
|
||||
extern int board_setup(void);
|
||||
int main(void)
|
||||
{
|
||||
int8_t status;
|
||||
uint32_t loop;
|
||||
|
||||
/**
|
||||
* Brief delay to give the debugger a chance to stop the core before we
|
||||
* muck around with the chip's configuration.
|
||||
*/
|
||||
for(loop = 0;loop < 1000000;++loop){
|
||||
__asm__("nop");
|
||||
}
|
||||
|
||||
board_setup();
|
||||
|
||||
/**
|
||||
* Initialise OS and set up idle thread
|
||||
*/
|
||||
status = atomOSInit(&thread_stacks[0][0], STACK_SIZE, FALSE);
|
||||
|
||||
if(status == ATOM_OK){
|
||||
/* Set up main thread */
|
||||
status = atomThreadCreate(&main_tcb, THREAD_PRIO, main_thread_func, 0,
|
||||
&thread_stacks[1][0], STACK_SIZE, TRUE);
|
||||
|
||||
if(status == ATOM_OK){
|
||||
atomOSStart();
|
||||
}
|
||||
}
|
||||
|
||||
while(1)
|
||||
;
|
||||
|
||||
/* We will never get here */
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void test_led_toggle(void);
|
||||
static void main_thread_func(uint32_t data __maybe_unused)
|
||||
{
|
||||
/* Print message */
|
||||
printf("Hello, world!\n");
|
||||
|
||||
/* Loop forever and blink the LED */
|
||||
while(1){
|
||||
test_led_toggle();
|
||||
|
||||
atomTimerDelay(SYSTEM_TICKS_PER_SEC);
|
||||
}
|
||||
|
||||
}
|
||||
93
ports/cortex-m/common/lm4f_con.c
Normal file
93
ports/cortex-m/common/lm4f_con.c
Normal 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;
|
||||
}
|
||||
92
ports/cortex-m/common/stm32_con.c
Normal file
92
ports/cortex-m/common/stm32_con.c
Normal 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;
|
||||
}
|
||||
|
||||
116
ports/cortex-m/common/stubs.c
Normal file
116
ports/cortex-m/common/stubs.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#include "atomport.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 __maybe_unused)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _fstat(int file __maybe_unused, struct stat *st)
|
||||
{
|
||||
st->st_mode = S_IFCHR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _isatty(int file __maybe_unused)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _lseek(int file __maybe_unused,
|
||||
int ptr __maybe_unused,
|
||||
int dir __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _open(const char *name __maybe_unused,
|
||||
int flags __maybe_unused,
|
||||
int mode __maybe_unused)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
10
ports/cortex-m/linker/lm4f120xl.ld
Normal file
10
ports/cortex-m/linker/lm4f120xl.ld
Normal 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
|
||||
10
ports/cortex-m/linker/stm32f072rb.ld
Normal file
10
ports/cortex-m/linker/stm32f072rb.ld
Normal file
@@ -0,0 +1,10 @@
|
||||
/* Memory regions for STM32F072RB, 128K flash, 16K RAM. */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
|
||||
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
|
||||
}
|
||||
|
||||
/* Include main opencm3 linker script */
|
||||
INCLUDE libopencm3_stm32f0.ld
|
||||
10
ports/cortex-m/linker/stm32f103rb.ld
Normal file
10
ports/cortex-m/linker/stm32f103rb.ld
Normal 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
|
||||
10
ports/cortex-m/linker/stm32f411re.ld
Normal file
10
ports/cortex-m/linker/stm32f411re.ld
Normal 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
|
||||
283
ports/cortex-m/tests-main.c
Normal file
283
ports/cortex-m/tests-main.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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 <libopencm3/cm3/nvic.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;
|
||||
uint32_t loop;
|
||||
|
||||
/**
|
||||
* Brief delay to give the debugger a chance to stop the core before we
|
||||
* muck around with the chip's configuration.
|
||||
*/
|
||||
for(loop = 0; loop < 1000000; ++loop){
|
||||
__asm__("nop");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 __maybe_unused)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user