|
| 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 | + } |
| 117 | +}; |
| 118 | +TaskParameters_t xRegTest2TaskParameters = |
| 119 | +{ |
| 120 | + .pvTaskCode = prvRegTest2Task, |
| 121 | + .pcName = "RegTest2", |
| 122 | + .usStackDepth = configMINIMAL_STACK_SIZE, |
| 123 | + .pvParameters = REG_TEST_TASK_2_PARAMETER, |
| 124 | + .uxPriority = tskIDLE_PRIORITY | portPRIVILEGE_BIT, |
| 125 | + .puxStackBuffer = xRegTest2TaskStack, |
| 126 | + .xRegions = { |
| 127 | + { 0, 0, 0 }, |
| 128 | + { 0, 0, 0 }, |
| 129 | + { 0, 0, 0 } |
| 130 | + } |
| 131 | +}; |
| 132 | +TaskParameters_t xRegTest3TaskParameters = |
| 133 | +{ |
| 134 | + .pvTaskCode = prvRegTest3Task, |
| 135 | + .pcName = "RegTest3", |
| 136 | + .usStackDepth = configMINIMAL_STACK_SIZE, |
| 137 | + .pvParameters = REG_TEST_TASK_3_PARAMETER, |
| 138 | + .uxPriority = tskIDLE_PRIORITY | portPRIVILEGE_BIT, |
| 139 | + .puxStackBuffer = xRegTest3TaskStack, |
| 140 | + .xRegions = { |
| 141 | + { 0, 0, 0 }, |
| 142 | + { 0, 0, 0 }, |
| 143 | + { 0, 0, 0 } |
| 144 | + } |
| 145 | +}; |
| 146 | +TaskParameters_t xRegTest4TaskParameters = |
| 147 | +{ |
| 148 | + .pvTaskCode = prvRegTest4Task, |
| 149 | + .pcName = "RegTest4", |
| 150 | + .usStackDepth = configMINIMAL_STACK_SIZE, |
| 151 | + .pvParameters = REG_TEST_TASK_4_PARAMETER, |
| 152 | + .uxPriority = tskIDLE_PRIORITY | portPRIVILEGE_BIT, |
| 153 | + .puxStackBuffer = xRegTest4TaskStack, |
| 154 | + .xRegions = { |
| 155 | + { 0, 0, 0 }, |
| 156 | + { 0, 0, 0 }, |
| 157 | + { 0, 0, 0 } |
| 158 | + } |
| 159 | +}; |
| 160 | + |
| 161 | +TaskParameters_t xCheckTaskParameters = |
| 162 | +{ |
| 163 | + .pvTaskCode = prvCheckTask, |
| 164 | + .pcName = "Check", |
| 165 | + .usStackDepth = configMINIMAL_STACK_SIZE, |
| 166 | + .pvParameters = NULL, |
| 167 | + .uxPriority = ( CHECK_TASK_PRIORITY | portPRIVILEGE_BIT ), |
| 168 | + .puxStackBuffer = xCheckTaskStack, |
| 169 | + .xRegions = { |
| 170 | + { 0, 0, 0 }, |
| 171 | + { 0, 0, 0 }, |
| 172 | + { 0, 0, 0 } |
| 173 | + } |
| 174 | +}; |
| 175 | + |
| 176 | + xTaskCreateRestricted( &( xRegTest1TaskParameters ), NULL ); |
| 177 | + xTaskCreateRestricted( &( xRegTest2TaskParameters ), NULL ); |
| 178 | + xTaskCreateRestricted( &( xRegTest3TaskParameters ), NULL ); |
| 179 | + xTaskCreateRestricted( &( xRegTest4TaskParameters ), NULL ); |
| 180 | + xTaskCreateRestricted( &( xCheckTaskParameters ), NULL ); |
| 181 | +} |
| 182 | +/*-----------------------------------------------------------*/ |
| 183 | + |
| 184 | +static void prvRegTest1Task( void * pvParameters ) |
| 185 | +{ |
| 186 | + /* Although the reg tests are written in assembly, its entry |
| 187 | + * point is written in C for convenience of checking that the |
| 188 | + * task parameter is being passed in correctly. */ |
| 189 | + if( pvParameters == REG_TEST_TASK_1_PARAMETER ) |
| 190 | + { |
| 191 | + /* Start the part of the test that is written in assembler. */ |
| 192 | + vRegTest1Asm(); |
| 193 | + } |
| 194 | + |
| 195 | + /* The following line will only execute if the task parameter |
| 196 | + * is found to be incorrect. The check task will detect that |
| 197 | + * the reg test loop counter is not being incremented and flag |
| 198 | + * an error. */ |
| 199 | + vTaskDelete( NULL ); |
| 200 | +} |
| 201 | +/*-----------------------------------------------------------*/ |
| 202 | + |
| 203 | +static void prvRegTest2Task( void * pvParameters ) |
| 204 | +{ |
| 205 | + /* Although the reg tests are written in assembly, its entry |
| 206 | + * point is written in C for convenience of checking that the |
| 207 | + * task parameter is being passed in correctly. */ |
| 208 | + if( pvParameters == REG_TEST_TASK_2_PARAMETER ) |
| 209 | + { |
| 210 | + /* Start the part of the test that is written in assembler. */ |
| 211 | + vRegTest2Asm(); |
| 212 | + } |
| 213 | + |
| 214 | + /* The following line will only execute if the task parameter |
| 215 | + * is found to be incorrect. The check task will detect that |
| 216 | + * the reg test loop counter is not being incremented and flag |
| 217 | + * an error. */ |
| 218 | + vTaskDelete( NULL ); |
| 219 | +} |
| 220 | +/*-----------------------------------------------------------*/ |
| 221 | + |
| 222 | +static void prvRegTest3Task( void * pvParameters ) |
| 223 | +{ |
| 224 | + /* Although the reg tests are written in assembly, its entry |
| 225 | + * point is written in C for convenience of checking that the |
| 226 | + * task parameter is being passed in correctly. */ |
| 227 | + if( pvParameters == REG_TEST_TASK_3_PARAMETER ) |
| 228 | + { |
| 229 | + /* Start the part of the test that is written in assembler. */ |
| 230 | + vRegTest3Asm(); |
| 231 | + } |
| 232 | + |
| 233 | + /* The following line will only execute if the task parameter |
| 234 | + * is found to be incorrect. The check task will detect that |
| 235 | + * the reg test loop counter is not being incremented and flag |
| 236 | + * an error. */ |
| 237 | + vTaskDelete( NULL ); |
| 238 | +} |
| 239 | +/*-----------------------------------------------------------*/ |
| 240 | + |
| 241 | +static void prvRegTest4Task( void * pvParameters ) |
| 242 | +{ |
| 243 | + /* Although the reg tests are written in assembly, its entry |
| 244 | + * point is written in C for convenience of checking that the |
| 245 | + * task parameter is being passed in correctly. */ |
| 246 | + if( pvParameters == REG_TEST_TASK_4_PARAMETER ) |
| 247 | + { |
| 248 | + /* Start the part of the test that is written in assembler. */ |
| 249 | + vRegTest4Asm(); |
| 250 | + } |
| 251 | + |
| 252 | + /* The following line will only execute if the task parameter |
| 253 | + * is found to be incorrect. The check task will detect that |
| 254 | + * the reg test loop counter is not being incremented and flag |
| 255 | + * an error. */ |
| 256 | + vTaskDelete( NULL ); |
| 257 | +} |
| 258 | +/*-----------------------------------------------------------*/ |
| 259 | + |
| 260 | +static void prvCheckTask( void * pvParameters ) |
| 261 | +{ |
| 262 | +TickType_t xDelayPeriod = NO_ERROR_CHECK_TASK_PERIOD; |
| 263 | +TickType_t xLastExecutionTime; |
| 264 | +unsigned long ulErrorFound = pdFALSE; |
| 265 | +static unsigned long ulLastRegTest1Value = 0, ulLastRegTest2Value = 0; |
| 266 | +static unsigned long ulLastRegTest3Value = 0, ulLastRegTest4Value = 0; |
| 267 | + |
| 268 | + /* Just to stop compiler warnings. */ |
| 269 | + ( void ) pvParameters; |
| 270 | + |
| 271 | + /* Initialize xLastExecutionTime so the first call to vTaskDelayUntil() |
| 272 | + * works correctly. */ |
| 273 | + xLastExecutionTime = xTaskGetTickCount(); |
| 274 | + |
| 275 | + /* Cycle for ever, delaying then checking all the other tasks are still |
| 276 | + * operating without error. The onboard LED is toggled on each iteration. |
| 277 | + * If an error is detected then the delay period is decreased from |
| 278 | + * mainNO_ERROR_CHECK_TASK_PERIOD to mainERROR_CHECK_TASK_PERIOD. This has |
| 279 | + * the effect of increasing the rate at which the onboard LED toggles, and |
| 280 | + * in so doing gives visual feedback of the system status. */ |
| 281 | + for( ;; ) |
| 282 | + { |
| 283 | + /* Delay until it is time to execute again. */ |
| 284 | + vTaskDelayUntil( &xLastExecutionTime, xDelayPeriod ); |
| 285 | + |
| 286 | + /* Check that the register test 1 task is still running. */ |
| 287 | + if( ulLastRegTest1Value == ulRegTest1LoopCounter ) |
| 288 | + { |
| 289 | + ulErrorFound |= 1UL << 0UL; |
| 290 | + } |
| 291 | + ulLastRegTest1Value = ulRegTest1LoopCounter; |
| 292 | + |
| 293 | + /* Check that the register test 2 task is still running. */ |
| 294 | + if( ulLastRegTest2Value == ulRegTest2LoopCounter ) |
| 295 | + { |
| 296 | + ulErrorFound |= 1UL << 1UL; |
| 297 | + } |
| 298 | + ulLastRegTest2Value = ulRegTest2LoopCounter; |
| 299 | + |
| 300 | + /* Check that the register test 3 task is still running. */ |
| 301 | + if( ulLastRegTest3Value == ulRegTest3LoopCounter ) |
| 302 | + { |
| 303 | + ulErrorFound |= 1UL << 2UL; |
| 304 | + } |
| 305 | + ulLastRegTest3Value = ulRegTest3LoopCounter; |
| 306 | + |
| 307 | + /* Check that the register test 4 task is still running. */ |
| 308 | + if( ulLastRegTest4Value == ulRegTest4LoopCounter ) |
| 309 | + { |
| 310 | + ulErrorFound |= 1UL << 3UL; |
| 311 | + } |
| 312 | + ulLastRegTest4Value = ulRegTest4LoopCounter; |
| 313 | + |
| 314 | + |
| 315 | + /* Toggle the Green LED to give an indication of the system status. |
| 316 | + * If the LED toggles every NO_ERROR_CHECK_TASK_PERIOD milliseconds |
| 317 | + * then everything is ok. A faster toggle indicates an error. */ |
| 318 | + HAL_GPIO_TogglePin( LD2_GPIO_Port, LD2_Pin ); |
| 319 | + |
| 320 | + if( ulErrorFound != pdFALSE ) |
| 321 | + { |
| 322 | + /* An error has been detected in one of the tasks - flash the LED |
| 323 | + * at a higher frequency to give visible feedback that something has |
| 324 | + * gone wrong. */ |
| 325 | + xDelayPeriod = ERROR_CHECK_TASK_PERIOD; |
| 326 | + |
| 327 | + /* Increment error detection count. */ |
| 328 | + ulCheckTaskLoops++; |
| 329 | + } |
| 330 | + } |
| 331 | +} |
| 332 | +/*-----------------------------------------------------------*/ |
0 commit comments