Make Cortex-M0 set/clear interrupt flag from ISR functions nestable.

Don't reset the stack location when starting the scheduler in Cortex-M0 ports as the vector offset register is not implemented and XMC1000 devices have their application vector address somewhere other than 0x00.
This commit is contained in:
Richard Barry 2013-09-01 19:53:24 +00:00
parent ed399e801e
commit 73606369c4
9 changed files with 146 additions and 102 deletions

View File

@ -158,10 +158,10 @@ void vPortSVCHandler( void )
void vPortStartFirstTask( void ) void vPortStartFirstTask( void )
{ {
/* The MSP stack is not reset as, unlike on M3/4 parts, there is no vector
table offset register that can be used to locate the initial stack value.
Not all M0 parts have the application vector table at address 0. */
__asm volatile( __asm volatile(
" movs r0, #0x00 \n" /* Locate the top of stack. */
" ldr r0, [r0] \n"
" msr msp, r0 \n" /* Set the msp back to the start of the stack. */
" cpsie i \n" /* Globally enable interrupts. */ " cpsie i \n" /* Globally enable interrupts. */
" svc 0 \n" /* System call to start first task. */ " svc 0 \n" /* System call to start first task. */
" nop \n" " nop \n"
@ -231,6 +231,28 @@ void vPortExitCritical( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
unsigned long ulSetInterruptMaskFromISR( void )
{
__asm volatile(
" mrs r0, PRIMASK \n"
" cpsid i \n"
" bx lr "
);
/* To avoid compiler warnings. This line will never be reached. */
return 0;
}
/*-----------------------------------------------------------*/
void vClearInterruptMaskFromISR( unsigned long ulMask )
{
__asm volatile(
" msr PRIMASK, r0 \n"
" bx lr "
);
}
/*-----------------------------------------------------------*/
void xPortPendSVHandler( void ) void xPortPendSVHandler( void )
{ {
/* This is a naked function. */ /* This is a naked function. */
@ -281,9 +303,9 @@ void xPortPendSVHandler( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy; unsigned long ulPreviousMask;
ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
{ {
/* Increment the RTOS tick. */ /* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
@ -292,7 +314,7 @@ unsigned long ulDummy;
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
} }
} }
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View File

@ -118,12 +118,13 @@ extern void vPortYield( void );
/* Critical section management. */ /* Critical section management. */
extern void vPortEnterCritical( void ); extern void vPortEnterCritical( void );
extern void vPortExitCritical( void ); extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK() __asm volatile ( " cpsid i " ) extern unsigned long ulSetInterruptMaskFromISR( void ) __attribute__((naked));
#define portCLEAR_INTERRUPT_MASK() __asm volatile ( " cpsie i " ) extern void vClearInterruptMaskFromISR( unsigned long ulMask ) __attribute__((naked));
#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR()
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vClearInterruptMaskFromISR( x )
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() #define portDISABLE_INTERRUPTS() __asm volatile ( " cpsid i " )
#define portENABLE_INTERRUPTS() __asm volatile ( " cpsie i " )
#define portENTER_CRITICAL() vPortEnterCritical() #define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical() #define portEXIT_CRITICAL() vPortExitCritical()

View File

@ -92,7 +92,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE * pxTopOfStack, pdTASK_COD
pxTopOfStack -= 20; pxTopOfStack -= 20;
/* Fill the registers with known values to assist debugging. */ /* Fill the registers with known values to assist debugging. */
pxTopOfStack[ 16 ] = portKERNEL_INTERRUPT_PRIORITY_LEVEL; pxTopOfStack[ 16 ] = 0;
pxTopOfStack[ 15 ] = portINITIAL_PSR; pxTopOfStack[ 15 ] = portINITIAL_PSR;
pxTopOfStack[ 14 ] = ( unsigned long ) pxCode; pxTopOfStack[ 14 ] = ( unsigned long ) pxCode;
pxTopOfStack[ 13 ] = 0x00000000UL; /* R15. */ pxTopOfStack[ 13 ] = 0x00000000UL; /* R15. */
@ -119,10 +119,6 @@ portBASE_TYPE xPortStartScheduler( void )
/* Set-up the timer interrupt. */ /* Set-up the timer interrupt. */
prvSetupTimerInterrupt(); prvSetupTimerInterrupt();
/* Enable the TRAP yield. */
irq[ portIRQ_TRAP_YIELD ].ien = 1;
irq[ portIRQ_TRAP_YIELD ].ipl = portKERNEL_INTERRUPT_PRIORITY_LEVEL;
/* Integrated Interrupt Controller: Enable all interrupts. */ /* Integrated Interrupt Controller: Enable all interrupts. */
ic->ien = 1; ic->ien = 1;
@ -143,7 +139,6 @@ static void prvSetupTimerInterrupt( void )
/* Set the IRQ Handler priority and enable it. */ /* Set the IRQ Handler priority and enable it. */
irq[ IRQ_COUNTER1 ].ien = 1; irq[ IRQ_COUNTER1 ].ien = 1;
irq[ IRQ_COUNTER1 ].ipl = portKERNEL_INTERRUPT_PRIORITY_LEVEL;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View File

@ -69,7 +69,7 @@
extern "C" { extern "C" {
#endif #endif
#include <machine/ic.h> #include <machine/cpu.h>
/*----------------------------------------------------------- /*-----------------------------------------------------------
* Port specific definitions. * Port specific definitions.
@ -106,8 +106,6 @@ extern "C" {
#define portNOP() __asm__ volatile ( "mov r0, r0" ) #define portNOP() __asm__ volatile ( "mov r0, r0" )
#define portCRITICAL_NESTING_IN_TCB 1 #define portCRITICAL_NESTING_IN_TCB 1
#define portIRQ_TRAP_YIELD 31 #define portIRQ_TRAP_YIELD 31
#define portKERNEL_INTERRUPT_PRIORITY_LEVEL 0
#define portSYSTEM_INTERRUPT_PRIORITY_LEVEL 0
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task utilities. */ /* Task utilities. */
@ -126,8 +124,8 @@ extern void vTaskExitCritical( void );
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Critical section management. */ /* Critical section management. */
#define portDISABLE_INTERRUPTS() ic->cpl = ( portSYSTEM_INTERRUPT_PRIORITY_LEVEL + 1 ) #define portDISABLE_INTERRUPTS() cpu_int_disable()
#define portENABLE_INTERRUPTS() ic->cpl = portKERNEL_INTERRUPT_PRIORITY_LEVEL #define portENABLE_INTERRUPTS() cpu_int_enable()
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View File

@ -198,9 +198,9 @@ void vPortExitCritical( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy; unsigned long ulPreviousMask;
ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
{ {
/* Increment the RTOS tick. */ /* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
@ -209,7 +209,7 @@ unsigned long ulDummy;
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
} }
} }
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View File

@ -64,14 +64,6 @@
#include <FreeRTOSConfig.h> #include <FreeRTOSConfig.h>
/* For backward compatibility, ensure configKERNEL_INTERRUPT_PRIORITY is
defined. The value zero should also ensure backward compatibility.
FreeRTOS.org versions prior to V4.3.0 did not include this definition. */
#ifndef configKERNEL_INTERRUPT_PRIORITY
#define configKERNEL_INTERRUPT_PRIORITY 0
#endif
RSEG CODE:CODE(2) RSEG CODE:CODE(2)
thumb thumb
@ -83,7 +75,8 @@ FreeRTOS.org versions prior to V4.3.0 did not include this definition. */
PUBLIC xPortPendSVHandler PUBLIC xPortPendSVHandler
PUBLIC vPortSVCHandler PUBLIC vPortSVCHandler
PUBLIC vPortStartFirstTask PUBLIC vPortStartFirstTask
PUBLIC ulSetInterruptMaskFromISR
PUBLIC vClearInterruptMaskFromISR
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -155,12 +148,24 @@ vPortSVCHandler;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
vPortStartFirstTask vPortStartFirstTask
movs r0, #0x00 /* Locate the top of stack. */ /* The MSP stack is not reset as, unlike on M3/4 parts, there is no vector
ldr r0, [r0] table offset register that can be used to locate the initial stack value.
msr msp, r0 /* Set the msp back to the start of the stack. */ Not all M0 parts have the application vector table at address 0. */
cpsie i /* Globally enable interrupts. */ cpsie i /* Globally enable interrupts. */
svc 0 /* System call to start first task. */ svc 0 /* System call to start first task. */
nop nop
END /*-----------------------------------------------------------*/
ulSetInterruptMaskFromISR
mrs r0, PRIMASK
cpsid i
bx lr
/*-----------------------------------------------------------*/
vClearInterruptMaskFromISR
msr PRIMASK, r0
bx lr
END

View File

@ -119,13 +119,15 @@ extern void vPortYield( void );
extern void vPortEnterCritical( void ); extern void vPortEnterCritical( void );
extern void vPortExitCritical( void ); extern void vPortExitCritical( void );
extern unsigned long ulSetInterruptMaskFromISR( void );
extern void vClearInterruptMaskFromISR( unsigned long ulMask );
#define portDISABLE_INTERRUPTS() __asm volatile( "cpsid i" ) #define portDISABLE_INTERRUPTS() __asm volatile( "cpsid i" )
#define portENABLE_INTERRUPTS() __asm volatile( "cpsie i" ) #define portENABLE_INTERRUPTS() __asm volatile( "cpsie i" )
#define portENTER_CRITICAL() vPortEnterCritical() #define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical() #define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portDISABLE_INTERRUPTS() #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portENABLE_INTERRUPTS();(void)x #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vClearInterruptMaskFromISR( x )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -135,6 +137,11 @@ extern void vPortExitCritical( void );
#define portNOP() #define portNOP()
/* Suppress warnings that are generated by the IAR tools, but cannot be fixed in
the source code because to do so would cause other compilers to generate
warnings. */
#pragma diag_suppress=Pa082
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -108,7 +108,7 @@ void vPortSVCHandler( void );
/* /*
* Start first task is a separate function so it can be tested in isolation. * Start first task is a separate function so it can be tested in isolation.
*/ */
static void vPortStartFirstTask( void ); static void prvPortStartFirstTask( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -137,11 +137,11 @@ __asm void vPortSVCHandler( void )
PRESERVE8 PRESERVE8
ldr r3, =pxCurrentTCB /* Restore the context. */ ldr r3, =pxCurrentTCB /* Obtain location of pxCurrentTCB. */
ldr r1, [r3] /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */ ldr r1, [r3]
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */
adds r0, #16 /* Move to the high registers. */ adds r0, #16 /* Pop the high registers. */
ldmia r0!, {r4-r7} /* Pop the high registers. */ ldmia r0!, {r4-r7}
mov r8, r4 mov r8, r4
mov r9, r5 mov r9, r5
mov r10, r6 mov r10, r6
@ -155,20 +155,20 @@ __asm void vPortSVCHandler( void )
movs r0, #0x0d movs r0, #0x0d
orrs r1, r0 orrs r1, r0
bx r1 bx r1
nop ALIGN
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
__asm void vPortStartFirstTask( void ) __asm void prvPortStartFirstTask( void )
{ {
PRESERVE8 PRESERVE8
movs r0, #0x00 /* Locate the top of stack. */ /* The MSP stack is not reset as, unlike on M3/4 parts, there is no vector
ldr r0, [r0] table offset register that can be used to locate the initial stack value.
msr msp, r0 /* Set the msp back to the start of the stack. */ Not all M0 parts have the application vector table at address 0. */
cpsie i /* Globally enable interrupts. */ cpsie i /* Globally enable interrupts. */
svc 0 /* System call to start first task. */ svc 0 /* System call to start first task. */
nop ALIGN
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -189,7 +189,7 @@ portBASE_TYPE xPortStartScheduler( void )
uxCriticalNesting = 0; uxCriticalNesting = 0;
/* Start the first task. */ /* Start the first task. */
vPortStartFirstTask(); prvPortStartFirstTask();
/* Should not get here! */ /* Should not get here! */
return 0; return 0;
@ -234,6 +234,21 @@ void vPortExitCritical( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
__asm unsigned long ulSetInterruptMaskFromISR( void )
{
mrs r0, PRIMASK
cpsid i
bx lr
}
/*-----------------------------------------------------------*/
__asm void vClearInterruptMaskFromISR( unsigned long ulMask )
{
msr PRIMASK, r0
bx lr
}
/*-----------------------------------------------------------*/
__asm void xPortPendSVHandler( void ) __asm void xPortPendSVHandler( void )
{ {
extern vTaskSwitchContext extern vTaskSwitchContext
@ -276,14 +291,15 @@ __asm void xPortPendSVHandler( void )
ldmia r0!, {r4-r7} /* Pop low registers. */ ldmia r0!, {r4-r7} /* Pop low registers. */
bx r3 bx r3
ALIGN
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
unsigned long ulDummy; unsigned long ulPreviousMask;
ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
{ {
/* Increment the RTOS tick. */ /* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
@ -292,7 +308,7 @@ unsigned long ulDummy;
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
} }
} }
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View File

@ -114,16 +114,16 @@ extern void vPortYield( void );
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Critical section management. */ /* Critical section management. */
extern void vPortEnterCritical( void ); extern void vPortEnterCritical( void );
extern void vPortExitCritical( void ); extern void vPortExitCritical( void );
#define portSET_INTERRUPT_MASK() __disable_irq() extern unsigned long ulSetInterruptMaskFromISR( void );
#define portCLEAR_INTERRUPT_MASK() __enable_irq() extern void vClearInterruptMaskFromISR( unsigned long ulMask );
#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x #define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR()
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vClearInterruptMaskFromISR( x )
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() #define portDISABLE_INTERRUPTS() __disable_irq()
#define portENABLE_INTERRUPTS() __enable_irq()
#define portENTER_CRITICAL() vPortEnterCritical() #define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical() #define portEXIT_CRITICAL() vPortExitCritical()