diff --git a/platform/mcu/MK22FN512xxx12/boot/bsp.cpp b/platform/mcu/MK22FN512xxx12/boot/bsp.cpp new file mode 100644 index 00000000..f44eb3b3 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/boot/bsp.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO, * + * Federico Terraneo * + * * + * This program 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. * + * * + * This program 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 this program; if not, see * + ***************************************************************************/ + +/*********************************************************************** +* bsp.cpp Part of the Miosix Embedded OS. +* Board support package, this file initializes hardware. +************************************************************************/ + +#include +#include +#include +#include + +#include + +namespace miosix +{ + +// +// Initialization +// + +void IRQbspInit() +{ + SIM->SCGC5 |= 0x3E00; // Enable GPIO clock +} + +void bspInit2() +{ + +} + +// +// Shutdown and reboot +// + +void shutdown() +{ + reboot(); +} + +void reboot() +{ + disableInterrupts(); + miosix_private::IRQsystemReboot(); +} + +} //namespace miosix diff --git a/platform/mcu/MK22FN512xxx12/boot/libc_integration.c b/platform/mcu/MK22FN512xxx12/boot/libc_integration.c deleted file mode 100644 index ebc2e8a9..00000000 --- a/platform/mcu/MK22FN512xxx12/boot/libc_integration.c +++ /dev/null @@ -1,440 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2020 by Silvano Seva IU2KWO * - * * - * This program 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. * - * * - * This program 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 this program; if not, see * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -void pthread_mutex_unlock(){} -void pthread_mutex_lock() {} -void pthread_mutex_destroy() {} -int pthread_setcancelstate(int state, int *oldstate) -{ - (void) state; - (void) oldstate; - return 0; -} - -#ifdef __cplusplus -extern "C" { -#endif - -// -// C atexit support, for thread safety and code size optimizations -// =============================================================== - -/** - * Function called by atexit(), on_exit() and __cxa_atexit() to register - * C functions/C++ destructors to be run at program termintion. - * It is called in this way: - * atexit(): __register_exitproc(__et_atexit, fn, 0, 0) - * on_exit(): __register_exitproc(__et_onexit, fn, arg, 0) - * __cxa_atexit(): __register_exitproc(__et_cxa, fn, arg, d) - * \param type to understand if the function was called by atexit, on_exit, ... - * \param fn pointer to function to be called - * \param arg 0 in case of atexit, function argument in case of on_exit, - * "this" parameter for C++ destructors registered with __cxa_atexit - * \param d __dso_handle used to selectively call C++ destructors of a shared - * library loaded dynamically, unused since Miosix does not support shared libs - * \return 0 on success - */ -int __register_exitproc(int type, void (*fn)(void), void *arg, void *d) -{ - (void) type; - (void) fn; - (void) arg; - (void) d; - - return 0; -} - -/** - * Called by exit() to call functions registered through atexit() - * \param code the exit code, for example with exit(1), code==1 - * \param d __dso_handle, see __register_exitproc - */ -void __call_exitprocs(int code, void *d) -{ - (void) code; - (void) d; -} - -/** - * \internal - * Required by C++ standard library. - * See http://lists.debian.org/debian-gcc/2003/07/msg00057.html - */ -void *__dso_handle=(void*) &__dso_handle; - - - - -// -// C/C++ system calls, to support malloc, printf, fopen, etc. -// ========================================================== - -/** - * \internal - * _exit, lock system in infinite loop until reboot - */ -void _exit(int status) -{ - (void) status; - for(;;) ; -} - -/** - * \internal - * _sbrk_r, allocates memory dynamically - */ -void *_sbrk_r(struct _reent *ptr, ptrdiff_t incr) -{ - (void) ptr; - - //This is the absolute start of the heap - extern char _end asm("_end"); //defined in the linker script - //This is the absolute end of the heap - extern char _heap_end asm("_heap_end"); //defined in the linker script - //This holds the current end of the heap (static) - static char *curHeapEnd=NULL; - //This holds the previous end of the heap - char *prevHeapEnd; - - //Check if it's first time called - if(curHeapEnd==NULL) curHeapEnd=&_end; - - prevHeapEnd=curHeapEnd; - - if((curHeapEnd+incr)>&_heap_end) - { - return (void*)(-1); - } - curHeapEnd+=incr; - - return (void*)(prevHeapEnd); -} - -/** - * \internal - * __malloc_lock, called by malloc to ensure no context switch happens during - * memory allocation. Since this environment is not a multithreaded one, this - * function is left empty. Allocating memory inside interrupts is anyway - * forbidden. - */ -void __malloc_lock() {} - -/** - * \internal - * __malloc_unlock, called by malloc after performing operations on the heap - */ -void __malloc_unlock() {} - -/** - * \internal - * __getreent(), return the reentrancy structure of the current thread. - * Used by newlib to make the C standard library thread safe. - * Not a multithreaded environment, we return global reentrancy data. - */ -struct _reent *__getreent() -{ - return _GLOBAL_REENT; -} - - - - -/** - * \internal - * _open_r, open a file. Actually unimpemented - */ -int _open_r(struct _reent *ptr, const char *name, int flags, int mode) -{ - (void) ptr; - (void) name; - (void) flags; - (void) mode; - - return -1; -} - -/** - * \internal - * _close_r, close a file. Actually unimpemented - */ -int _close_r(struct _reent *ptr, int fd) -{ - (void) ptr; - (void) fd; - - return -1; -} - -/** - * \internal - * _write_r, write to a file. - */ -int _write_r(struct _reent *ptr, int fd, const void *buf, size_t cnt) -{ - if(fd == STDOUT_FILENO || fd == STDERR_FILENO) - { - return vcom_writeBlock(buf, cnt); - } - - /* If fd is not stdout or stderr */ - ptr->_errno = EBADF; - return -1; -} - -/** - * \internal - * _read_r, read from a file. - */ -int _read_r(struct _reent *ptr, int fd, void *buf, size_t cnt) -{ - int ret = -1; - - if(fd == STDIN_FILENO) - { - for(;;) - { - ssize_t r = vcom_readBlock(buf, cnt); - if((r < 0) || (r == ((ssize_t) cnt))) - { - ret = ((int) r); - break; - } - } - } - else - { - /* If fd is not stdin */ - ptr->_errno = EBADF; - ret = -1; - } - - return ret; -} - -int _read(int fd, void *buf, size_t cnt) -{ - return _read_r(__getreent(), fd, buf, cnt); -} - -/** - * \internal - * _lseek_r, move file pointer. Actually unimpemented - */ -off_t _lseek_r(struct _reent *ptr, int fd, off_t pos, int whence) -{ - (void) ptr; - (void) fd; - (void) pos; - (void) whence; - - return -1; -} - -off_t _lseek(int fd, off_t pos, int whence) -{ - (void) fd; - (void) pos; - (void) whence; - - return -1; -} - -/** - * \internal - * _fstat_r, return file info. Actually unimpemented - */ -int _fstat_r(struct _reent *ptr, int fd, struct stat *pstat) -{ - (void) ptr; - (void) fd; - (void) pstat; - - return -1; -} - -int _fstat(int fd, struct stat *pstat) -{ - (void) fd; - (void) pstat; - - return -1; -} - -/** - * \internal - * _stat_r, collect data about a file. Actually unimpemented - */ -int _stat_r(struct _reent *ptr, const char *file, struct stat *pstat) -{ - (void) ptr; - (void) file; - (void) pstat; - - return -1; -} - -/** - * \internal - * isatty, returns 1 if fd is associated with a terminal. - * Always return 1 because read and write are implemented only in - * terms of serial communication - */ -int _isatty_r(struct _reent *ptr, int fd) -{ - (void) ptr; - (void) fd; - - return 1; -} - -int isatty(int fd) -{ - (void) fd; - - return 1; -} - -int _isatty(int fd) -{ - (void) fd; - - return 1; -} - -/** - * \internal - * _mkdir, create a directory. Actually unimpemented - */ -int mkdir(const char *path, mode_t mode) -{ - (void) path; - (void) mode; - - return -1; -} - -/** - * \internal - * _link_r: create hardlinks. Actually unimpemented - */ -int _link_r(struct _reent *ptr, const char *f_old, const char *f_new) -{ - (void) ptr; - (void) f_old; - (void) f_new; - - return -1; -} - -/** - * \internal - * _unlink_r, remove a file. Actually unimpemented - */ -int _unlink_r(struct _reent *ptr, const char *file) -{ - (void) ptr; - (void) file; - - return -1; -} - -/** - * \internal - * _times_r, return elapsed time. Actually unimpemented - */ -clock_t _times_r(struct _reent *ptr, struct tms *tim) -{ - (void) ptr; - (void) tim; - - return -1; -} - - - - - -/** - * \internal - * it looks like abort() calls _kill instead of exit, this implementation - * calls _exit() so that calling abort() really terminates the program - */ -int _kill_r(struct _reent* ptr, int pid, int sig) -{ - (void) ptr; - (void) sig; - - if(pid == 0) - _exit(1); - else - return -1; -} - -int _kill(int pid, int sig) -{ - return _kill_r(0, pid, sig); -} - -/** - * \internal - * _getpid_r. Not a multiprocess system, return always 0 - */ -int _getpid_r(struct _reent* ptr) -{ - (void) ptr; - return 0; -} - -int _getpid() -{ - return 0; -} - -/** - * \internal - * _wait_r, unimpemented because processes are not supported. - */ -int _wait_r(struct _reent *ptr, int *status) -{ - (void) ptr; - (void) status; - - return -1; -} - -int _fork_r(struct _reent *ptr) -{ - (void) ptr; - - return -1; -} - -#ifdef __cplusplus -} -#endif diff --git a/platform/mcu/MK22FN512xxx12/boot/libc_integration.cpp b/platform/mcu/MK22FN512xxx12/boot/libc_integration.cpp new file mode 100644 index 00000000..dc9ab69f --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/boot/libc_integration.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2020, 2021 by Silvano Seva IU2KWO * + * * + * This program 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. * + * * + * This program 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 this program; if not, see * + ***************************************************************************/ + +#include +#include +#include "filesystem/file_access.h" + +using namespace std; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \internal + * _write_r, write to a file + */ +int _write_r(struct _reent *ptr, int fd, const void *buf, size_t cnt) +{ +// if(fd == STDOUT_FILENO || fd == STDERR_FILENO) +// { +// vcom_writeBlock(buf, cnt); +// return cnt; +// } + + /* If fd is not stdout or stderr */ + ptr->_errno = EBADF; + return -1; +} + +/** + * \internal + * _read_r, read from a file. + */ +int _read_r(struct _reent *ptr, int fd, void *buf, size_t cnt) +{ +// if(fd == STDIN_FILENO) +// { +// for(;;) +// { +// ssize_t r = vcom_readBlock(buf, cnt); +// if((r < 0) || (r == (ssize_t)(cnt))) return r; +// } +// } +// else + + /* If fd is not stdin */ + ptr->_errno = EBADF; + return -1; +} + +#ifdef __cplusplus +} +#endif diff --git a/platform/mcu/MK22FN512xxx12/boot/startup.c b/platform/mcu/MK22FN512xxx12/boot/startup.cpp similarity index 81% rename from platform/mcu/MK22FN512xxx12/boot/startup.c rename to platform/mcu/MK22FN512xxx12/boot/startup.cpp index 4b9cc43a..9fcb5a01 100644 --- a/platform/mcu/MK22FN512xxx12/boot/startup.c +++ b/platform/mcu/MK22FN512xxx12/boot/startup.cpp @@ -1,6 +1,9 @@ /*************************************************************************** - * Copyright (C) 2020 by Federico Izzo IU2NUO, Niccolò Izzo IU2KIN and * - * Silvano Seva IU2KWO * + * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO, * + * Federico Terraneo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -15,25 +18,41 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, see * ***************************************************************************/ - -#include +/* + * startup.cpp + * STM32 C++ startup. + * NOTE: for stm32f4 devices ONLY. + * Supports interrupt handlers in C++ without extern "C" + * Developed by Terraneo Federico, based on ST startup code. + * Additionally modified to boot Miosix. + */ + +#include "interfaces/arch_registers.h" +#include "kernel/stage_2_boot.h" +#include "core/interrupts.h" //For the unexpected interrupt call #include -#include -#include -#include -///< Entry point for system bootstrap after initial configurations. -void systemBootstrap(); - -void Reset_Handler() __attribute__((__interrupt__, noreturn)); -void Reset_Handler() +/** + * Called by Reset_Handler, performs initialization and calls main. + * Never returns. + */ +void program_startup() __attribute__((noreturn)); +void program_startup() { - // Disable interrupts at startup, as the RTOS requires this. + //Cortex M3 core appears to get out of reset with interrupts already enabled __disable_irq(); - // Call CMSIS init function, it's safe to do it here. - // This function initialises VTOR. + //SystemInit() is called *before* initializing .data and zeroing .bss + //Despite all startup files provided by ST do the opposite, there are three + //good reasons to do so: + //First, the CMSIS specifications say that SystemInit() must not access + //global variables, so it is actually possible to call it before + //Second, when running Miosix with the xram linker scripts .data and .bss + //are placed in the external RAM, so we *must* call SystemInit(), which + //enables xram, before touching .data and .bss + //Third, this is a performance improvement since the loops that initialize + //.data and zeros .bss now run with the CPU at full speed instead of 8MHz SystemInit(); // Initialise clock tree for full speed run, since SystemInit by NXP does not. @@ -72,49 +91,66 @@ void Reset_Handler() extern unsigned char _bss_start asm("_bss_start"); extern unsigned char _bss_end asm("_bss_end"); - // Initialize .data section, clear .bss section + //Initialize .data section, clear .bss section unsigned char *etext=&_etext; unsigned char *data=&_data; unsigned char *edata=&_edata; unsigned char *bss_start=&_bss_start; unsigned char *bss_end=&_bss_end; - memcpy(data, etext, edata-data); memset(bss_start, 0, bss_end-bss_start); - SIM->SCGC5 |= 0x3E00; // Enable GPIO clock + //Move on to stage 2 + _init(); - // Enable virtual com port (for stdin, stdout and stderr redirection) - vcom_init(); - - // Set no buffer for stdin, required to make scanf, getchar, ... working - // correctly - setvbuf(stdin, NULL, _IONBF, 0); - - - // Jump to application code - systemBootstrap(); - - // If main returns loop indefinitely + //If main returns, reboot + NVIC_SystemReset(); for(;;) ; } -void Default_Handler() +/** + * Reset handler, called by hardware immediately after reset + */ +void Reset_Handler() __attribute__((__interrupt__, noreturn)); +void Reset_Handler() { - // default handler does nothing + /* + * Initialize process stack and switch to it. + * This is required for booting Miosix, a small portion of the top of the + * heap area will be used as stack until the first thread starts. After, + * this stack will be abandoned and the process stack will point to the + * current thread's stack. + */ + asm volatile("ldr r0, =_heap_end \n\t" + "msr psp, r0 \n\t" + "movw r0, #2 \n\n" //Privileged, process stack + "msr control, r0 \n\t" + "isb \n\t":::"r0"); + + program_startup(); } -void __attribute__((weak)) NMI_Handler(); -void __attribute__((weak)) HardFault_Handler(); -void __attribute__((weak)) MemManage_Handler(); -void __attribute__((weak)) BusFault_Handler(); -void __attribute__((weak)) UsageFault_Handler(); -void __attribute__((weak)) SVC_Handler(); -void __attribute__((weak)) DebugMon_Handler(); +/** + * All unused interrupts call this function. + */ +extern "C" void Default_Handler() +{ + unexpectedInterrupt(); +} -void __attribute__((weak)) OS_CPU_PendSVHandler(); // uC/OS-III naming convention -void __attribute__((weak)) OS_CPU_SysTickHandler(); +//System handlers +void /*__attribute__((weak))*/ Reset_Handler(); //These interrupts are not +void /*__attribute__((weak))*/ NMI_Handler(); //weak because they are +void /*__attribute__((weak))*/ HardFault_Handler(); //surely defined by Miosix +void /*__attribute__((weak))*/ MemManage_Handler(); +void /*__attribute__((weak))*/ BusFault_Handler(); +void /*__attribute__((weak))*/ UsageFault_Handler(); +void /*__attribute__((weak))*/ SVC_Handler(); +void /*__attribute__((weak))*/ DebugMon_Handler(); +void /*__attribute__((weak))*/ PendSV_Handler(); +void /*__attribute__((weak))*/ SysTick_Handler(); +//Interrupt handlers void __attribute__((weak)) DMA0_IRQHandler(); void __attribute__((weak)) DMA1_IRQHandler(); void __attribute__((weak)) DMA2_IRQHandler(); @@ -191,14 +227,14 @@ void __attribute__((weak)) DAC1_IRQHandler(); void __attribute__((weak)) ADC1_IRQHandler(); //Stack top, defined in the linker script -extern char _stack_top asm("_stack_top"); +extern char _main_stack_top asm("_main_stack_top"); //Interrupt vectors, must be placed @ address 0x00000000 //The extern declaration is required otherwise g++ optimizes it out extern void (* const __Vectors[])(); void (* const __Vectors[])() __attribute__ ((section(".isr_vector"))) = { - (void (*)())(&_stack_top), + reinterpret_cast(&_main_stack_top),/* Stack pointer*/ Reset_Handler, NMI_Handler, HardFault_Handler, @@ -212,8 +248,8 @@ void (* const __Vectors[])() __attribute__ ((section(".isr_vector"))) = SVC_Handler, DebugMon_Handler, 0, - OS_CPU_PendSVHandler, - OS_CPU_SysTickHandler, + PendSV_Handler, + SysTick_Handler, DMA0_IRQHandler, /* DMA Channel 0 Transfer Complete*/ DMA1_IRQHandler, /* DMA Channel 1 Transfer Complete*/ @@ -291,17 +327,6 @@ void (* const __Vectors[])() __attribute__ ((section(".isr_vector"))) = ADC1_IRQHandler /* ADC1 interrupt*/ }; -#pragma weak NMI_Handler= Default_Handler -#pragma weak HardFault_Handler= Default_Handler -#pragma weak MemManage_Handler= Default_Handler -#pragma weak BusFault_Handler= Default_Handler -#pragma weak UsageFault_Handler= Default_Handler -#pragma weak SVC_Handler= Default_Handler -#pragma weak DebugMon_Handler= Default_Handler -#pragma weak PendSV_Handler= Default_Handler -#pragma weak SysTick_Handler= Default_Handler -#pragma weak WWDG_IRQHandler= Default_Handler - #pragma weak DMA0_IRQHandler = Default_Handler #pragma weak DMA1_IRQHandler = Default_Handler #pragma weak DMA2_IRQHandler = Default_Handler diff --git a/platform/mcu/MK22FN512xxx12/linker_script.ld b/platform/mcu/MK22FN512xxx12/linker_script.ld index a353b956..2c944862 100644 --- a/platform/mcu/MK22FN512xxx12/linker_script.ld +++ b/platform/mcu/MK22FN512xxx12/linker_script.ld @@ -1,41 +1,75 @@ /* - RAM space is organized in this way: the stack begins at the end of - the RAM space and grows down towards the base, while the heap begins - at the end of the bss space (symbol _end) and grows up towards the - end of the RAM. - - WARNING: with this configuration we have an high risk of collision - between stack and heap, since none of them is limited. One thing to - do in the future is to put this limit to the stack. + * C++ enabled linker script + * Developed by TFT: Terraneo Federico Technologies + * Optimized for use with the Miosix kernel */ -_stack_top = 0x20010000; +/* + * This linker script puts: + * - read only data and code (.text, .rodata, .eh_*) in flash + * - stacks, heap and sections .data and .bss in the internal ram + * - the external ram (if available) is not used. + */ -/* temporary set heap end equal to stack top */ -_heap_end = _stack_top; +/* + * The main stack is used for interrupt handling by the kernel. + * + * *** Readme *** + * This linker script places the main stack (used by the kernel for interrupts) + * at the bottom of the ram, instead of the top. This is done for two reasons: + * + * - as an optimization for microcontrollers with little ram memory. In fact + * the implementation of malloc from newlib requests memory to the OS in 4KB + * block (except the first block that can be smaller). This is probably done + * for compatibility with OSes with an MMU and paged memory. To see why this + * is bad, consider a microcontroller with 8KB of ram: when malloc finishes + * up the first 4KB it will call _sbrk_r asking for a 4KB block, but this will + * fail because the top part of the ram is used by the main stack. As a + * result, the top part of the memory will not be used by malloc, even if + * available (and it is nearly *half* the ram on an 8KB mcu). By placing the + * main stack at the bottom of the ram, the upper 4KB block will be entirely + * free and available as heap space. + * + * - In case of main stack overflow the cpu will fault because access to memory + * before the beginning of the ram faults. Instead with the default stack + * placement the main stack will silently collide with the heap. + * Note: if increasing the main stack size also increase the ORIGIN value in + * the MEMORY definitions below accordingly. + */ + +/* + * NOTE:in spite of what is written above, this linker script puts the main stack + * on top of the RAM because, otherwise, the on-board bootloader refuses to + * start the executable image. + */ +_main_stack_size = 0x00000200; /* main stack = 512Bytes */ +_main_stack_top = 0x20010000; +ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error"); + +_heap_end = _main_stack_top - _main_stack_size; /* end of available ram */ /* identify the Entry Point */ -ENTRY(Reset_Handler) +ENTRY(_Z13Reset_Handlerv) /* specify the memory areas */ MEMORY { - flash(rx) : ORIGIN = 0x4000, LENGTH = 0x7B800 - ram(wx) : ORIGIN = 0x1FFF0000, LENGTH = 128K + flash(rx) : ORIGIN = 0x4000, LENGTH = 0x7B800 + ram(wx) : ORIGIN = 0x1FFF0000, LENGTH = 128K } /* now define the output sections */ SECTIONS { . = 0; - + /* .text section: code goes to flash */ .text : { /* Startup code must go at address 0 */ KEEP(*(.isr_vector)) - + *(.text) *(.text.*) *(.gnu.linkonce.t.*) @@ -57,7 +91,13 @@ SECTIONS /* C++ Static constructors/destructors (eabi) */ . = ALIGN(4); KEEP(*(.init)) - + + . = ALIGN(4); + __miosix_init_array_start = .; + KEEP (*(SORT(.miosix_init_array.*))) + KEEP (*(.miosix_init_array)) + __miosix_init_array_end = .; + . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) @@ -102,7 +142,7 @@ SECTIONS } > flash __exidx_end = .; - /* .data section: global variables go to ram, but also store a copy to + /* .data section: global variables go to ram, but also store a copy to flash to initialize them */ .data : ALIGN(8) { @@ -116,9 +156,9 @@ SECTIONS _etext = LOADADDR(.data); /* .bss section: uninitialized global variables go to ram */ + _bss_start = .; .bss : { - _bss_start = .; *(.bss) *(.bss.*) *(.gnu.linkonce.b.*)