]> begriffs open source - cmsis-freertos/blob - Source/portable/IAR/STR91x/port.c
Updated to FreeRTOS V10.0.1
[cmsis-freertos] / Source / portable / IAR / STR91x / port.c
1 /*
2  * FreeRTOS Kernel V10.0.1
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://www.FreeRTOS.org
23  * http://aws.amazon.com/freertos
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /*-----------------------------------------------------------
29  * Implementation of functions defined in portable.h for the ST STR91x ARM9
30  * port.
31  *----------------------------------------------------------*/
32
33 /* Library includes. */
34 #include "91x_lib.h"
35
36 /* Standard includes. */
37 #include <stdlib.h>
38 #include <assert.h>
39
40 /* Scheduler includes. */
41 #include "FreeRTOS.h"
42 #include "task.h"
43
44 #ifndef configUSE_WATCHDOG_TICK
45         #error configUSE_WATCHDOG_TICK must be set to either 1 or 0 in FreeRTOSConfig.h to use either the Watchdog or timer 2 to generate the tick interrupt respectively.
46 #endif
47
48 /* Constants required to setup the initial stack. */
49 #ifndef _RUN_TASK_IN_ARM_MODE_
50         #define portINITIAL_SPSR                        ( ( StackType_t ) 0x3f ) /* System mode, THUMB mode, interrupts enabled. */
51 #else
52         #define portINITIAL_SPSR                        ( ( StackType_t ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
53 #endif
54
55 #define portINSTRUCTION_SIZE                    ( ( StackType_t ) 4 )
56
57 /* Constants required to handle critical sections. */
58 #define portNO_CRITICAL_NESTING                 ( ( uint32_t ) 0 )
59
60 #ifndef abs
61         #define abs(x) ((x)>0 ? (x) : -(x))
62 #endif
63
64 /**
65  * Toggle a led using the following algorithm:
66  * if ( GPIO_ReadBit(GPIO9, GPIO_Pin_2) )
67  * {
68  *   GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
69  * }
70  * else
71  * {
72  *   GPIO_WriteBit( GPIO9, GPIO_Pin_2, Bit_RESET );
73  * }
74  *
75  */
76 #define TOGGLE_LED(port,pin)                                                                    \
77         if ( ((((port)->DR[(pin)<<2])) & (pin)) != Bit_RESET )          \
78         {                                                                                                                       \
79         (port)->DR[(pin) <<2] = 0x00;                                                   \
80         }                                                                                                                       \
81         else                                                                                                            \
82         {                                                                                                                       \
83         (port)->DR[(pin) <<2] = (pin);                                                  \
84         }
85
86
87 /*-----------------------------------------------------------*/
88
89 /* Setup the watchdog to generate the tick interrupts. */
90 static void prvSetupTimerInterrupt( void );
91
92 /* ulCriticalNesting will get set to zero when the first task starts.  It
93 cannot be initialised to 0 as this will cause interrupts to be enabled
94 during the kernel initialisation process. */
95 uint32_t ulCriticalNesting = ( uint32_t ) 9999;
96
97 /* Tick interrupt routines for cooperative and preemptive operation
98 respectively.  The preemptive version is not defined as __irq as it is called
99 from an asm wrapper function. */
100 void WDG_IRQHandler( void );
101
102 /* VIC interrupt default handler. */
103 static void prvDefaultHandler( void );
104
105 #if configUSE_WATCHDOG_TICK == 0
106         /* Used to update the OCR timer register */
107         static u16 s_nPulseLength;
108 #endif
109
110 /*-----------------------------------------------------------*/
111
112 /*
113  * Initialise the stack of a task to look exactly as if a call to
114  * portSAVE_CONTEXT had been called.
115  *
116  * See header file for description.
117  */
118 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
119 {
120         StackType_t *pxOriginalTOS;
121
122         pxOriginalTOS = pxTopOfStack;
123
124         /* To ensure asserts in tasks.c don't fail, although in this case the assert
125         is not really required. */
126         pxTopOfStack--;
127
128         /* Setup the initial stack of the task.  The stack is set exactly as
129         expected by the portRESTORE_CONTEXT() macro. */
130
131         /* First on the stack is the return address - which in this case is the
132         start of the task.  The offset is added to make the return address appear
133         as it would within an IRQ ISR. */
134         *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;          
135         pxTopOfStack--;
136
137         *pxTopOfStack = ( StackType_t ) 0xaaaaaaaa;     /* R14 */
138         pxTopOfStack--; 
139         *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
140         pxTopOfStack--;
141         *pxTopOfStack = ( StackType_t ) 0x12121212;     /* R12 */
142         pxTopOfStack--; 
143         *pxTopOfStack = ( StackType_t ) 0x11111111;     /* R11 */
144         pxTopOfStack--; 
145         *pxTopOfStack = ( StackType_t ) 0x10101010;     /* R10 */
146         pxTopOfStack--; 
147         *pxTopOfStack = ( StackType_t ) 0x09090909;     /* R9 */
148         pxTopOfStack--; 
149         *pxTopOfStack = ( StackType_t ) 0x08080808;     /* R8 */
150         pxTopOfStack--; 
151         *pxTopOfStack = ( StackType_t ) 0x07070707;     /* R7 */
152         pxTopOfStack--; 
153         *pxTopOfStack = ( StackType_t ) 0x06060606;     /* R6 */
154         pxTopOfStack--; 
155         *pxTopOfStack = ( StackType_t ) 0x05050505;     /* R5 */
156         pxTopOfStack--; 
157         *pxTopOfStack = ( StackType_t ) 0x04040404;     /* R4 */
158         pxTopOfStack--; 
159         *pxTopOfStack = ( StackType_t ) 0x03030303;     /* R3 */
160         pxTopOfStack--; 
161         *pxTopOfStack = ( StackType_t ) 0x02020202;     /* R2 */
162         pxTopOfStack--; 
163         *pxTopOfStack = ( StackType_t ) 0x01010101;     /* R1 */
164         pxTopOfStack--; 
165
166         /* When the task starts is will expect to find the function parameter in
167         R0. */
168         *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
169         pxTopOfStack--;
170
171         /* The status register is set for system mode, with interrupts enabled. */
172         *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;
173         pxTopOfStack--;
174
175         /* Interrupt flags cannot always be stored on the stack and will
176         instead be stored in a variable, which is then saved as part of the
177         tasks context. */
178         *pxTopOfStack = portNO_CRITICAL_NESTING;
179
180         return pxTopOfStack;    
181 }
182 /*-----------------------------------------------------------*/
183
184 BaseType_t xPortStartScheduler( void )
185 {
186 extern void vPortStartFirstTask( void );
187
188         /* Start the timer that generates the tick ISR.  Interrupts are disabled
189         here already. */
190         prvSetupTimerInterrupt();
191
192         /* Start the first task. */
193         vPortStartFirstTask();  
194
195         /* Should not get here! */
196         return 0;
197 }
198 /*-----------------------------------------------------------*/
199
200 void vPortEndScheduler( void )
201 {
202         /* It is unlikely that the ARM port will require this function as there
203         is nothing to return to.  */
204 }
205 /*-----------------------------------------------------------*/
206
207 /* This function is called from an asm wrapper, so does not require the __irq
208 keyword. */
209 #if configUSE_WATCHDOG_TICK == 1
210
211         static void prvFindFactors(u32 n, u16 *a, u32 *b)
212         {
213                 /* This function is copied from the ST STR7 library and is
214                 copyright STMicroelectronics.  Reproduced with permission. */
215         
216                 u32 b0;
217                 u16 a0;
218                 int32_t err, err_min=n;
219         
220                 *a = a0 = ((n-1)/65536ul) + 1;
221                 *b = b0 = n / *a;
222         
223                 for (; *a <= 256; (*a)++)
224                 {
225                         *b = n / *a;
226                         err = (int32_t)*a * (int32_t)*b - (int32_t)n;
227                         if (abs(err) > (*a / 2))
228                         {
229                                 (*b)++;
230                                 err = (int32_t)*a * (int32_t)*b - (int32_t)n;
231                         }
232                         if (abs(err) < abs(err_min))
233                         {
234                                 err_min = err;
235                                 a0 = *a;
236                                 b0 = *b;
237                                 if (err == 0) break;
238                         }
239                 }
240         
241                 *a = a0;
242                 *b = b0;
243         }
244         /*-----------------------------------------------------------*/
245
246         static void prvSetupTimerInterrupt( void )
247         {
248         WDG_InitTypeDef xWdg;
249         uint16_t a;
250         uint32_t n = configCPU_PERIPH_HZ / configTICK_RATE_HZ, b;
251         
252                 /* Configure the watchdog as a free running timer that generates a
253                 periodic interrupt. */
254         
255                 SCU_APBPeriphClockConfig( __WDG, ENABLE );
256                 WDG_DeInit();
257                 WDG_StructInit(&xWdg);
258                 prvFindFactors( n, &a, &b );
259                 xWdg.WDG_Prescaler = a - 1;
260                 xWdg.WDG_Preload = b - 1;
261                 WDG_Init( &xWdg );
262                 WDG_ITConfig(ENABLE);
263                 
264                 /* Configure the VIC for the WDG interrupt. */
265                 VIC_Config( WDG_ITLine, VIC_IRQ, 10 );
266                 VIC_ITCmd( WDG_ITLine, ENABLE );
267                 
268                 /* Install the default handlers for both VIC's. */
269                 VIC0->DVAR = ( uint32_t ) prvDefaultHandler;
270                 VIC1->DVAR = ( uint32_t ) prvDefaultHandler;
271                 
272                 WDG_Cmd(ENABLE);
273         }
274         /*-----------------------------------------------------------*/
275
276         void WDG_IRQHandler( void )
277         {
278                 {
279                         /* Increment the tick counter. */
280                         if( xTaskIncrementTick() != pdFALSE )
281                         {               
282                                 /* Select a new task to execute. */
283                                 vTaskSwitchContext();
284                         }
285                 
286                         /* Clear the interrupt in the watchdog. */
287                         WDG->SR &= ~0x0001;
288                 }
289         }
290
291 #else
292
293         static void prvFindFactors(u32 n, u8 *a, u16 *b)
294         {
295                 /* This function is copied from the ST STR7 library and is
296                 copyright STMicroelectronics.  Reproduced with permission. */
297         
298                 u16 b0;
299                 u8 a0;
300                 int32_t err, err_min=n;
301         
302         
303                 *a = a0 = ((n-1)/256) + 1;
304                 *b = b0 = n / *a;
305         
306                 for (; *a <= 256; (*a)++)
307                 {
308                         *b = n / *a;
309                         err = (int32_t)*a * (int32_t)*b - (int32_t)n;
310                         if (abs(err) > (*a / 2))
311                         {
312                                 (*b)++;
313                                 err = (int32_t)*a * (int32_t)*b - (int32_t)n;
314                         }
315                         if (abs(err) < abs(err_min))
316                         {
317                                 err_min = err;
318                                 a0 = *a;
319                                 b0 = *b;
320                                 if (err == 0) break;
321                         }
322                 }
323         
324                 *a = a0;
325                 *b = b0;
326         }
327         /*-----------------------------------------------------------*/
328
329         static void prvSetupTimerInterrupt( void )
330         {
331                 uint8_t a;
332                 uint16_t b;
333                 uint32_t n = configCPU_PERIPH_HZ / configTICK_RATE_HZ;
334                 
335                 TIM_InitTypeDef timer;
336                 
337                 SCU_APBPeriphClockConfig( __TIM23, ENABLE );
338                 TIM_DeInit(TIM2);
339                 TIM_StructInit(&timer);
340                 prvFindFactors( n, &a, &b );
341                 
342                 timer.TIM_Mode           = TIM_OCM_CHANNEL_1;
343                 timer.TIM_OC1_Modes      = TIM_TIMING;
344                 timer.TIM_Clock_Source   = TIM_CLK_APB;
345                 timer.TIM_Clock_Edge     = TIM_CLK_EDGE_RISING;
346                 timer.TIM_Prescaler      = a-1;
347                 timer.TIM_Pulse_Level_1  = TIM_HIGH;
348                 timer.TIM_Pulse_Length_1 = s_nPulseLength  = b-1;
349                 
350                 TIM_Init (TIM2, &timer);
351                 TIM_ITConfig(TIM2, TIM_IT_OC1, ENABLE);
352                 /* Configure the VIC for the WDG interrupt. */
353                 VIC_Config( TIM2_ITLine, VIC_IRQ, 10 );
354                 VIC_ITCmd( TIM2_ITLine, ENABLE );
355                 
356                 /* Install the default handlers for both VIC's. */
357                 VIC0->DVAR = ( uint32_t ) prvDefaultHandler;
358                 VIC1->DVAR = ( uint32_t ) prvDefaultHandler;
359                 
360                 TIM_CounterCmd(TIM2, TIM_CLEAR);
361                 TIM_CounterCmd(TIM2, TIM_START);
362         }
363         /*-----------------------------------------------------------*/
364
365         void TIM2_IRQHandler( void )
366         {
367                 /* Reset the timer counter to avioid overflow. */
368                 TIM2->OC1R += s_nPulseLength;
369                 
370                 /* Increment the tick counter. */
371                 if( xTaskIncrementTick() != pdFALSE )
372                 {
373                         /* Select a new task to run. */
374                         vTaskSwitchContext();
375                 }
376                 
377                 /* Clear the interrupt in the watchdog. */
378                 TIM2->SR &= ~TIM_FLAG_OC1;
379         }
380
381 #endif /* USE_WATCHDOG_TICK */
382
383 /*-----------------------------------------------------------*/
384
385 __arm __interwork void vPortEnterCritical( void )
386 {
387         /* Disable interrupts first! */
388         portDISABLE_INTERRUPTS();
389
390         /* Now interrupts are disabled ulCriticalNesting can be accessed
391         directly.  Increment ulCriticalNesting to keep a count of how many times
392         portENTER_CRITICAL() has been called. */
393         ulCriticalNesting++;
394 }
395 /*-----------------------------------------------------------*/
396
397 __arm __interwork void vPortExitCritical( void )
398 {
399         if( ulCriticalNesting > portNO_CRITICAL_NESTING )
400         {
401                 /* Decrement the nesting count as we are leaving a critical section. */
402                 ulCriticalNesting--;
403
404                 /* If the nesting level has reached zero then interrupts should be
405                 re-enabled. */
406                 if( ulCriticalNesting == portNO_CRITICAL_NESTING )
407                 {
408                         portENABLE_INTERRUPTS();
409                 }
410         }
411 }
412 /*-----------------------------------------------------------*/
413
414 static void prvDefaultHandler( void )
415 {
416 }
417
418
419
420
421