00001 /* 00002 * Copyright (C) 2001-2006 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.17 2009/02/06 15:37:40 haraldkipp 00037 * Added stack space multiplier and addend. Adjusted stack space. 00038 * 00039 * Revision 1.16 2009/01/16 17:02:19 haraldkipp 00040 * No longer save any default OS configuration in non-volatile RAM. 00041 * All platforms will now call NutLoadConfig(). 00042 * 00043 * Revision 1.15 2008/08/27 06:40:41 thornen 00044 * Added MMnet03..04 and MMnet102..104 CPLD initialization. 00045 * 00046 * Revision 1.14 2008/08/26 17:36:45 haraldkipp 00047 * Revoked changes 2008/08/26 by thornen. 00048 * 00049 * Revision 1.12 2008/08/11 11:51:19 thiagocorrea 00050 * Preliminary Atmega2560 compile options, but not yet supported. 00051 * It builds, but doesn't seam to run properly at this time. 00052 * 00053 * Revision 1.11 2008/08/11 06:59:39 haraldkipp 00054 * BSD types replaced by stdint types (feature request #1282721). 00055 * 00056 * Revision 1.10 2007/06/14 07:24:38 freckle 00057 * Disable ADC and buskeeper during idle thread sleep, if IDLE_THREAD_ADC_OFF and IDLE_THREAD_BUSKEEPER_OFF are defined 00058 * 00059 * Revision 1.9 2006/10/07 00:24:14 hwmaier 00060 * Include of sys/heap.h added. 00061 * 00062 * Revision 1.8 2006/09/29 12:39:23 haraldkipp 00063 * Added support for ATmega2561. 00064 * 00065 * Revision 1.7 2006/07/04 03:38:56 hwmaier 00066 * Changed binary constants to hex constants in XNUT board 00067 * initialization code. 00068 * 00069 * Revision 1.6 2006/05/15 11:46:49 haraldkipp 00070 * Added heartbeat port bit, which is regularly toggled by the idle thread. 00071 * Helps to develop on boards with external watchdog hardware that can't be 00072 * disabled. 00073 * 00074 * Revision 1.5 2005/10/17 08:24:55 hwmaier 00075 * All platform specific initialisation (CPLD, IO pins etc.) has been consolidated using the new PLATFORM macro into a new function called NutCustomInit() 00076 * 00077 * Revision 1.4 2005/10/04 06:11:11 hwmaier 00078 * Added support for separating stack and conventional heap as required by AT09CAN128 MCUs 00079 * 00080 * Revision 1.3 2005/09/07 16:22:45 christianwelzel 00081 * Added MMnet02 CPLD initialization 00082 * 00083 * Revision 1.2 2005/08/02 17:46:46 haraldkipp 00084 * Major API documentation update. 00085 * 00086 * Revision 1.1 2005/05/27 17:17:31 drsung 00087 * Moved the file 00088 * 00089 * Revision 1.18 2005/05/16 08:49:37 haraldkipp 00090 * Arthernet requires different wait state settings. 00091 * 00092 * Revision 1.17 2005/02/28 08:44:54 drsung 00093 * Fixed missing return type of NutInitSP 00094 * Removed inlcude file avrpio.h 00095 * 00096 * Revision 1.16 2005/02/26 12:09:28 drsung 00097 * Moved heap initialization to section .init5 to support c++ constructors for static objects. 00098 * 00099 * Revision 1.15 2005/02/10 07:06:48 hwmaier 00100 * Changes to incorporate support for AT90CAN128 CPU 00101 * 00102 * Revision 1.12 2005/01/22 19:30:56 haraldkipp 00103 * Fixes Ethernut 1.3G memory bug. 00104 * 00105 * Revision 1.11 2004/11/08 18:58:59 haraldkipp 00106 * Configurable stack sizes 00107 * 00108 * Revision 1.10 2004/09/01 14:27:03 haraldkipp 00109 * Using configuration values from cfg/memory.h. 00110 * Added configurable reserved memory area. 00111 * Automatic check for external memory removed. 00112 * 00113 * Revision 1.9 2004/07/28 13:43:25 drsung 00114 * Corrected a misplaced #endif after last change. 00115 * 00116 * Revision 1.8 2004/07/09 19:51:17 freckle 00117 * Added new function NutThreadSetSleepMode to tell nut/os to set the MCU 00118 * into sleep mode when idle (avr-gcc && avr128 only) 00119 * 00120 * Revision 1.7 2004/07/09 14:40:43 freckle 00121 * Moved ((volatile u_char *) NUTRAMEND) cast into NUTRAMENDPTR define 00122 * 00123 * Revision 1.6 2004/07/09 14:23:13 freckle 00124 * Allow setting of NUTRAMEND by giving it as a compiler flag 00125 * 00126 * Revision 1.5 2004/05/25 17:13:48 drsung 00127 * Bit name SRW10 is not defined for atmega103, so added some defines to make it compatible.. :-X 00128 * 00129 * Revision 1.4 2004/05/25 12:03:37 olereinhardt 00130 * Sorry, fixed typing bug 00131 * 00132 * Revision 1.3 2004/05/25 12:00:37 olereinhardt 00133 * Newly added 3Waitstate support now needs to be enabled by 00134 * defining NUT_3WAITSTATES. By default this behaves like normal 00135 * 00136 * 00137 * Revision 1.1 2004/03/16 16:48:46 haraldkipp 00138 * Added Jan Dubiec's H8/300 port. 00139 * 00140 * 00141 */ 00142 00143 #include <sys/thread.h> 00144 #include <sys/heap.h> 00145 #include <cfg/memory.h> 00146 #include <cfg/os.h> 00147 #include <cfg/arch/avr.h> 00148 #include <cfg/arch.h> 00149 00150 #include <dev/board.h> 00151 00156 00157 #ifdef NUTXMEM_SIZE 00158 00161 #define NUTMEM_END (uint16_t)(NUTXMEM_START + (uint16_t)NUTXMEM_SIZE - 1U) 00162 00163 #else 00164 00170 #define NUTMEM_END (uint16_t)(NUTMEM_START + (uint16_t)NUTMEM_SIZE - 1U) 00171 00172 #endif 00173 00174 #ifndef NUT_THREAD_MAINSTACK 00175 #define NUT_THREAD_MAINSTACK 1024 00176 #endif 00177 00178 #ifndef NUT_THREAD_IDLESTACK 00179 #if defined(__GNUC__) 00180 /* avr-gcc optimized code used 36 bytes. */ 00181 #define NUT_THREAD_IDLESTACK 128 00182 #else 00183 /* icc-avr v7.19 used 132 bytes. */ 00184 #define NUT_THREAD_IDLESTACK 256 00185 #endif 00186 #endif 00187 00188 #ifdef NUTMEM_RESERVED 00189 00199 uint8_t nutmem_onchip[NUTMEM_RESERVED]; 00200 #endif 00201 00202 /* sleep mode to put avr in idle thread, SLEEP_MODE_NONE is used for for non sleeping */ 00203 #if defined(__GNUC__) && defined(__AVR_ENHANCED__) 00204 uint8_t idle_sleep_mode = SLEEP_MODE_NONE; 00205 00206 /* AT90CAN128 uses a different register to enter sleep mode */ 00207 #if defined(SMCR) 00208 #define AVR_SLEEP_CTRL_REG SMCR 00209 #else 00210 #define AVR_SLEEP_CTRL_REG MCUCR 00211 #endif 00212 00213 #endif 00214 00215 #ifdef __GNUC__ 00216 /* 00217 * Some special declarations for AVRGCC. The runtime library 00218 * executes section .init8 before finally jumping to main(). 00219 * We never let it do that jump, but start main() as a 00220 * separate thread. This introduces new problems: 00221 * 1. The compiler reinitializes the stack pointer when 00222 * entering main, at least version 3.3 does it. 00223 * 2. The compiler doesn't allow to redeclare main to make 00224 * it fit for NutThreadCreate(). 00225 * 3. The runtime library requires, that main is defined 00226 * somewhere. 00227 * Solutions: 00228 * 1. We do not use main at all, but let the preprocessor 00229 * redefine it to NutAppMain() in the application code. 00230 * See compiler.h. Note, that the declaration of NutAppMain 00231 * in this module differs from the one in the application 00232 * code. Fortunately the linker doesn't detect this hack. 00233 * 2. We use a linker option to set the symbol main to zero. 00234 * 00235 * Thanks to Joerg Wunsch, who helped to solve this. 00236 */ 00237 void NutInit(void) __attribute__ ((naked)) __attribute__ ((section(".init8"))); 00238 extern void NutAppMain(void *arg) __attribute__ ((noreturn)); 00239 #else 00240 extern void main(void *); 00241 #endif 00242 00243 /* 00244 * External memory interface for GCC. 00245 */ 00246 #if defined(__GNUC__) && defined(NUTXMEM_SIZE) 00247 00248 /* 00249 * At the very beginning enable extended memory interface. 00250 */ 00251 static void NutInitXRAM(void) __attribute__ ((naked, section(".init1"), used)); 00252 void NutInitXRAM(void) 00253 { 00254 #if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) 00255 /* 00256 * Note: Register structure of ATCAN128 differs from ATMEGA128 in regards 00257 * to wait states. 00258 */ 00259 #ifdef NUT_3WAITSTATES /* One wait state 1 for low, 3 for high memory range */ 00260 XMCRA = _BV(SRE) | _BV(SRL2) | _BV(SRW00) | _BV(SRW10) | _BV(SRW11); 00261 #else 00262 XMCRA = _BV(SRE) | _BV(SRW10); /* One wait state for the whole memory range */ 00263 #endif 00264 00265 #elif defined(__AVR_ATmega128__) 00266 00267 MCUCR = _BV(SRE) | _BV(SRW10); 00268 00269 /* Configure two sectors, lower sector = 0x1100 - 0x7FFF, 00270 * Upper sector = 0x8000 - 0xFFFF and run 3 wait states for the 00271 * upper sector (NIC), 1 wait state for lower sector (XRAM). 00272 */ 00273 #ifdef NUT_3WAITSTATES 00274 XMCRA |= _BV(SRL2) | _BV(SRW00) | _BV(SRW11); /* SRW10 is set in MCUCR */ 00275 XMCRB = 0; 00276 #endif 00277 00278 #else /* ATmega103 */ 00279 MCUCR = _BV(SRE) | _BV(SRW); 00280 #endif 00281 } 00282 00283 #endif 00284 00296 #if defined(__GNUC__) && defined(__AVR_ENHANCED__) 00297 uint8_t NutThreadSetSleepMode(uint8_t mode) 00298 { 00299 uint8_t old_mode = idle_sleep_mode; 00300 idle_sleep_mode = mode; 00301 return old_mode; 00302 } 00303 #endif 00304 00310 THREAD(NutIdle, arg) 00311 { 00312 #if defined(__GNUC__) && defined(__AVR_ENHANCED__) 00313 uint8_t sleep_mode; 00314 #endif 00315 #ifdef IDLE_HEARTBEAT_BIT 00316 uint8_t beat = 0; 00317 #endif 00318 00319 #ifdef NUT_INIT_IDLE 00320 NutIdleInit(); 00321 #endif 00322 00323 /* Initialize system timers. */ 00324 NutTimerInit(); 00325 00326 #ifdef NUT_INIT_MAIN 00327 NutMainInit(); 00328 #endif 00329 00330 /* Create the main application thread. */ 00331 NutThreadCreate("main", main, 0, 00332 (NUT_THREAD_MAINSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD); 00333 00334 /* 00335 * Run in an idle loop at the lowest priority. We can still 00336 * do something useful here, like killing terminated threads 00337 * or putting the CPU into sleep mode. 00338 */ 00339 NutThreadSetPriority(254); 00340 for (;;) { 00341 NutThreadYield(); 00342 NutThreadDestroy(); 00343 00344 #ifdef IDLE_HEARTBEAT_BIT 00345 if ((beat = !beat) == 0) { 00346 //UDR = '*'; 00347 cbi(IDLE_HEARTBEAT_PORT, IDLE_HEARTBEAT_BIT); 00348 } 00349 else { 00350 sbi(IDLE_HEARTBEAT_PORT, IDLE_HEARTBEAT_BIT); 00351 } 00352 sbi(IDLE_HEARTBEAT_DDR, IDLE_HEARTBEAT_BIT); 00353 #endif 00354 00355 #if defined(__GNUC__) && defined(__AVR_ENHANCED__) 00356 if (idle_sleep_mode != SLEEP_MODE_NONE) { 00357 sleep_mode = AVR_SLEEP_CTRL_REG & _SLEEP_MODE_MASK; 00358 set_sleep_mode(idle_sleep_mode); 00359 #ifdef IDLE_THREAD_ADC_OFF 00360 uint8_t adc = bit_is_set(ADCSR, ADEN); 00361 cbi(ADCSR, ADEN); // disable ADC 00362 #endif 00363 #ifdef IDLE_THREAD_BUSKEEPER_OFF 00364 uint8_t bitkeeper = bit_is_set(XMCRB, XMBK); 00365 cbi(XMCRB, XMBK); // disable buskeeper 00366 #endif 00367 /* Note: avr-libc has a sleep_mode() function, but it's broken for 00368 AT90CAN128 with avr-libc version earlier than 1.2 */ 00369 AVR_SLEEP_CTRL_REG |= _BV(SE); 00370 __asm__ __volatile__ ("sleep" "\n\t" :: ); 00371 AVR_SLEEP_CTRL_REG &= ~_BV(SE); 00372 #ifdef IDLE_THREAD_ADC_OFF 00373 if (bitkeeper) { 00374 sbi(XMCRB, XMBK); // re-enable buskeeper 00375 } 00376 #endif 00377 #ifdef IDLE_THREAD_BUSKEEPER_OFF 00378 if (adc) { 00379 sbi(ADCSR, ADEN); // re-enable ADC 00380 } 00381 #endif 00382 set_sleep_mode(sleep_mode); 00383 } 00384 #endif 00385 } 00386 } 00387 00388 #if defined(__GNUC__) 00389 static void NutInitSP(void) __attribute__ ((naked, section (".init5"), used)); 00390 void NutInitSP(void) 00391 { 00392 #if defined (NUTMEM_STACKHEAP) 00393 /* Stack must remain in internal RAM where avr-libc's runtime lib init placed it */ 00394 #else 00395 /* Initialize stack pointer to end of external RAM while starting up the system 00396 * to avoid overwriting .data and .bss section. 00397 */ 00398 SP = (uint16_t)(NUTMEM_END); 00399 #endif 00400 } 00401 #endif 00402 00403 #if defined(__GNUC__) 00404 static void NutInitHeap(void) __attribute__ ((naked, section (".init5"), used)); 00405 #endif 00406 void NutInitHeap() 00407 { 00408 #if defined (NUTMEM_STACKHEAP) /* Stack resides in internal memory */ 00409 NutStackAdd((void *) NUTMEM_START, NUTMEM_STACKHEAP); 00410 #endif 00411 /* Then add the remaining RAM to heap. 00412 * 00413 * 20.Aug.2004 haraldkipp: This had been messed up somehow. It's nice to have 00414 * one continuous heap area, but we lost the ability to have systems with 00415 * a gap between internal and external RAM. 00416 */ 00417 if ((uint16_t)NUTMEM_END - (uint16_t) (&__heap_start) > 384) { 00418 NutHeapAdd(&__heap_start, (uint16_t) NUTMEM_END - 256 - (uint16_t) (&__heap_start)); 00419 } 00420 } 00421 00422 #if defined(__GNUC__) 00423 static void NutCustomInit(void) __attribute__ ((naked, section (".init1"), used)); 00424 #endif 00425 00434 void NutCustomInit(void) 00435 /* 00436 * MMnet02..04 and MMnet102..104 CPLD initialization. 00437 */ 00438 #if defined(MMNET02) || defined(MMNET03) || defined(MMNET04) ||\ 00439 defined(MMNET102) || defined(MMNET103) || defined(MMNET104) 00440 { 00441 volatile uint8_t *breg = (uint8_t *)((size_t)-1 & ~0xFF); 00442 00443 *(breg + 1) = 0x01; // Memory Mode 1, Banked Memory 00444 00445 /* Assume 14.745600 MHz crystal, set to 115200bps */ 00446 outb(UBRR, 7); 00447 outb(UBRR1L, 7); 00448 } 00449 /* 00450 * Arthernet CPLD initialization. 00451 */ 00452 #elif defined(ARTHERNET1) 00453 { 00454 /* Arthernet1 memory setup - mt - TODO: check this 00455 Note: This overwrites the default settings of NutInitXRAM()! 00456 0x1100-0x14FF CLPD area -> use 3 Waitstates for 0x1100-0x1FFF (no Limit at 0x1500 available) 00457 0x1500-0xFFFF Heap/Stack -> use 1 Waitstate for 0x2000-0xFFFF 00458 */ 00459 MCUCR = _BV(SRE); /* enable xmem-Interface */ 00460 XMCRA |= _BV(SRL0) | _BV(SRW01) | _BV(SRW00); /* sep. at 0x2000, 3WS for lower Sector */ 00461 XMCRB = 0; 00462 00463 *((volatile uint8_t *)(ARTHERCPLDSTART)) = 0x10; // arthernet cpld init - Bank 00464 *((volatile uint8_t *)(ARTHERCPLDSPI)) = 0xFF; // arthernet cpld init - SPI 00465 00466 /* Assume standard Arthernet1 with 16 MHz crystal, set to 38400 bps */ 00467 outb(UBRR, 25); 00468 outb(UBRR1L, 25); 00469 } 00470 /* 00471 * XNUT board initialization 00472 */ 00473 #elif defined(XNUT_100) || defined(XNUT_105) 00474 { 00475 PORTB = 0x35; 00476 DDRB = 0x3F; 00477 PORTD = 0xE8; 00478 DDRD = 0xB0; 00479 PORTE = 0x0E; 00480 DDRE = 0x02; 00481 PORTF = 0xF0; 00482 DDRF = 0x0F; 00483 PORTG = 0x1F; 00484 DDRG = 0x07; 00485 00486 ACSR |= _BV(ACD); /* Switch off analog comparator to reduce power consumption */ 00487 00488 /* Init I2C bus w/ 100 kHz */ 00489 TWSR = 0; 00490 TWBR = (NUT_CPU_FREQ / 100000UL - 16) / 2; /* 100 kHz I2C */ 00491 00492 /* Set default baudrate */ 00493 #if NUT_CPU_FREQ == 14745600 00494 UBRR0L = (NUT_CPU_FREQ / (16 * 9600UL)) - 1; 00495 UBRR1L = (NUT_CPU_FREQ / (16 * 9600UL)) - 1; 00496 #else 00497 sbi(UCSR0A, U2X0); 00498 sbi(UCSR1A, U2X1); 00499 UBRR0L = (NUT_CPU_FREQ / (8 * 9600UL)) - 1; 00500 UBRR1L = (NUT_CPU_FREQ / (8 * 9600UL)) - 1; 00501 #endif 00502 } 00503 /* 00504 * HHOpen 63f board initialization 00505 */ 00506 #elif defined(HHOPEN_63F) 00507 { 00508 PORTA = 0xF8; DDRA = 0x08; 00509 PORTB = 0x01; DDRB = 0xE7; 00510 PORTC = 0xFF; DDRC = 0x01; 00511 PORTD = 0x18; DDRD = 0xDB; 00512 PORTE = 0x5A; DDRE = 0xEA; 00513 PORTF = 0x80; DDRF = 0xFF; 00514 PORTG = 0x00; DDRG = 0xFF; 00515 00516 ACSR |= _BV(ACD); /* Switch off analog comparator to reduce power consumption */ 00517 00518 /* Init I2C bus w/ 100 kHz */ 00519 TWSR = 0; 00520 TWBR = (NUT_CPU_FREQ / 100000UL - 16) / 2; /* 100 kHz I2C */ 00521 00522 /* Set default baudrate */ 00523 #if NUT_CPU_FREQ == 14745600 00524 UBRR0L = (NUT_CPU_FREQ / (16 * 9600UL)) - 1; 00525 UBRR1L = (NUT_CPU_FREQ / (16 * 9600UL)) - 1; 00526 #else 00527 sbi(UCSR0A, U2X0); 00528 sbi(UCSR1A, U2X1); 00529 UBRR0L = (NUT_CPU_FREQ / (8 * 9600UL)) - 1; 00530 UBRR1L = (NUT_CPU_FREQ / (8 * 9600UL)) - 1; 00531 #endif 00532 } 00533 00534 /* 00535 * Rest of the world and standard ETHERNUT 1/2 00536 */ 00537 #else 00538 { 00539 /* Assume standard Ethernut with 14.745600 MHz crystal, set to 115200bps */ 00540 outb(UBRR, 7); 00541 #ifdef __AVR_ENHANCED__ 00542 outb(UBRR1L, 7); 00543 #endif 00544 } 00545 #endif 00546 00579 void NutInit(void) 00580 { 00581 /* 00582 * We can't use local variables in naked functions. 00583 */ 00584 00585 #ifdef NUTDEBUG 00586 /* Note: The platform's default baudrate will be set in NutCustomInit() */ 00587 outb(UCR, BV(RXEN) | BV(TXEN)); 00588 #endif 00589 00590 #ifdef NUT_INIT_BOARD 00591 NutBoardInit(); 00592 #endif 00593 00594 #ifndef __GNUC__ 00595 NutCustomInit(); 00596 00597 /* Initialize stack pointer to end of external RAM while starting up the system 00598 * to avoid overwriting .data and .bss section. 00599 */ 00600 SP = (uint16_t)(NUTMEM_END); 00601 00602 /* Initialize the heap memory 00603 */ 00604 NutInitHeap(); 00605 #endif /* __GNUC__ */ 00606 00607 /* Read OS configuration from non-volatile memory. */ 00608 NutLoadConfig(); 00609 00610 /* Create idle thread 00611 */ 00612 NutThreadCreate("idle", NutIdle, 0, 00613 (NUT_THREAD_IDLESTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD); 00614 } 00615