LPC2888 port, crash in first CRITICAL_SECTION

darkvegetable wrote on Tuesday, October 28, 2008:

Hi

I’m working on an LPC2888 port using GCC (v4.3.2). I started with the LPC2106_GCC project & tested it with a simple main() that blinks the LED on the Olimex board

I then removed all the demo tasks except the LEDFlashTask and modded the prvSetupTimerInterrupt function to support the 2888 timer hardware. When I test this code everything starts up correctly and I make it through the first task switch and into the LEDFlashTask. I then hit the call to portENTER_CRITICAL and the processor jumps into hyperspace.

I can see the cpsr mode bits and it’s definitely in supervisor mode, any ideas anyone?

darkvegetable wrote on Tuesday, October 28, 2008:

hmm, that last sentence is wrong. The CPU is in supervisor mode when the scheduler started.

Further debugging & everything looks good all the way upto vPortISRStartFirstTask(). The portRESTORE_CONTEXT() call starts the LEDFlashTask running. The task context has been correctly loaded into the CPUs registers and ulCriticalNesting = 0. At this point cpsr = 0x3F*. The first thing the LEDFlashTask does is call portENTER_CRITICAL and the code crashes in there. 

*I’m an ARM n00b but I don’t understand why the mode bits are 11111, my datasheet suggests user mode is 10000

rtel wrote on Wednesday, October 29, 2008:

11111 is correct as tasks run in System mode, not user mode.

It also looks like you are compiling to run the tasks in THUMB mode as the T bit is also set.  Do you have THUMB_INTERWORK set?  (compiler option -DTHUMB_INTERWORK in the makefile)  If not then that would explain the problem.

Note that the LPC2106 demo on which you based yours has 4 batch files to build for 4 different modes arm_ram.bat, arm_rom.bat, thumb_ram.bat and thumb_rom.bat.  These setup the required build options to switch between ARM and THUMB mode.

Regards.

darkvegetable wrote on Wednesday, October 29, 2008:

I’m using the ram_thumb batch file to build so I think -DTHUMB_INTERWORK should be set correctly.

I removed the contents of the ENTER_CRITICAL function and it still crashed! So I replaced the ENTER_CRITICAL function with a simple dummy function & it still crashes.

I now think I have a problem with the task stack. When I step into the first task with the debugger all the CPU regs are loaded correctly and the sp is set to the same value as StartTask calculated for TopOfStack.

Thanks for the info about the mode flags

darkvegetable wrote on Monday, November 10, 2008:

Well, after a lot of head scratching and debugging I fixed the first crash. Turns out the timer interrupt was firing & I wasn’t handling the IRQ at all :frowning:

Now I have the IRQ handler setup correctly (LPC2888 is very different to other LPC parts) I have a problem in the vTickISR.

When my interrupt fires I execute the following:

void IRQHandler( void ) __attribute__ ((naked));
void IRQHandler( void )
{
    irq = (INT_VECTOR0 & 0x000000FF) >> 3;
    fptr = (FnPtr)Int_Table[irq];
    if(fptr)
    {
        fptr();
    }
}

This reads the interrupt cause reg and looks for the ISR in a lookup table. (irq & fptr are global vars since this function is ‘naked’ and local vars don’t work). I then jump to the FreeRTOS vTickISR()

void vTickISR( void ) __attribute__((naked));
void vTickISR( void )
{
    /* Save the context of the interrupted task. */
    portSAVE_CONTEXT();   
        …
        …
        …
        /* Clear the interrupt source */
    T0CLR = 0x0;
   
    /* Restore the context of the new task. */
    portRESTORE_CONTEXT();
}

When I hit that portRESTORE_CONTEXT() I jump into hyperspace (pabt). Is the problem that I have an IRQHandler() function and that is destroying my task context info? If so, can I call SAVE/RESTORE from ARM mode?

All help gratefully received.

darkvegetable wrote on Monday, November 10, 2008:

Finally, got it running! If anyone else is having trouble with this chip & FreeRTOS/GCC you need to

1) Put the IRQ handler in a file that is config’ed to build in ARM mode (see makefile & portISR.c)

2) Your IRQ handler should look like this:

void IRQHandler( void ) __attribute__ ((naked));
void IRQHandler( void )
{
    portSAVE_CONTEXT();
    irq = (INT_VECTOR0 & 0x000000FF) >> 3;

    fptr = (FnPtr)Int_Table[irq];
    if(fptr)
    {
        fptr();
    }
    portRESTORE_CONTEXT();
}

Then the vTickISR becomes (note, remove the naked attribute)

void vTickISR( void )
{
    /* Increment the RTOS tick count, then look for the highest priority
    task that is ready to run. */
    vTaskIncrementTick();

    #if configUSE_PREEMPTION == 1
        vTaskSwitchContext();
    #endif

    T0CLR = 0x0;
}

Sorted, LED blinking :slight_smile: