[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. */

        "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.


More information about the En-Nut-Discussion mailing list