xref: /Kernel-v10.6.2/portable/IAR/STR75x/port.c (revision ef7b253b56c9788077f5ecd6c9deb4021923d646)
1 /*
2  * FreeRTOS Kernel V10.6.2
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 /*-----------------------------------------------------------
30  * Implementation of functions defined in portable.h for the ST STR75x ARM7
31  * port.
32  *----------------------------------------------------------*/
33 
34 /* Library includes. */
35 #include "75x_tb.h"
36 #include "75x_eic.h"
37 
38 /* Scheduler includes. */
39 #include "FreeRTOS.h"
40 #include "task.h"
41 
42 /* Constants required to setup the initial stack. */
43 #define portINITIAL_SPSR                ( ( StackType_t ) 0x3f ) /* System mode, THUMB mode, interrupts enabled. */
44 #define portINSTRUCTION_SIZE            ( ( StackType_t ) 4 )
45 
46 /* Constants required to handle critical sections. */
47 #define portNO_CRITICAL_NESTING         ( ( uint32_t ) 0 )
48 
49 /* Prescale used on the timer clock when calculating the tick period. */
50 #define portPRESCALE 20
51 
52 
53 /*-----------------------------------------------------------*/
54 
55 /* Setup the TB to generate the tick interrupts. */
56 static void prvSetupTimerInterrupt( void );
57 
58 /* ulCriticalNesting will get set to zero when the first task starts.  It
59 cannot be initialised to 0 as this will cause interrupts to be enabled
60 during the kernel initialisation process. */
61 uint32_t ulCriticalNesting = ( uint32_t ) 9999;
62 
63 /* Tick interrupt routines for preemptive operation. */
64 __arm void vPortPreemptiveTick( void );
65 
66 /*-----------------------------------------------------------*/
67 
68 /*
69  * Initialise the stack of a task to look exactly as if a call to
70  * portSAVE_CONTEXT had been called.
71  *
72  * See header file for description.
73  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)74 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
75 {
76 StackType_t *pxOriginalTOS;
77 
78     pxOriginalTOS = pxTopOfStack;
79 
80     /* To ensure asserts in tasks.c don't fail, although in this case the assert
81     is not really required. */
82     pxTopOfStack--;
83 
84     /* Setup the initial stack of the task.  The stack is set exactly as
85     expected by the portRESTORE_CONTEXT() macro. */
86 
87     /* First on the stack is the return address - which in this case is the
88     start of the task.  The offset is added to make the return address appear
89     as it would within an IRQ ISR. */
90     *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;
91     pxTopOfStack--;
92 
93     *pxTopOfStack = ( StackType_t ) 0xaaaaaaaa; /* R14 */
94     pxTopOfStack--;
95     *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
96     pxTopOfStack--;
97     *pxTopOfStack = ( StackType_t ) 0x12121212; /* R12 */
98     pxTopOfStack--;
99     *pxTopOfStack = ( StackType_t ) 0x11111111; /* R11 */
100     pxTopOfStack--;
101     *pxTopOfStack = ( StackType_t ) 0x10101010; /* R10 */
102     pxTopOfStack--;
103     *pxTopOfStack = ( StackType_t ) 0x09090909; /* R9 */
104     pxTopOfStack--;
105     *pxTopOfStack = ( StackType_t ) 0x08080808; /* R8 */
106     pxTopOfStack--;
107     *pxTopOfStack = ( StackType_t ) 0x07070707; /* R7 */
108     pxTopOfStack--;
109     *pxTopOfStack = ( StackType_t ) 0x06060606; /* R6 */
110     pxTopOfStack--;
111     *pxTopOfStack = ( StackType_t ) 0x05050505; /* R5 */
112     pxTopOfStack--;
113     *pxTopOfStack = ( StackType_t ) 0x04040404; /* R4 */
114     pxTopOfStack--;
115     *pxTopOfStack = ( StackType_t ) 0x03030303; /* R3 */
116     pxTopOfStack--;
117     *pxTopOfStack = ( StackType_t ) 0x02020202; /* R2 */
118     pxTopOfStack--;
119     *pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
120     pxTopOfStack--;
121 
122     /* When the task starts is will expect to find the function parameter in
123     R0. */
124     *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
125     pxTopOfStack--;
126 
127     /* The status register is set for system mode, with interrupts enabled. */
128     *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;
129     pxTopOfStack--;
130 
131     /* Interrupt flags cannot always be stored on the stack and will
132     instead be stored in a variable, which is then saved as part of the
133     tasks context. */
134     *pxTopOfStack = portNO_CRITICAL_NESTING;
135 
136     return pxTopOfStack;
137 }
138 /*-----------------------------------------------------------*/
139 
xPortStartScheduler(void)140 BaseType_t xPortStartScheduler( void )
141 {
142 extern void vPortStartFirstTask( void );
143 
144     /* Start the timer that generates the tick ISR.  Interrupts are disabled
145     here already. */
146     prvSetupTimerInterrupt();
147 
148     /* Start the first task. */
149     vPortStartFirstTask();
150 
151     /* Should not get here! */
152     return 0;
153 }
154 /*-----------------------------------------------------------*/
155 
vPortEndScheduler(void)156 void vPortEndScheduler( void )
157 {
158     /* It is unlikely that the ARM port will require this function as there
159     is nothing to return to.  */
160 }
161 /*-----------------------------------------------------------*/
162 
vPortPreemptiveTick(void)163 __arm void vPortPreemptiveTick( void )
164 {
165     /* Increment the tick counter. */
166     if( xTaskIncrementTick() != pdFALSE )
167     {
168         /* Select a new task to execute. */
169         vTaskSwitchContext();
170     }
171 
172     TB_ClearITPendingBit( TB_IT_Update );
173 }
174 /*-----------------------------------------------------------*/
175 
prvSetupTimerInterrupt(void)176 static void prvSetupTimerInterrupt( void )
177 {
178 EIC_IRQInitTypeDef  EIC_IRQInitStructure;
179 TB_InitTypeDef      TB_InitStructure;
180 
181     /* Setup the EIC for the TB. */
182     EIC_IRQInitStructure.EIC_IRQChannelCmd = ENABLE;
183     EIC_IRQInitStructure.EIC_IRQChannel = TB_IRQChannel;
184     EIC_IRQInitStructure.EIC_IRQChannelPriority = 1;
185     EIC_IRQInit(&EIC_IRQInitStructure);
186 
187     /* Setup the TB for the generation of the tick interrupt. */
188     TB_InitStructure.TB_Mode = TB_Mode_Timing;
189     TB_InitStructure.TB_CounterMode = TB_CounterMode_Down;
190     TB_InitStructure.TB_Prescaler = portPRESCALE - 1;
191     TB_InitStructure.TB_AutoReload = ( ( configCPU_CLOCK_HZ / portPRESCALE ) / configTICK_RATE_HZ );
192     TB_Init(&TB_InitStructure);
193 
194     /* Enable TB Update interrupt */
195     TB_ITConfig(TB_IT_Update, ENABLE);
196 
197     /* Clear TB Update interrupt pending bit */
198     TB_ClearITPendingBit(TB_IT_Update);
199 
200     /* Enable TB */
201     TB_Cmd(ENABLE);
202 }
203 /*-----------------------------------------------------------*/
204 
vPortEnterCritical(void)205 __arm __interwork void vPortEnterCritical( void )
206 {
207     /* Disable interrupts first! */
208     __disable_interrupt();
209 
210     /* Now interrupts are disabled ulCriticalNesting can be accessed
211     directly.  Increment ulCriticalNesting to keep a count of how many times
212     portENTER_CRITICAL() has been called. */
213     ulCriticalNesting++;
214 }
215 /*-----------------------------------------------------------*/
216 
vPortExitCritical(void)217 __arm __interwork void vPortExitCritical( void )
218 {
219     if( ulCriticalNesting > portNO_CRITICAL_NESTING )
220     {
221         /* Decrement the nesting count as we are leaving a critical section. */
222         ulCriticalNesting--;
223 
224         /* If the nesting level has reached zero then interrupts should be
225         re-enabled. */
226         if( ulCriticalNesting == portNO_CRITICAL_NESTING )
227         {
228             __enable_interrupt();
229         }
230     }
231 }
232 /*-----------------------------------------------------------*/
233