]> begriffs open source - freertos/blob - portable/IAR/STR71x/port.c
Style: uncrustify kernel files
[freertos] / portable / IAR / STR71x / port.c
1 /*\r
2  * FreeRTOS Kernel V10.3.1\r
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /*-----------------------------------------------------------\r
29 * Implementation of functions defined in portable.h for the ST STR71x ARM7\r
30 * port.\r
31 *----------------------------------------------------------*/\r
32 \r
33 /* Library includes. */\r
34 #include "wdg.h"\r
35 #include "eic.h"\r
36 \r
37 /* Standard includes. */\r
38 #include <stdlib.h>\r
39 \r
40 /* Scheduler includes. */\r
41 #include "FreeRTOS.h"\r
42 #include "task.h"\r
43 \r
44 /* Constants required to setup the initial stack. */\r
45 #define portINITIAL_SPSR           ( ( StackType_t ) 0x1f )      /* System mode, ARM mode, interrupts enabled. */\r
46 #define portTHUMB_MODE_BIT         ( ( StackType_t ) 0x20 )\r
47 #define portINSTRUCTION_SIZE       ( ( StackType_t ) 4 )\r
48 \r
49 /* Constants required to handle critical sections. */\r
50 #define portNO_CRITICAL_NESTING    ( ( uint32_t ) 0 )\r
51 \r
52 #define portMICROS_PER_SECOND      1000000\r
53 \r
54 /*-----------------------------------------------------------*/\r
55 \r
56 /* Setup the watchdog to generate the tick interrupts. */\r
57 static void prvSetupTimerInterrupt( void );\r
58 \r
59 /* ulCriticalNesting will get set to zero when the first task starts.  It\r
60  * cannot be initialised to 0 as this will cause interrupts to be enabled\r
61  * during the kernel initialisation process. */\r
62 uint32_t ulCriticalNesting = ( uint32_t ) 9999;\r
63 \r
64 /* Tick interrupt routines for cooperative and preemptive operation\r
65  * respectively.  The preemptive version is not defined as __irq as it is called\r
66  * from an asm wrapper function. */\r
67 __arm __irq void vPortNonPreemptiveTick( void );\r
68 void vPortPreemptiveTick( void );\r
69 \r
70 /*-----------------------------------------------------------*/\r
71 \r
72 /*\r
73  * Initialise the stack of a task to look exactly as if a call to\r
74  * portSAVE_CONTEXT had been called.\r
75  *\r
76  * See header file for description.\r
77  */\r
78 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
79                                      TaskFunction_t pxCode,\r
80                                      void * pvParameters )\r
81 {\r
82     StackType_t * pxOriginalTOS;\r
83 \r
84     pxOriginalTOS = pxTopOfStack;\r
85 \r
86     /* To ensure asserts in tasks.c don't fail, although in this case the assert\r
87      * is not really required. */\r
88     pxTopOfStack--;\r
89 \r
90     /* Setup the initial stack of the task.  The stack is set exactly as\r
91      * expected by the portRESTORE_CONTEXT() macro. */\r
92 \r
93     /* First on the stack is the return address - which in this case is the\r
94      * start of the task.  The offset is added to make the return address appear\r
95      * as it would within an IRQ ISR. */\r
96     *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;\r
97     pxTopOfStack--;\r
98 \r
99     *pxTopOfStack = ( StackType_t ) 0xaaaaaaaa;    /* R14 */\r
100     pxTopOfStack--;\r
101     *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */\r
102     pxTopOfStack--;\r
103     *pxTopOfStack = ( StackType_t ) 0x12121212;    /* R12 */\r
104     pxTopOfStack--;\r
105     *pxTopOfStack = ( StackType_t ) 0x11111111;    /* R11 */\r
106     pxTopOfStack--;\r
107     *pxTopOfStack = ( StackType_t ) 0x10101010;    /* R10 */\r
108     pxTopOfStack--;\r
109     *pxTopOfStack = ( StackType_t ) 0x09090909;    /* R9 */\r
110     pxTopOfStack--;\r
111     *pxTopOfStack = ( StackType_t ) 0x08080808;    /* R8 */\r
112     pxTopOfStack--;\r
113     *pxTopOfStack = ( StackType_t ) 0x07070707;    /* R7 */\r
114     pxTopOfStack--;\r
115     *pxTopOfStack = ( StackType_t ) 0x06060606;    /* R6 */\r
116     pxTopOfStack--;\r
117     *pxTopOfStack = ( StackType_t ) 0x05050505;    /* R5 */\r
118     pxTopOfStack--;\r
119     *pxTopOfStack = ( StackType_t ) 0x04040404;    /* R4 */\r
120     pxTopOfStack--;\r
121     *pxTopOfStack = ( StackType_t ) 0x03030303;    /* R3 */\r
122     pxTopOfStack--;\r
123     *pxTopOfStack = ( StackType_t ) 0x02020202;    /* R2 */\r
124     pxTopOfStack--;\r
125     *pxTopOfStack = ( StackType_t ) 0x01010101;    /* R1 */\r
126     pxTopOfStack--;\r
127 \r
128     /* When the task starts is will expect to find the function parameter in\r
129      * R0. */\r
130     *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */\r
131     pxTopOfStack--;\r
132 \r
133     /* The status register is set for system mode, with interrupts enabled. */\r
134     *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;\r
135 \r
136     if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00UL )\r
137     {\r
138         /* We want the task to start in thumb mode. */\r
139         *pxTopOfStack |= portTHUMB_MODE_BIT;\r
140     }\r
141 \r
142     pxTopOfStack--;\r
143 \r
144     /* Interrupt flags cannot always be stored on the stack and will\r
145      * instead be stored in a variable, which is then saved as part of the\r
146      * tasks context. */\r
147     *pxTopOfStack = portNO_CRITICAL_NESTING;\r
148 \r
149     return pxTopOfStack;\r
150 }\r
151 /*-----------------------------------------------------------*/\r
152 \r
153 BaseType_t xPortStartScheduler( void )\r
154 {\r
155     extern void vPortStartFirstTask( void );\r
156 \r
157     /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
158      * here already. */\r
159     prvSetupTimerInterrupt();\r
160 \r
161     /* Start the first task. */\r
162     vPortStartFirstTask();\r
163 \r
164     /* Should not get here! */\r
165     return 0;\r
166 }\r
167 /*-----------------------------------------------------------*/\r
168 \r
169 void vPortEndScheduler( void )\r
170 {\r
171     /* It is unlikely that the ARM port will require this function as there\r
172      * is nothing to return to.  */\r
173 }\r
174 /*-----------------------------------------------------------*/\r
175 \r
176 /* The cooperative scheduler requires a normal IRQ service routine to\r
177  * simply increment the system tick. */\r
178 __arm __irq void vPortNonPreemptiveTick( void )\r
179 {\r
180     /* Increment the tick count - which may wake some tasks but as the\r
181      * preemptive scheduler is not being used any woken task is not given\r
182      * processor time no matter what its priority. */\r
183     xTaskIncrementTick();\r
184 \r
185     /* Clear the interrupt in the watchdog and EIC. */\r
186     WDG->SR = 0x0000;\r
187     portCLEAR_EIC();\r
188 }\r
189 /*-----------------------------------------------------------*/\r
190 \r
191 /* This function is called from an asm wrapper, so does not require the __irq\r
192  * keyword. */\r
193 void vPortPreemptiveTick( void )\r
194 {\r
195     /* Increment the tick counter. */\r
196     if( xTaskIncrementTick() != pdFALSE )\r
197     {\r
198         /* Select a new task to execute. */\r
199         vTaskSwitchContext();\r
200     }\r
201 \r
202     /* Clear the interrupt in the watchdog and EIC. */\r
203     WDG->SR = 0x0000;\r
204     portCLEAR_EIC();\r
205 }\r
206 /*-----------------------------------------------------------*/\r
207 \r
208 static void prvSetupTimerInterrupt( void )\r
209 {\r
210     /* Set the watchdog up to generate a periodic tick. */\r
211     WDG_ECITConfig( DISABLE );\r
212     WDG_CntOnOffConfig( DISABLE );\r
213     WDG_PeriodValueConfig( portMICROS_PER_SECOND / configTICK_RATE_HZ );\r
214 \r
215     /* Setup the tick interrupt in the EIC. */\r
216     EIC_IRQChannelPriorityConfig( WDG_IRQChannel, 1 );\r
217     EIC_IRQChannelConfig( WDG_IRQChannel, ENABLE );\r
218     EIC_IRQConfig( ENABLE );\r
219     WDG_ECITConfig( ENABLE );\r
220 \r
221     /* Start the timer - interrupts are actually disabled at this point so\r
222      * it is safe to do this here. */\r
223     WDG_CntOnOffConfig( ENABLE );\r
224 }\r
225 /*-----------------------------------------------------------*/\r
226 \r
227 __arm __interwork void vPortEnterCritical( void )\r
228 {\r
229     /* Disable interrupts first! */\r
230     __disable_interrupt();\r
231 \r
232     /* Now interrupts are disabled ulCriticalNesting can be accessed\r
233      * directly.  Increment ulCriticalNesting to keep a count of how many times\r
234      * portENTER_CRITICAL() has been called. */\r
235     ulCriticalNesting++;\r
236 }\r
237 /*-----------------------------------------------------------*/\r
238 \r
239 __arm __interwork void vPortExitCritical( void )\r
240 {\r
241     if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
242     {\r
243         /* Decrement the nesting count as we are leaving a critical section. */\r
244         ulCriticalNesting--;\r
245 \r
246         /* If the nesting level has reached zero then interrupts should be\r
247          * re-enabled. */\r
248         if( ulCriticalNesting == portNO_CRITICAL_NESTING )\r
249         {\r
250             __enable_interrupt();\r
251         }\r
252     }\r
253 }\r
254 /*-----------------------------------------------------------*/\r