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$ 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 #include <dev/board.h> 00145 00146 #ifdef EARLY_STDIO_DEV 00147 #include <sys/device.h> 00148 #include <stdio.h> 00149 #include <fcntl.h> 00150 #include <dev/debug.h> 00151 struct __iobuf { 00152 int iob_fd; 00153 uint16_t iob_mode; 00154 uint8_t iob_flags; 00155 int iob_unget; 00156 }; 00157 #endif 00158 00163 00164 #ifndef NUT_THREAD_MAINSTACK 00165 #define NUT_THREAD_MAINSTACK 1024 00166 #endif 00167 00168 #ifndef NUT_THREAD_IDLESTACK 00169 /* arm-elf-gcc optimized code used 160 bytes. */ 00170 #define NUT_THREAD_IDLESTACK 256 00171 #endif 00172 00173 #ifdef __CROSSWORKS_ARM 00174 00175 /* 00176 * A CrossWorks MemoryMap file will be used. Here the memory 00177 * between __heap_start__ and __External_RAM_segment_end__ 00178 * can be used for NutOS. 00179 */ 00180 extern void *__heap_start__; 00181 extern void *__RAM_END_segment_end__; 00182 00183 #define HEAP_START &__heap_start__ 00184 #define HEAP_SIZE ((uintptr_t)(&__RAM_END_segment_end__ - 1) - (uintptr_t)(HEAP_START) - 256) 00185 00186 #else /* GCC */ 00187 00191 #define NUTMEM_END (uintptr_t)(NUTMEM_START + NUTMEM_SIZE - 1U) 00192 extern void *__heap_start; 00193 00194 #define HEAP_START &__heap_start 00195 #define HEAP_SIZE ((uintptr_t) (NUTMEM_END - 256 - (uintptr_t) (&__heap_start))) 00196 #endif 00197 00198 #if !defined(__arm__) && !defined(__cplusplus) 00199 extern void NutAppMain(void *arg) __attribute__ ((noreturn)); 00200 #else 00201 extern void main(void *); 00202 #endif 00203 00204 00205 #if defined(OLIMEX_LPCE2294) 00206 /* 00207 * InitHW for OLIMEX LPC-E2294 00208 */ 00209 static void InitHW (void) 00210 { 00211 PINSEL0 = 0; 00212 PINSEL1 = 0; 00213 00214 BCFG2 = 0x03501; 00215 PINSEL2 |= 0x00804000; 00216 } /* InitHW */ 00217 00218 #endif /* OLIMEX_LPCE2294 */ 00219 00220 00221 00229 THREAD(NutIdle, arg) 00230 { 00231 #if defined(MCU_GBA) || defined(MCU_LPC2XXX) 00232 InitIrqHandler(); 00233 #endif 00234 #ifdef NUT_INIT_IDLE 00235 NutIdleInit(); 00236 #endif 00237 /* Initialize system timers. */ 00238 NutTimerInit(); 00239 00240 /* Read OS configuration from non-volatile memory. We can't do this 00241 ** earlier, because the low level driver may be interrupt driven. */ 00242 NutLoadConfig(); 00243 00244 #ifdef NUT_INIT_MAIN 00245 NutMainInit(); 00246 #endif 00247 00248 /* Create the main application thread. Watch this carefully when 00249 ** changing compilers and compiler versions. Some handle main() 00250 ** in a special way, like setting the stack pointer and other 00251 ** weird stuff that may break this code. */ 00252 NutThreadCreate("main", main, 0, 00253 (NUT_THREAD_MAINSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD); 00254 00255 /* Enter an idle loop at the lowest priority. This will run when 00256 ** all other threads are waiting for an event. */ 00257 NutThreadSetPriority(254); 00258 for (;;) { 00259 /* Check if other threads became ready to run. */ 00260 NutThreadYield(); 00261 /* Remove terminated threads. */ 00262 NutThreadDestroy(); 00263 /* We could do some power management. */ 00264 } 00265 } 00266 00274 void NutInit(void) 00275 { 00276 /* Do some basic hardware initialization first. Frankly, these 00277 ** are all hacks and could be done in a more general way. */ 00278 #if defined(OLIMEX_LPCE2294) 00279 InitHW(); 00280 #elif defined(MCU_AT91) 00281 McuInit(); 00282 #endif 00283 #if defined(MCU_AT91SAM7X) || defined (MCU_AT91SAM7S) || defined(MCU_AT91SAM7SE) 00284 { 00285 uint32_t freq = NutGetCpuClock(); 00286 /* Set Flash Waite state. */ 00287 outr(MC_FMR, ((((freq + freq / 2) / 1000000UL) & 0xFF) << 16) | MC_FWS_2R3W); 00288 } 00289 #endif 00290 #ifdef EARLY_STDIO_DEV 00291 /* We may optionally initialize stdout as early as possible. 00292 ** Be aware, that no heap is available and no threads are 00293 ** running. We need a very basic driver here, which won't 00294 ** use interrupts or call malloc, NutEventXxx, NutSleep etc. */ 00295 { 00296 extern NUTDEVICE EARLY_STDIO_DEV; 00297 static struct __iobuf early_stdout; 00298 /* Initialize the output device. */ 00299 EARLY_STDIO_DEV.dev_init(&EARLY_STDIO_DEV); 00300 /* Assign a static iobuf. */ 00301 stdout = &early_stdout; 00302 /* Open the device. */ 00303 stdout->iob_fd = (int)EARLY_STDIO_DEV.dev_open(&EARLY_STDIO_DEV, "", 0, 0); 00304 /* Set the mode. No idea if this is required. */ 00305 stdout->iob_mode = _O_WRONLY | _O_CREAT | _O_TRUNC; 00306 /* A first trial. */ 00307 puts("\nStarting Nut/OS"); 00308 } 00309 #endif 00310 #ifdef NUT_INIT_BOARD 00311 NutBoardInit(); 00312 #endif 00313 /* Initialize our heap memory. */ 00314 NutHeapAdd(HEAP_START, HEAP_SIZE & ~3); 00315 00316 /* Create idle thread. Note, that the first call to NutThreadCreate 00317 ** will never return. */ 00318 NutThreadCreate("idle", NutIdle, 0, 00319 (NUT_THREAD_IDLESTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD); 00320 } 00321