qft0 wrote on Thursday, February 26, 2009:
I should probably say that I’m using the heap_1 scheme: create all tasks before starting the RTOS, and never kill a task or release any memory after.
If I remove one task, and change the declaration to static, all is well. If I look at the memory usage from within the debugger, I get 8181/32768 locations of code space used up, and 2057/3968 locations of ram space used up. Oddly enough, if I add the extra task back into the mix, I end up with 8213 locations of code space, and the same 2057 locations of ram space. I went back and played with the heap and the number of tasks. Here’s what I got:
Heap | # of tasks
496 | 2
752 | 3
1008 | 3
1776 | 3
…bla bla bla…
3312 | 3
So, I suspect the heap’s not the problem. I can’t see how I’d need an order of magnitude more heap space to pull this off.
The next thing I tried was to leave the heap at 3312, but increase the stack for each task to 512 bytes. It works with three instantiations of vDasBlinkenTask, not four.
If I dump the ram into the debugger, all allocated space from the heap lives below 0x530, or 1328 (stack set to 128 bytes/task). Also, since the unused stack space is padded with 0xa5 I can see where each unused portion of stack lives. They all look like there’s a lot of space available, both in unused stack and in overall heap space. There are five visible blocks of space filled with 0xa5, some are smaller than others, but they are all there. I expect five because there’s an Idle task too. Increasing configMINIMAL_STACK_SIZE, doesn’t seem to matter. I have lots of space in RAM.
If I set a break point at the first instruction in main(), the processor hits the breakpoint after the rtos is started, meaning something has gone terribly wrong. It can’t get to this point unless it was reset. When this happens, some of the statically assigned variables have been overwritten. Specifically the pointer assignment for led.portreg is pointing to the wrong address, and led.period is corrupt. The rest of the table is fine. Something is overwriting these variables after the RTOS begins executing. If I move the call to app_init() above the led[x] assignments, it all works. It would be great news, if I knew why.
The app_init() function is pitifully simple:
// Set up the ports
PORTA = PORTAINI;
PORTB = PORTBINI;
PORTC = PORTCINI;
PORTD = PORTDINI;
PORTE = PORTEINI;
TRISA = TRISAINI;
TRISB = TRISBINI;
TRISC = TRISCINI;
TRISD = TRISDINI;
TRISE = TRISEINI;
ADCON0 = 0; // Kill ADC so port A can be digital inputs.
ADCON1 = 0x0f;
CMCON = 0x07; // Ensure comparator is off
WDTCONbits.SWDTEN = 1; // Turn on watchdog timer.
STKPTRbits.STKFUL = 0; // Clear any stack over/underflow errors.
STKPTRbits.STKUNF = 0;
…so I wouldn’t expect this to make any difference at all. For completeness, WATCHDOG is undefined, so that’s not it. Besides, if it were, moving the function wouldn’t matter.
Lastly, since it works with app_init() called prior to the variable assignments in main(), I tried shrinking the heap and stack sizes down to a ridiculous level, and it still works. Currently it works with:
#define configMINIMAL_STACK_SIZE 76
#define configTOTAL_HEAP_SIZE (size_t) 752
It’s out of memory. Why would the function location matter?