idle task crashing when restored

marshallmallow wrote on Monday, May 12, 2008:

I’m using jc wren’s demo code for the lpc2148 and I’m running into an odd problem when the idle task is restored. I’m not using the same development board as jc’s code so I initially commented out creation of all tasks but the blink led. 

When I ran this code, the led would blink once and then a data abort would cause the system to restart. In order to narrow down the problem I created my own blink task with the following code:

portTASK_FUNCTION( vLEDFlashTask, pvParameters __attribute__ ((unused)) )
{
    GPIO0_IODIR |= GPIO_IO_P31;
    for ( ;; )
    {
        GPIO0_IOSET = GPIO_IO_P31;
        vTaskDelay( 100 );
        GPIO0_IOCLR = GPIO_IO_P31;
        vTaskDelay( 100 );
    }
}

The data abort occurred for this task as well during the first call to vTaskDelay. I stepped through the code and found that the error occurs after the idle task is restored and begins executing. The first instruction in prvIdleTask consisted of

str r0, [r11]

r0 contained 0 (NULL) the value of the first parameter passed to prvIdleTask when created and r11 contained 0x11111111 which was set when the stack was created for the task. Obviously, trying to store 0 into address 0x11111111 is wrong, but I couldn’t figure out why this code was generated.  I expected to see code that pushed registers onto the stack where they could be restored before exiting the function.

I eventually figured out that this function is declared naked and that’s why the registers aren’t being saved. I still don’t understand why the naked version of this function generates the str r0, [r11] instruction at the beginning. Can anyone explain why this function is naked and/or why it’s generating this instruction? I assume its naked since it will only ever be called from the scheduler and so shouldn’t need to save any registers since they’re already on the stack.

marshallmallow wrote on Monday, May 12, 2008:

I took a look at the latest source code for FreeRTOS and in portmacro.h the portTASK_FUNCTION_PROTO is not defined as naked.  I don’t know if jc added the naked or if the 4.3 version of FreeRTOS was wrong.  Either way, it looks like this should indeed not be defined as naked.

rtel wrote on Tuesday, May 13, 2008:

I would expect the idle task to crash if it were declared naked, especially at lower optimisation.  Wren is a competent engineer so I’m sure he has done this for a good reason - I’m just not sure what.  Maybe it is only supposed to be like that when the optimisation is higher.  With higher optimisation the redundant pushes to the stack would probably be removed and the code might then work.  Did you change the optimisation level?

Regards.

marshallmallow wrote on Tuesday, May 13, 2008:

Yes, I saw in his makefile optimization at -O3 so I tried that and still had the same problem. I’ll drop him an email and ask him to explain. 

jcwren wrote on Wednesday, May 14, 2008:

Well, it appears that "competent engineer" has a certain randomization function to it.

I believe I added that because I reasoned the register pushes were unnecessary since the tasks never exited, and I don’t create or delete tasks on the fly.

Marshall, curiously, I cannot find the ‘str’ instruction you mentioned.  I’m using arm-elf-gcc 4.2.2.  What version are you running?

Richard, why would you expect the idle task to crash with naked and lower optimizations?

I do know that I have 3 projects that use this same code base, and I know the idle task is running in at least one of them.  So whatever this behavior is, I haven’t seen it affect me yet.  That’s not to say that it’s right, however.

–jc

rtel wrote on Wednesday, May 14, 2008:

>Richard, why would you expect the idle task to
>crash with naked and lower optimizations?

Primarily because of its parameter - which at lower optimisation it could attempt to push on to the stack.  With naked being used it would not create a stack frame, so the push could end up anywhere.

Also it calls listCURRENT_LIST_LENGTH(), which is a macro.  This will use registers which at lower optimisation will probably be saved somewhere.  listCURRENT_LIST_LENGTH() only defines local variables within its own block {}, which may create its own frame, but I think this too will depend on optimisation.

Regards.

marshallmallow wrote on Wednesday, May 14, 2008:

arm-elf-gcc.exe (GCC) 4.2.2 (WinARM Nov. 2007)

This may be a result of my build options.  I customized the Makefile that came with the lpc2138_openocd_jtag WinARM example. I don’t know what option would produce this code but I can provide it if needed.

I’ve also discovered that a str r0, [ X ] instruction is generated for all the other tasks except the LEDFlash task if I leave them as naked. Here’s what I see in the .lss:

portTASK_FUNCTION (vLEDFlashTask, pvParameters __attribute__ ((unused)))
{
    cf14:    e1a0c00d     mov    ip, sp
    cf18:    e92dd800     stmdb    sp!, {fp, ip, lr, pc}

portTASK_FUNCTION (vSensorsTask, pvParameters __attribute__ ((unused)))
{
   16108:    e50b0018     str    r0, [fp, #-24]
  portTickType xTickCount;
  int adcValue;
  int adcLastValue = -1;
   1610c:    e3e03000     mvn    r3, #0    ; 0x0
   16110:    e50b300c     str    r3, [fp, #-12]

portTASK_FUNCTION (vMonitorTask, pvParameters __attribute__ ((unused)))
{
   1347c:    e50b0018     str    r0, [fp, #-24]

I double checked and compiling with -O3 eliminates the str instruction so that must have been the problem all along. So it looks like Richard is indeed correct.  At lower optimizations there is no stack frame and attempting to push r0 causes the data abort. I’m compiling at -O0 in order to simplify debugging as I’m new to the arm architecture. 

jcwren wrote on Wednesday, May 14, 2008:

OK.  I can’t see a reason that the function needs to remain naked, so in the next release I’ll put some clothes on it.

Americans are such prudes! :slight_smile:

In my .lst files, I don’t see any STRs.  Guess I was lucky that I didn’t get snake-bit by it.

–jc