Nut/OS  4.10.3
API Reference
nutinit.c
Go to the documentation of this file.
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