From 7defdc3296d110b3c6c1d66a4d6b88980529c8b2 Mon Sep 17 00:00:00 2001 From: Frank Voorburg Date: Fri, 2 Mar 2012 17:48:15 +0000 Subject: [PATCH] - Added the EFM32 port specific sources git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@24 5dc33758-31d5-4daf-9ae8-b24bf3d40d73 --- .../Source/ARMCM3_EFM32/Crossworks/cstart.s | 434 ++++++++++ .../Source/ARMCM3_EFM32/Crossworks/memory.x | 275 +++++++ .../Source/ARMCM3_EFM32/Crossworks/vectors.c | 127 +++ Target/Source/ARMCM3_EFM32/cpu.c | 132 ++++ Target/Source/ARMCM3_EFM32/cpu.h | 44 ++ Target/Source/ARMCM3_EFM32/flash.c | 745 ++++++++++++++++++ Target/Source/ARMCM3_EFM32/flash.h | 46 ++ Target/Source/ARMCM3_EFM32/nvm.c | 201 +++++ Target/Source/ARMCM3_EFM32/nvm.h | 60 ++ Target/Source/ARMCM3_EFM32/timer.c | 156 ++++ Target/Source/ARMCM3_EFM32/timer.h | 45 ++ Target/Source/ARMCM3_EFM32/types.h | 58 ++ Target/Source/ARMCM3_EFM32/uart.c | 224 ++++++ Target/Source/ARMCM3_EFM32/uart.h | 45 ++ 14 files changed, 2592 insertions(+) create mode 100644 Target/Source/ARMCM3_EFM32/Crossworks/cstart.s create mode 100644 Target/Source/ARMCM3_EFM32/Crossworks/memory.x create mode 100644 Target/Source/ARMCM3_EFM32/Crossworks/vectors.c create mode 100644 Target/Source/ARMCM3_EFM32/cpu.c create mode 100644 Target/Source/ARMCM3_EFM32/cpu.h create mode 100644 Target/Source/ARMCM3_EFM32/flash.c create mode 100644 Target/Source/ARMCM3_EFM32/flash.h create mode 100644 Target/Source/ARMCM3_EFM32/nvm.c create mode 100644 Target/Source/ARMCM3_EFM32/nvm.h create mode 100644 Target/Source/ARMCM3_EFM32/timer.c create mode 100644 Target/Source/ARMCM3_EFM32/timer.h create mode 100644 Target/Source/ARMCM3_EFM32/types.h create mode 100644 Target/Source/ARMCM3_EFM32/uart.c create mode 100644 Target/Source/ARMCM3_EFM32/uart.h 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 *************************************/