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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions