123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /*
- FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
- All rights reserved
- VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
- This file is part of the FreeRTOS distribution.
- FreeRTOS is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License (version 2) as published by the
- Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
- ***************************************************************************
- >>! NOTE: The modification to the GPL is included to allow you to !<<
- >>! distribute a combined work that includes FreeRTOS without being !<<
- >>! obliged to provide the source code for proprietary components !<<
- >>! outside of the FreeRTOS kernel. !<<
- ***************************************************************************
- FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. Full license text is available on the following
- link: http://www.freertos.org/a00114.html
- ***************************************************************************
- * *
- * FreeRTOS provides completely free yet professionally developed, *
- * robust, strictly quality controlled, supported, and cross *
- * platform software that is more than just the market leader, it *
- * is the industry's de facto standard. *
- * *
- * Help yourself get started quickly while simultaneously helping *
- * to support the FreeRTOS project by purchasing a FreeRTOS *
- * tutorial book, reference manual, or both: *
- * http://www.FreeRTOS.org/Documentation *
- * *
- ***************************************************************************
- http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
- the FAQ page "My application does not run, what could be wrong?". Have you
- defined configASSERT()?
- http://www.FreeRTOS.org/support - In return for receiving this top quality
- embedded software for free we request you assist our global community by
- participating in the support forum.
- http://www.FreeRTOS.org/training - Investing in training allows your team to
- be as productive as possible as early as possible. Now you can receive
- FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
- Ltd, and the world's leading authority on the world's leading RTOS.
- http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
- including FreeRTOS+Trace - an indispensable productivity tool, a DOS
- compatible FAT file system, and our tiny thread aware UDP/IP stack.
- http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
- Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
- http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
- Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
- licenses offer ticketed support, indemnification and commercial middleware.
- http://www.SafeRTOS.com - High Integrity Systems also provide a safety
- engineered and independently SIL3 certified version for use in safety and
- mission critical applications that require provable dependability.
- 1 tab == 4 spaces!
- */
- /*-----------------------------------------------------------
- * Implementation of functions defined in portable.h for the ARM CM0 port.
- *----------------------------------------------------------*/
- /* Scheduler includes. */
- #include "FreeRTOS.h"
- #include "task.h"
- /* Constants required to manipulate the NVIC. */
- #define portNVIC_SYSTICK_CTRL ( ( volatile uint32_t *) 0xe000e010 )
- #define portNVIC_SYSTICK_LOAD ( ( volatile uint32_t *) 0xe000e014 )
- #define portNVIC_INT_CTRL ( ( volatile uint32_t *) 0xe000ed04 )
- #define portNVIC_SYSPRI2 ( ( volatile uint32_t *) 0xe000ed20 )
- #define portNVIC_SYSTICK_CLK 0x00000004
- #define portNVIC_SYSTICK_INT 0x00000002
- #define portNVIC_SYSTICK_ENABLE 0x00000001
- #define portNVIC_PENDSVSET 0x10000000
- #define portMIN_INTERRUPT_PRIORITY ( 255UL )
- #define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL )
- #define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL )
- /* Constants required to set up the initial stack. */
- #define portINITIAL_XPSR ( 0x01000000 )
- /* Constants used with memory barrier intrinsics. */
- #define portSY_FULL_READ_WRITE ( 15 )
- /* Each task maintains its own interrupt status in the critical nesting
- variable. */
- static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
- /*
- * Setup the timer to generate the tick interrupts.
- */
- static void prvSetupTimerInterrupt( void );
- /*
- * Exception handlers.
- */
- void xPortPendSVHandler( void );
- void xPortSysTickHandler( void );
- void vPortSVCHandler( void );
- /*
- * Start first task is a separate function so it can be tested in isolation.
- */
- static void prvPortStartFirstTask( void );
- /*
- * Used to catch tasks that attempt to return from their implementing function.
- */
- static void prvTaskExitError( void );
- /*-----------------------------------------------------------*/
- /*
- * See header file for description.
- */
- StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
- {
- /* Simulate the stack frame as it would be created by a context switch
- interrupt. */
- pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
- *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) pxCode; /* PC */
- pxTopOfStack--;
- *pxTopOfStack = ( StackType_t ) prvTaskExitError; /* LR */
- pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
- *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
- pxTopOfStack -= 8; /* R11..R4. */
- return pxTopOfStack;
- }
- /*-----------------------------------------------------------*/
- static void prvTaskExitError( void )
- {
- /* A function that implements a task must not exit or attempt to return to
- its caller as there is nothing to return to. If a task wants to exit it
- should instead call vTaskDelete( NULL ).
- Artificially force an assert() to be triggered if configASSERT() is
- defined, then stop here so application writers can catch the error. */
- configASSERT( uxCriticalNesting == ~0UL );
- portDISABLE_INTERRUPTS();
- for( ;; );
- }
- /*-----------------------------------------------------------*/
- void vPortSVCHandler( void )
- {
- /* This function is no longer used, but retained for backward
- compatibility. */
- }
- /*-----------------------------------------------------------*/
- __asm void prvPortStartFirstTask( void )
- {
- extern pxCurrentTCB;
- PRESERVE8
- /* 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. */
- 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, #32 /* Discard everything up to r0. */
- msr psp, r0 /* This is now the new top of stack to use in the task. */
- movs r0, #2 /* Switch to the psp stack. */
- msr CONTROL, r0
- isb
- pop {r0-r5} /* Pop the registers that are saved automatically. */
- mov lr, r5 /* lr is now in r5. */
- pop {r3} /* The return address is now in r3. */
- pop {r2} /* Pop and discard the XPSR. */
- cpsie i /* The first task has its context and interrupts can be enabled. */
- bx r3 /* Finally, jump to the user defined task code. */
- ALIGN
- }
- /*-----------------------------------------------------------*/
- /*
- * See header file for description.
- */
- BaseType_t xPortStartScheduler( void )
- {
- /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */
- *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
- *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;
- /* Start the timer that generates the tick ISR. Interrupts are disabled
- here already. */
- prvSetupTimerInterrupt();
- /* Initialise the critical nesting count ready for the first task. */
- uxCriticalNesting = 0;
- /* Start the first task. */
- prvPortStartFirstTask();
- /* Should not get here! */
- return 0;
- }
- /*-----------------------------------------------------------*/
- void vPortEndScheduler( void )
- {
- /* Not implemented in ports where there is nothing to return to.
- Artificially force an assert. */
- configASSERT( uxCriticalNesting == 1000UL );
- }
- /*-----------------------------------------------------------*/
- void vPortYield( void )
- {
- /* Set a PendSV to request a context switch. */
- *( portNVIC_INT_CTRL ) = portNVIC_PENDSVSET;
- /* Barriers are normally not required but do ensure the code is completely
- within the specified behaviour for the architecture. */
- __dsb( portSY_FULL_READ_WRITE );
- __isb( portSY_FULL_READ_WRITE );
- }
- /*-----------------------------------------------------------*/
- void vPortEnterCritical( void )
- {
- portDISABLE_INTERRUPTS();
- uxCriticalNesting++;
- __dsb( portSY_FULL_READ_WRITE );
- __isb( portSY_FULL_READ_WRITE );
- }
- /*-----------------------------------------------------------*/
- void vPortExitCritical( void )
- {
- configASSERT( uxCriticalNesting );
- uxCriticalNesting--;
- if( uxCriticalNesting == 0 )
- {
- portENABLE_INTERRUPTS();
- }
- }
- /*-----------------------------------------------------------*/
- __asm uint32_t ulSetInterruptMaskFromISR( void )
- {
- mrs r0, PRIMASK
- cpsid i
- bx lr
- }
- /*-----------------------------------------------------------*/
- __asm void vClearInterruptMaskFromISR( uint32_t ulMask )
- {
- msr PRIMASK, r0
- bx lr
- }
- /*-----------------------------------------------------------*/
- __asm void xPortPendSVHandler( void )
- {
- extern vTaskSwitchContext
- extern pxCurrentTCB
- PRESERVE8
- mrs r0, psp
- ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */
- ldr r2, [r3]
- subs 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
- pop {r2, r3} /* lr goes in r3. r2 now holds tcb pointer. */
- ldr r1, [r2]
- 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. */
- 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, #32 /* Go back for the low registers that are not automatically restored. */
- ldmia r0!, {r4-r7} /* Pop low registers. */
- bx r3
- ALIGN
- }
- /*-----------------------------------------------------------*/
- void xPortSysTickHandler( void )
- {
- uint32_t ulPreviousMask;
- ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
- {
- /* Increment the RTOS tick. */
- if( xTaskIncrementTick() != pdFALSE )
- {
- /* Pend a context switch. */
- *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
- }
- }
- portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
- }
- /*-----------------------------------------------------------*/
- /*
- * Setup the systick timer to generate the tick interrupts at the required
- * frequency.
- */
- void prvSetupTimerInterrupt( void )
- {
- /* Configure SysTick to interrupt at the requested rate. */
- *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
- *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE;
- }
- /*-----------------------------------------------------------*/
|