1 /*
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28 
29 /* Scheduler includes. */
30 #include "FreeRTOS.h"
31 #include "task.h"
32 
33 /* Hardware includes. */
34 #include "msp430.h"
35 
36 /*-----------------------------------------------------------
37 * Implementation of functions defined in portable.h for the MSP430X port.
38 *----------------------------------------------------------*/
39 
40 /* Constants required for hardware setup.  The tick ISR runs off the ACLK,
41  * not the MCLK. */
42 #define portACLK_FREQUENCY_HZ           ( ( TickType_t ) 32768 )
43 #define portINITIAL_CRITICAL_NESTING    ( ( uint16_t ) 10 )
44 #define portFLAGS_INT_ENABLED           ( ( StackType_t ) 0x08 )
45 
46 /* We require the address of the pxCurrentTCB variable, but don't want to know
47  * any details of its type. */
48 typedef void TCB_t;
49 extern volatile TCB_t * volatile pxCurrentTCB;
50 
51 /* Each task maintains a count of the critical section nesting depth.  Each
52  * time a critical section is entered the count is incremented.  Each time a
53  * critical section is exited the count is decremented - with interrupts only
54  * being re-enabled if the count is zero.
55  *
56  * usCriticalNesting will get set to zero when the scheduler starts, but must
57  * not be initialised to zero as this will cause problems during the startup
58  * sequence. */
59 volatile uint16_t usCriticalNesting = portINITIAL_CRITICAL_NESTING;
60 /*-----------------------------------------------------------*/
61 
62 
63 /*
64  * Sets up the periodic ISR used for the RTOS tick.  This uses timer 0, but
65  * could have alternatively used the watchdog timer or timer 1.
66  */
67 void vPortSetupTimerInterrupt( void );
68 /*-----------------------------------------------------------*/
69 
70 /*
71  * Initialise the stack of a task to look exactly as if a call to
72  * portSAVE_CONTEXT had been called.
73  *
74  * See the header file portable.h.
75  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)76 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
77                                      TaskFunction_t pxCode,
78                                      void * pvParameters )
79 {
80     uint16_t * pusTopOfStack;
81     uint32_t * pulTopOfStack;
82 
83     /*
84      *  Place a few bytes of known values on the bottom of the stack.
85      *  This is just useful for debugging and can be included if required.
86      *
87      * pxTopOfStack = ( StackType_t ) 0x1111;
88      *  pxTopOfStack--;
89      * pxTopOfStack = ( StackType_t ) 0x2222;
90      *  pxTopOfStack--;
91      * pxTopOfStack = ( StackType_t ) 0x3333;
92      */
93 
94     /* StackType_t is either 16 bits or 32 bits depending on the data model.
95      * Some stacked items do not change size depending on the data model so have
96      * to be explicitly cast to the correct size so this function will work
97      * whichever data model is being used. */
98     if( sizeof( StackType_t ) == sizeof( uint16_t ) )
99     {
100         /* Make room for a 20 bit value stored as a 32 bit value. */
101         pusTopOfStack = ( uint16_t * ) pxTopOfStack;
102         pusTopOfStack--;
103         pulTopOfStack = ( uint32_t * ) pusTopOfStack;
104     }
105     else
106     {
107         pulTopOfStack = ( uint32_t * ) pxTopOfStack;
108     }
109 
110     *pulTopOfStack = ( uint32_t ) pxCode;
111 
112     pusTopOfStack = ( uint16_t * ) pulTopOfStack;
113     pusTopOfStack--;
114     *pusTopOfStack = portFLAGS_INT_ENABLED;
115     pusTopOfStack -= ( sizeof( StackType_t ) / 2 );
116 
117     /* From here on the size of stacked items depends on the memory model. */
118     pxTopOfStack = ( StackType_t * ) pusTopOfStack;
119 
120     /* Next the general purpose registers. */
121     #ifdef PRELOAD_REGISTER_VALUES
122         *pxTopOfStack = ( StackType_t ) 0xffff;
123         pxTopOfStack--;
124         *pxTopOfStack = ( StackType_t ) 0xeeee;
125         pxTopOfStack--;
126         *pxTopOfStack = ( StackType_t ) 0xdddd;
127         pxTopOfStack--;
128         *pxTopOfStack = ( StackType_t ) pvParameters;
129         pxTopOfStack--;
130         *pxTopOfStack = ( StackType_t ) 0xbbbb;
131         pxTopOfStack--;
132         *pxTopOfStack = ( StackType_t ) 0xaaaa;
133         pxTopOfStack--;
134         *pxTopOfStack = ( StackType_t ) 0x9999;
135         pxTopOfStack--;
136         *pxTopOfStack = ( StackType_t ) 0x8888;
137         pxTopOfStack--;
138         *pxTopOfStack = ( StackType_t ) 0x5555;
139         pxTopOfStack--;
140         *pxTopOfStack = ( StackType_t ) 0x6666;
141         pxTopOfStack--;
142         *pxTopOfStack = ( StackType_t ) 0x5555;
143         pxTopOfStack--;
144         *pxTopOfStack = ( StackType_t ) 0x4444;
145         pxTopOfStack--;
146     #else /* ifdef PRELOAD_REGISTER_VALUES */
147         pxTopOfStack -= 3;
148         *pxTopOfStack = ( StackType_t ) pvParameters;
149         pxTopOfStack -= 9;
150     #endif /* ifdef PRELOAD_REGISTER_VALUES */
151 
152 
153     /* A variable is used to keep track of the critical section nesting.
154      * This variable has to be stored as part of the task context and is
155      * initially set to zero. */
156     *pxTopOfStack = ( StackType_t ) portNO_CRITICAL_SECTION_NESTING;
157 
158     /* Return a pointer to the top of the stack we have generated so this can
159      * be stored in the task control block for the task. */
160     return pxTopOfStack;
161 }
162 /*-----------------------------------------------------------*/
163 
vPortEndScheduler(void)164 void vPortEndScheduler( void )
165 {
166     /* It is unlikely that the MSP430 port will get stopped.  If required simply
167      * disable the tick interrupt here. */
168 }
169 /*-----------------------------------------------------------*/
170 
171 /*
172  * Hardware initialisation to generate the RTOS tick.
173  */
vPortSetupTimerInterrupt(void)174 void vPortSetupTimerInterrupt( void )
175 {
176     vApplicationSetupTimerInterrupt();
177 }
178 /*-----------------------------------------------------------*/
179 
180 #pragma vector=configTICK_VECTOR
vTickISREntry(void)181 __interrupt __raw void vTickISREntry( void )
182 {
183     extern void vPortTickISR( void );
184 
185     __bic_SR_register_on_exit( SCG1 + SCG0 + OSCOFF + CPUOFF );
186     vPortTickISR();
187 }
188