00001 /* 00002 * Copyright (C) 2001-2005 by egnite Software GmbH. All rights reserved. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holders nor the names of 00014 * contributors may be used to endorse or promote products derived 00015 * from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS 00018 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00019 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00020 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE 00021 * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00022 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00023 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 00024 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 00025 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00026 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 00027 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00028 * SUCH DAMAGE. 00029 * 00030 * For additional information see http://www.ethernut.de/ 00031 * 00032 */ 00033 00034 /* 00035 * $Log: nutinit.c,v $ 00036 * Revision 1.21 2009/02/06 15:37:39 haraldkipp 00037 * Added stack space multiplier and addend. Adjusted stack space. 00038 * 00039 * Revision 1.20 2009/01/19 10:38:00 haraldkipp 00040 * Moved NutLoadConfig from NutInit to the idle thread. We can now use 00041 * standard drivers to read the configuration. 00042 * Added support for early stdout. 00043 * 00044 * Revision 1.19 2009/01/17 11:26:37 haraldkipp 00045 * Getting rid of two remaining BSD types in favor of stdint. 00046 * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'. 00047 * 00048 * Revision 1.18 2009/01/16 17:02:18 haraldkipp 00049 * No longer save any default OS configuration in non-volatile RAM. 00050 * All platforms will now call NutLoadConfig(). 00051 * 00052 * Revision 1.17 2008/08/11 06:59:14 haraldkipp 00053 * BSD types replaced by stdint types (feature request #1282721). 00054 * 00055 * Revision 1.16 2008/08/06 12:51:05 haraldkipp 00056 * Added support for Ethernut 5 (AT91SAM9XE reference design). 00057 * 00058 * Revision 1.15 2008/02/15 16:59:27 haraldkipp 00059 * Spport for AT91SAM7SE512 added. 00060 * 00061 * Revision 1.14 2007/10/04 20:08:00 olereinhardt 00062 * Support for SAM7S256 added 00063 * 00064 * Revision 1.13 2006/09/29 12:39:51 haraldkipp 00065 * Spurious interrupt handling on all supported AT91 devices. 00066 * 00067 * Revision 1.12 2006/07/26 11:17:16 haraldkipp 00068 * Defining AT91_PLL_MAINCK will automatically determine SAM7X clock by 00069 * reading PLL settings. 00070 * 00071 * Revision 1.11 2006/07/18 14:04:10 haraldkipp 00072 * Low level hardware initialization moved to crtat91sam7x256_rom.S. This 00073 * avoids the ugly jump from C code back into the runtime initialization. 00074 * Watchdog reset (tiger bell) removed from idle thread. 00075 * 00076 * Revision 1.10 2006/07/15 11:13:30 haraldkipp 00077 * CPU ran into the data pool of Sam7xLowLevelInit(). Temporarily 00078 * fixed by Andras Albert with an additional global label in the 00079 * startup code. Furthermore Andras changed the clock initialization. 00080 * The CPU is now running at 47.9232 MHz and the MAC starts working. 00081 * Great, TCP/IP is now running on the SAM7X. 00082 * 00083 * Revision 1.9 2006/07/10 14:27:03 haraldkipp 00084 * C++ will use main instead of NutAppMain. Contributed by Matthias Wilde. 00085 * 00086 * Revision 1.8 2006/07/05 07:57:52 haraldkipp 00087 * Daidai's support for AT91SAM7X added. Possibly taken from Atmel. 00088 * May require new coding from ground up in order to not conflict with 00089 * original copyright. 00090 * Nevertheless, many thanks to Daidai for providing his adaption. 00091 * 00092 * Revision 1.7 2006/06/28 17:22:34 haraldkipp 00093 * Make it compile for AT91SAM7X256. 00094 * 00095 * Revision 1.6 2006/03/02 19:43:11 haraldkipp 00096 * Added MCU specific hardware initialization routine. This should be done 00097 * later for all MCUs to avoid contaminating NutInit() with MCU specific 00098 * stuff. For the AT91 the spurious interrupt handler has been added, 00099 * which fixes SF 1440948. 00100 * 00101 * Revision 1.5 2006/02/23 15:34:00 haraldkipp 00102 * Support for Philips LPC2xxx Family and LPC-E2294 Board from Olimex added. 00103 * Many thanks to Michael Fischer for this port. 00104 * 00105 * Revision 1.4 2005/10/24 09:22:29 haraldkipp 00106 * Default idle and main thread stack sizes increased. 00107 * AT91 header file moved. 00108 * 00109 * Revision 1.3 2005/08/02 17:46:45 haraldkipp 00110 * Major API documentation update. 00111 * 00112 * Revision 1.2 2005/07/26 16:17:03 haraldkipp 00113 * Use default stack sizes for main and idle, if none had been defined. 00114 * 00115 * Revision 1.1 2005/05/27 17:16:40 drsung 00116 * Moved the file. 00117 * 00118 * Revision 1.4 2005/04/05 17:52:41 haraldkipp 00119 * Much better implementation of GBA interrupt registration. 00120 * 00121 * Revision 1.3 2004/11/08 18:58:59 haraldkipp 00122 * Configurable stack sizes 00123 * 00124 * Revision 1.2 2004/09/08 10:19:23 haraldkipp 00125 * Made it look more general 00126 * 00127 * Revision 1.1 2004/03/16 16:48:46 haraldkipp 00128 * Added Jan Dubiec's H8/300 port. 00129 * 00130 * 00131 */ 00132 00133 #include <cfg/arch.h> 00134 #include <cfg/memory.h> 00135 #include <cfg/os.h> 00136 #ifdef MCU_GBA 00137 #include <dev/irqreg.h> 00138 #elif defined(MCU_LPC2XXX) 00139 #include <arch/arm/lpc2xxx.h> 00140 #else 00141 #include <arch/arm/at91.h> 00142 #endif 00143 00144 #ifdef EARLY_STDIO_DEV 00145 #include <sys/device.h> 00146 #include <stdio.h> 00147 #include <fcntl.h> 00148 struct __iobuf { 00149 int iob_fd; 00150 uint16_t iob_mode; 00151 uint8_t iob_flags; 00152 int iob_unget; 00153 }; 00154 #endif 00155 00160 00161 #ifndef NUT_THREAD_MAINSTACK 00162 #define NUT_THREAD_MAINSTACK 1024 00163 #endif 00164 00165 #ifndef NUT_THREAD_IDLESTACK 00166 /* arm-elf-gcc optimized code used 160 bytes. */ 00167 #define NUT_THREAD_IDLESTACK 256 00168 #endif 00169 00170 #ifdef __CROSSWORKS4ARM__ 00171 extern void *__unused_start__; 00172 /* 00173 * Michael, Why does Crossworks needs this one. Is memory configurable 00174 * with the Configurator? 00175 */ 00176 extern void *__External_SRAM_segment_end__; 00177 00178 #define HEAP_START &__unused_start__ 00179 #define HEAP_SIZE ((uintptr_t)(&__External_SRAM_segment_end__ - 1) - (uintptr_t)(HEAP_START) - 256) 00180 #else /* GCC */ 00181 00184 #define NUTMEM_END (uintptr_t)(NUTMEM_START + NUTMEM_SIZE - 1U) 00185 extern void *__heap_start; 00186 00187 #define HEAP_START &__heap_start 00188 #define HEAP_SIZE ((uintptr_t) (NUTMEM_END - 256 - (uintptr_t) (&__heap_start))) 00189 #endif 00190 00191 #if !defined(__arm__) && !defined(__cplusplus) 00192 extern void NutAppMain(void *arg) __attribute__ ((noreturn)); 00193 #else 00194 extern void main(void *); 00195 #endif 00196 00197 00198 #if defined(OLIMEX_LPCE2294) 00199 /* 00200 * InitHW for OLIMEX LPC-E2294 00201 */ 00202 static void InitHW (void) 00203 { 00204 PINSEL0 = 0; 00205 PINSEL1 = 0; 00206 00207 BCFG2 = 0x03501; 00208 PINSEL2 |= 0x00804000; 00209 } /* InitHW */ 00210 00211 #endif /* OLIMEX_LPCE2294 */ 00212 00213 00214 00222 THREAD(NutIdle, arg) 00223 { 00224 #if defined(MCU_GBA) || defined(MCU_LPC2XXX) 00225 InitIrqHandler(); 00226 #endif 00227 /* Initialize system timers. */ 00228 NutTimerInit(); 00229 00230 /* Read OS configuration from non-volatile memory. We can't do this 00231 ** earlier, because the low level driver may be interrupt driven. */ 00232 NutLoadConfig(); 00233 00234 /* Create the main application thread. Watch this carefully when 00235 ** changing compilers and compiler versions. Some handle main() 00236 ** in a special way, like setting the stack pointer and other 00237 ** weird stuff that may break this code. */ 00238 NutThreadCreate("main", main, 0, 00239 (NUT_THREAD_MAINSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD); 00240 00241 /* Enter an idle loop at the lowest priority. This will run when 00242 ** all other threads are waiting for an event. */ 00243 NutThreadSetPriority(254); 00244 for (;;) { 00245 /* Check if other threads became ready to run. */ 00246 NutThreadYield(); 00247 /* Remove terminated threads. */ 00248 NutThreadDestroy(); 00249 /* We could do some power management. */ 00250 } 00251 } 00252 00260 void NutInit(void) 00261 { 00262 /* Do some basic hardware initialization first. Frankly, these 00263 ** are all hacks and could be done in a more general way. */ 00264 #if defined(OLIMEX_LPCE2294) 00265 InitHW(); 00266 #elif defined(MCU_AT91) 00267 McuInit(); 00268 #endif 00269 #if defined(MCU_AT91SAM7X) || defined (MCU_AT91SAM7S) || defined(MCU_AT91SAM7SE) 00270 { 00271 uint32_t freq = NutGetCpuClock(); 00272 /* Set Flash Waite state. */ 00273 outr(MC_FMR, ((((freq + freq / 2) / 1000000UL) & 0xFF) << 16) | MC_FWS_2R3W); 00274 } 00275 #endif 00276 #ifdef EARLY_STDIO_DEV 00277 /* We may optionally initialize stdout as early as possible. 00278 ** Be aware, that no heap is available and no threads are 00279 ** running. We need a very basic driver here, which won't 00280 ** use interrupts or call malloc, NutEventXxx, NutSleep etc. */ 00281 { 00282 extern NUTDEVICE EARLY_STDIO_DEV; 00283 static struct __iobuf early_stdout; 00284 /* Initialize the output device. */ 00285 EARLY_STDIO_DEV.dev_init(&EARLY_STDIO_DEV); 00286 /* Assign a static iobuf. */ 00287 stdout = &early_stdout; 00288 /* Open the device. */ 00289 stdout->iob_fd = (int)EARLY_STDIO_DEV.dev_open(&EARLY_STDIO_DEV, "", 0, 0); 00290 /* Set the mode. No idea if this is required. */ 00291 stdout->iob_mode = _O_WRONLY | _O_CREAT | _O_TRUNC; 00292 /* A first trial. */ 00293 puts("\nStarting Nut/OS"); 00294 } 00295 #endif 00296 /* Initialize our heap memory. */ 00297 NutHeapAdd(HEAP_START, HEAP_SIZE); 00298 00299 /* Create idle thread. Note, that the first call to NutThreadCreate 00300 ** will never return. */ 00301 NutThreadCreate("idle", NutIdle, 0, 00302 (NUT_THREAD_IDLESTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD); 00303 } 00304