From: richardbarry Date: Sun, 1 Sep 2013 19:53:24 +0000 (+0000) Subject: Make Cortex-M0 set/clear interrupt flag from ISR functions nestable. X-Git-Tag: V7.5.3~51 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=8ee879c18eeffc6b848e5f5542e595dd9b6e9d17;p=freertos 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. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2015 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c index 8c4d78ead..6966c848e 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c @@ -158,14 +158,14 @@ void vPortSVCHandler( 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( - " 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. */ " svc 0 \n" /* System call to start first task. */ " 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 ) { /* This is a naked function. */ @@ -281,9 +303,9 @@ void xPortPendSVHandler( 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. */ if( xTaskIncrementTick() != pdFALSE ) @@ -292,7 +314,7 @@ unsigned long ulDummy; *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM0/portmacro.h b/FreeRTOS/Source/portable/GCC/ARM_CM0/portmacro.h index d641bacfe..bc5c72f9d 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM0/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/ARM_CM0/portmacro.h @@ -118,12 +118,13 @@ extern void vPortYield( void ); /* Critical section management. */ extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -#define portSET_INTERRUPT_MASK() __asm volatile ( " cpsid i " ) -#define portCLEAR_INTERRUPT_MASK() __asm volatile ( " cpsie i " ) -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x -#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() -#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() +extern unsigned long ulSetInterruptMaskFromISR( void ) __attribute__((naked)); +extern void vClearInterruptMaskFromISR( unsigned long ulMask ) __attribute__((naked)); + +#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vClearInterruptMaskFromISR( x ) +#define portDISABLE_INTERRUPTS() __asm volatile ( " cpsid i " ) +#define portENABLE_INTERRUPTS() __asm volatile ( " cpsie i " ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() diff --git a/FreeRTOS/Source/portable/GCC/CORTUS_APS3/port.c b/FreeRTOS/Source/portable/GCC/CORTUS_APS3/port.c index 0e0d9ab5f..22dbb38ce 100644 --- a/FreeRTOS/Source/portable/GCC/CORTUS_APS3/port.c +++ b/FreeRTOS/Source/portable/GCC/CORTUS_APS3/port.c @@ -92,7 +92,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE * pxTopOfStack, pdTASK_COD pxTopOfStack -= 20; /* Fill the registers with known values to assist debugging. */ - pxTopOfStack[ 16 ] = portKERNEL_INTERRUPT_PRIORITY_LEVEL; + pxTopOfStack[ 16 ] = 0; pxTopOfStack[ 15 ] = portINITIAL_PSR; pxTopOfStack[ 14 ] = ( unsigned long ) pxCode; pxTopOfStack[ 13 ] = 0x00000000UL; /* R15. */ @@ -119,10 +119,6 @@ portBASE_TYPE xPortStartScheduler( void ) /* Set-up the timer interrupt. */ 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. */ ic->ien = 1; @@ -143,7 +139,6 @@ static void prvSetupTimerInterrupt( void ) /* Set the IRQ Handler priority and enable it. */ irq[ IRQ_COUNTER1 ].ien = 1; - irq[ IRQ_COUNTER1 ].ipl = portKERNEL_INTERRUPT_PRIORITY_LEVEL; } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/GCC/CORTUS_APS3/portmacro.h b/FreeRTOS/Source/portable/GCC/CORTUS_APS3/portmacro.h index 1e7f2d23f..d0418266e 100644 --- a/FreeRTOS/Source/portable/GCC/CORTUS_APS3/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/CORTUS_APS3/portmacro.h @@ -69,7 +69,7 @@ extern "C" { #endif -#include +#include /*----------------------------------------------------------- * Port specific definitions. @@ -106,8 +106,6 @@ extern "C" { #define portNOP() __asm__ volatile ( "mov r0, r0" ) #define portCRITICAL_NESTING_IN_TCB 1 #define portIRQ_TRAP_YIELD 31 -#define portKERNEL_INTERRUPT_PRIORITY_LEVEL 0 -#define portSYSTEM_INTERRUPT_PRIORITY_LEVEL 0 /*-----------------------------------------------------------*/ /* Task utilities. */ @@ -126,8 +124,8 @@ extern void vTaskExitCritical( void ); /*---------------------------------------------------------------------------*/ /* Critical section management. */ -#define portDISABLE_INTERRUPTS() ic->cpl = ( portSYSTEM_INTERRUPT_PRIORITY_LEVEL + 1 ) -#define portENABLE_INTERRUPTS() ic->cpl = portKERNEL_INTERRUPT_PRIORITY_LEVEL +#define portDISABLE_INTERRUPTS() cpu_int_disable() +#define portENABLE_INTERRUPTS() cpu_int_enable() /*---------------------------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM0/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM0/port.c index a652ea9a7..6b3cc4162 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM0/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM0/port.c @@ -198,9 +198,9 @@ void vPortExitCritical( 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. */ if( xTaskIncrementTick() != pdFALSE ) @@ -209,7 +209,7 @@ unsigned long ulDummy; *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM0/portasm.s b/FreeRTOS/Source/portable/IAR/ARM_CM0/portasm.s index 6bc3c8eff..741a2c605 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM0/portasm.s +++ b/FreeRTOS/Source/portable/IAR/ARM_CM0/portasm.s @@ -64,14 +64,6 @@ #include -/* 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) thumb @@ -83,52 +75,53 @@ FreeRTOS.org versions prior to V4.3.0 did not include this definition. */ PUBLIC xPortPendSVHandler PUBLIC vPortSVCHandler PUBLIC vPortStartFirstTask - + PUBLIC ulSetInterruptMaskFromISR + PUBLIC vClearInterruptMaskFromISR /*-----------------------------------------------------------*/ vSetMSP msr msp, r0 bx lr - + /*-----------------------------------------------------------*/ xPortPendSVHandler: - mrs r0, psp - + mrs r0, psp + ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */ - ldr r2, [r3] - + ldr r2, [r3] + subs r0, r0, #32 /* Make space for the remaining low registers. */ str r0, [r2] /* Save the new top of stack. */ stmia r0!, {r4-r7} /* Store the low registers that are not saved automatically. */ mov r4, r8 /* Store the high registers. */ - mov r5, r9 - mov r6, r10 - mov r7, r11 - stmia r0!, {r4-r7} - - push {r3, r14} - cpsid i - bl vTaskSwitchContext - cpsie i + mov r5, r9 + mov r6, r10 + mov r7, r11 + stmia r0!, {r4-r7} + + push {r3, r14} + cpsid i + bl vTaskSwitchContext + cpsie i pop {r2, r3} /* lr goes in r3. r2 now holds tcb pointer. */ - - ldr r1, [r2] + + ldr r1, [r2] ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ adds r0, r0, #16 /* Move to the high registers. */ ldmia r0!, {r4-r7} /* Pop the high registers. */ - mov r8, r4 - mov r9, r5 - mov r10, r6 - mov r11, r7 - + mov r8, r4 + mov r9, r5 + mov r10, r6 + mov r11, r7 + msr psp, r0 /* Remember the new top of stack for the task. */ - + subs r0, r0, #32 /* Go back for the low registers that are not automatically restored. */ ldmia r0!, {r4-r7} /* Pop low registers. */ - - bx r3 + + bx r3 /*-----------------------------------------------------------*/ @@ -138,29 +131,41 @@ vPortSVCHandler; ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ adds r0, r0, #16 /* Move to the high registers. */ ldmia r0!, {r4-r7} /* Pop the high registers. */ - mov r8, r4 - mov r9, r5 - mov r10, r6 - mov r11, r7 - + mov r8, r4 + mov r9, r5 + mov r10, r6 + mov r11, r7 + msr psp, r0 /* Remember the new top of stack for the task. */ - + subs r0, r0, #32 /* Go back for the low registers that are not automatically restored. */ ldmia r0!, {r4-r7} /* Pop low registers. */ mov r1, r14 /* OR R14 with 0x0d. */ - movs r0, #0x0d - orrs r1, r0 - bx r1 + movs r0, #0x0d + orrs r1, r0 + bx r1 /*-----------------------------------------------------------*/ vPortStartFirstTask - movs r0, #0x00 /* Locate the top of stack. */ - ldr r0, [r0] - msr msp, r0 /* Set the msp back to the start of the stack. */ + /* 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. */ cpsie i /* Globally enable interrupts. */ svc 0 /* System call to start first task. */ - nop - + nop + +/*-----------------------------------------------------------*/ + +ulSetInterruptMaskFromISR + mrs r0, PRIMASK + cpsid i + bx lr + +/*-----------------------------------------------------------*/ + +vClearInterruptMaskFromISR + msr PRIMASK, r0 + bx lr + END - \ No newline at end of file diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM0/portmacro.h b/FreeRTOS/Source/portable/IAR/ARM_CM0/portmacro.h index f9577b296..4f46d038e 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM0/portmacro.h +++ b/FreeRTOS/Source/portable/IAR/ARM_CM0/portmacro.h @@ -119,13 +119,15 @@ extern void vPortYield( void ); extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); +extern unsigned long ulSetInterruptMaskFromISR( void ); +extern void vClearInterruptMaskFromISR( unsigned long ulMask ); #define portDISABLE_INTERRUPTS() __asm volatile( "cpsid i" ) #define portENABLE_INTERRUPTS() __asm volatile( "cpsie i" ) #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical() -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portDISABLE_INTERRUPTS() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portENABLE_INTERRUPTS();(void)x +#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vClearInterruptMaskFromISR( x ) /*-----------------------------------------------------------*/ @@ -135,6 +137,11 @@ extern void vPortExitCritical( void ); #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 } #endif diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM0/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM0/port.c index 4cee00c39..2c0169f7e 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM0/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM0/port.c @@ -108,7 +108,7 @@ void vPortSVCHandler( void ); /* * 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 - ldr r3, =pxCurrentTCB /* Restore the context. */ - ldr r1, [r3] /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */ + ldr r3, =pxCurrentTCB /* Obtain location of pxCurrentTCB. */ + ldr r1, [r3] ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */ - adds r0, #16 /* Move to the high registers. */ - ldmia r0!, {r4-r7} /* Pop the high registers. */ + adds r0, #16 /* Pop the high registers. */ + ldmia r0!, {r4-r7} mov r8, r4 mov r9, r5 mov r10, r6 @@ -155,20 +155,20 @@ __asm void vPortSVCHandler( void ) movs r0, #0x0d orrs r1, r0 bx r1 - nop + ALIGN } /*-----------------------------------------------------------*/ -__asm void vPortStartFirstTask( void ) +__asm void prvPortStartFirstTask( void ) { PRESERVE8 - - movs r0, #0x00 /* Locate the top of stack. */ - ldr r0, [r0] - msr msp, r0 /* Set the msp back to the start of the stack. */ - cpsie i /* Globally enable interrupts. */ - svc 0 /* System call to start first task. */ - nop + + /* 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. */ + cpsie i /* Globally enable interrupts. */ + svc 0 /* System call to start first task. */ + ALIGN } /*-----------------------------------------------------------*/ @@ -189,7 +189,7 @@ portBASE_TYPE xPortStartScheduler( void ) uxCriticalNesting = 0; /* Start the first task. */ - vPortStartFirstTask(); + prvPortStartFirstTask(); /* Should not get here! */ 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 ) { extern vTaskSwitchContext @@ -276,14 +291,15 @@ __asm void xPortPendSVHandler( void ) ldmia r0!, {r4-r7} /* Pop low registers. */ bx r3 + ALIGN } /*-----------------------------------------------------------*/ 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. */ if( xTaskIncrementTick() != pdFALSE ) @@ -292,7 +308,7 @@ unsigned long ulDummy; *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM0/portmacro.h b/FreeRTOS/Source/portable/RVDS/ARM_CM0/portmacro.h index 8ab2dc79d..56d357d7e 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM0/portmacro.h +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM0/portmacro.h @@ -114,16 +114,16 @@ extern void vPortYield( void ); #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) /*-----------------------------------------------------------*/ - /* Critical section management. */ extern void vPortEnterCritical( void ); extern void vPortExitCritical( void ); -#define portSET_INTERRUPT_MASK() __disable_irq() -#define portCLEAR_INTERRUPT_MASK() __enable_irq() -#define portSET_INTERRUPT_MASK_FROM_ISR() 0;portSET_INTERRUPT_MASK() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) portCLEAR_INTERRUPT_MASK();(void)x -#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() -#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK() +extern unsigned long ulSetInterruptMaskFromISR( void ); +extern void vClearInterruptMaskFromISR( unsigned long ulMask ); + +#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMaskFromISR() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vClearInterruptMaskFromISR( x ) +#define portDISABLE_INTERRUPTS() __disable_irq() +#define portENABLE_INTERRUPTS() __enable_irq() #define portENTER_CRITICAL() vPortEnterCritical() #define portEXIT_CRITICAL() vPortExitCritical()