[En-Nut-Discussion] Correction to previous post and more info

Ralph Mason ralph.mason at telogis.com
Fri Nov 21 20:16:14 CET 2003


> You also mentioned, that you do never expect fread()
> to fail with an error. This assumption is wrong.
> Running out of memory may be one cause to let this
> (and most other functions) fail.

This is personal preference I guess, but you should never have functions
fail due to lack of memory.  If you run out of memory in an embedded
application there is almost nothing you can do except redesign your
application.  This clearly makes coding to handle low memory pointless. All
this being the case you never need to check the return form malloc and all
your code can always proceed happily. I back this up with my watchdog.

I use the following Idle code, it checks the amount of free ram, and also
checks that the heapspace available Variable matches the calculated heap
space available (catches using freed memory), it also catches starvation of
processes since one thread runs at the highest priority which also monitors
the idle thread.

u_char idle_wdt;

//30 seconds
#define IDLE_TIMER_VAL 20

THREAD(watchdog,arg){
    u_char tmp;
    u_char logged;
    //Most important thread in the system
    NutThreadSetPriority(1);

	//2 second timeout
	wdt_enable(WDTO_2S);

	while(1){
		logged=0;
		//Sleep for Seconds and Reset
		wdt_reset();
		NutSleep(500);

		//Check for a block with 2k or more free
		while( NutHeapMaxFreeBlock(&tmp) < 0x400){
			if ( ! logged ){
				LogError(LOG_GENERAL,PSTR("LOW MEM"));
				logged = 1;
			}
			//give it a chance to come right
			NutSleep(25);
		};

		//Check for heap corruption
		while(tmp){
			if ( ! logged ){
				LogError(LOG_GENERAL,PSTR("CORRUPTED MEM DETECTED"));
				logged = 1;
			}
		}

		//Make sure that the idle thread gets to run
		idle_wdt--;
		while( idle_wdt == 0 ){
			//idle thread not running
			if ( ! logged ){
				LogError(LOG_GENERAL,PSTR("IDLE THREAD NOT RUNNING"));
				logged = 1;
			}
			//give it a chance to come right
			NutSleep(25);
		}
	}
}

#endif

THREAD(NutIdle, arg)
{
    NutTimerInit();
#ifdef _PC
   NutThreadCreatePaged("main", NutMain, 123, 3);
    //2 second watchdog
#else
   NutThreadCreate("wdog", watchdog, 0, 384 );
   NutThreadCreatePaged("main", NutMain, 0, 1);
#endif

   //NutThreadCreate("main", NutMain, 123, 2048);
   NutThreadSetPriority(254);
    for (;;) {

        NutThreadYield();
        NutFreeKilledThread();
#ifdef _PC
		//Yield to the OS so we don't hog the processor
		PC_SYS_CODE_START
			Sleep(10);
		PC_SYS_CODE_END
#else
		idle_wdt=IDLE_TIMER_VAL;

		//AVR Sleep code - nothing to do but save power!
		sbi( MCUCR,5) ; asm volatile("sleep" ::);
#endif
    }
}



> Another cause may be lack of stack space. It may work
> hundreds of times and suddenly fail, because an interrupt
> routine uses 20 Bytes of stack, when nothing is available.
> This problem is discussed in
> http://www.ethernut.de/pdf/enmem100.pdf

I really subscribe to the idea of an interrupt stack.  This would make stack
usage more deterministic, and cut down the requirement for each thread to
allocate enough stack space to cover the largest interrupt handler.

Ralph




More information about the En-Nut-Discussion mailing list