[En-Nut-Discussion] Move NutLoadConfig() into main thread?

Philipp Burch phip at hb9etc.ch
Sun Nov 2 22:39:58 CET 2014


Hi Uwe!

On 02.11.2014 21:37, Uwe Bonnes wrote:
>>>>>> "Philipp" == Philipp Burch <phip at hb9etc.ch> writes:
> 
>     Philipp> Hi everyone, I'm using an I2C EEPROM as non-volatile storage on
>     Philipp> my board. Since Nut/OS and/or Nut/Net already contain
> ...
>     Philipp> But I also needed a workaround/hack in my I2C driver to make
>     Philipp> that stuff work. The problem is that NutLoadConfig() is called
>     Philipp> during system initialization from the idle loop. The driver
>     Philipp> normally is interrupt-driven and waits for an event using
>     Philipp> NutEventWait(), but this crashes when called from the idle
>     Philipp> thread (NutThreadSwitch() causes a BusFault on the
>     Philipp> Cortex-M4). 
> 
> Unexpected crashed often result from a stack to small. Did you try with more
> stack space?

Stack size for both idle and main is set to 4096 bytes, which should be
far more than is required.
Single-stepping with the debugger revealed that when NutThreadSwitch()
is called, the global runQueue is 0 (NULL). What then follows is

//...
    /* Select thread on top of the run queue. */
    runningThread = runQueue;
    runningThread->td_state = TDS_RUNNING;
//...

and this surprisingly doesn't fault. I don't really understand that, as
the second line is a write directly into flash space (address 0x15
according to the debugger). But in the next inline-ASM block, the last
instruction to restore the registers crashes:

//...
    /* Restore context. */
#if       (__CORTEX_M >= 0x03)
     __asm__ __volatile__(              /* */
        "@ Load context\n\t"            /* */
        "ldr     sp, %0\n\t"            /* Restore stack pointer. */

#if defined (MCU_USE_CORTEX_FPU)
        "ldmfd   sp!, {r4}\n\t"         /* Get saved FPU status... */

        "vmsr    fpscr, r4\n\t"         /* ...and save back. */
        "vpop    {s16-s31}\n\t"         /* Restore FPU registers. */
#endif

        "ldmfd   sp!, {r4}\n\t"         /* Get saved status... */
        "msr     xpsr_nzcvq, r4\n\t"   /* ...and save execution and
application status in psr. */
        "cpsie   i\n\t"                 /* ...enable interrupts */
        "ldmfd   sp!, {r4-r11, pc}\n\t" /* Restore registers. */
        ::"m"(runningThread->td_sp)     /* */
    );
//...

Seeking for the cause of runQueue being 0, I found the NutEventWait()
function. Unless the queue has been signaled, program flow continues
along the lines

//...
    /*
     * Remove the current thread from the list of running threads
     * and add it to the specified queue.
     */
    NutThreadRemoveQueue(runningThread, &runQueue);
    NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) qhp);
//...

The first line makes runQueue 0x0 and the second one doesn't change
that. I think this is basically correct operation, but then
NutThreadResume() should not try to switch to the next thread in the
runQueue when it is empty.

Cheers,
Philipp


More information about the En-Nut-Discussion mailing list