Skip to content

S32K + FreeRTOS: Interrupts are enabled too soon #362

@jan-bruckner-esr

Description

@jan-bruckner-esr

In xPortStartScheduler():

/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled
* here already. */
vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
/* Ensure the VFP is enabled - it should be anyway. */
vPortEnableVFP();
/* Lazy save always. */
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
/* Start the first task. */
prvPortStartFirstTask();
/* Should never get here as the tasks will now be executing! Call the task
* exit error function to prevent compiler warnings about a static function
* not being called in the case that the application writer overrides this
* functionality by defining configTASK_RETURN_ADDRESS. Call
* vTaskSwitchContext() so link time optimisation does not remove the
* symbol. */
vTaskSwitchContext();
prvTaskExitError();
/* Should not get here! */
return 0;
}

vPortSetupTimerInterrupt() is called which calls setupApplicationsIsr():

void setupApplicationsIsr(void)
{
// interrupts
SYS_SetPriority(CAN0_ORed_0_15_MB_IRQn, 8); // can0 buffer 0 - 15
SYS_SetPriority(CAN0_ORed_16_31_MB_IRQn, 8); // can0 buffer 16 - 32
SYS_EnableIRQ(CAN0_ORed_0_15_MB_IRQn);
SYS_EnableIRQ(CAN0_ORed_16_31_MB_IRQn);
// Data transfer done, Transmit Buffer Done for Ring/Queue 0, Transmit Frame Done for Ring/Queue
// 0
SYS_SetPriority(ENET_TX_Buffer_IRQn, 9);
// Receive Buffer Done for Ring/Queue 0, Receive Frame Done for Ring/Queue 0
SYS_SetPriority(ENET_RX_Buffer_IRQn, 9);
// Payload receive error, Collision retry limit reached, Late collision detected, AXI Bus Error
// detected, Babbling transmit error, Babbling receive error, Transmit FIFO underrun
// SYS_SetPriority(ENET_PRE_IRQn, 9);
SYS_EnableIRQ(ENET_TX_Buffer_IRQn);
SYS_EnableIRQ(ENET_RX_Buffer_IRQn);
// SYS_EnableIRQ(ENET_PRE_IRQn);
ENABLE_INTERRUPTS();
}

which enables interrupts in the last line.

However, FreeRTOS enables interrupts later in:

static void prvPortStartFirstTask( void )
{
/* Start the first task. This also clears the bit that indicates the FPU is
* in use in case the FPU was used before the scheduler was started - which
* would otherwise result in the unnecessary leaving of space in the SVC stack
* for lazy saving of FPU registers. */
__asm volatile (
" ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */
" ldr r0, [r0] \n"
" ldr r0, [r0] \n"
" msr msp, r0 \n" /* Set the msp back to the start of the stack. */
" mov r0, #0 \n" /* Clear the bit that indicates the FPU is in use, see comment above. */
" msr control, r0 \n"
" cpsie i \n" /* Globally enable interrupts. */
" cpsie f \n"
" dsb \n"
" isb \n"
" svc 0 \n" /* System call to start first task. */
" nop \n"
" .ltorg \n"
);
}

Is there a reason why we enable interrupts ourselves earlier?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions