1+ /*
2+ * FreeRTOS V202212.00
3+ * Copyright (C) 2020 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+ * https://www.FreeRTOS.org
23+ * https://github.com/FreeRTOS
24+ *
25+ */
26+
27+ /* Scheduler includes. */
28+ #include "FreeRTOS.h"
29+ #include "task.h"
30+
31+ /* Reg test includes. */
32+ #include "reg_tests.h"
33+
34+ /* Hardware includes. */
35+ #include "main.h"
36+
37+ /*
38+ * Functions that implement reg test tasks.
39+ */
40+ static void prvRegTest1Task ( void * pvParameters );
41+ static void prvRegTest2Task ( void * pvParameters );
42+ static void prvRegTest3Task ( void * pvParameters );
43+ static void prvRegTest4Task ( void * pvParameters );
44+
45+ /*
46+ * Check task periodically checks that reg tests tasks
47+ * are running fine.
48+ */
49+ static void prvCheckTask ( void * pvParameters );
50+
51+ /*
52+ * Functions implemented in assembly.
53+ */
54+ extern void vRegTest1Asm ( void ) __attribute__( ( naked ) );
55+ extern void vRegTest2Asm ( void ) __attribute__( ( naked ) );
56+ extern void vRegTest3Asm ( void ) __attribute__( ( naked ) );
57+ extern void vRegTest4Asm ( void ) __attribute__( ( naked ) );
58+ /*-----------------------------------------------------------*/
59+
60+ /*
61+ * Priority of the check task.
62+ */
63+ #define CHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
64+
65+ /*
66+ * Frequency of check task.
67+ */
68+ #define NO_ERROR_CHECK_TASK_PERIOD ( pdMS_TO_TICKS( 5000UL ) )
69+ #define ERROR_CHECK_TASK_PERIOD ( pdMS_TO_TICKS( 200UL ) )
70+
71+ /*
72+ * Parameters passed to reg test tasks.
73+ */
74+ #define REG_TEST_TASK_1_PARAMETER ( ( void * ) 0x12345678 )
75+ #define REG_TEST_TASK_2_PARAMETER ( ( void * ) 0x87654321 )
76+ #define REG_TEST_TASK_3_PARAMETER ( ( void * ) 0x12348765 )
77+ #define REG_TEST_TASK_4_PARAMETER ( ( void * ) 0x43215678 )
78+ /*-----------------------------------------------------------*/
79+
80+ /*
81+ * The following variables are used to communicate the status of the register
82+ * test tasks to the check task. If the variables keep incrementing, then the
83+ * register test tasks have not discovered any errors. If a variable stops
84+ * incrementing, then an error has been found.
85+ */
86+ volatile unsigned long ulRegTest1LoopCounter = 0UL , ulRegTest2LoopCounter = 0UL ;
87+ volatile unsigned long ulRegTest3LoopCounter = 0UL , ulRegTest4LoopCounter = 0UL ;
88+
89+ /**
90+ * Counter to keep a count of how may times the check task loop has detected
91+ * error.
92+ */
93+ volatile unsigned long ulCheckTaskLoops = 0UL ;
94+ /*-----------------------------------------------------------*/
95+
96+ void vStartRegTests ( void )
97+ {
98+ static StackType_t xRegTest1TaskStack [ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned ( configMINIMAL_STACK_SIZE * sizeof ( StackType_t ) ) ) );
99+ static StackType_t xRegTest2TaskStack [ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned ( configMINIMAL_STACK_SIZE * sizeof ( StackType_t ) ) ) );
100+ static StackType_t xRegTest3TaskStack [ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned ( configMINIMAL_STACK_SIZE * sizeof ( StackType_t ) ) ) );
101+ static StackType_t xRegTest4TaskStack [ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned ( configMINIMAL_STACK_SIZE * sizeof ( StackType_t ) ) ) );
102+ static StackType_t xCheckTaskStack [ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned ( configMINIMAL_STACK_SIZE * sizeof ( StackType_t ) ) ) );
103+
104+ TaskParameters_t xRegTest1TaskParameters =
105+ {
106+ .pvTaskCode = prvRegTest1Task ,
107+ .pcName = "RegTest1" ,
108+ .usStackDepth = configMINIMAL_STACK_SIZE ,
109+ .pvParameters = REG_TEST_TASK_1_PARAMETER ,
110+ .uxPriority = tskIDLE_PRIORITY | portPRIVILEGE_BIT ,
111+ .puxStackBuffer = xRegTest1TaskStack ,
112+ .xRegions = {
113+ { 0 , 0 , 0 },
114+ { 0 , 0 , 0 },
115+ { 0 , 0 , 0 },
116+ { 0 , 0 , 0 },
117+ { 0 , 0 , 0 },
118+ { 0 , 0 , 0 },
119+ { 0 , 0 , 0 },
120+ { 0 , 0 , 0 },
121+ { 0 , 0 , 0 },
122+ { 0 , 0 , 0 },
123+ { 0 , 0 , 0 }
124+ }
125+ };
126+ TaskParameters_t xRegTest2TaskParameters =
127+ {
128+ .pvTaskCode = prvRegTest2Task ,
129+ .pcName = "RegTest2" ,
130+ .usStackDepth = configMINIMAL_STACK_SIZE ,
131+ .pvParameters = REG_TEST_TASK_2_PARAMETER ,
132+ .uxPriority = tskIDLE_PRIORITY | portPRIVILEGE_BIT ,
133+ .puxStackBuffer = xRegTest2TaskStack ,
134+ .xRegions = {
135+ { 0 , 0 , 0 },
136+ { 0 , 0 , 0 },
137+ { 0 , 0 , 0 },
138+ { 0 , 0 , 0 },
139+ { 0 , 0 , 0 },
140+ { 0 , 0 , 0 },
141+ { 0 , 0 , 0 },
142+ { 0 , 0 , 0 },
143+ { 0 , 0 , 0 },
144+ { 0 , 0 , 0 },
145+ { 0 , 0 , 0 }
146+ }
147+ };
148+ TaskParameters_t xRegTest3TaskParameters =
149+ {
150+ .pvTaskCode = prvRegTest3Task ,
151+ .pcName = "RegTest3" ,
152+ .usStackDepth = configMINIMAL_STACK_SIZE ,
153+ .pvParameters = REG_TEST_TASK_3_PARAMETER ,
154+ .uxPriority = tskIDLE_PRIORITY | portPRIVILEGE_BIT ,
155+ .puxStackBuffer = xRegTest3TaskStack ,
156+ .xRegions = {
157+ { 0 , 0 , 0 },
158+ { 0 , 0 , 0 },
159+ { 0 , 0 , 0 },
160+ { 0 , 0 , 0 },
161+ { 0 , 0 , 0 },
162+ { 0 , 0 , 0 },
163+ { 0 , 0 , 0 },
164+ { 0 , 0 , 0 },
165+ { 0 , 0 , 0 },
166+ { 0 , 0 , 0 },
167+ { 0 , 0 , 0 }
168+ }
169+ };
170+ TaskParameters_t xRegTest4TaskParameters =
171+ {
172+ .pvTaskCode = prvRegTest4Task ,
173+ .pcName = "RegTest4" ,
174+ .usStackDepth = configMINIMAL_STACK_SIZE ,
175+ .pvParameters = REG_TEST_TASK_4_PARAMETER ,
176+ .uxPriority = tskIDLE_PRIORITY | portPRIVILEGE_BIT ,
177+ .puxStackBuffer = xRegTest4TaskStack ,
178+ .xRegions = {
179+ { 0 , 0 , 0 },
180+ { 0 , 0 , 0 },
181+ { 0 , 0 , 0 },
182+ { 0 , 0 , 0 },
183+ { 0 , 0 , 0 },
184+ { 0 , 0 , 0 },
185+ { 0 , 0 , 0 },
186+ { 0 , 0 , 0 },
187+ { 0 , 0 , 0 },
188+ { 0 , 0 , 0 },
189+ { 0 , 0 , 0 }
190+ }
191+ };
192+
193+ TaskParameters_t xCheckTaskParameters =
194+ {
195+ .pvTaskCode = prvCheckTask ,
196+ .pcName = "Check" ,
197+ .usStackDepth = configMINIMAL_STACK_SIZE ,
198+ .pvParameters = NULL ,
199+ .uxPriority = ( CHECK_TASK_PRIORITY | portPRIVILEGE_BIT ),
200+ .puxStackBuffer = xCheckTaskStack ,
201+ .xRegions = {
202+ { 0 , 0 , 0 },
203+ { 0 , 0 , 0 },
204+ { 0 , 0 , 0 },
205+ { 0 , 0 , 0 },
206+ { 0 , 0 , 0 },
207+ { 0 , 0 , 0 },
208+ { 0 , 0 , 0 },
209+ { 0 , 0 , 0 },
210+ { 0 , 0 , 0 },
211+ { 0 , 0 , 0 },
212+ { 0 , 0 , 0 }
213+ }
214+ };
215+
216+ xTaskCreateRestricted ( & ( xRegTest1TaskParameters ), NULL );
217+ xTaskCreateRestricted ( & ( xRegTest2TaskParameters ), NULL );
218+ xTaskCreateRestricted ( & ( xRegTest3TaskParameters ), NULL );
219+ xTaskCreateRestricted ( & ( xRegTest4TaskParameters ), NULL );
220+ xTaskCreateRestricted ( & ( xCheckTaskParameters ), NULL );
221+ }
222+ /*-----------------------------------------------------------*/
223+
224+ static void prvRegTest1Task ( void * pvParameters )
225+ {
226+ /* Although the reg tests are written in assembly, its entry
227+ * point is written in C for convenience of checking that the
228+ * task parameter is being passed in correctly. */
229+ if ( pvParameters == REG_TEST_TASK_1_PARAMETER )
230+ {
231+ /* Start the part of the test that is written in assembler. */
232+ vRegTest1Asm ();
233+ }
234+
235+ /* The following line will only execute if the task parameter
236+ * is found to be incorrect. The check task will detect that
237+ * the reg test loop counter is not being incremented and flag
238+ * an error. */
239+ vTaskDelete ( NULL );
240+ }
241+ /*-----------------------------------------------------------*/
242+
243+ static void prvRegTest2Task ( void * pvParameters )
244+ {
245+ /* Although the reg tests are written in assembly, its entry
246+ * point is written in C for convenience of checking that the
247+ * task parameter is being passed in correctly. */
248+ if ( pvParameters == REG_TEST_TASK_2_PARAMETER )
249+ {
250+ /* Start the part of the test that is written in assembler. */
251+ vRegTest2Asm ();
252+ }
253+
254+ /* The following line will only execute if the task parameter
255+ * is found to be incorrect. The check task will detect that
256+ * the reg test loop counter is not being incremented and flag
257+ * an error. */
258+ vTaskDelete ( NULL );
259+ }
260+ /*-----------------------------------------------------------*/
261+
262+ static void prvRegTest3Task ( void * pvParameters )
263+ {
264+ /* Although the reg tests are written in assembly, its entry
265+ * point is written in C for convenience of checking that the
266+ * task parameter is being passed in correctly. */
267+ if ( pvParameters == REG_TEST_TASK_3_PARAMETER )
268+ {
269+ /* Start the part of the test that is written in assembler. */
270+ vRegTest3Asm ();
271+ }
272+
273+ /* The following line will only execute if the task parameter
274+ * is found to be incorrect. The check task will detect that
275+ * the reg test loop counter is not being incremented and flag
276+ * an error. */
277+ vTaskDelete ( NULL );
278+ }
279+ /*-----------------------------------------------------------*/
280+
281+ static void prvRegTest4Task ( void * pvParameters )
282+ {
283+ /* Although the reg tests are written in assembly, its entry
284+ * point is written in C for convenience of checking that the
285+ * task parameter is being passed in correctly. */
286+ if ( pvParameters == REG_TEST_TASK_4_PARAMETER )
287+ {
288+ /* Start the part of the test that is written in assembler. */
289+ vRegTest4Asm ();
290+ }
291+
292+ /* The following line will only execute if the task parameter
293+ * is found to be incorrect. The check task will detect that
294+ * the reg test loop counter is not being incremented and flag
295+ * an error. */
296+ vTaskDelete ( NULL );
297+ }
298+ /*-----------------------------------------------------------*/
299+
300+ static void prvCheckTask ( void * pvParameters )
301+ {
302+ TickType_t xDelayPeriod = NO_ERROR_CHECK_TASK_PERIOD ;
303+ TickType_t xLastExecutionTime ;
304+ unsigned long ulErrorFound = pdFALSE ;
305+ static unsigned long ulLastRegTest1Value = 0 , ulLastRegTest2Value = 0 ;
306+ static unsigned long ulLastRegTest3Value = 0 , ulLastRegTest4Value = 0 ;
307+
308+ /* Just to stop compiler warnings. */
309+ ( void ) pvParameters ;
310+
311+ /* Initialize xLastExecutionTime so the first call to vTaskDelayUntil()
312+ * works correctly. */
313+ xLastExecutionTime = xTaskGetTickCount ();
314+
315+ /* Cycle for ever, delaying then checking all the other tasks are still
316+ * operating without error. The onboard LED is toggled on each iteration.
317+ * If an error is detected then the delay period is decreased from
318+ * mainNO_ERROR_CHECK_TASK_PERIOD to mainERROR_CHECK_TASK_PERIOD. This has
319+ * the effect of increasing the rate at which the onboard LED toggles, and
320+ * in so doing gives visual feedback of the system status. */
321+ for ( ;; )
322+ {
323+ /* Delay until it is time to execute again. */
324+ vTaskDelayUntil ( & xLastExecutionTime , xDelayPeriod );
325+
326+ /* Check that the register test 1 task is still running. */
327+ if ( ulLastRegTest1Value == ulRegTest1LoopCounter )
328+ {
329+ ulErrorFound |= 1UL << 0UL ;
330+ }
331+ ulLastRegTest1Value = ulRegTest1LoopCounter ;
332+
333+ /* Check that the register test 2 task is still running. */
334+ if ( ulLastRegTest2Value == ulRegTest2LoopCounter )
335+ {
336+ ulErrorFound |= 1UL << 1UL ;
337+ }
338+ ulLastRegTest2Value = ulRegTest2LoopCounter ;
339+
340+ /* Check that the register test 3 task is still running. */
341+ if ( ulLastRegTest3Value == ulRegTest3LoopCounter )
342+ {
343+ ulErrorFound |= 1UL << 2UL ;
344+ }
345+ ulLastRegTest3Value = ulRegTest3LoopCounter ;
346+
347+ /* Check that the register test 4 task is still running. */
348+ if ( ulLastRegTest4Value == ulRegTest4LoopCounter )
349+ {
350+ ulErrorFound |= 1UL << 3UL ;
351+ }
352+ ulLastRegTest4Value = ulRegTest4LoopCounter ;
353+
354+
355+ /* Toggle the green LED to give an indication of the system status.
356+ * If the LED toggles every NO_ERROR_CHECK_TASK_PERIOD milliseconds
357+ * then everything is ok. A faster toggle indicates an error. */
358+ HAL_GPIO_TogglePin ( LD1_GPIO_Port , LD1_Pin );
359+
360+ if ( ulErrorFound != pdFALSE )
361+ {
362+ /* An error has been detected in one of the tasks - flash the LED
363+ * at a higher frequency to give visible feedback that something has
364+ * gone wrong (it might just be that the loop back connector required
365+ * by the comtest tasks has not been fitted). */
366+ xDelayPeriod = ERROR_CHECK_TASK_PERIOD ;
367+
368+ /* Turn on Red LED to indicate error. */
369+ HAL_GPIO_WritePin ( LD3_GPIO_Port , LD3_Pin , GPIO_PIN_SET );
370+
371+ /* Increment error detection count. */
372+ ulCheckTaskLoops ++ ;
373+ }
374+ }
375+ }
376+ /*-----------------------------------------------------------*/
0 commit comments