README.md: wrote section about adding new boards

Renamed board Makefile fragments to Makefile.include
board_setup.c: initialise NVIC priorities for PendSv and SysTick
General cleanup
This commit is contained in:
Tido Klaassen
2015-07-12 16:28:48 +02:00
parent ca81d186a7
commit 3cc6b9bea4
13 changed files with 206 additions and 61 deletions

View File

@@ -1,5 +1,5 @@
################################################
# Toplevel makefile for all libopencm3 targets #
# Toplevel makefile for all Cortex-M targets #
################################################
ifeq ($(V),)
@@ -20,13 +20,14 @@ 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 $(src_dir)/boards/$(BOARD)/Makefile.include
# Make sure target MCU is set
ifndef TARGET
@@ -135,22 +136,24 @@ LDLIBS += -l$(LIBNAME)
## Flags for newlibc.
# This uses the version of newlib optimised for size and without libnosys.
# This is the configuration you want to use unless you really know what
# you are doing.
# 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 optimized for speed.
# 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
# because libnosys' standard _sbrk() expects the stack to start at the top
# end of memory while the threads' stacks are positioned inside the BSS.
# 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
# All
.PHONY: all
all: $(LIB_DIR)/lib$(LIBNAME).a $(build_tbins) $(build_thexs) $(build_telfs) $(build_tobjs) $(build_objs) Makefile
all: $(LIB_DIR)/lib$(LIBNAME).a $(build_tbins) $(build_thexs) $(build_telfs) $(build_tobjs) $(build_objs) Makefile $(board_dir)/Makefile.include
# add build dependency for local libopencm3 if no external libopencm3 is used
$(LIB_DIR)/lib$(LIBNAME).a: $(lib_needed)
@@ -170,8 +173,6 @@ build_lib:
fi
$(Q)$(MAKE) -C libopencm3
flash: $(BINARY).flash
$(build_dir)/%.bin: $(build_dir)/%.elf
$(Q)mkdir -p `dirname $@`
$(if $(Q), @echo " (OBJCOPY) $(subst $(build_dir)/,,$@)")
@@ -197,32 +198,42 @@ $(build_dir)/%.elf $(build_dir)/%.map: $(build_dir)/%.o $(build_objs) $(LDSCRIPT
$(if $(Q), @echo " (ELF) $(subst $(build_dir)/,,$@)")
$(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(build_objs) $(build_dir)/$(*).o $(LDLIBS) -o $@
$(build_dir)/%.o: $(src_dir)/%.S Makefile
$(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
$(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)/%.c Makefile
$(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)/%.c Makefile
$(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
$(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
$(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 $@
@@ -243,6 +254,11 @@ doxygen:
doxygen $(kernel_dir)/Doxyfile
doxygen ./Doxyfile
################################################################
# target flashing recipes "borrowed" from libopencm3-examples #
################################################################
flash: $(BINARY).flash
%.stlink-flash: $(build_dir)/%.bin
@printf " FLASH $<\n"
$(Q)$(STFLASH) write $(build_dir)/$(*).bin 0x8000000

View File

@@ -1,8 +1,8 @@
# ARM Cortex-M Port
## 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]
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)
@@ -18,24 +18,24 @@ apt-get install openocd
```
## Code Layout
The "classic" port components (code needed for task setup and context
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, 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)
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 memory areas (RAM, Flash) of the chip and include libopencm3's
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
@@ -77,13 +77,108 @@ use it to flash the application image:
```
make BOARD=*yourboard* BINARY=*yourimage* flash
```
N.B.: with the ek-lm4f120xl board openocd will report an error after flashing.
NB: 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
*TODO*
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 config to use
**OOCD_BOARD** tells openocd which board config 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.
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 Setup
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 suit 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
@@ -95,7 +190,7 @@ 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 preempted by an exception of higher
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

View File

@@ -36,7 +36,7 @@
#define THUMB_2
#endif
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
#if defined(__VFP_FP__) && !defined(__SOFTFP__)
#define WITH_FPU
#endif

View File

@@ -1,16 +0,0 @@
TARGET := lm4f120xl
LIBNAME = opencm3_lm4f
DEFS = -DLM4F
DEFS += -DSTD_CON=UART0
DEFS += -DMST_SIZE=0x400
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
OOCD ?= openocd
OOCD_INTERFACE ?= ti-icdi
OOCD_BOARD ?= ek-lm4f120xl
objs += board_setup.o
objs += stubs.o lm4f_con.o

View File

@@ -0,0 +1,16 @@
TARGET ?= lm4f120xl
LIBNAME ?= opencm3_lm4f
DEFS ?= -DLM4F
DEFS += -DSTD_CON=UART0
DEFS += -DMST_SIZE=0x400
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
OOCD ?= openocd
OOCD_INTERFACE ?= ti-icdi
OOCD_BOARD ?= ek-lm4f120xl
objs += board_setup.o
objs += stubs.o lm4f_con.o

View File

@@ -34,6 +34,7 @@
#include <libopencm3/lm4f/uart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
@@ -127,8 +128,14 @@ int board_setup(void)
test_led_setup();
uart_setup(115200);
/* initialise SysTick counter */
/* 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;
}

View File

@@ -1,11 +1,11 @@
TARGET := stm32f072rb
LIBNAME = opencm3_stm32f0
DEFS = -DSTM32F0
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
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m0
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2-1

View File

@@ -34,6 +34,7 @@
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
@@ -80,7 +81,7 @@ static void systick_setup(void)
*/
static void clock_setup(void)
{
/* set core clock to 72MHz, generated from external 8MHz crystal */
/* set core clock to 48MHz, generated from PIOSC */
rcc_clock_setup_in_hsi_out_48mhz();
}
@@ -122,6 +123,12 @@ int board_setup(void)
/* 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;
}

View File

@@ -1,11 +1,11 @@
TARGET := stm32f103rb
LIBNAME = opencm3_stm32f1
DEFS = -DSTM32F1
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
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2-1

View File

@@ -34,6 +34,7 @@
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
@@ -126,6 +127,12 @@ int board_setup(void)
/* 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;
}

View File

@@ -1,11 +1,11 @@
TARGET := stm32f411re
LIBNAME = opencm3_stm32f4
DEFS = -DSTM32F4
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)
ARCH_FLAGS ?= -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
OOCD ?= openocd
OOCD_INTERFACE ?= stlink-v2-1

View File

@@ -34,6 +34,7 @@
#include <libopencm3/stm32/usart.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include "atomport.h"
@@ -125,5 +126,11 @@ int board_setup(void)
/* 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;
}

View File

@@ -144,9 +144,15 @@ extern int board_setup(void);
int main ( void )
{
int8_t status;
uint32_t loop;
nvic_set_priority(NVIC_PENDSV_IRQ, 0xFF);
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xFE);
/**
* 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,