diff --git a/Target/Source/ARMCM3_EFM32/Crossworks/cstart.s b/Target/Source/ARMCM3_EFM32/Crossworks/cstart.s
new file mode 100644
index 00000000..326f8c77
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/Crossworks/cstart.s
@@ -0,0 +1,434 @@
+/*****************************************************************************
+ * Copyright (c) 2009 Rowley Associates Limited. *
+ * *
+ * This file may be distributed under the terms of the License Agreement *
+ * provided with this software. *
+ * *
+ * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE *
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preprocessor Definitions
+ * ------------------------
+ * APP_ENTRY_POINT
+ *
+ * Defines the application entry point function, if undefined this setting
+ * defaults to "main".
+ *
+ * USE_PROCESS_STACK
+ *
+ * If defined, thread mode will be configured to use the process stack if
+ * the size of the process stack is greater than zero bytes in length.
+ *
+ * INITIALIZE_STACK
+ *
+ * If defined, the contents of the stack will be initialized to a the
+ * value 0xCC.
+ *
+ * INITIALIZE_SECONDARY_SECTIONS
+ *
+ * If defined, the .data2, .text2, .rodata2 and .bss2 sections will be initialized.
+ *
+ * FULL_LIBRARY
+ *
+ * If defined then
+ * - argc, argv are setup by the debug_getargs.
+ * - the exit symbol is defined and executes on return from main.
+ * - the exit symbol calls destructors, atexit functions and then debug_exit.
+ *
+ * If not defined then
+ * - argc and argv are zero.
+ * - the exit symbol is defined, executes on return from main and loops
+ *****************************************************************************/
+
+#ifndef APP_ENTRY_POINT
+#define APP_ENTRY_POINT main
+#endif
+
+#ifndef ARGSSPACE
+#define ARGSSPACE 128
+#endif
+
+ .extern APP_ENTRY_POINT
+ .global exit
+ .global reset_handler
+ .global EntryFromProg
+ .extern ComSetConnectEntryState
+
+ .section .init, "ax"
+ .code 16
+ .align 2
+
+ .thumb_func
+/****************************************************************************************
+** NAME: EntryFromProg
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Called by the user program to activate the bootloader. Do not place
+** any assembly code before this function and the end of the vector
+** table. This guarantees that this function is located at address
+** 0x08000150. The user program can call this function from C in the
+** following way:
+** void ActivateBootloader(void)
+** {
+** void (*pEntryFromProgFnc)(void);
+**
+** pEntryFromProgFnc = (void*)0x08000150 + 1;
+** pEntryFromProgFnc();
+** }
+** Note that the + 1 added to the function address is neccassary to
+** enable a switch from Thumb2 to Thumb mode.
+**
+****************************************************************************************/
+EntryFromProg:
+ /* disable interrupts first */
+ cpsid i
+ /* configure vector table offset register to use bootloader's vector table*/
+ ldr r0, =0xE000ED08
+ ldr r1, =_vectors
+ str r1, [r0]
+ /* initialize stack pointer */
+ ldr r1, =__stack_end__
+#ifdef __ARM_EABI__
+ mov r2, #0x7
+ bic r1, r2
+#endif
+ mov sp, r1
+#ifdef INITIALIZE_STACK
+ mov r2, #0xCC
+ ldr r0, =__stack_start__
+ bl memory_set
+#endif
+
+#ifdef USE_PROCESS_STACK
+ /* Set up process stack if size > 0 */
+ ldr r1, =__stack_process_end__
+ ldr r0, =__stack_process_start__
+ sub r2, r1, r0
+ beq 1f
+#ifdef __ARM_EABI__
+ mov r2, #0x7
+ bic r1, r2
+#endif
+ msr psp, r1
+ mov r2, #2
+ msr control, r2
+#ifdef INITIALIZE_STACK
+ mov r2, #0xCC
+ bl memory_set
+#endif
+1:
+#endif
+ /* Copy initialised memory sections into RAM (if necessary). */
+ ldr r0, =__data_load_start__
+ ldr r1, =__data_start__
+ ldr r2, =__data_end__
+ bl memory_copy
+ ldr r0, =__text_load_start__
+ ldr r1, =__text_start__
+ ldr r2, =__text_end__
+ bl memory_copy
+ ldr r0, =__fast_load_start__
+ ldr r1, =__fast_start__
+ ldr r2, =__fast_end__
+ bl memory_copy
+ ldr r0, =__ctors_load_start__
+ ldr r1, =__ctors_start__
+ ldr r2, =__ctors_end__
+ bl memory_copy
+ ldr r0, =__dtors_load_start__
+ ldr r1, =__dtors_start__
+ ldr r2, =__dtors_end__
+ bl memory_copy
+ ldr r0, =__rodata_load_start__
+ ldr r1, =__rodata_start__
+ ldr r2, =__rodata_end__
+ bl memory_copy
+#ifdef INITIALIZE_SECONDARY_SECTIONS
+ ldr r0, =__data2_load_start__
+ ldr r1, =__data2_start__
+ ldr r2, =__data2_end__
+ bl memory_copy
+ ldr r0, =__text2_load_start__
+ ldr r1, =__text2_start__
+ ldr r2, =__text2_end__
+ bl memory_copy
+ ldr r0, =__rodata2_load_start__
+ ldr r1, =__rodata2_start__
+ ldr r2, =__rodata2_end__
+ bl memory_copy
+#endif /* #ifdef INITIALIZE_SECONDARY_SECTIONS */
+
+ /* Zero the bss. */
+ ldr r0, =__bss_start__
+ ldr r1, =__bss_end__
+ mov r2, #0
+ bl memory_set
+#ifdef INITIALIZE_SECONDARY_SECTIONS
+ ldr r0, =__bss2_start__
+ ldr r1, =__bss2_end__
+ mov r2, #0
+ bl memory_set
+#endif /* #ifdef INITIALIZE_SECONDARY_SECTIONS */
+
+ /* Initialise the heap */
+ ldr r0, = __heap_start__
+ ldr r1, = __heap_end__
+ sub r1, r1, r0
+ cmp r1, #8
+ blt 1f
+ mov r2, #0
+ str r2, [r0]
+ add r0, r0, #4
+ str r1, [r0]
+1:
+
+ /* Call constructors */
+ ldr r0, =__ctors_start__
+ ldr r1, =__ctors_end__
+ctor_loop:
+ cmp r0, r1
+ beq ctor_end
+ ldr r2, [r0]
+ add r0, #4
+ push {r0-r1}
+ blx r2
+ pop {r0-r1}
+ b ctor_loop
+ctor_end:
+
+ /* Setup initial call frame */
+ mov r0, #0
+ mov lr, r0
+ mov r12, sp
+
+start:
+ /* this part makes the difference with the normal reset_handler */
+ bl ComSetConnectEntryState
+ /* Jump to application entry point */
+#ifdef FULL_LIBRARY
+ mov r0, #ARGSSPACE
+ ldr r1, =args
+ ldr r2, =debug_getargs
+ blx r2
+ ldr r1, =args
+#else
+ mov r0, #0
+ mov r1, #0
+#endif
+ ldr r2, =APP_ENTRY_POINT
+ blx r2
+
+ .thumb_func
+/****************************************************************************************
+** NAME: reset_handler
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Reset interrupt service routine. Configures the stack, initializes
+** RAM and jumps to function main.
+**
+****************************************************************************************/
+reset_handler:
+ /* disable interrupts first */
+ cpsid i
+ ldr r1, =__stack_end__
+#ifdef __ARM_EABI__
+ mov r2, #0x7
+ bic r1, r2
+#endif
+ mov sp, r1
+#ifdef INITIALIZE_STACK
+ mov r2, #0xCC
+ ldr r0, =__stack_start__
+ bl memory_set
+#endif
+
+#ifdef USE_PROCESS_STACK
+ /* Set up process stack if size > 0 */
+ ldr r1, =__stack_process_end__
+ ldr r0, =__stack_process_start__
+ sub r2, r1, r0
+ beq 1f
+#ifdef __ARM_EABI__
+ mov r2, #0x7
+ bic r1, r2
+#endif
+ msr psp, r1
+ mov r2, #2
+ msr control, r2
+#ifdef INITIALIZE_STACK
+ mov r2, #0xCC
+ bl memory_set
+#endif
+1:
+#endif
+ /* Copy initialised memory sections into RAM (if necessary). */
+ ldr r0, =__data_load_start__
+ ldr r1, =__data_start__
+ ldr r2, =__data_end__
+ bl memory_copy
+ ldr r0, =__text_load_start__
+ ldr r1, =__text_start__
+ ldr r2, =__text_end__
+ bl memory_copy
+ ldr r0, =__fast_load_start__
+ ldr r1, =__fast_start__
+ ldr r2, =__fast_end__
+ bl memory_copy
+ ldr r0, =__ctors_load_start__
+ ldr r1, =__ctors_start__
+ ldr r2, =__ctors_end__
+ bl memory_copy
+ ldr r0, =__dtors_load_start__
+ ldr r1, =__dtors_start__
+ ldr r2, =__dtors_end__
+ bl memory_copy
+ ldr r0, =__rodata_load_start__
+ ldr r1, =__rodata_start__
+ ldr r2, =__rodata_end__
+ bl memory_copy
+#ifdef INITIALIZE_SECONDARY_SECTIONS
+ ldr r0, =__data2_load_start__
+ ldr r1, =__data2_start__
+ ldr r2, =__data2_end__
+ bl memory_copy
+ ldr r0, =__text2_load_start__
+ ldr r1, =__text2_start__
+ ldr r2, =__text2_end__
+ bl memory_copy
+ ldr r0, =__rodata2_load_start__
+ ldr r1, =__rodata2_start__
+ ldr r2, =__rodata2_end__
+ bl memory_copy
+#endif /* #ifdef INITIALIZE_SECONDARY_SECTIONS */
+
+ /* Zero the bss. */
+ ldr r0, =__bss_start__
+ ldr r1, =__bss_end__
+ mov r2, #0
+ bl memory_set
+#ifdef INITIALIZE_SECONDARY_SECTIONS
+ ldr r0, =__bss2_start__
+ ldr r1, =__bss2_end__
+ mov r2, #0
+ bl memory_set
+#endif /* #ifdef INITIALIZE_SECONDARY_SECTIONS */
+
+ /* Initialise the heap */
+ ldr r0, = __heap_start__
+ ldr r1, = __heap_end__
+ sub r1, r1, r0
+ cmp r1, #8
+ blt 1f
+ mov r2, #0
+ str r2, [r0]
+ add r0, r0, #4
+ str r1, [r0]
+1:
+
+ /* Call constructors */
+ ldr r0, =__ctors_start__
+ ldr r1, =__ctors_end__
+ctor_loop2:
+ cmp r0, r1
+ beq ctor_end2
+ ldr r2, [r0]
+ add r0, #4
+ push {r0-r1}
+ blx r2
+ pop {r0-r1}
+ b ctor_loop2
+ctor_end2:
+
+ /* Setup initial call frame */
+ mov r0, #0
+ mov lr, r0
+ mov r12, sp
+
+start2:
+ /* Jump to application entry point */
+#ifdef FULL_LIBRARY
+ mov r0, #ARGSSPACE
+ ldr r1, =args
+ ldr r2, =debug_getargs
+ blx r2
+ ldr r1, =args
+#else
+ mov r0, #0
+ mov r1, #0
+#endif
+ ldr r2, =APP_ENTRY_POINT
+ blx r2
+
+ .thumb_func
+exit:
+#ifdef FULL_LIBRARY
+ mov r5, r0 // save the exit parameter/return result
+
+ /* Call destructors */
+ ldr r0, =__dtors_start__
+ ldr r1, =__dtors_end__
+dtor_loop:
+ cmp r0, r1
+ beq dtor_end
+ ldr r2, [r0]
+ add r0, #4
+ push {r0-r1}
+ blx r2
+ pop {r0-r1}
+ b dtor_loop
+dtor_end:
+
+ /* Call atexit functions */
+ ldr r2, =_execute_at_exit_fns
+ blx r2
+
+ /* Call debug_exit with return result/exit parameter */
+ mov r0, r5
+ ldr r2, =debug_exit
+ blx r2
+#endif
+
+ /* Returned from application entry point, loop forever. */
+exit_loop:
+ b exit_loop
+
+ .thumb_func
+memory_copy:
+ cmp r0, r1
+ beq 2f
+ sub r2, r2, r1
+ beq 2f
+1:
+ ldrb r3, [r0]
+ add r0, r0, #1
+ strb r3, [r1]
+ add r1, r1, #1
+ sub r2, r2, #1
+ bne 1b
+2:
+ bx lr
+
+ .thumb_func
+memory_set:
+ cmp r0, r1
+ beq 1f
+ strb r2, [r0]
+ add r0, r0, #1
+ b memory_set
+1:
+ bx lr
+
+
+#ifdef FULL_LIBRARY
+ .bss
+args:
+ .space ARGSSPACE
+#endif
+
+ /* Setup attibutes of stack and heap sections so they don't take up room in the elf file */
+ .section .stack, "wa", %nobits
+ .section .stack_process, "wa", %nobits
+ .section .heap, "wa", %nobits
+
diff --git a/Target/Source/ARMCM3_EFM32/Crossworks/memory.x b/Target/Source/ARMCM3_EFM32/Crossworks/memory.x
new file mode 100644
index 00000000..cbc60c5f
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/Crossworks/memory.x
@@ -0,0 +1,275 @@
+MEMORY
+{
+ UNPLACED_SECTIONS (wx) : ORIGIN = 0x100000000, LENGTH = 0
+ CM3_System_Control_Space (wx) : ORIGIN = 0xe000e000, LENGTH = 0x00001000
+ RAM (wx) : ORIGIN = 0x20000000, LENGTH = 0x00001000
+ FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00004000
+}
+
+
+SECTIONS
+{
+ __CM3_System_Control_Space_segment_start__ = 0xe000e000;
+ __CM3_System_Control_Space_segment_end__ = 0xe000f000;
+ __RAM_segment_start__ = 0x20000000;
+ __RAM_segment_end__ = 0x20001000;
+ __FLASH_segment_start__ = 0x00000000;
+ __FLASH_segment_end__ = 0x00004000;
+
+ __STACKSIZE__ = 256;
+ __STACKSIZE_PROCESS__ = 0;
+ __STACKSIZE_IRQ__ = 0;
+ __STACKSIZE_FIQ__ = 0;
+ __STACKSIZE_SVC__ = 0;
+ __STACKSIZE_ABT__ = 0;
+ __STACKSIZE_UND__ = 0;
+ __HEAPSIZE__ = 128;
+
+ __vectors_ram_load_start__ = ALIGN(__RAM_segment_start__ , 256);
+ .vectors_ram ALIGN(__RAM_segment_start__ , 256) (NOLOAD) : AT(ALIGN(__RAM_segment_start__ , 256))
+ {
+ __vectors_ram_start__ = .;
+ *(.vectors_ram .vectors_ram.*)
+ }
+ __vectors_ram_end__ = __vectors_ram_start__ + SIZEOF(.vectors_ram);
+
+ __vectors_ram_load_end__ = __vectors_ram_end__;
+
+ . = ASSERT(__vectors_ram_end__ >= __RAM_segment_start__ && __vectors_ram_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .vectors_ram is too large to fit in RAM memory segment");
+
+ __vectors_load_start__ = ALIGN(__FLASH_segment_start__ , 256);
+ .vectors ALIGN(__FLASH_segment_start__ , 256) : AT(ALIGN(__FLASH_segment_start__ , 256))
+ {
+ __vectors_start__ = .;
+ *(.vectors .vectors.*)
+ }
+ __vectors_end__ = __vectors_start__ + SIZEOF(.vectors);
+
+ __vectors_load_end__ = __vectors_end__;
+
+ . = ASSERT(__vectors_end__ >= __FLASH_segment_start__ && __vectors_end__ <= (__FLASH_segment_start__ + 0x00020000) , "error: .vectors is too large to fit in FLASH memory segment");
+
+ __init_load_start__ = ALIGN(__vectors_end__ , 4);
+ .init ALIGN(__vectors_end__ , 4) : AT(ALIGN(__vectors_end__ , 4))
+ {
+ __init_start__ = .;
+ *(.init .init.*)
+ }
+ __init_end__ = __init_start__ + SIZEOF(.init);
+
+ __init_load_end__ = __init_end__;
+
+ . = ASSERT(__init_end__ >= __FLASH_segment_start__ && __init_end__ <= (__FLASH_segment_start__ + 0x00020000) , "error: .init is too large to fit in FLASH memory segment");
+
+ __text_load_start__ = ALIGN(__init_end__ , 4);
+ .text ALIGN(__init_end__ , 4) : AT(ALIGN(__init_end__ , 4))
+ {
+ __text_start__ = .;
+ *(.text .text.* .glue_7t .glue_7 .gnu.linkonce.t.* .gcc_except_table .ARM.extab* .gnu.linkonce.armextab.*)
+ }
+ __text_end__ = __text_start__ + SIZEOF(.text);
+
+ __text_load_end__ = __text_end__;
+
+ . = ASSERT(__text_end__ >= __FLASH_segment_start__ && __text_end__ <= (__FLASH_segment_start__ + 0x00020000) , "error: .text is too large to fit in FLASH memory segment");
+
+ __dtors_load_start__ = ALIGN(__text_end__ , 4);
+ .dtors ALIGN(__text_end__ , 4) : AT(ALIGN(__text_end__ , 4))
+ {
+ __dtors_start__ = .;
+ KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) KEEP (*(.fini_array .fini_array.*))
+ }
+ __dtors_end__ = __dtors_start__ + SIZEOF(.dtors);
+
+ __dtors_load_end__ = __dtors_end__;
+
+ . = ASSERT(__dtors_end__ >= __FLASH_segment_start__ && __dtors_end__ <= (__FLASH_segment_start__ + 0x00020000) , "error: .dtors is too large to fit in FLASH memory segment");
+
+ __ctors_load_start__ = ALIGN(__dtors_end__ , 4);
+ .ctors ALIGN(__dtors_end__ , 4) : AT(ALIGN(__dtors_end__ , 4))
+ {
+ __ctors_start__ = .;
+ KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) KEEP (*(.init_array .init_array.*))
+ }
+ __ctors_end__ = __ctors_start__ + SIZEOF(.ctors);
+
+ __ctors_load_end__ = __ctors_end__;
+
+ . = ASSERT(__ctors_end__ >= __FLASH_segment_start__ && __ctors_end__ <= (__FLASH_segment_start__ + 0x00020000) , "error: .ctors is too large to fit in FLASH memory segment");
+
+ __rodata_load_start__ = ALIGN(__ctors_end__ , 4);
+ .rodata ALIGN(__ctors_end__ , 4) : AT(ALIGN(__ctors_end__ , 4))
+ {
+ __rodata_start__ = .;
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ }
+ __rodata_end__ = __rodata_start__ + SIZEOF(.rodata);
+
+ __rodata_load_end__ = __rodata_end__;
+
+ . = ASSERT(__rodata_end__ >= __FLASH_segment_start__ && __rodata_end__ <= (__FLASH_segment_start__ + 0x00020000) , "error: .rodata is too large to fit in FLASH memory segment");
+
+ __ARM.exidx_load_start__ = ALIGN(__rodata_end__ , 4);
+ .ARM.exidx ALIGN(__rodata_end__ , 4) : AT(ALIGN(__rodata_end__ , 4))
+ {
+ __ARM.exidx_start__ = .;
+ __exidx_start = __ARM.exidx_start__;
+ *(.ARM.exidx .ARM.exidx.*)
+ }
+ __ARM.exidx_end__ = __ARM.exidx_start__ + SIZEOF(.ARM.exidx);
+
+ __exidx_end = __ARM.exidx_end__;
+ __ARM.exidx_load_end__ = __ARM.exidx_end__;
+
+ . = ASSERT(__ARM.exidx_end__ >= __FLASH_segment_start__ && __ARM.exidx_end__ <= (__FLASH_segment_start__ + 0x00020000) , "error: .ARM.exidx is too large to fit in FLASH memory segment");
+
+ __fast_load_start__ = ALIGN(__ARM.exidx_end__ , 4);
+ .fast ALIGN(__vectors_ram_end__ , 4) : AT(ALIGN(__ARM.exidx_end__ , 4))
+ {
+ __fast_start__ = .;
+ *(.fast .fast.*)
+ }
+ __fast_end__ = __fast_start__ + SIZEOF(.fast);
+
+ __fast_load_end__ = __fast_load_start__ + SIZEOF(.fast);
+
+ . = ASSERT((__fast_load_start__ + SIZEOF(.fast)) >= __FLASH_segment_start__ && (__fast_load_start__ + SIZEOF(.fast)) <= (__FLASH_segment_start__ + 0x00020000) , "error: .fast is too large to fit in FLASH memory segment");
+
+ .fast_run ALIGN(__vectors_ram_end__ , 4) (NOLOAD) :
+ {
+ __fast_run_start__ = .;
+ . = MAX(__fast_run_start__ + SIZEOF(.fast), .);
+ }
+ __fast_run_end__ = __fast_run_start__ + SIZEOF(.fast_run);
+
+ __fast_run_load_end__ = __fast_run_end__;
+
+ . = ASSERT(__fast_run_end__ >= __RAM_segment_start__ && __fast_run_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .fast_run is too large to fit in RAM memory segment");
+
+ __data_load_start__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4);
+ .data ALIGN(__fast_run_end__ , 4) : AT(ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4))
+ {
+ __data_start__ = .;
+ *(.data .data.* .gnu.linkonce.d.*)
+ }
+ __data_end__ = __data_start__ + SIZEOF(.data);
+
+ __data_load_end__ = __data_load_start__ + SIZEOF(.data);
+
+ . = ASSERT((__data_load_start__ + SIZEOF(.data)) >= __FLASH_segment_start__ && (__data_load_start__ + SIZEOF(.data)) <= (__FLASH_segment_start__ + 0x00020000) , "error: .data is too large to fit in FLASH memory segment");
+
+ .data_run ALIGN(__fast_run_end__ , 4) (NOLOAD) :
+ {
+ __data_run_start__ = .;
+ . = MAX(__data_run_start__ + SIZEOF(.data), .);
+ }
+ __data_run_end__ = __data_run_start__ + SIZEOF(.data_run);
+
+ __data_run_load_end__ = __data_run_end__;
+
+ . = ASSERT(__data_run_end__ >= __RAM_segment_start__ && __data_run_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .data_run is too large to fit in RAM memory segment");
+
+ __bss_load_start__ = ALIGN(__data_run_end__ , 4);
+ .bss ALIGN(__data_run_end__ , 4) (NOLOAD) : AT(ALIGN(__data_run_end__ , 4))
+ {
+ __bss_start__ = .;
+ *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON)
+ }
+ __bss_end__ = __bss_start__ + SIZEOF(.bss);
+
+ __bss_load_end__ = __bss_end__;
+
+ . = ASSERT(__bss_end__ >= __RAM_segment_start__ && __bss_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .bss is too large to fit in RAM memory segment");
+
+ __non_init_load_start__ = ALIGN(__bss_end__ , 4);
+ .non_init ALIGN(__bss_end__ , 4) (NOLOAD) : AT(ALIGN(__bss_end__ , 4))
+ {
+ __non_init_start__ = .;
+ *(.non_init .non_init.*)
+ }
+ __non_init_end__ = __non_init_start__ + SIZEOF(.non_init);
+
+ __non_init_load_end__ = __non_init_end__;
+
+ . = ASSERT(__non_init_end__ >= __RAM_segment_start__ && __non_init_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .non_init is too large to fit in RAM memory segment");
+
+ __heap_load_start__ = ALIGN(__non_init_end__ , 4);
+ .heap ALIGN(__non_init_end__ , 4) (NOLOAD) : AT(ALIGN(__non_init_end__ , 4))
+ {
+ __heap_start__ = .;
+ *(.heap .heap.*)
+ . = ALIGN(MAX(__heap_start__ + __HEAPSIZE__ , .), 4);
+ }
+ __heap_end__ = __heap_start__ + SIZEOF(.heap);
+
+ __heap_load_end__ = __heap_end__;
+
+ . = ASSERT(__heap_end__ >= __RAM_segment_start__ && __heap_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .heap is too large to fit in RAM memory segment");
+
+ __stack_load_start__ = ALIGN(__heap_end__ , 4);
+ .stack ALIGN(__heap_end__ , 4) (NOLOAD) : AT(ALIGN(__heap_end__ , 4))
+ {
+ __stack_start__ = .;
+ *(.stack .stack.*)
+ . = ALIGN(MAX(__stack_start__ + __STACKSIZE__ , .), 4);
+ }
+ __stack_end__ = __stack_start__ + SIZEOF(.stack);
+
+ __stack_load_end__ = __stack_end__;
+
+ . = ASSERT(__stack_end__ >= __RAM_segment_start__ && __stack_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .stack is too large to fit in RAM memory segment");
+
+ __stack_process_load_start__ = ALIGN(__stack_end__ , 4);
+ .stack_process ALIGN(__stack_end__ , 4) (NOLOAD) : AT(ALIGN(__stack_end__ , 4))
+ {
+ __stack_process_start__ = .;
+ *(.stack_process .stack_process.*)
+ . = ALIGN(MAX(__stack_process_start__ + __STACKSIZE_PROCESS__ , .), 4);
+ }
+ __stack_process_end__ = __stack_process_start__ + SIZEOF(.stack_process);
+
+ __stack_process_load_end__ = __stack_process_end__;
+
+ . = ASSERT(__stack_process_end__ >= __RAM_segment_start__ && __stack_process_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .stack_process is too large to fit in RAM memory segment");
+
+ __tbss_load_start__ = ALIGN(__stack_process_end__ , 4);
+ .tbss ALIGN(__stack_process_end__ , 4) (NOLOAD) : AT(ALIGN(__stack_process_end__ , 4))
+ {
+ __tbss_start__ = .;
+ *(.tbss .tbss.*)
+ }
+ __tbss_end__ = __tbss_start__ + SIZEOF(.tbss);
+
+ __tbss_load_end__ = __tbss_end__;
+
+ . = ASSERT(__tbss_end__ >= __RAM_segment_start__ && __tbss_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .tbss is too large to fit in RAM memory segment");
+
+ __tdata_load_start__ = ALIGN(__data_load_start__ + SIZEOF(.data) , 4);
+ .tdata ALIGN(__tbss_end__ , 4) : AT(ALIGN(__data_load_start__ + SIZEOF(.data) , 4))
+ {
+ __tdata_start__ = .;
+ *(.tdata .tdata.*)
+ }
+ __tdata_end__ = __tdata_start__ + SIZEOF(.tdata);
+
+ __tdata_load_end__ = __tdata_load_start__ + SIZEOF(.tdata);
+
+ __FLASH_segment_used_end__ = ALIGN(__data_load_start__ + SIZEOF(.data) , 4) + SIZEOF(.tdata);
+
+ . = ASSERT((__tdata_load_start__ + SIZEOF(.tdata)) >= __FLASH_segment_start__ && (__tdata_load_start__ + SIZEOF(.tdata)) <= (__FLASH_segment_start__ + 0x00020000) , "error: .tdata is too large to fit in FLASH memory segment");
+
+ .tdata_run ALIGN(__tbss_end__ , 4) (NOLOAD) :
+ {
+ __tdata_run_start__ = .;
+ . = MAX(__tdata_run_start__ + SIZEOF(.tdata), .);
+ }
+ __tdata_run_end__ = __tdata_run_start__ + SIZEOF(.tdata_run);
+
+ __tdata_run_load_end__ = __tdata_run_end__;
+
+ __RAM_segment_used_end__ = ALIGN(__tbss_end__ , 4) + SIZEOF(.tdata_run);
+
+ . = ASSERT(__tdata_run_end__ >= __RAM_segment_start__ && __tdata_run_end__ <= (__RAM_segment_start__ + 0x00004000) , "error: .tdata_run is too large to fit in RAM memory segment");
+
+}
+
diff --git a/Target/Source/ARMCM3_EFM32/Crossworks/vectors.c b/Target/Source/ARMCM3_EFM32/Crossworks/vectors.c
new file mode 100644
index 00000000..04c59c7a
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/Crossworks/vectors.c
@@ -0,0 +1,127 @@
+/****************************************************************************************
+| Description: bootloader interrupt vector table source file
+| File Name: vectors.c
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+
+/****************************************************************************************
+* Include files
+****************************************************************************************/
+#include "boot.h" /* bootloader generic header */
+
+
+/****************************************************************************************
+* External functions
+****************************************************************************************/
+extern void reset_handler(void); /* implemented in cstart.s */
+
+
+/****************************************************************************************
+* External data declarations
+****************************************************************************************/
+extern blt_int32u __stack_end__; /* stack end address (memory.x) */
+
+
+/****************************************************************************************
+** NAME: UnusedISR
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Catch-all for unused interrrupt service routines.
+**
+****************************************************************************************/
+void UnusedISR(void)
+{
+ /* unexpected interrupt occured, so trigger an assertion to halt the system */
+ ASSERT_RT(BLT_FALSE);
+} /*** end of UnusedISR ***/
+
+
+/****************************************************************************************
+* I N T E R R U P T V E C T O R T A B L E
+****************************************************************************************/
+typedef union
+{
+ void (*func)(void); /* for ISR function pointers */
+ blt_int32u ptr; /* for stack pointer entry */
+}tIsrFunc; /* type for vector table entries */
+
+__attribute__ ((section(".vectors")))
+const tIsrFunc _vectors[] =
+{
+ { .ptr = (blt_int32u)&__stack_end__ }, /* the initial stack pointer */
+ reset_handler, /* the reset handler */
+ UnusedISR, /* NMI Handler */
+ UnusedISR, /* Hard Fault Handler */
+ UnusedISR, /* MPU Fault Handler */
+ UnusedISR, /* Bus Fault Handler */
+ UnusedISR, /* Usage Fault Handler */
+ UnusedISR, /* Reserved */
+ UnusedISR, /* Reserved */
+ UnusedISR, /* Reserved */
+ UnusedISR, /* Reserved */
+ UnusedISR, /* SVCall Handler */
+ UnusedISR, /* Debug Monitor Handler */
+ UnusedISR, /* Reserved */
+ UnusedISR, /* PendSV Handler */
+ UnusedISR, /* SysTick Handler */
+ UnusedISR, /* 0 - DMA Handler */
+ UnusedISR, /* 1 - GPIO_EVEN Handler */
+ UnusedISR, /* 2 - TIMER0 Handler */
+ UnusedISR, /* 3 - USART0_RX Handler */
+ UnusedISR, /* 4 - USART0_TX Handler */
+ UnusedISR, /* 5 - ACMP0 Handler */
+ UnusedISR, /* 6 - ADC0 Handler */
+ UnusedISR, /* 7 - DAC0 Handler */
+ UnusedISR, /* 8 - I2C0 Handler */
+ UnusedISR, /* 9 - GPIO_ODD Handler */
+ UnusedISR, /* 10 - TIMER1 Handler */
+ UnusedISR, /* 11 - TIMER2 Handler */
+ UnusedISR, /* 12 - USART1_RX Handler */
+ UnusedISR, /* 13 - USART1_TX Handler */
+ UnusedISR, /* 14 - USART2_RX Handler */
+ UnusedISR, /* 15 - USART2_TX Handler */
+ UnusedISR, /* 16 - UART0_RX Handler */
+ UnusedISR, /* 17 - UART0_TX Handler */
+ UnusedISR, /* 18 - LEUART0 Handler */
+ UnusedISR, /* 19 - LEUART1 Handler */
+ UnusedISR, /* 20 - LETIMER0 Handler */
+ UnusedISR, /* 21 - PCNT0 Handler */
+ UnusedISR, /* 22 - PCNT1 Handler */
+ UnusedISR, /* 23 - PCNT2 Handler */
+ UnusedISR, /* 24 - RTC Handler */
+ UnusedISR, /* 25 - CMU Handler */
+ UnusedISR, /* 26 - VCMP Handler */
+ UnusedISR, /* 27 - LCD Handler */
+ UnusedISR, /* 28 - MSC Handler */
+ UnusedISR /* 29 - AES Handler */
+};
+
+
+/************************************ end of hw.c **************************************/
+
+
diff --git a/Target/Source/ARMCM3_EFM32/cpu.c b/Target/Source/ARMCM3_EFM32/cpu.c
new file mode 100644
index 00000000..a5913346
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/cpu.c
@@ -0,0 +1,132 @@
+/****************************************************************************************
+| Description: bootloader cpu module source file
+| File Name: cpu.c
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+
+/****************************************************************************************
+* Include files
+****************************************************************************************/
+#include "boot.h" /* bootloader generic header */
+
+
+/****************************************************************************************
+* Macro definitions
+****************************************************************************************/
+#define CPU_USER_PROGRAM_STARTADDR_PTR ((blt_addr) 0x00004004)
+#define CPU_USER_PROGRAM_VECTABLE_OFFSET ((blt_int32u)0x00004000)
+
+/****************************************************************************************
+* Register definitions
+****************************************************************************************/
+/* vector table offset register */
+#define SCB_VTOR (*((volatile blt_int32u *) 0xE000ED08))
+
+
+/****************************************************************************************
+* External functions
+****************************************************************************************/
+extern void reset_handler(void); /* implemented in cstart.s */
+
+
+/****************************************************************************************
+** NAME: CpuStartUserProgram
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Starts the user program, if one is present. In this case this function
+** does not return.
+**
+****************************************************************************************/
+void CpuStartUserProgram(void)
+{
+ void (*pProgResetHandler)(void);
+
+ /* check if a user program is present by verifying the checksum */
+ if (NvmVerifyChecksum() == BLT_FALSE)
+ {
+ /* not a valid user program so it cannot be started */
+ return;
+ }
+ /* release the communication interface */
+ ComFree();
+ /* remap user program's vector table */
+ SCB_VTOR = CPU_USER_PROGRAM_VECTABLE_OFFSET & (blt_int32u)0x1FFFFF80;
+ /* set the address where the bootloader needs to jump to. this is the address of
+ * the 2nd entry in the user program's vector table. this address points to the
+ * user program's reset handler.
+ */
+ pProgResetHandler = (void(*)(void))(*((blt_addr*)CPU_USER_PROGRAM_STARTADDR_PTR));
+ /* start the user program by activating its reset interrupt service routine */
+ pProgResetHandler();
+} /*** end of CpuStartUserProgram ***/
+
+
+/****************************************************************************************
+** NAME: CpuMemCopy
+** PARAMETER: dest destination address for the data.
+** src source address of the data.
+** len length of the data in bytes.
+** RETURN VALUE: none
+** DESCRIPTION: Copies data from the source to the destination address.
+**
+****************************************************************************************/
+void CpuMemCopy(blt_addr dest, blt_addr src, blt_int16u len)
+{
+ blt_int8u *from, *to;
+
+ /* set casted pointers */
+ from = (blt_int8u *)src;
+ to = (blt_int8u *)dest;
+
+ /* copy all bytes from source address to destination address */
+ while(len-- > 0)
+ {
+ /* store byte value from source to destination */
+ *to++ = *from++;
+ /* keep the watchdog happy */
+ CopService();
+ }
+} /*** end of CpuMemCopy ***/
+
+
+/****************************************************************************************
+** NAME: CpuReset
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Perform a soft reset of the microcontroller by starting from the reset
+** ISR.
+**
+****************************************************************************************/
+void CpuReset(void)
+{
+ /* perform a software reset by calling the reset ISR routine */
+ reset_handler();
+} /*** end of CpuReset ***/
+
+
+/*********************************** end of cpu.c **************************************/
diff --git a/Target/Source/ARMCM3_EFM32/cpu.h b/Target/Source/ARMCM3_EFM32/cpu.h
new file mode 100644
index 00000000..e8722991
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/cpu.h
@@ -0,0 +1,44 @@
+/****************************************************************************************
+| Description: bootloader cpu module header file
+| File Name: cpu.h
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+#ifndef CPU_H
+#define CPU_H
+
+
+/****************************************************************************************
+* Function prototypes
+****************************************************************************************/
+void CpuStartUserProgram(void);
+void CpuMemCopy(blt_addr dest, blt_addr src, blt_int16u len);
+void CpuReset(void);
+
+
+#endif /* CPU_H */
+/*********************************** end of cpu.h **************************************/
diff --git a/Target/Source/ARMCM3_EFM32/flash.c b/Target/Source/ARMCM3_EFM32/flash.c
new file mode 100644
index 00000000..39647358
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/flash.c
@@ -0,0 +1,745 @@
+/****************************************************************************************
+| Description: bootloader flash driver source file
+| File Name: flash.c
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+
+/****************************************************************************************
+* Include files
+****************************************************************************************/
+#include "boot.h" /* bootloader generic header */
+#include "efm32_msc.h" /* MSC driver from EFM32 library */
+
+
+/****************************************************************************************
+* Macro definitions
+****************************************************************************************/
+#define FLASH_INVALID_SECTOR (0xff)
+#define FLASH_INVALID_ADDRESS (0xffffffff)
+#define FLASH_WRITE_BLOCK_SIZE (512)
+#define FLASH_TOTAL_SECTORS (sizeof(flashLayout)/sizeof(flashLayout[0]))
+#define FLASH_VECTOR_TABLE_CS_OFFSET (0x0B8)
+
+
+/****************************************************************************************
+* Type definitions
+****************************************************************************************/
+/* flash sector descriptor type */
+typedef struct
+{
+ blt_addr sector_start; /* sector start address */
+ blt_int32u sector_size; /* sector size in bytes */
+ blt_int8u sector_num; /* sector number */
+} tFlashSector; /* flash sector description */
+
+/* programming is done per block of max FLASH_WRITE_BLOCK_SIZE. for this a flash block
+ * manager is implemented in this driver. this flash block manager depends on this
+ * flash block info structure. It holds the base address of the flash block and the
+ * data that should be programmed into the flash block. The .base_addr must be a multiple
+ * of FLASH_WRITE_BLOCK_SIZE.
+ */
+typedef struct
+{
+ blt_addr base_addr;
+ blt_int8u data[FLASH_WRITE_BLOCK_SIZE];
+} tFlashBlockInfo;
+
+
+/****************************************************************************************
+* Function prototypes
+****************************************************************************************/
+static blt_bool FlashInitBlock(tFlashBlockInfo *block, blt_addr address);
+static tFlashBlockInfo *FlashSwitchBlock(tFlashBlockInfo *block, blt_addr base_addr);
+static blt_bool FlashAddToBlock(tFlashBlockInfo *block, blt_addr address,
+ blt_int8u *data, blt_int16u len);
+static blt_bool FlashWriteBlock(tFlashBlockInfo *block);
+static blt_bool FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector);
+static blt_int8u FlashGetSector(blt_addr address);
+static blt_addr FlashGetSectorBaseAddr(blt_int8u sector);
+static blt_addr FlashGetSectorSize(blt_int8u sector);
+static blt_int32u FlashCalcPageSize(void);
+
+
+/****************************************************************************************
+* Local constant declarations
+****************************************************************************************/
+/* The current flash layout does not reflect the minimum sector size of the physical
+ * flash (1 - 2kb), because this would make the table quit long and a waste of ROM. The
+ * minimum sector size is only really needed when erasing the flash. This can still be
+ * done in combination with macro FLASH_ERASE_BLOCK_SIZE.
+ */
+static const tFlashSector flashLayout[] =
+{
+ /* { 0x00000000, 0x02000, 0}, flash sector 0 - reserved for bootloader */
+ /* { 0x00002000, 0x02000, 1}, flash sector 1 - reserved for bootloader */
+ { 0x00004000, 0x02000, 2}, /* flash sector 2 - 8kb */
+ { 0x00006000, 0x02000, 3}, /* flash sector 3 - 8kb */
+#if (BOOT_NVM_SIZE_KB > 32)
+ { 0x00008000, 0x02000, 4}, /* flash sector 4 - 8kb */
+ { 0x0000A000, 0x02000, 5}, /* flash sector 5 - 8kb */
+ { 0x0000C000, 0x02000, 6}, /* flash sector 6 - 8kb */
+ { 0x0000E000, 0x02000, 7}, /* flash sector 7 - 8kb */
+#endif
+#if (BOOT_NVM_SIZE_KB > 64)
+ { 0x00010000, 0x02000, 8}, /* flash sector 8 - 8kb */
+ { 0x00012000, 0x02000, 9}, /* flash sector 9 - 8kb */
+ { 0x00014000, 0x02000, 10}, /* flash sector 10 - 8kb */
+ { 0x00016000, 0x02000, 11}, /* flash sector 11 - 8kb */
+ { 0x00018000, 0x02000, 12}, /* flash sector 12 - 8kb */
+ { 0x0001A000, 0x02000, 13}, /* flash sector 13 - 8kb */
+ { 0x0001C000, 0x02000, 14}, /* flash sector 14 - 8kb */
+ { 0x0001E000, 0x02000, 15}, /* flash sector 15 - 8kb */
+#endif
+#if (BOOT_NVM_SIZE_KB > 128)
+ { 0x00020000, 0x08000, 16}, /* flash sector 16 - 32kb */
+ { 0x00028000, 0x08000, 17}, /* flash sector 17 - 32kb */
+ { 0x00030000, 0x08000, 18}, /* flash sector 18 - 32kb */
+ { 0x00038000, 0x08000, 19}, /* flash sector 19 - 32kb */
+#endif
+#if (BOOT_NVM_SIZE_KB > 256)
+ { 0x00040000, 0x08000, 20}, /* flash sector 20 - 32kb */
+ { 0x00048000, 0x08000, 21}, /* flash sector 21 - 32kb */
+ { 0x00050000, 0x08000, 22}, /* flash sector 22 - 32kb */
+ { 0x00058000, 0x08000, 23}, /* flash sector 23 - 32kb */
+ { 0x00060000, 0x08000, 24}, /* flash sector 24 - 32kb */
+ { 0x00068000, 0x08000, 25}, /* flash sector 25 - 32kb */
+ { 0x00070000, 0x08000, 26}, /* flash sector 26 - 32kb */
+ { 0x00078000, 0x08000, 27}, /* flash sector 27 - 32kb */
+#endif
+#if (BOOT_NVM_SIZE_KB > 512)
+#error "BOOT_NVM_SIZE_KB > 512 is currently not supported."
+#endif
+};
+
+
+/****************************************************************************************
+* Local data declarations
+****************************************************************************************/
+/* The smallest amount of flash that can be programmed is FLASH_WRITE_BLOCK_SIZE. A flash
+ * block manager is implemented in this driver and stores info in this variable. Whenever
+ * new data should be flashed, it is first added to a RAM buffer, which is part of this
+ * variable. Whenever the RAM buffer, which has the size of a flash block, is full or
+ * data needs to be written to a different block, the contents of the RAM buffer are
+ * programmed to flash. The flash block manager requires some software overhead, yet
+ * results is faster flash programming because data is first harvested, ideally until
+ * there is enough to program an entire flash block, before the flash device is actually
+ * operated on.
+ */
+static tFlashBlockInfo blockInfo;
+
+/* The first block of the user program holds the vector table, which on the STM32 is
+ * also the where the checksum is written to. Is it likely that the vector table is
+ * first flashed and then, at the end of the programming sequence, the checksum. This
+ * means that this flash block need to be written to twice. Normally this is not a
+ * problem with flash memory, as long as you write the same values to those bytes that
+ * are not supposed to be changed and the locations where you do write to are still in
+ * the erased 0xFF state. Unfortunately, writing twice to flash this way, does not work
+ * reliably on all micros. This is why we need to have an extra block, the bootblock,
+ * placed under the management of the block manager. This way is it possible to implement
+ * functionality so that the bootblock is only written to once at the end of the
+ * programming sequency.
+ */
+static tFlashBlockInfo bootBlockInfo;
+
+
+/****************************************************************************************
+** NAME: FlashInit
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Initializes the flash driver.
+**
+****************************************************************************************/
+void FlashInit(void)
+{
+ /* enable the flash controller for writing */
+ MSC_Init();
+ /* init the flash block info structs by setting the address to an invalid address */
+ blockInfo.base_addr = FLASH_INVALID_ADDRESS;
+ bootBlockInfo.base_addr = FLASH_INVALID_ADDRESS;
+} /*** end of FlashInit ***/
+
+
+/****************************************************************************************
+** NAME: FlashWrite
+** PARAMETER: addr start address
+** len length in bytes
+** data pointer to the data buffer.
+** RETURN VALUE: BLT_TRUE if successful, BLT_FALSE otherwise.
+** DESCRIPTION: Writes the data to flash through a flash block manager. Note that this
+** function also checks that no data is programmed outside the flash
+** memory region, so the bootloader can never be overwritten.
+**
+****************************************************************************************/
+blt_bool FlashWrite(blt_addr addr, blt_int32u len, blt_int8u *data)
+{
+ blt_addr base_addr;
+
+ /* make sure the addresses are within the flash device */
+ if ( (FlashGetSector(addr) == FLASH_INVALID_SECTOR) || \
+ (FlashGetSector(addr+len-1) == FLASH_INVALID_SECTOR) )
+ {
+ return BLT_FALSE;
+ }
+
+ /* if this is the bootblock, then let the boot block manager handle it */
+ base_addr = (addr/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE;
+ if (base_addr == flashLayout[0].sector_start)
+ {
+ /* let the boot block manager handle it */
+ return FlashAddToBlock(&bootBlockInfo, addr, data, len);
+ }
+ /* let the block manager handle it */
+ return FlashAddToBlock(&blockInfo, addr, data, len);
+} /*** end of FlashWrite ***/
+
+
+/****************************************************************************************
+** NAME: FlashErase
+** PARAMETER: addr start address
+** len length in bytes
+** RETURN VALUE: BLT_TRUE if successful, BLT_FALSE otherwise.
+** DESCRIPTION: Erases the flash memory. Note that this function also checks that no
+** data is erased outside the flash memory region, so the bootloader can
+** never be erased.
+**
+****************************************************************************************/
+blt_bool FlashErase(blt_addr addr, blt_int32u len)
+{
+ blt_int8u first_sector;
+ blt_int8u last_sector;
+
+ /* obtain the first and last sector number */
+ first_sector = FlashGetSector(addr);
+ last_sector = FlashGetSector(addr+len-1);
+ /* check them */
+ if ( (first_sector == FLASH_INVALID_SECTOR) || (last_sector == FLASH_INVALID_SECTOR) )
+ {
+ return BLT_FALSE;
+ }
+ /* erase the sectors */
+ return FlashEraseSectors(first_sector, last_sector);
+} /*** end of FlashErase ***/
+
+
+/****************************************************************************************
+** NAME: FlashWriteChecksum
+** PARAMETER: none
+** RETURN VALUE: BLT_TRUE is successful, BTL_FALSE otherwise.
+** DESCRIPTION: Writes a checksum of the user program to non-volatile memory. This is
+** performed once the entire user program has been programmed. Through
+** the checksum, the bootloader can check if the programming session
+** was completed, which indicates that a valid user programming is
+** present and can be started.
+**
+****************************************************************************************/
+blt_bool FlashWriteChecksum(void)
+{
+ blt_int32u signature_checksum = 0;
+
+ /* for the STM32 target we defined the checksum as the Two's complement value of the
+ * sum of the first 7 exception addresses.
+ *
+ * Layout of the vector table:
+ * 0x00000000 Initial stack pointer
+ * 0x00000004 Reset Handler
+ * 0x00000008 NMI Handler
+ * 0x0000000C Hard Fault Handler
+ * 0x00000010 MPU Fault Handler
+ * 0x00000014 Bus Fault Handler
+ * 0x00000018 Usage Fault Handler
+ *
+ * signature_checksum = Two's complement of (SUM(exception address values))
+ *
+ * the bootloader writes this 32-bit checksum value right after the vector table
+ * of the user program. note that this means one extra dummy entry must be added
+ * at the end of the user program's vector table to reserve storage space for the
+ * checksum.
+ */
+
+ /* first check that the bootblock contains valid data. if not, this means the
+ * bootblock is not part of the reprogramming this time and therefore no
+ * new checksum needs to be written
+ */
+ if (bootBlockInfo.base_addr == FLASH_INVALID_ADDRESS)
+ {
+ return BLT_TRUE;
+ }
+
+ /* compute the checksum. note that the user program's vectors are not yet written
+ * to flash but are present in the bootblock data structure at this point.
+ */
+ signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x00]));
+ signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x04]));
+ signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x08]));
+ signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x0C]));
+ signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x10]));
+ signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x14]));
+ signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x18]));
+ signature_checksum = ~signature_checksum; /* one's complement */
+ signature_checksum += 1; /* two's complement */
+
+ /* write the checksum */
+ return FlashWrite(flashLayout[0].sector_start+FLASH_VECTOR_TABLE_CS_OFFSET,
+ sizeof(blt_addr), (blt_int8u*)&signature_checksum);
+} /*** end of FlashWriteChecksum ***/
+
+
+/****************************************************************************************
+** NAME: FlashVerifyChecksum
+** PARAMETER: none
+** RETURN VALUE: BLT_TRUE is successful, BTL_FALSE otherwise.
+** DESCRIPTION: Verifies the checksum, which indicates that a valid user program is
+** present and can be started.
+**
+****************************************************************************************/
+blt_bool FlashVerifyChecksum(void)
+{
+ blt_int32u signature_checksum = 0;
+
+ /* verify the checksum based on how it was written by CpuWriteChecksum() */
+ signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start));
+ signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x04));
+ signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x08));
+ signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x0C));
+ signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x10));
+ signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x14));
+ signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x18));
+ signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+FLASH_VECTOR_TABLE_CS_OFFSET));
+ /* sum should add up to an unsigned 32-bit value of 0 */
+ if (signature_checksum == 0)
+ {
+ /* checksum okay */
+ return BLT_TRUE;
+ }
+ /* checksum incorrect */
+ return BLT_FALSE;
+} /*** end of FlashVerifyChecksum ***/
+
+
+/****************************************************************************************
+** NAME: FlashDone
+** PARAMETER: none
+** RETURN VALUE: BLT_TRUE is succesful, BLT_FALSE otherwise.
+** DESCRIPTION: Finilizes the flash driver operations. There could still be data in
+** the currently active block that needs to be flashed.
+**
+****************************************************************************************/
+blt_bool FlashDone(void)
+{
+ /* check if there is still data waiting to be programmed in the boot block */
+ if (bootBlockInfo.base_addr != FLASH_INVALID_ADDRESS)
+ {
+ if (FlashWriteBlock(&bootBlockInfo) == BLT_FALSE)
+ {
+ return BLT_FALSE;
+ }
+ }
+
+ /* check if there is still data waiting to be programmed */
+ if (blockInfo.base_addr != FLASH_INVALID_ADDRESS)
+ {
+ if (FlashWriteBlock(&blockInfo) == BLT_FALSE)
+ {
+ return BLT_FALSE;
+ }
+ }
+ /* disable the flash controller for writing */
+ MSC_Deinit();
+ /* still here so all is okay */
+ return BLT_TRUE;
+} /*** end of FlashDone ***/
+
+
+/****************************************************************************************
+** NAME: FlashInitBlock
+** PARAMETER: block pointer to flash block info structure to operate on.
+** address base address of the block data.
+** RETURN VALUE: BLT_TRUE is succesful, BLT_FALSE otherwise.
+** DESCRIPTION: Copies data currently in flash to the block->data and sets the
+** base address.
+**
+****************************************************************************************/
+static blt_bool FlashInitBlock(tFlashBlockInfo *block, blt_addr address)
+{
+ /* check address alignment */
+ if ((address % FLASH_WRITE_BLOCK_SIZE) != 0)
+ {
+ return BLT_FALSE;
+ }
+ /* make sure that we are initializing a new block and not the same one */
+ if (block->base_addr == address)
+ {
+ /* block already initialized, so nothing to do */
+ return BLT_TRUE;
+ }
+ /* set the base address and copies the current data from flash */
+ block->base_addr = address;
+ CpuMemCopy((blt_addr)block->data, address, FLASH_WRITE_BLOCK_SIZE);
+ return BLT_TRUE;
+} /*** end of FlashInitBlock ***/
+
+
+/****************************************************************************************
+** NAME: FlashSwitchBlock
+** PARAMETER: block pointer to flash block info structure to operate on.
+** base_addr base address for the next block
+** RETURN VALUE: the pointer of the block info struct that is no being used, or a NULL
+** pointer in case of error.
+** DESCRIPTION: Switches blocks by programming the current one and initializing the
+** next.
+**
+****************************************************************************************/
+static tFlashBlockInfo *FlashSwitchBlock(tFlashBlockInfo *block, blt_addr base_addr)
+{
+ /* check if a switch needs to be made away from the boot block. in this case the boot
+ * block shouldn't be written yet, because this is done at the end of the programming
+ * session by FlashDone(), this is right after the checksum was written.
+ */
+ if (block == &bootBlockInfo)
+ {
+ /* switch from the boot block to the generic block info structure */
+ block = &blockInfo;
+ }
+ /* check if a switch back into the bootblock is needed. in this case the generic block
+ * doesn't need to be written here yet.
+ */
+ else if (base_addr == flashLayout[0].sector_start)
+ {
+ /* switch from the generic block to the boot block info structure */
+ block = &bootBlockInfo;
+ base_addr = flashLayout[0].sector_start;
+ }
+ else
+ {
+ /* need to switch to a new block, so program the current one and init the next */
+ if (FlashWriteBlock(block) == BLT_FALSE)
+ {
+ return BLT_NULL;
+ }
+ }
+
+ /* initialize tne new block when necessary */
+ if (FlashInitBlock(block, base_addr) == BLT_FALSE)
+ {
+ return BLT_NULL;
+ }
+
+ /* still here to all is okay */
+ return block;
+} /*** end of FlashSwitchBlock ***/
+
+
+/****************************************************************************************
+** NAME: FlashAddToBlock
+** PARAMETER: block pointer to flash block info structure to operate on.
+** address flash destination address
+** data pointer to the byte array with data
+** len number of bytes to add to the block
+** RETURN VALUE: BLT_TRUE if successful, BLT_FALSE otherwise.
+** DESCRIPTION: Programming is done per block. This function adds data to the block
+** that is currently collecting data to be written to flash. If the
+** address is outside of the current block, the current block is written
+** to flash an a new block is initialized.
+**
+****************************************************************************************/
+static blt_bool FlashAddToBlock(tFlashBlockInfo *block, blt_addr address,
+ blt_int8u *data, blt_int16u len)
+{
+ blt_addr current_base_addr;
+ blt_int8u *dst;
+ blt_int8u *src;
+
+ /* determine the current base address */
+ current_base_addr = (address/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE;
+
+ /* make sure the blockInfo is not uninitialized */
+ if (block->base_addr == FLASH_INVALID_ADDRESS)
+ {
+ /* initialize the blockInfo struct for the current block */
+ if (FlashInitBlock(block, current_base_addr) == BLT_FALSE)
+ {
+ return BLT_FALSE;
+ }
+ }
+
+ /* check if the new data fits in the current block */
+ if (block->base_addr != current_base_addr)
+ {
+ /* need to switch to a new block, so program the current one and init the next */
+ block = FlashSwitchBlock(block, current_base_addr);
+ if (block == BLT_NULL)
+ {
+ return BLT_FALSE;
+ }
+ }
+
+ /* add the data to the current block, but check for block overflow */
+ dst = &(block->data[address - block->base_addr]);
+ src = data;
+ do
+ {
+ /* keep the watchdog happy */
+ CopService();
+ /* buffer overflow? */
+ if ((blt_addr)(dst-&(block->data[0])) >= FLASH_WRITE_BLOCK_SIZE)
+ {
+ /* need to switch to a new block, so program the current one and init the next */
+ block = FlashSwitchBlock(block, current_base_addr+FLASH_WRITE_BLOCK_SIZE);
+ if (block == BLT_NULL)
+ {
+ return BLT_FALSE;
+ }
+ /* reset destination pointer */
+ dst = &(block->data[0]);
+ }
+ /* write the data to the buffer */
+ *dst = *src;
+ /* update pointers */
+ dst++;
+ src++;
+ /* decrement byte counter */
+ len--;
+ }
+ while (len > 0);
+ /* still here so all is good */
+ return BLT_TRUE;
+} /*** end of FlashAddToBlock ***/
+
+
+/****************************************************************************************
+** NAME: FlashWriteBlock
+** PARAMETER: block pointer to flash block info structure to operate on.
+** RETURN VALUE: BLT_TRUE if successful, BLT_FALSE otherwise.
+** DESCRIPTION: Programs FLASH_WRITE_BLOCK_SIZE bytes to flash from the block->data
+** array.
+**
+****************************************************************************************/
+static blt_bool FlashWriteBlock(tFlashBlockInfo *block)
+{
+ blt_int8u sector_num;
+ msc_Return_TypeDef result;
+ blt_addr prog_addr;
+ blt_int32u prog_data;
+ blt_int32u word_cnt;
+
+
+ /* check that address is actually within flash */
+ sector_num = FlashGetSector(block->base_addr);
+ if (sector_num == FLASH_INVALID_SECTOR)
+ {
+ return BLT_FALSE;
+ }
+
+ /* program all words in the block one by one */
+ for (word_cnt=0; word_cnt<(FLASH_WRITE_BLOCK_SIZE/sizeof(blt_int32u)); word_cnt++)
+ {
+ prog_addr = block->base_addr + (word_cnt * sizeof(blt_int32u));
+ prog_data = *(volatile blt_int32u*)(&block->data[word_cnt * sizeof(blt_int32u)]);
+ /* keep the watchdog happy */
+ CopService();
+ /* program a word */
+ if (MSC_WriteWord((uint32_t *)prog_addr, &prog_data, sizeof(blt_int32u)) != mscReturnOk)
+ {
+ result = BLT_FALSE;
+ break;
+ }
+ /* verify that the written data is actually there */
+ if (*(volatile blt_int32u*)prog_addr != prog_data)
+ {
+ result = BLT_FALSE;
+ break;
+ }
+ }
+ /* still here so all is okay */
+ return BLT_TRUE;
+} /*** end of FlashWriteBlock ***/
+
+
+/****************************************************************************************
+** NAME: FlashCalcPageSize
+** PARAMETER: none
+** RETURN VALUE: The flash page size
+** DESCRIPTION: Determines the flash page size for the specific EFM32 derivative. This
+** is the minimum erase size.
+**
+****************************************************************************************/
+static blt_int32u FlashCalcPageSize(void)
+{
+ blt_int8u family = *(blt_int8u*)0x0FE081FE;
+
+ if ( ( family == 71 ) || ( family == 73 ) )
+ {
+ /* Gecko and Tiny, 'G' or 'I' */
+ return 512;
+ }
+ else if ( family == 72 )
+ {
+ /* Giant, 'H' */
+ return 4096;
+ }
+ else
+ {
+ /* Leopard, 'J' */
+ return 2048;
+ }
+} /*** end of FlashCalcPageSize ***/
+
+
+/****************************************************************************************
+** NAME: FlashEraseSectors
+** PARAMETER: first_sector first flash sector number
+** last_sector last flash sector number
+** RETURN VALUE: BLT_TRUE if successful, BLT_FALSE otherwise.
+** DESCRIPTION: Erases the flash sectors from first_sector up until last_sector
+**
+****************************************************************************************/
+static blt_bool FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector)
+{
+ blt_int16u nr_of_blocks;
+ blt_int16u block_cnt;
+ blt_addr start_addr;
+ blt_addr end_addr;
+ blt_int32u erase_block_size;
+
+ /* validate the sector numbers */
+ if (first_sector > last_sector)
+ {
+ return BLT_FALSE;
+ }
+ if ( (first_sector < flashLayout[0].sector_num) || \
+ (last_sector > flashLayout[FLASH_TOTAL_SECTORS-1].sector_num) )
+ {
+ return BLT_FALSE;
+ }
+ /* determine the minimum erase size */
+ erase_block_size = FlashCalcPageSize();
+ /* determine how many blocks need to be erased */
+ start_addr = FlashGetSectorBaseAddr(first_sector);
+ end_addr = FlashGetSectorBaseAddr(last_sector) + FlashGetSectorSize(last_sector) - 1;
+ nr_of_blocks = (end_addr - start_addr + 1) / erase_block_size;
+
+ /* erase all blocks one by one */
+ for (block_cnt=0; block_cnt= flashLayout[sectorIdx].sector_start) && \
+ (address < (flashLayout[sectorIdx].sector_start + \
+ flashLayout[sectorIdx].sector_size)) )
+ {
+ /* return the sector number */
+ return flashLayout[sectorIdx].sector_num;
+ }
+ }
+ /* still here so no valid sector found */
+ return FLASH_INVALID_SECTOR;
+} /*** end of FlashGetSector ***/
+
+
+/****************************************************************************************
+** NAME: FlashGetSectorBaseAddr
+** PARAMETER: sector sector to get the base address of.
+** RETURN VALUE: flash sector base address or FLASH_INVALID_ADDRESS
+** DESCRIPTION: Determines the flash sector base address.
+**
+****************************************************************************************/
+static blt_addr FlashGetSectorBaseAddr(blt_int8u sector)
+{
+ blt_int8u sectorIdx;
+
+ /* search through the sectors to find the right one */
+ for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++)
+ {
+ /* keep the watchdog happy */
+ CopService();
+ if (flashLayout[sectorIdx].sector_num == sector)
+ {
+ return flashLayout[sectorIdx].sector_start;
+ }
+ }
+ /* still here so no valid sector found */
+ return FLASH_INVALID_ADDRESS;
+} /*** end of FlashGetSectorBaseAddr ***/
+
+
+/****************************************************************************************
+** NAME: FlashGetSectorSize
+** PARAMETER: sector sector to get the size of.
+** RETURN VALUE: flash sector size or 0
+** DESCRIPTION: Determines the flash sector size.
+**
+****************************************************************************************/
+static blt_addr FlashGetSectorSize(blt_int8u sector)
+{
+ blt_int8u sectorIdx;
+
+ /* search through the sectors to find the right one */
+ for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++)
+ {
+ /* keep the watchdog happy */
+ CopService();
+ if (flashLayout[sectorIdx].sector_num == sector)
+ {
+ return flashLayout[sectorIdx].sector_size;
+ }
+ }
+ /* still here so no valid sector found */
+ return 0;
+} /*** end of FlashGetSectorSize ***/
+
+
+/*********************************** end of flash.c ************************************/
diff --git a/Target/Source/ARMCM3_EFM32/flash.h b/Target/Source/ARMCM3_EFM32/flash.h
new file mode 100644
index 00000000..ea81acfa
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/flash.h
@@ -0,0 +1,46 @@
+/****************************************************************************************
+| Description: bootloader flash driver header file
+| File Name: flash.h
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+#ifndef FLASH_H
+#define FLASH_H
+
+/****************************************************************************************
+* Function prototypes
+****************************************************************************************/
+void FlashInit(void);
+blt_bool FlashWrite(blt_addr addr, blt_int32u len, blt_int8u *data);
+blt_bool FlashErase(blt_addr addr, blt_int32u len);
+blt_bool FlashWriteChecksum(void);
+blt_bool FlashVerifyChecksum(void);
+blt_bool FlashDone(void);
+
+
+#endif /* FLASH_H */
+/*********************************** end of flash.h ************************************/
diff --git a/Target/Source/ARMCM3_EFM32/nvm.c b/Target/Source/ARMCM3_EFM32/nvm.c
new file mode 100644
index 00000000..a84a5107
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/nvm.c
@@ -0,0 +1,201 @@
+/****************************************************************************************
+| Description: bootloader non-volatile memory driver source file
+| File Name: nvm.c
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+
+/****************************************************************************************
+* Include files
+****************************************************************************************/
+#include "boot.h" /* bootloader generic header */
+
+
+/****************************************************************************************
+* Hook functions
+****************************************************************************************/
+#if (BOOT_NVM_HOOKS_ENABLE > 0)
+extern void NvmInitHook(void);
+extern blt_int8u NvmWriteHook(blt_addr addr, blt_int32u len, blt_int8u *data);
+extern blt_int8u NvmEraseHook(blt_addr addr, blt_int32u len);
+extern blt_bool NvmDoneHook(void);
+#endif
+
+
+/****************************************************************************************
+** NAME: NvmInit
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Initializes the NVM driver.
+**
+****************************************************************************************/
+void NvmInit(void)
+{
+#if (BOOT_NVM_HOOKS_ENABLE > 0)
+ /* give the application a chance to initialize a driver for operating on NVM
+ * that is not by default supported by this driver.
+ */
+ NvmInitHook();
+#endif
+
+ /* init the internal driver */
+ FlashInit();
+} /*** end of NvmInit ***/
+
+
+/****************************************************************************************
+** NAME: NvmWrite
+** PARAMETER: addr start address
+** len length in bytes
+** data pointer to the data buffer.
+** RETURN VALUE: BLT_TRUE if successful, BLT_FALSE otherwise.
+** DESCRIPTION: Programs the non-volatile memory.
+**
+****************************************************************************************/
+blt_bool NvmWrite(blt_addr addr, blt_int32u len, blt_int8u *data)
+{
+#if (BOOT_NVM_HOOKS_ENABLE > 0)
+ blt_int8u result = BLT_NVM_NOT_IN_RANGE;
+#endif
+
+#if (BOOT_NVM_HOOKS_ENABLE > 0)
+ /* give the application a chance to operate on memory that is not by default supported
+ * by this driver.
+ */
+ result = NvmWriteHook(addr, len, data);
+
+ /* process the return code */
+ if (result == BLT_NVM_OKAY)
+ {
+ /* data was within range of the additionally supported memory and succesfully
+ * programmed, so we are all done.
+ */
+ return BLT_TRUE;
+ }
+ else if (result == BLT_NVM_ERROR)
+ {
+ /* data was within range of the additionally supported memory and attempted to be
+ * programmed, but an error occurred, so we can't continue.
+ */
+ return BLT_FALSE;
+ }
+#endif
+
+ /* still here so the internal driver should try and perform the program operation */
+ return FlashWrite(addr, len, data);
+} /*** end of NvmWrite ***/
+
+
+/****************************************************************************************
+** NAME: NvmErase
+** PARAMETER: addr start address
+** len length in bytes
+** RETURN VALUE: BLT_TRUE if successful, BLT_FALSE otherwise.
+** DESCRIPTION: Erases the non-volatile memory.
+**
+****************************************************************************************/
+blt_bool NvmErase(blt_addr addr, blt_int32u len)
+{
+#if (BOOT_NVM_HOOKS_ENABLE > 0)
+ blt_int8u result = BLT_NVM_NOT_IN_RANGE;
+#endif
+
+#if (BOOT_NVM_HOOKS_ENABLE > 0)
+ /* give the application a chance to operate on memory that is not by default supported
+ * by this driver.
+ */
+ result = NvmEraseHook(addr, len);
+
+ /* process the return code */
+ if (result == BLT_NVM_OKAY)
+ {
+ /* address was within range of the additionally supported memory and succesfully
+ * erased, so we are all done.
+ */
+ return BLT_TRUE;
+ }
+ else if (result == BLT_NVM_ERROR)
+ {
+ /* address was within range of the additionally supported memory and attempted to be
+ * erased, but an error occurred, so we can't continue.
+ */
+ return BLT_FALSE;
+ }
+#endif
+
+ /* still here so the internal driver should try and perform the erase operation */
+ return FlashErase(addr, len);
+} /*** end of NvmErase ***/
+
+
+/****************************************************************************************
+** NAME: NvmVerifyChecksum
+** PARAMETER: none
+** RETURN VALUE: BLT_TRUE is successful, BTL_FALSE otherwise.
+** DESCRIPTION: Verifies the checksum, which indicates that a valid user program is
+** present and can be started.
+**
+****************************************************************************************/
+blt_bool NvmVerifyChecksum(void)
+{
+ /* check checksum */
+ return FlashVerifyChecksum();
+} /*** end of NvmVerifyChecksum ***/
+
+
+/****************************************************************************************
+** NAME: NvmDone
+** PARAMETER: none
+** RETURN VALUE: BLT_TRUE is successful, BLT_FALSE otherwise.
+** DESCRIPTION: Once all erase and programming operations are completed, this
+** function is called, so at the end of the programming session and
+** right before a software reset is performed. It is used to calculate
+** a checksum and program this into flash. This checksum is later used
+** to determine if a valid user program is present in flash.
+**
+****************************************************************************************/
+blt_bool NvmDone(void)
+{
+#if (BOOT_NVM_HOOKS_ENABLE > 0)
+ /* give the application's NVM driver a chance to finish up */
+ if (NvmDoneHook() == BLT_FALSE)
+ {
+ /* error so no need to continue */
+ return BLT_FALSE;
+ }
+#endif
+ /* compute and write checksum, which is programmed by the internal driver */
+ if (FlashWriteChecksum() == BLT_FALSE)
+ {
+ return BLT_FALSE;
+ }
+ /* finish up internal driver operations */
+ return FlashDone();
+} /*** end of NvmDone ***/
+
+
+/*********************************** end of nvm.c **************************************/
diff --git a/Target/Source/ARMCM3_EFM32/nvm.h b/Target/Source/ARMCM3_EFM32/nvm.h
new file mode 100644
index 00000000..4b58cd8c
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/nvm.h
@@ -0,0 +1,60 @@
+/****************************************************************************************
+| Description: bootloader non-volatile memory driver header file
+| File Name: nvm.h
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+#ifndef NVM_H
+#define NVM_H
+
+/****************************************************************************************
+* Include files
+****************************************************************************************/
+#include "flash.h" /* LPC2xxx flash driver */
+
+
+/****************************************************************************************
+* Function prototypes
+****************************************************************************************/
+void NvmInit(void);
+blt_bool NvmWrite(blt_addr addr, blt_int32u len, blt_int8u *data);
+blt_bool NvmErase(blt_addr addr, blt_int32u len);
+blt_bool NvmVerifyChecksum(void);
+blt_bool NvmDone(void);
+
+
+/****************************************************************************************
+* Macro definitions
+****************************************************************************************/
+/* return codes for hook function NvmWrite/Erase */
+#define BLT_NVM_ERROR (0x00) /* return code for success */
+#define BLT_NVM_OKAY (0x01) /* return code for error */
+#define BLT_NVM_NOT_IN_RANGE (0x02) /* return code for not in range */
+
+
+#endif /* NVM_H */
+/*********************************** end of nvm.h **************************************/
diff --git a/Target/Source/ARMCM3_EFM32/timer.c b/Target/Source/ARMCM3_EFM32/timer.c
new file mode 100644
index 00000000..0e5ac9d7
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/timer.c
@@ -0,0 +1,156 @@
+/****************************************************************************************
+| Description: bootloader timer driver source file
+| File Name: timer.c
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+
+/****************************************************************************************
+* Include files
+****************************************************************************************/
+#include "boot.h" /* bootloader generic header */
+
+
+/****************************************************************************************
+* Type definitions
+****************************************************************************************/
+typedef struct
+{
+ volatile blt_int32u CTRL; /* SysTick Control and Status Register */
+ volatile blt_int32u LOAD; /* SysTick Reload Value Register */
+ volatile blt_int32u VAL; /* SysTick Current Value Register */
+} tSysTickRegs;
+
+
+/****************************************************************************************
+* Macro definitions
+****************************************************************************************/
+#define SYSTICK_BIT_CLKSOURCE ((blt_int32u)0x00000004)
+#define SYSTICK_BIT_ENABLE ((blt_int32u)0x00000001)
+#define SYSTICK_BIT_COUNTERFLAG ((blt_int32u)0x00010000)
+
+
+/****************************************************************************************
+* Local data declarations
+****************************************************************************************/
+static blt_int16u millisecond_counter;
+
+
+/****************************************************************************************
+* Register definitions
+****************************************************************************************/
+#define SYSTICK ((tSysTickRegs *) (blt_int32u)0xE000E010)
+
+
+/****************************************************************************************
+** NAME: TimerInit
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Initializes the polling based millisecond timer driver.
+**
+****************************************************************************************/
+void TimerInit(void)
+{
+ /* reset the timer configuration */
+ TimerReset();
+ /* configure the systick frequency as a 1 ms event generator */
+ SYSTICK->LOAD = BOOT_CPU_SYSTEM_SPEED_KHZ - 1;
+ /* reset the current counter value */
+ SYSTICK->VAL = 0;
+ /* select core clock as source and enable the timer */
+ SYSTICK->CTRL = SYSTICK_BIT_CLKSOURCE | SYSTICK_BIT_ENABLE;
+ /* reset the millisecond counter value */
+ TimerSet(0);
+} /*** end of TimerInit ***/
+
+
+/****************************************************************************************
+** NAME: TimerReset
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Reset the timer by placing the timer back into it's default reset
+** configuration.
+**
+****************************************************************************************/
+void TimerReset(void)
+{
+ /* set the systick's status and control register back into the default reset value */
+ SYSTICK->CTRL = 0;
+} /* end of TimerReset */
+
+
+/****************************************************************************************
+** NAME: TimerUpdate
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Updates the millisecond timer.
+**
+****************************************************************************************/
+void TimerUpdate(void)
+{
+ /* check if the milliseond event occurred */
+ if ((SYSTICK->CTRL & SYSTICK_BIT_COUNTERFLAG) != 0)
+ {
+ /* increment the millisecond counter */
+ millisecond_counter++;
+ }
+} /*** end of TimerUpdate ***/
+
+
+/****************************************************************************************
+** NAME: TimerSet
+** PARAMETER: timer_value initialize value of the millisecond timer.
+** RETURN VALUE: none
+** DESCRIPTION: Sets the initial counter value of the millisecond timer.
+**
+****************************************************************************************/
+void TimerSet(blt_int32u timer_value)
+{
+ /* set the millisecond counter value */
+ millisecond_counter = timer_value;
+} /*** end of TimerSet ***/
+
+
+/****************************************************************************************
+** NAME: TimerGet
+** PARAMETER: none
+** RETURN VALUE: current value of the millisecond timer
+** DESCRIPTION: Obtains the counter value of the millisecond timer.
+**
+****************************************************************************************/
+blt_int32u TimerGet(void)
+{
+ /* updating timer here allows this function to be called in a loop with timeout
+ * detection.
+ */
+ TimerUpdate();
+ /* read and return the amount of milliseconds that passed since initialization */
+ return millisecond_counter;
+} /*** end of TimerGet ***/
+
+
+/*********************************** end of timer.c ************************************/
diff --git a/Target/Source/ARMCM3_EFM32/timer.h b/Target/Source/ARMCM3_EFM32/timer.h
new file mode 100644
index 00000000..a0fa926b
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/timer.h
@@ -0,0 +1,45 @@
+/****************************************************************************************
+| Description: bootloader timer driver header file
+| File Name: timer.h
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+#ifndef TIMER_H
+#define TIMER_H
+
+/****************************************************************************************
+* Function prototypes
+****************************************************************************************/
+void TimerInit(void);
+void TimerUpdate(void);
+void TimerSet(blt_int32u timer_value);
+blt_int32u TimerGet(void);
+void TimerReset(void);
+
+
+#endif /* TIMER_H */
+/*********************************** end of timer.h ************************************/
diff --git a/Target/Source/ARMCM3_EFM32/types.h b/Target/Source/ARMCM3_EFM32/types.h
new file mode 100644
index 00000000..97f7bcf5
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/types.h
@@ -0,0 +1,58 @@
+/****************************************************************************************
+| Description: bootloader types header file
+| File Name: types.h
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+#ifndef TYPES_H
+#define TYPES_H
+
+
+/****************************************************************************************
+* Macro definitions
+****************************************************************************************/
+#define BLT_TRUE (1)
+#define BLT_FALSE (0)
+#define BLT_NULL ((void *)0)
+
+
+/****************************************************************************************
+* Type definitions
+****************************************************************************************/
+typedef unsigned char blt_bool; /* boolean type */
+typedef char blt_char; /* character type */
+typedef unsigned long blt_addr; /* memory address type */
+typedef unsigned char blt_int8u; /* 8-bit unsigned integer */
+typedef signed char blt_int8s; /* 8-bit signed integer */
+typedef unsigned short blt_int16u; /* 16-bit unsigned integer */
+typedef signed short blt_int16s; /* 16-bit signed integer */
+typedef unsigned int blt_int32u; /* 32-bit unsigned integer */
+typedef signed int blt_int32s; /* 32-bit signed integer */
+
+
+#endif /* TYPES_H */
+/*********************************** end of types.h ************************************/
diff --git a/Target/Source/ARMCM3_EFM32/uart.c b/Target/Source/ARMCM3_EFM32/uart.c
new file mode 100644
index 00000000..e3007577
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/uart.c
@@ -0,0 +1,224 @@
+/****************************************************************************************
+| Description: bootloader UART communication interface source file
+| File Name: uart.c
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+
+/****************************************************************************************
+* Include files
+****************************************************************************************/
+#include "boot.h" /* bootloader generic header */
+#include "efm32.h"
+#include "efm32_cmu.h"
+#include "efm32_gpio.h"
+#include "efm32_leuart.h"
+
+
+#if (BOOT_COM_UART_ENABLE > 0)
+/****************************************************************************************
+* Function prototypes
+****************************************************************************************/
+static blt_bool UartReceiveByte(blt_int8u *data);
+static blt_bool UartTransmitByte(blt_int8u data);
+
+
+/****************************************************************************************
+** NAME: UartInit
+** PARAMETER: none
+** RETURN VALUE: none
+** DESCRIPTION: Initializes the UART communication interface
+**
+****************************************************************************************/
+void UartInit(void)
+{
+ LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;
+
+ /* currently, only LEUART1 is supported */
+ ASSERT_CT(BOOT_COM_UART_CHANNEL_INDEX == 1);
+ /* max baudrate for LEUART is 9600 bps */
+ ASSERT_CT(BOOT_COM_UART_BAUDRATE <= 9600);
+ /* configure GPIO pins */
+ CMU_ClockEnable(cmuClock_GPIO, true);
+ /* to avoid false start, configure output as high */
+ GPIO_PinModeSet(gpioPortC, 6, gpioModePushPull, 1);
+ GPIO_PinModeSet(gpioPortC, 7, gpioModeInput, 0);
+ /* enable CORE LE clock in order to access LE modules */
+ CMU_ClockEnable(cmuClock_CORELE, true);
+ /* select LFXO for LEUARTs (and wait for it to stabilize) */
+ CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
+ /* do not prescale clock */
+ CMU_ClockDivSet(cmuClock_LEUART1, cmuClkDiv_1);
+ /* enable LEUART1 clock */
+ CMU_ClockEnable(cmuClock_LEUART1, true);
+ /* configure LEUART */
+ init.enable = leuartDisable;
+ LEUART_Init(LEUART1, &init);
+ LEUART_BaudrateSet(LEUART1, 0, BOOT_COM_UART_BAUDRATE);
+ /* enable pins at default location */
+ LEUART1->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN;
+ /* clear previous RX interrupts */
+ LEUART_IntClear(LEUART1, LEUART_IF_RXDATAV);
+ /* finally enable it */
+ LEUART_Enable(LEUART1, leuartEnable);
+} /*** end of UartInit ***/
+
+
+/****************************************************************************************
+** NAME: UartTransmitPacket
+** PARAMETER: data pointer to byte array with data that it to be transmitted.
+** len number of bytes that are to be transmitted.
+** RETURN VALUE: none
+** DESCRIPTION: Transmits a packet formatted for the communication interface.
+**
+****************************************************************************************/
+void UartTransmitPacket(blt_int8u *data, blt_int8u len)
+{
+ blt_int16u data_index;
+
+ /* verify validity of the len-paramenter */
+ ASSERT_RT(len <= BOOT_COM_TX_MAX_DATA);
+
+ /* first transmit the length of the packet */
+ ASSERT_RT(UartTransmitByte(len) == BLT_TRUE);
+
+ /* transmit all the packet bytes one-by-one */
+ for (data_index = 0; data_index < len; data_index++)
+ {
+ /* keep the watchdog happy */
+ CopService();
+ /* write byte */
+ ASSERT_RT(UartTransmitByte(data[data_index]) == BLT_TRUE);
+ }
+} /*** end of UartTransmitPacket ***/
+
+
+/****************************************************************************************
+** NAME: UartReceivePacket
+** PARAMETER: data pointer to byte array where the data is to be stored.
+** RETURN VALUE: BLT_TRUE if a packet was received, BLT_FALSE otherwise.
+** DESCRIPTION: Receives a communication interface packet if one is present.
+**
+****************************************************************************************/
+blt_bool UartReceivePacket(blt_int8u *data)
+{
+ static blt_int8u xcpCtoReqPacket[XCP_CTO_PACKET_LEN+1]; /* one extra for length */
+ static blt_int8u xcpCtoRxLength;
+ static blt_bool xcpCtoRxInProgress = BLT_FALSE;
+
+ /* start of cto packet received? */
+ if (xcpCtoRxInProgress == BLT_FALSE)
+ {
+ /* store the message length when received */
+ if (UartReceiveByte(&xcpCtoReqPacket[0]) == BLT_TRUE)
+ {
+ /* indicate that a cto packet is being received */
+ xcpCtoRxInProgress = BLT_TRUE;
+
+ /* reset packet data count */
+ xcpCtoRxLength = 0;
+ }
+ }
+ else
+ {
+ /* store the next packet byte */
+ if (UartReceiveByte(&xcpCtoReqPacket[xcpCtoRxLength+1]) == BLT_TRUE)
+ {
+ /* increment the packet data count */
+ xcpCtoRxLength++;
+
+ /* check to see if the entire packet was received */
+ if (xcpCtoRxLength == xcpCtoReqPacket[0])
+ {
+ /* copy the packet data */
+ CpuMemCopy((blt_int32u)data, (blt_int32u)&xcpCtoReqPacket[1], xcpCtoRxLength);
+ /* done with cto packet reception */
+ xcpCtoRxInProgress = BLT_FALSE;
+
+ /* packet reception complete */
+ return BLT_TRUE;
+ }
+ }
+ }
+ /* packet reception not yet complete */
+ return BLT_FALSE;
+} /*** end of UartReceivePacket ***/
+
+
+/****************************************************************************************
+** NAME: UartReceiveByte
+** PARAMETER: data pointer to byte where the data is to be stored.
+** RETURN VALUE: BLT_TRUE if a byte was received, BLT_FALSE otherwise.
+** DESCRIPTION: Receives a communication interface byte if one is present.
+**
+****************************************************************************************/
+static blt_bool UartReceiveByte(blt_int8u *data)
+{
+ blt_bool result = BLT_FALSE;
+
+ /* check to see if a new bytes was received */
+ if ((LEUART1->IF & LEUART_IF_RXDATAV) != 0)
+ {
+ /* store the received data byte and set return value to positive */
+ *data = LEUART_Rx(LEUART1);
+ result = BLT_TRUE;
+ }
+ /* inform caller about the result */
+ return result;
+} /*** end of UartReceiveByte ***/
+
+
+/****************************************************************************************
+** NAME: UartTransmitByte
+** PARAMETER: data value of byte that is to be transmitted.
+** RETURN VALUE: BLT_TRUE if the byte was transmitted, BLT_FALSE otherwise.
+** DESCRIPTION: Transmits a communication interface byte.
+**
+****************************************************************************************/
+static blt_bool UartTransmitByte(blt_int8u data)
+{
+ /* check if tx holding register can accept new data */
+ if ((LEUART1->STATUS & LEUART_STATUS_TXBL) == 0)
+ {
+ /* UART not ready. should not happen */
+ return BLT_FALSE;
+ }
+ /* write byte to transmit holding register */
+ LEUART_Tx(LEUART1, data);
+ /* wait for tx holding register to be empty */
+ while((LEUART1->STATUS & LEUART_STATUS_TXBL) == 0)
+ {
+ /* keep the watchdog happy */
+ CopService();
+ }
+ /* byte transmitted */
+ return BLT_TRUE;
+} /*** end of UartTransmitByte ***/
+#endif /* BOOT_COM_UART_ENABLE > 0 */
+
+
+/*********************************** end of uart.c *************************************/
diff --git a/Target/Source/ARMCM3_EFM32/uart.h b/Target/Source/ARMCM3_EFM32/uart.h
new file mode 100644
index 00000000..f4b9b5d9
--- /dev/null
+++ b/Target/Source/ARMCM3_EFM32/uart.h
@@ -0,0 +1,45 @@
+/****************************************************************************************
+| Description: bootloader UART communication interface header file
+| File Name: uart.h
+|
+|----------------------------------------------------------------------------------------
+| C O P Y R I G H T
+|----------------------------------------------------------------------------------------
+| Copyright (c) 2012 by Feaser http://www.feaser.com All rights reserved
+|
+|----------------------------------------------------------------------------------------
+| L I C E N S E
+|----------------------------------------------------------------------------------------
+| This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
+| modify it under the terms of the GNU General Public License as published by the Free
+| Software Foundation, either version 3 of the License, or (at your option) any later
+| version.
+|
+| OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+| PURPOSE. See the GNU General Public License for more details.
+|
+| You should have received a copy of the GNU General Public License along with OpenBLT.
+| If not, see .
+|
+| A special exception to the GPL is included to allow you to distribute a combined work
+| that includes OpenBLT without being obliged to provide the source code for any
+| proprietary components. The exception text is included at the bottom of the license
+| file .
+|
+****************************************************************************************/
+#ifndef UART_H
+#define UART_H
+
+#if (BOOT_COM_UART_ENABLE > 0)
+/****************************************************************************************
+* Function prototypes
+****************************************************************************************/
+void UartInit(void);
+void UartTransmitPacket(blt_int8u *data, blt_int8u len);
+blt_bool UartReceivePacket(blt_int8u *data);
+#endif /* BOOT_COM_UART_ENABLE > 0 */
+
+
+#endif /* UART_H */
+/*********************************** end of uart.h *************************************/