aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2017-01-15 15:04:02 +0100
committerTrygve Laugstøl <trygvis@inamo.no>2017-01-15 15:04:02 +0100
commit2155ab2b72cc4f076dc0a25d0e3a5fdd4d218998 (patch)
tree8f89f8a86b949382456a2813d467518033995782
parent7bd30b64fb5eaccb9c4a78b0bb4413d5a476089c (diff)
downloadmcu.cmake-2155ab2b72cc4f076dc0a25d0e3a5fdd4d218998.tar.gz
mcu.cmake-2155ab2b72cc4f076dc0a25d0e3a5fdd4d218998.tar.bz2
mcu.cmake-2155ab2b72cc4f076dc0a25d0e3a5fdd4d218998.tar.xz
mcu.cmake-2155ab2b72cc4f076dc0a25d0e3a5fdd4d218998.zip
o Adding a generic binutils part for creating the info files (.nm, disassembly, size, hex and bin files.)
o Adding initial support for STM32F103xx chips. Can easily be expanded to all at least the F1 series.
-rw-r--r--binutils.cmake40
-rw-r--r--mcu.cmake9
-rw-r--r--nrf5x.cmake12
-rw-r--r--stm32f103/include/mcu/init.h136
-rw-r--r--stm32f103/index.cmake81
-rw-r--r--stm32f103/src/default_handler.cpp7
-rw-r--r--stm32f103/src/init_high.cpp384
-rw-r--r--stm32f103/src/init_low.s47
-rw-r--r--stm32f103/stm32f103.ld62
-rw-r--r--stm32f103/toolchain.cmake26
10 files changed, 797 insertions, 7 deletions
diff --git a/binutils.cmake b/binutils.cmake
new file mode 100644
index 0000000..742fb06
--- /dev/null
+++ b/binutils.cmake
@@ -0,0 +1,40 @@
+function(mcu_binutils_create_dump_targets TARGET)
+ if (MCU_ARM_OBJDUMP)
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET}-info
+ COMMAND ${MCU_ARM_OBJDUMP} -D ${TARGET} > ${TARGET}-info/${TARGET}.asm
+ BYPRODUCTS ${TARGET}-info/${TARGET}.asm)
+ endif ()
+
+ if (MCU_ARM_NM)
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET}-info
+ COMMAND ${MCU_ARM_NM} -C ${TARGET} > ${TARGET}-info/${TARGET}.nm
+ BYPRODUCTS ${TARGET}-info/${TARGET}.nm)
+ endif ()
+
+ if (MCU_ARM_SIZE)
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET}-info
+ COMMAND ${MCU_ARM_SIZE} ${TARGET} > ${TARGET}-info/${TARGET}.size
+ BYPRODUCTS ${TARGET}-info/${TARGET}.size)
+ endif ()
+
+ if (MCU_ARM_READELF)
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET}-info
+ COMMAND ${MCU_ARM_READELF} -a ${TARGET} > ${TARGET}-info/${TARGET}.readelf
+ BYPRODUCTS ${TARGET}-info/${TARGET}.readelf)
+ endif ()
+
+ if (MCU_ARM_OBJCOPY)
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET}-info
+ COMMAND ${MCU_ARM_OBJCOPY} -O ihex ${TARGET} ${TARGET}-info/${TARGET}.hex
+ BYPRODUCTS ${TARGET}-info/${TARGET}.hex)
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET}-info
+ COMMAND ${MCU_ARM_OBJCOPY} -O binary ${TARGET} ${TARGET}-info/${TARGET}.bin
+ BYPRODUCTS ${TARGET}-info/${TARGET}.bin)
+ endif ()
+endfunction()
diff --git a/mcu.cmake b/mcu.cmake
index 00795ab..94c134a 100644
--- a/mcu.cmake
+++ b/mcu.cmake
@@ -1,5 +1,8 @@
+set(MCU_BASEDIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "The mcu.cmake installation path" FORCE)
+message("MCU_BASEDIR=${MCU_BASEDIR}")
+
if (NOT MCU_CHIP)
- message(FATAL_ERROR "Missing required argument CHIP.")
+ message(FATAL_ERROR "Missing required argument MCU_CHIP.")
elseif (MCU_CHIP MATCHES "nrf5.*")
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/nrf5x.cmake")
@@ -7,11 +10,15 @@ elseif (MCU_CHIP MATCHES "nrf5.*")
include(${CMAKE_CURRENT_LIST_DIR}/nrf5x/utils.cmake)
elseif (MCU_CHIP MATCHES D2000)
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/intel-quark-d2000.toolchain.cmake")
+elseif (MCU_CHIP MATCHES "stm32f103.*")
+ set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/stm32f103/toolchain.cmake")
+ include(${CMAKE_CURRENT_LIST_DIR}/stm32f103/index.cmake)
else ()
message(FATAL_ERROR "Unsupported MCU_CHIP setting: ${MCU_CHIP}")
endif ()
include(${CMAKE_CURRENT_LIST_DIR}/mcu_include_directories_from_sources.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/binutils.cmake)
# Required on Windows
set(CMAKE_SYSTEM_NAME Generic)
diff --git a/nrf5x.cmake b/nrf5x.cmake
index ee3a814..fe76731 100644
--- a/nrf5x.cmake
+++ b/nrf5x.cmake
@@ -94,18 +94,18 @@ _mcu_find_toolchain()
find_program(MCU_ARM_CC arm-none-eabi-gcc ${MCU_TOOLCHAIN_DIR}/bin)
find_program(MCU_ARM_CXX arm-none-eabi-g++ ${MCU_TOOLCHAIN_DIR}/bin)
find_program(MCU_ARM_OBJCOPY arm-none-eabi-objcopy ${MCU_TOOLCHAIN_DIR}/bin)
-find_program(MCU_ARM_SIZE_TOOL arm-none-eabi-size ${MCU_TOOLCHAIN_DIR}/bin)
+find_program(MCU_ARM_SIZE arm-none-eabi-size ${MCU_TOOLCHAIN_DIR}/bin)
find_program(MCU_ARM_NM arm-none-eabi-nm ${MCU_TOOLCHAIN_DIR}/bin)
set(_CMAKE_TOOLCHAIN_PREFIX arm-none-eabi-)
include(CMakeFindBinUtils)
-#message("MCU_ARM_CC = ${MCU_ARM_CC}")
-#message("MCU_ARM_CXX = ${MCU_ARM_CXX}")
-#message("MCU_ARM_OBJCOPY = ${MCU_ARM_OBJCOPY}")
-#message("MCU_ARM_SIZE_TOOL = ${MCU_ARM_SIZE_TOOL}")
+#message("MCU_ARM_CC = ${MCU_ARM_CC}")
+#message("MCU_ARM_CXX = ${MCU_ARM_CXX}")
+#message("MCU_ARM_OBJCOPY = ${MCU_ARM_OBJCOPY}")
+#message("MCU_ARM_SIZE = ${MCU_ARM_SIZE}")
-if (NOT MCU_ARM_CC OR NOT MCU_ARM_CXX OR NOT MCU_ARM_OBJCOPY OR NOT MCU_ARM_SIZE_TOOL)
+if (NOT MCU_ARM_CC OR NOT MCU_ARM_CXX OR NOT MCU_ARM_OBJCOPY OR NOT MCU_ARM_SIZE)
message(FATAL_ERROR "Could not find required compiler tools.")
endif()
diff --git a/stm32f103/include/mcu/init.h b/stm32f103/include/mcu/init.h
new file mode 100644
index 0000000..6c870c2
--- /dev/null
+++ b/stm32f103/include/mcu/init.h
@@ -0,0 +1,136 @@
+#ifndef INIT_HIGH_H
+#define INIT_HIGH_H
+
+extern "C"
+int halt();
+
+extern "C"
+int main();
+
+extern "C" {
+
+// Symbols for interrupt handlers. They all have a default implementation, but can be overridden by creating a function
+// with the same name.
+
+extern void _Reset_Handler();
+
+extern void NMI_Handler();
+
+extern void HardFault_Handler();
+
+extern void MemManage_Handler();
+
+extern void BusFault_Handler();
+
+extern void UsageFault_Handler();
+
+extern void SVC_Handler();
+
+extern void DebugMon_Handler();
+
+extern void PendSV_Handler();
+
+extern void SysTick_Handler();
+
+extern void WWDG_IRQHandler();
+
+extern void PVD_IRQHandler();
+
+extern void TAMPER_IRQHandler();
+
+extern void RTC_IRQHandler();
+
+extern void FLASH_IRQHandler();
+
+extern void RCC_IRQHandler();
+
+extern void EXTI0_IRQHandler();
+
+extern void EXTI1_IRQHandler();
+
+extern void EXTI2_IRQHandler();
+
+extern void EXTI3_IRQHandler();
+
+extern void EXTI4_IRQHandler();
+
+extern void DMA1_Channel1_IRQHandler();
+
+extern void DMA1_Channel2_IRQHandler();
+
+extern void DMA1_Channel3_IRQHandler();
+
+extern void DMA1_Channel4_IRQHandler();
+
+extern void DMA1_Channel5_IRQHandler();
+
+extern void DMA1_Channel6_IRQHandler();
+
+extern void DMA1_Channel7_IRQHandler();
+
+extern void ADC1_2_IRQHandler();
+
+extern void USB_HP_CAN1_TX_IRQHandler();
+
+extern void USB_LP_CAN1_RX0_IRQHandler();
+
+extern void CAN1_RX1_IRQHandler();
+
+extern void CAN1_SCE_IRQHandler();
+
+extern void EXTI9_5_IRQHandler();
+
+extern void TIM1_BRK_IRQHandler();
+
+extern void TIM1_UP_IRQHandler();
+
+extern void TIM1_TRG_COM_IRQHandler();
+
+extern void TIM1_CC_IRQHandler();
+
+extern void TIM2_IRQHandler();
+
+extern void TIM3_IRQHandler();
+
+extern void TIM4_IRQHandler();
+
+extern void I2C1_EV_IRQHandler();
+
+extern void I2C1_ER_IRQHandler();
+
+extern void I2C2_EV_IRQHandler();
+
+extern void I2C2_ER_IRQHandler();
+
+extern void SPI1_IRQHandler();
+
+extern void SPI2_IRQHandler();
+
+extern void USART1_IRQHandler();
+
+extern void USART2_IRQHandler();
+
+extern void USART3_IRQHandler();
+
+extern void EXTI15_10_IRQHandler();
+
+extern void RTCAlarm_IRQHandler();
+
+extern void USBWakeUp_IRQHandler();
+}
+
+
+#include <limits>
+
+namespace mcu {
+
+template<typename R = std::size_t, typename T, std::size_t N>
+static inline constexpr
+R SizeOfArray(const T(&)[N]) {
+ static_assert(std::numeric_limits<R>::max() >= N, "N does not fit in R");
+ return static_cast<R>(N);
+}
+
+}; // namespace mcu
+
+#endif
diff --git a/stm32f103/index.cmake b/stm32f103/index.cmake
new file mode 100644
index 0000000..c840aa5
--- /dev/null
+++ b/stm32f103/index.cmake
@@ -0,0 +1,81 @@
+set(CMAKE_C_STANDARD "11")
+set(CMAKE_CXX_STANDARD "14")
+
+set(MCU_INIT_SOURCES "")
+list(APPEND MCU_INIT_SOURCES "${MCU_BASEDIR}/stm32f103/src/init_low.s")
+list(APPEND MCU_INIT_SOURCES "${MCU_BASEDIR}/stm32f103/src/init_high.cpp")
+list(APPEND MCU_INIT_SOURCES "${MCU_BASEDIR}/stm32f103/src/default_handler.cpp")
+list(APPEND MCU_INIT_SOURCES "${MCU_BASEDIR}/stm32f103/include/mcu/init.h")
+set(MCU_INIT_INCLUDES "")
+list(APPEND MCU_INIT_INCLUDES "${MCU_BASEDIR}/stm32f103/include")
+
+function(mcu_add_executable)
+
+ set(options)
+ set(oneValueArgs TARGET LINKER_SCRIPT)
+ set(multiValueArgs)
+ cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if (NOT ARGS_TARGET)
+ message(FATAL_ERROR "MCU: Missing required argument: TARGET")
+ endif ()
+
+ if (MCU_CHIP MATCHES "stm32f103.4" OR MCU_CHIP MATCHES "stm32f103.6")
+ set(size_define STM32F10X_SM)
+ elseif (MCU_CHIP MATCHES "stm32f103.8" OR MCU_CHIP MATCHES "stm32f103.b")
+ set(size_define STM32F10X_MD)
+ elseif (MCU_CHIP MATCHES "stm32f103.c" OR MCU_CHIP MATCHES "stm32f103.d" OR MCU_CHIP MATCHES "stm32f103.e")
+ set(size_define STM32F10X_LD)
+ else ()
+ message(FATAL_ERROR "Unknown STM32 version: ${MCU_CHIP}")
+ endif ()
+
+ target_compile_definitions(${ARGS_TARGET} PUBLIC ${size_define})
+
+ # Compile and linker options
+
+ set(o_level "$<TARGET_PROPERTY:O_LEVEL>")
+ target_compile_options(${ARGS_TARGET} PUBLIC
+ "$<$<BOOL:${o_level}>:-O${o_level}>$<$<NOT:$<BOOL:${o_level}>>:-O3>")
+ unset(o_level)
+
+ target_compile_options(${ARGS_TARGET} PUBLIC
+ -mcpu=cortex-m3
+ -mthumb
+ -g
+ )
+
+ target_link_libraries(${ARGS_TARGET} PUBLIC
+ -mcpu=cortex-m3
+ -mthumb
+ -nostdlib
+ -nostartfiles
+ -Wl,--gc-sections
+ )
+
+ # Linker script
+
+ if (ARGS_LINKER_SCRIPT)
+ if (NOT IS_ABSOLUTE "${ARGS_LINKER_SCRIPT}")
+ set(ARGS_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_LINKER_SCRIPT}")
+ endif ()
+ set_target_properties(${ARGS_TARGET} PROPERTIES MCU_LINKER_SCRIPT "${ARGS_LINKER_SCRIPT}")
+ endif ()
+
+ stm32_configure_linker_script(${ARGS_TARGET})
+
+endfunction()
+
+function(stm32_configure_linker_script T)
+ get_target_property(MCU_LINKER_SCRIPT ${T} MCU_LINKER_SCRIPT)
+
+ if (NOT MCU_LINKER_SCRIPT)
+ set(ld "${MCU_BASEDIR}/stm32f103/stm32f103.ld")
+ message("MCU: Using built-in linker script: ${ld}")
+
+ set_target_properties(${T} PROPERTIES MCU_LINKER_SCRIPT ${ld})
+ endif ()
+
+ target_link_libraries(${T} PUBLIC
+ "-T\"$<TARGET_PROPERTY:MCU_LINKER_SCRIPT>\"")
+endfunction()
diff --git a/stm32f103/src/default_handler.cpp b/stm32f103/src/default_handler.cpp
new file mode 100644
index 0000000..68a5dff
--- /dev/null
+++ b/stm32f103/src/default_handler.cpp
@@ -0,0 +1,7 @@
+#include <cstddef>
+#include <cstdint>
+#include <stm32f10x.h>
+#include <core_cm3.h>
+
+#include "mcu/init.h"
+
diff --git a/stm32f103/src/init_high.cpp b/stm32f103/src/init_high.cpp
new file mode 100644
index 0000000..ca083de
--- /dev/null
+++ b/stm32f103/src/init_high.cpp
@@ -0,0 +1,384 @@
+#include <cstdint>
+#include <cstddef>
+#include "stm32f10x.h"
+#include "mcu/init.h"
+
+// This is required to keep the compiler from replacing parts of a function with calls to library functions like memcpy.
+# define disable_replace_with_library_calls \
+ __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
+
+using namespace mcu;
+
+/**
+ * Symbols that are defined by the linker
+ */
+extern "C"
+{
+extern uint8_t _copy_data_load, _copy_data_store, _copy_data_store_end;
+extern uint8_t _bss_start, _bss_end;
+
+typedef void(*constructor_t)();
+extern constructor_t _init_array_start[], _init_array_end[];
+}
+
+extern "C"
+__attribute__((used))
+void __cxa_pure_virtual()
+{
+ halt();
+}
+
+extern "C"
+__attribute__((used))
+void __aeabi_unwind_cpp_pr0()
+{
+}
+
+extern "C"
+__attribute__((used))
+void __aeabi_unwind_cpp_pr1()
+{
+}
+
+extern "C"
+__attribute__((used))
+void __aeabi_unwind_cpp_pr2()
+{
+}
+
+extern "C"
+__attribute__((used))
+disable_replace_with_library_calls
+void *memset(void *dst, int i, size_t n)
+{
+ auto *d = static_cast<uint8_t *>(dst);
+ auto c = (uint8_t) i;
+ while (n > 0) {
+ *d = c;
+ d++;
+ n--;
+ }
+ return dst;
+}
+
+extern "C"
+__attribute__((used))
+disable_replace_with_library_calls
+void *memcpy(void *destination, void *source, size_t num)
+{
+ auto *d = (uint8_t *) destination;
+ auto *s = (uint8_t *) source;
+ for (size_t i = 0; i < num; i++) {
+ d[i] = s[i];
+ }
+ return destination;
+}
+
+extern "C"
+__attribute__((used))
+void init_high()
+{
+ // Copy data from flash to ram
+ size_t num = &_copy_data_store_end - &_copy_data_store;
+ memcpy(&_copy_data_store, &_copy_data_load, num);
+
+ // Clear the BSS segment
+ memset(&_bss_start, 0, &_bss_end - &_bss_start);
+
+ // Initialize c++ constructors
+ for (constructor_t *fn = _init_array_start; fn < _init_array_end; fn++) {
+ (*fn)();
+ }
+
+ main();
+}
+
+__attribute__((used))
+struct {
+ uint32_t CFSR;
+ uint32_t HFSR;
+ uint32_t DFSR;
+ uint32_t AFSR;
+// uint32_t MMAR;
+ uint32_t BFAR;
+} Default_Handler_Info;
+
+#define dbg_printf
+//void dbg_printf(...);
+
+extern "C"
+__attribute__((weak, used))
+void HardFault_Handler_C()
+{
+ halt();
+}
+
+extern "C"
+__attribute__((used))
+void Default_Handler()
+{
+ Default_Handler_Info = {
+ CFSR: SCB->CFSR,
+ HFSR: SCB->HFSR,
+ DFSR: SCB->DFSR,
+ AFSR: SCB->AFSR,
+ BFAR: SCB->BFAR,
+ };
+
+ dbg_printf("Default handler:\n");
+
+ dbg_printf("HFSR: 0x%08lx\n", Default_Handler_Info.HFSR);
+ if (Default_Handler_Info.HFSR & SCB_HFSR_DEBUGEVT) {
+ dbg_printf(" HFSR.DEBUGEVT\n");
+ }
+ if (Default_Handler_Info.HFSR & SCB_HFSR_FORCED) {
+ dbg_printf(" HFSR.FORCED\n");
+ }
+ if (Default_Handler_Info.HFSR & SCB_HFSR_VECTTBL) {
+ dbg_printf(" HFSR.VECTTBL\n");
+ }
+
+ dbg_printf("CFSR: 0x%08lx\n", Default_Handler_Info.CFSR);
+ if (Default_Handler_Info.CFSR & SCB_CFSR_DIVBYZERO) {
+ dbg_printf(" UFSR.DIVBYZERO\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_UNALIGNED) {
+ dbg_printf(" UFSR.UNALIGED\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_NOCP) {
+ dbg_printf(" UFSR.NOCP\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_INVPC) {
+ dbg_printf(" UFSR.INVPC\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_INVSTATE) {
+ dbg_printf(" UFSR.INVSTATE\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_UNDEFINSTR) {
+ dbg_printf(" UFSR.UNDEFINSTR\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_BFARVALID) {
+ dbg_printf(" BFSR.BFARVALID\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_STKERR) {
+ dbg_printf(" BFSR.STKERR\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_UNSTKERR) {
+ dbg_printf(" BFSR.UNSTKERR\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_IMPRECISERR) {
+ dbg_printf(" BFSR.IMPRECISERR\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_PRECISERR) {
+ dbg_printf(" BFSR.PRECISERR\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_IBUSERR) {
+ dbg_printf(" BFSR.IBUSERR\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_MMARVALID) {
+ dbg_printf(" MMFSR.MMARVALID\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_MSTKERR) {
+ dbg_printf(" MMFSR.MSTKERR\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_MUNSTKERR) {
+ dbg_printf(" MMFSR.MUNSTKERR\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_DACCVIOL) {
+ dbg_printf(" MMFSR.DACCVIOL\n");
+ }
+ if (Default_Handler_Info.CFSR & SCB_CFSR_IACCVIOL) {
+ dbg_printf(" MMFSR.IACCVIOL\n");
+ }
+ dbg_printf("DFSR: 0x%08lx\n", Default_Handler_Info.DFSR);
+ dbg_printf("AFSR: 0x%08lx\n", Default_Handler_Info.AFSR);
+
+ if (Default_Handler_Info.CFSR & SCB_CFSR_BFARVALID) {
+ dbg_printf("BFAR: 0x%08lx\n", Default_Handler_Info.BFAR);
+ } else {
+ dbg_printf("BFAR: <invalid>\n");
+ }
+
+ dbg_printf("NVIC:\n");
+ for (size_t i = 0; i < SizeOfArray(NVIC->IABR); i++) {
+ dbg_printf(" IABR[%d]: 0x%08lx\n", i, NVIC->IABR[i]);
+ }
+
+ halt();
+}
+
+void _Reset_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void NMI_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void HardFault_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void MemManage_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void BusFault_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void UsageFault_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void SVC_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void DebugMon_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void PendSV_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void SysTick_Handler() __attribute__ ((weak, alias("Default_Handler")));
+
+void WWDG_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void PVD_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void TAMPER_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void RTC_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void FLASH_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void RCC_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void EXTI0_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void EXTI1_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void EXTI2_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void EXTI3_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void EXTI4_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void DMA1_Channel1_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void DMA1_Channel2_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void DMA1_Channel3_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void DMA1_Channel4_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void DMA1_Channel5_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void DMA1_Channel6_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void DMA1_Channel7_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void ADC1_2_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void USB_HP_CAN1_TX_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void USB_LP_CAN1_RX0_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void CAN1_RX1_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void CAN1_SCE_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void EXTI9_5_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void TIM1_BRK_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void TIM1_UP_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void TIM1_TRG_COM_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void TIM1_CC_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void TIM2_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void TIM3_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void TIM4_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void I2C1_EV_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void I2C1_ER_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void I2C2_EV_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void I2C2_ER_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void SPI1_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void SPI2_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void USART1_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void USART2_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void USART3_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void EXTI15_10_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void RTCAlarm_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+void USBWakeUp_IRQHandler() __attribute__ ((weak, alias("Default_Handler")));
+
+__attribute__((section(".isr_vectors"), used))
+uint32_t isr_vectors[74] = {
+ (uint32_t) _Reset_Handler,
+ (uint32_t) NMI_Handler,
+ (uint32_t) HardFault_Handler,
+ (uint32_t) MemManage_Handler,
+ (uint32_t) BusFault_Handler,
+ (uint32_t) UsageFault_Handler,
+ 0,
+ 0,
+ 0,
+ 0,
+ (uint32_t) SVC_Handler,
+ (uint32_t) DebugMon_Handler,
+ 0,
+ (uint32_t) PendSV_Handler,
+ (uint32_t) SysTick_Handler,
+ (uint32_t) WWDG_IRQHandler,
+ (uint32_t) PVD_IRQHandler,
+ (uint32_t) TAMPER_IRQHandler,
+ (uint32_t) RTC_IRQHandler,
+ (uint32_t) FLASH_IRQHandler,
+ (uint32_t) RCC_IRQHandler,
+ (uint32_t) EXTI0_IRQHandler,
+ (uint32_t) EXTI1_IRQHandler,
+ (uint32_t) EXTI2_IRQHandler,
+ (uint32_t) EXTI3_IRQHandler,
+ (uint32_t) EXTI4_IRQHandler,
+ (uint32_t) DMA1_Channel1_IRQHandler,
+ (uint32_t) DMA1_Channel2_IRQHandler,
+ (uint32_t) DMA1_Channel3_IRQHandler,
+ (uint32_t) DMA1_Channel4_IRQHandler,
+ (uint32_t) DMA1_Channel5_IRQHandler,
+ (uint32_t) DMA1_Channel6_IRQHandler,
+ (uint32_t) DMA1_Channel7_IRQHandler,
+ (uint32_t) ADC1_2_IRQHandler,
+ (uint32_t) USB_HP_CAN1_TX_IRQHandler,
+ (uint32_t) USB_LP_CAN1_RX0_IRQHandler,
+ (uint32_t) CAN1_RX1_IRQHandler,
+ (uint32_t) CAN1_SCE_IRQHandler,
+ (uint32_t) EXTI9_5_IRQHandler,
+ (uint32_t) TIM1_BRK_IRQHandler,
+ (uint32_t) TIM1_UP_IRQHandler,
+ (uint32_t) TIM1_TRG_COM_IRQHandler,
+ (uint32_t) TIM1_CC_IRQHandler,
+ (uint32_t) TIM2_IRQHandler,
+ (uint32_t) TIM3_IRQHandler,
+ (uint32_t) TIM4_IRQHandler,
+ (uint32_t) I2C1_EV_IRQHandler,
+ (uint32_t) I2C1_ER_IRQHandler,
+ (uint32_t) I2C2_EV_IRQHandler,
+ (uint32_t) I2C2_ER_IRQHandler,
+ (uint32_t) SPI1_IRQHandler,
+ (uint32_t) SPI2_IRQHandler,
+ (uint32_t) USART1_IRQHandler,
+ (uint32_t) USART2_IRQHandler,
+ (uint32_t) USART3_IRQHandler,
+ (uint32_t) EXTI15_10_IRQHandler,
+ (uint32_t) RTCAlarm_IRQHandler,
+ (uint32_t) USBWakeUp_IRQHandler,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
diff --git a/stm32f103/src/init_low.s b/stm32f103/src/init_low.s
new file mode 100644
index 0000000..b666ed4
--- /dev/null
+++ b/stm32f103/src/init_low.s
@@ -0,0 +1,47 @@
+.syntax unified
+.cpu cortex-m3
+.thumb
+
+.section .text
+
+.thumb_func
+.global _Reset_Handler
+_Reset_Handler:
+ bl init_high
+ b halt
+
+.thumb_func
+.global halt
+halt:
+ b .
+
+.thumb_func
+.global NMI_Handler
+NMI_Handler:
+ b halt
+
+.thumb_func
+.global HardFault_Handler
+HardFault_Handler:
+ tst lr, #4
+ ite eq
+ mrseq r0, msp
+ mrsne r0, psp
+ b HardFault_Handler_C
+
+.thumb_func
+.global MemManage_Handler
+MemManage_Handler:
+ b halt
+
+.thumb_func
+.global BusFault_Handler
+BusFault_Handler:
+ b halt
+
+.thumb_func
+.global UsageFault_Handler
+UsageFault_Handler:
+ b halt
+
+.end
diff --git a/stm32f103/stm32f103.ld b/stm32f103/stm32f103.ld
new file mode 100644
index 0000000..bafd520
--- /dev/null
+++ b/stm32f103/stm32f103.ld
@@ -0,0 +1,62 @@
+ENTRY(_Reset_Handler)
+
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20k
+ MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
+}
+
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+SECTIONS
+{
+ /* Put the ISR section at the start of the flash area */
+ .isr :
+ {
+ /* The first word has to be the initial stack pointer */
+ LONG(__initial_stack_pointer);
+ KEEP(*/init_high.cpp.obj(.isr_vectors))
+ } >FLASH
+ ASSERT(SIZEOF(.isr) > 100, "The isr_vectors section is too small")
+ ASSERT(SIZEOF(.isr) < 1000, "The isr_vectors section is too big")
+ ASSERT(ADDR(.isr) == ORIGIN(FLASH), "The isr_vectors section was not placed at the start of the flash area")
+
+ .text :
+ {
+ *(.text)
+ KEEP(*(.text.*))
+ *(.rodata*)
+ } >FLASH
+
+ .init_arrays :
+ {
+ _init_array_start = .;
+ KEEP(*(.init_array))
+ KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)))
+ _init_array_end = .;
+ } >FLASH
+
+ . = ORIGIN(RAM);
+
+ .data ALIGN(4) :
+ {
+ *(.data)
+ *(.data.*)
+ } >RAM AT >FLASH
+
+ .bss ALIGN(4) (NOLOAD) :
+ {
+ *(.bss)
+ *(.bss.*)
+ } >RAM
+
+ _copy_data_store = ADDR(.data);
+ _copy_data_store_end = _copy_data_store + SIZEOF(.data);
+ _copy_data_load = LOADADDR(.data);
+
+ _bss_start = ADDR(.bss);
+ _bss_end = _bss_start + SIZEOF(.bss);
+
+ __initial_stack_pointer = ORIGIN(RAM) + LENGTH(RAM) - 1;
+}
diff --git a/stm32f103/toolchain.cmake b/stm32f103/toolchain.cmake
new file mode 100644
index 0000000..2a0e5b8
--- /dev/null
+++ b/stm32f103/toolchain.cmake
@@ -0,0 +1,26 @@
+find_program(MCU_ARM_CC arm-none-eabi-gcc ${MCU_TOOLCHAIN_DIR}/bin)
+find_program(MCU_ARM_CXX arm-none-eabi-g++ ${MCU_TOOLCHAIN_DIR}/bin)
+find_program(MCU_ARM_OBJCOPY arm-none-eabi-objcopy ${MCU_TOOLCHAIN_DIR}/bin)
+find_program(MCU_ARM_OBJDUMP arm-none-eabi-objdump ${MCU_TOOLCHAIN_DIR}/bin)
+find_program(MCU_ARM_READELF arm-none-eabi-readelf ${MCU_TOOLCHAIN_DIR}/bin)
+find_program(MCU_ARM_SIZE arm-none-eabi-size ${MCU_TOOLCHAIN_DIR}/bin)
+find_program(MCU_ARM_NM arm-none-eabi-nm ${MCU_TOOLCHAIN_DIR}/bin)
+
+#message("MCU_ARM_CC = ${MCU_ARM_CC}")
+#message("MCU_ARM_CXX = ${MCU_ARM_CXX}")
+#message("MCU_ARM_OBJCOPY = ${MCU_ARM_OBJCOPY}")
+#message("MCU_ARM_SIZE = ${MCU_ARM_SIZE}")
+
+set(_CMAKE_TOOLCHAIN_PREFIX arm-none-eabi-)
+include(CMakeFindBinUtils)
+
+if (NOT MCU_ARM_CC OR NOT MCU_ARM_CXX OR NOT MCU_ARM_OBJCOPY OR NOT MCU_ARM_SIZE)
+ message(FATAL_ERROR "Could not find required compiler tools.")
+endif()
+
+set(CMAKE_C_COMPILER ${MCU_ARM_CC} CACHE FILE "")
+set(CMAKE_CXX_COMPILER ${MCU_ARM_CXX} CACHE FILE "")
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_CXX_STANDARD 14)