1 /* 2 * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 * @file : app.c 33 * @date : Set 26, 2023 34 * @author : Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar> 35 * @version v1.0.0 36 */ 37 38 /* Development on Bare Metal vs. RTOS 39 * (https://www.sysgo.com/professional-articles/bare-metal-vs-rtos) 40 */ 41 /* 42 * When developing embedded systems that are to be real-time capable, one of 43 * the first and most important questions is whether the applications should 44 * run under a real-time operating system (RTOS) or whether a bare-metal 45 * solution should be developed. 46 * 47 * Bare-metal programming is generally understood 48 * to mean that an application is written directly on the hardware without 49 * using an external programming interface, i.e. an operating system. 50 * 51 * Applications access here directly hardware registers of microcontrollers. 52 * Here one helps oneself with approaches such as endless loops, which execute 53 * tasks with fixed computing time. This sequential execution is only deviated 54 * from when an interrupt event occurs. This bare-metal development approach 55 * for embedded systems is therefore also known as super-loop. 56 */ 57 58 /* Event-Triggered Systems (ETS) and Time-Triggered (TTS) 59 * (https://ebrary.net/51334/computer_science/time_event_triggered_systems) 60 */ 61 /* 62 * A trigger is an event that causes the start of some action in the control 63 * system. The action may be the execution of a task reading a variable and 64 * computing a new value of a correcting variable, or the sending of a message 65 * reporting current values of variables like pressure or temperature. 66 * 67 * In event-triggered control, an action is started only if a significant event 68 * occurs. For instance, a sensor would send a message only if the temperature 69 * has changed by more than 3°C since the last message was sent. 70 * 71 * In time-triggered control, all actions are initiated periodically by a 72 * real-time clock. The sensor from our example would send a message every 73 * clock cycle even if the temperature remains constant. 74 */ 75 76 /* C Programming Language Tutorial (https://www.geeksforgeeks.org/) */ 77 /* 78 * C Basics - C Variables and Constants - C Data Types - C Input/Output 79 * C Operators - C Control Statements Decision-Making - C Functions 80 * C Arrays & Strings - C Pointers - C User-Defined Data Types 81 * C Storage Classes - C Memory Management - C Preprocessor - C File Handling 82 * Miscellaneous 83 */ 84 85 /* Embedded C Coding Standard by Michael Barr 86 * www.barrgroup.com/embedded-systems/books/embedded-c-coding-standard */ 87 /* 88 * Introduction - General Rules - Comment Rules - White Space Rules - 89 * Module Rules - Data Type Rules - Procedure Rules - Variable Rules 90 * Statement Rules - Appendices - Bibliography - Index 91 */ 92 93 /* Spaghetti Code (https://www.geeksforgeeks.org/) */ 94 /* 95 * Spaghetti Code is nothing but a generalized common-usage term for 96 * unstructured and difficult-to-read code. 97 * 98 * Such a type of code in any large code-base can create problems of its own, 99 * if not resolved on time. It can lead to a huge wastage of important 100 * resources like time and energy to find bugs and fix them because the code 101 * has no structure. 102 */ 103 104 /* Structured Programming Approach with Advantages and Disadvantages 105 * (https://www.geeksforgeeks.org/) 106 */ 107 /* 108 * , as the word suggests, can be defined as a programming approach in which 109 * the program is made as a single structure. 110 * 111 * It means that the code will execute the instruction by instruction one after 112 * the other. It doesn’t support the possibility of jumping from one 113 * instruction to some other with the help of any statement like GOTO, etc. 114 * Therefore, the instructions in this approach will be executed in a serial 115 * and structured manner. The languages that support Structured programming 116 * approach are: 117 * 118 * C 119 * C++ 120 * Java 121 * C# 122 * ..etc 123 */ 124 125 /* Introduction of Programming Paradigms 126 * (https://www.geeksforgeeks.org/) 127 */ 128 /* 129 * Paradigm can also be termed as method to solve some problem or do some task. 130 * Programming paradigm is an approach to solve problem using some programming 131 * language or also we can say it is a method to solve a problem using tools 132 * and techniques that are available to us following some approach. 133 * 134 * There are lots for programming language that are known but all of them need 135 * to follow some strategy when they are implemented and this methodology/ 136 * strategy is paradigms. Apart from varieties of programming language there 137 * are lots of paradigms to fulfill each and every demand. 138 */ 139 140 /* Differences between Procedural and Object Oriented Programming 141 * (https://www.geeksforgeeks.org/) 142 */ 143 /* 144 * Procedural Programming can be defined as a programming model which is 145 * derived from structured programming, based upon the concept of calling 146 * procedure. 147 * 148 * Procedures, also known as routines, subroutines or functions, 149 * simply consist of a series of computational steps to be carried out. During 150 * a program’s execution, any given procedure might be called at any point, 151 * including by other procedures or itself. 152 */ 153 154 /* Modular Approach in Programming (https://www.geeksforgeeks.org/) */ 155 /* 156 * Modular programming is the process of subdividing a computer program into 157 * separate sub-programs. A module is a separate software component. 158 * It can often be used in a variety of applications and functions with other 159 * components of the system. 160 */ 161 162 /* Features of C Programming Language (https://www.geeksforgeeks.org/) */ 163 /* 164 * C language is lavishly portable as programs that are written in C language 165 * can run and compile on any system with either no or small changes. 166 */ 167 168 /* Static functions in C (https://www.geeksforgeeks.org/) */ 169 /* 170 * Unlike global functions in C, access to static functions is restricted to 171 * the file where they are declared. Therefore, when we want to restrict 172 * access to functions, we make them static. Another reason for making 173 * functions static can be the reuse of the same function name in other files. 174 */ 175 176 /* Referencias */ 177 /* 178 * SW 179 * (https://campusgrado.fi.uba.ar/course/view.php?id=1217§ion=10#tabs-tree-start) 180 * 181 * HW & FW/MW 182 * (https://campusgrado.fi.uba.ar/course/view.php?id=1217§ion=11#tabs-tree-start) 183 * 184 * Files & Folders 185 * (https://campusgrado.fi.uba.ar/course/view.php?id=1217§ion=12#tabs-tree-start) 186 */ 187 188 /********************** inclusions *******************************************/ 189 190 /* C Preprocessors (https://www.geeksforgeeks.org/) */ 191 /* 192 * The #include preprocessor directive is used to include the header files in 193 * the C program. 194 */ 195 /* Project includes. */ 196 #include "main.h" 197 198 /* Demo includes. */ 199 #include "logger.h" 200 #include "dwt.h" 201 202 /* Application & Tasks includes. */ 203 #include "board.h" 204 #include "task_a.h" 205 #include "task_b.h" 206 #include "task_c.h" 207 208 /********************** macros and definitions *******************************/ 209 210 /* #define in C (https://www.geeksforgeeks.org/) */ 211 /* Macros and its types in C (https://www.geeksforgeeks.org/) */ 212 /* 213 * In C programming, #define is a preprocessor directive that is used to define 214 * macros. The macros are the identifiers defined by #define which are replaced 215 * by their value before compilation. We can define constants and functions 216 * like macros using #define. The generics in C are also implemented using the 217 * #define preprocessor directive along with _Generic. 218 * 219 * In C, a macro is a piece of code in a program that is replaced by the value 220 * of the macro. Macro is defined by #define directive. Whenever a macro name 221 * is encountered by the compiler, it replaces the name with the definition of 222 * the macro. Macro definitions need not be terminated by a semi-colon(;). 223 */ 224 #define G_APP_CNT_INI 0ul 225 #define G_APP_TICK_CNT_INI 0ul 226 227 #define TASK_X_WCET_INI 0ul 228 #define TASK_X_DELAY_MIN 0ul 229 230 /* C Structures (https://www.geeksforgeeks.org/) */ 231 /* 232 * The structure in C is a user-defined data type that can be used to group 233 * items of possibly different types into a single type. The struct keyword is 234 * used to define the structure in the C programming language. The items in 235 * the structure are called its member and they can be of any valid data type. 236 */ 237 238 /* Function Pointer in C - How to declare a pointer to a function? 239 * (https://www.geeksforgeeks.org/) 240 */ 241 /* 242 * In C, like normal data pointers (int *, char *, etc), we can have 243 * pointers to functions. 244 * 245 * While a pointer to a variable or an object is used to access them 246 * indirectly, a pointer to a function is used to invoke a function indirectly. 247 */ 248 typedef struct { 249 void (*task_init)(void *); // Pointer to task (must be a 250 // 'void (void *)' function) 251 void (*task_update)(void *); // Pointer to task (must be a 252 // 'void (void *)' function) 253 void *parameters; // Pointer to parameters 254 } task_cfg_t; 255 256 typedef struct { 257 uint32_t WCET; // Worst-case execution time (microseconds) 258 } task_dta_t; 259 260 /********************** internal data declaration ****************************/ 261 262 /* C Arrays (https://www.geeksforgeeks.org/) */ 263 /* 264 * Array in C is one of the most used data structures in C programming. It is a 265 * simple and fast way of storing multiple values under a single name. 266 */ 267 const task_cfg_t task_cfg_list[] = { 268 {task_a_init, task_a_update, NULL}, 269 {task_b_init, task_b_update, NULL}, 270 {task_c_init, task_c_update, NULL} 271 }; 272 273 #define TASK_QTY (sizeof(task_cfg_list)/sizeof(task_cfg_t)) 274 275 /********************** internal functions declaration ***********************/ 276 277 /********************** internal data definition *****************************/ 278 279 /* Memory Layout of C Programs (https://www.geeksforgeeks.org/) */ 280 /* Storage Classes in C (https://www.geeksforgeeks.org/) */ 281 /* C Variables (https://www.geeksforgeeks.org/) */ 282 /* Constants in C (https://www.geeksforgeeks.org/) */ 283 /* Const Qualifier in C (https://www.geeksforgeeks.org/) */ 284 /* 285 * The constants in C are the read-only variables whose values cannot be 286 * modified once they are declared in the C program. The type of constant can 287 * be an integer constant, a floating pointer constant, a string constant, or 288 * a character constant. In C language, the const keyword is used to define the 289 * constants. 290 * 291 * The qualifier const can be applied to the declaration of any variable to 292 * specify that its value will not be changed (which depends upon where const 293 * variables are stored, we may change the value of the const variable by 294 * using a pointer). 295 * The result is implementation-defined if an attempt is made to change a 296 * const. 297 * Using the const qualifier in C is a good practice when we want to ensure 298 * that some values should remain constant and should not be accidentally 299 * modified. 300 */ 301 const char *p_sys = " Bare Metal - Event-Triggered Systems (ETS)"; 302 const char *p_app = " App - retarget_printf_to_Console"; 303 304 /********************** external data declaration ****************************/ 305 306 /* Memory Layout of C Programs (https://www.geeksforgeeks.org/) */ 307 /* Storage Classes in C (https://www.geeksforgeeks.org/) */ 308 /* C Variables (https://www.geeksforgeeks.org/) */ 309 /* Global Variables in C (https://www.geeksforgeeks.org/) */ 310 /* 311 * A variable declared outside any function or a block of code is called a 312 * global variable. Global variables are frequently used to permanently store 313 * data in a defined scope where they can be accessed and manipulated. 314 * 315 * Global variables do not stay limited to a specific function, which means 316 * that one can use any given function to access and modify the global 317 * variables. The initialization of these variables occurs automatically to 0 318 * during the time of declaration. Also, we generally write the global 319 * variables before the main() function. 320 */ 321 uint32_t g_app_cnt; 322 uint32_t g_app_runtime_us; 323 324 /* Understanding “volatile” qualifier in C | Set 1 (Introduction) 325 * Understanding “volatile” qualifier in C | Set 2 (Examples) 326 * (https://www.geeksforgeeks.org/) 327 */ 328 /* 329 * The volatile keyword is intended to prevent the compiler from applying any 330 * optimizations on objects that can change in ways that cannot be determined 331 * by the compiler. 332 * Objects declared as volatile are omitted from optimization because their 333 * values can be changed by code outside the scope of current code at any time. 334 * The system always reads the current value of a volatile object from the 335 * memory location rather than keeping its value in a temporary register at the 336 * point it is requested, even if a previous instruction asked for the value 337 * from the same object. 338 */ 339 volatile uint32_t g_app_tick_cnt; 340 341 task_dta_t task_dta_list[TASK_QTY]; 342 343 /********************** external functions definition ************************/ 344 345 /* Memory Layout of C Programs (https://www.geeksforgeeks.org/) */ 346 /* Storage Classes in C (https://www.geeksforgeeks.org/) */ 347 /* C Functions (https://www.geeksforgeeks.org/) */ 348 /* 349 * The function definition consists of actual statements which are executed 350 * when the function is called (i.e. when the program control comes to the 351 * function). 352 */ 353 void app_init(void) 354 { 355 uint32_t index; 356 357 /* Print out: Application Initialized */ 358 LOGGER_INFO(" "); 359 LOGGER_INFO("%s is running - Tick [mS] = %lu", GET_NAME(app_init), HAL_GetTick()); 360 361 LOGGER_INFO(p_sys); 362 LOGGER_INFO(p_app); 363 364 /* Init & Print out: Application execution counter */ 365 g_app_cnt = G_APP_CNT_INI; 366 LOGGER_INFO(" %s = %lu", GET_NAME(g_app_cnt), g_app_cnt); 367 368 /* Init Cycle Counter */ 369 cycle_counter_init(); 370 371 /* Go through the task arrays */ 372 for (index = 0; TASK_QTY > index; index++) 373 { 374 /* C Functions (https://www.geeksforgeeks.org/) */ 375 /* 376 * A function call is a statement that instructs the compiler to execute 377 * the function. 378 * We use the function name and parameters in the function call. 379 */ 380 /* Run task_x_init */ 381 (*task_cfg_list[index].task_init)(task_cfg_list[index].parameters); 382 383 /* Init variables */ 384 task_dta_list[index].WCET = TASK_X_WCET_INI; 385 } 386 387 /* Protect shared resource */ 388 __asm("CPSID i"); /* disable interrupts */ 389 /* Init Tick Counter */ 390 g_app_tick_cnt = G_APP_TICK_CNT_INI; 391 g_task_c_tick_cnt = G_APP_TICK_CNT_INI; 392 __asm("CPSIE i"); /* enable interrupts */ 393 } 394 395 void app_update(void) 396 { 397 uint32_t index; 398 bool b_time_update_required = false; 399 uint32_t cycle_counter_time_us; 400 401 /* Protect shared resource */ 402 __asm("CPSID i"); /* disable interrupts */ 403 if (G_APP_TICK_CNT_INI < g_app_tick_cnt) 404 { 405 /* Update Tick Counter */ 406 g_app_tick_cnt--; 407 b_time_update_required = true; 408 } 409 __asm("CPSIE i"); /* enable interrupts */ 410 411 /* Check if it's time to run tasks */ 412 while (b_time_update_required) 413 { 414 /* Update App Counter */ 415 g_app_cnt++; 416 g_app_runtime_us = 0; 417 418 /* Go through the task arrays */ 419 for (index = 0; TASK_QTY > index; index++) 420 { 421 cycle_counter_reset(); 422 423 /* C Functions (https://www.geeksforgeeks.org/) */ 424 /* 425 * A function call is a statement that instructs the compiler to execute 426 * the function. 427 * We use the function name and parameters in the function call. 428 */ 429 /* Run task_x_update */ 430 (*task_cfg_list[index].task_update)(task_cfg_list[index].parameters); 431 432 cycle_counter_time_us = cycle_counter_get_time_us(); 433 434 /* Update variables */ 435 g_app_runtime_us += cycle_counter_time_us; 436 437 if (task_dta_list[index].WCET < cycle_counter_time_us) 438 { 439 task_dta_list[index].WCET = cycle_counter_time_us; 440 } 441 } 442 443 /* Protect shared resource */ 444 __asm("CPSID i"); /* disable interrupts */ 445 if (G_APP_TICK_CNT_INI < g_app_tick_cnt) 446 { 447 /* Update Tick Counter */ 448 g_app_tick_cnt--; 449 b_time_update_required = true; 450 } 451 else 452 { 453 b_time_update_required = false; 454 } 455 __asm("CPSIE i"); /* enable interrupts */ 456 } 457 } 458 459 /* Callbacks in C (https://www.geeksforgeeks.org/) */ 460 /* 461 * A callback is any executable code that is passed as an argument to another 462 * code, which is expected to call back (execute) the argument at a given time. 463 * In simple language, If a reference of a function is passed to another 464 * function as an argument to call it, then it will be called a Callback 465 * function. 466 */ 467 468 void HAL_SYSTICK_Callback(void) 469 { 470 /* Update Tick Counter */ 471 g_app_tick_cnt++; 472 473 g_task_c_tick_cnt++; 474 } 475 476 /********************** end of file ******************************************/
