1 ### **Análisis y Explicación del Código Fuente** 2 3 #### **1. `logger.c` y `logger.h` (Sistema de Registro/Log)** Estos archivos 4 implementan un sistema de registro de mensajes (logging) para depuración. 5 6 * **`logger.h`**: 7 * Define las macros `LOGGER_LOG` y `LOGGER_INFO` para facilitar el envío de 8 mensajes. 9 * La configuración `LOGGER_CONFIG_USE_SEMIHOSTING` (activada) indica que la 10 salida de los logs se realizará a través de "semihosting". Este es un 11 mecanismo de depuración que permite al microcontrolador enviar datos (como 12 texto) al computador anfitrión a través de la sonda de depuración (ej. 13 ST-Link), mostrándolos en la consola del IDE. 14 * **Crucialmente, la macro `LOGGER_LOG` deshabilita las interrupciones 15 (`__asm("CPSID i")`) antes de preparar y enviar el mensaje, y las 16 rehabilita después (`__asm("CPSIE i")`)**. Esto se hace para evitar que 17 una interrupción ocurra a mitad de una operación de log y corrompa los 18 datos, pero tiene importantes consecuencias en el rendimiento, como se 19 verá más adelante. 20 21 * **`logger.c`**: 22 * Implementa la función `logger_log_print_` que, en este caso, utiliza 23 `printf` para enviar el mensaje formateado a través de semihosting. 24 25 #### **2. `app.c` (Planificador Principal)** Este archivo es el núcleo del 26 sistema operativo simple, un planificador cooperativo basado en un "super-loop". 27 28 * **`app_init()`**: 29 * Se ejecuta una sola vez al inicio. 30 * Imprime mensajes de bienvenida e inicialización usando `LOGGER_INFO`. 31 * Recorre una lista de tareas (`task_cfg_list`) y llama a la función de 32 inicialización de cada una (ej. `task_sensor_init`, `task_menu_init`). 33 * Inicializa las variables de rendimiento, como el `WCET` (Worst-Case 34 Execution Time) de cada tarea, en cero. 35 * Inicializa los contadores de "ticks" que son la base de tiempo del 36 sistema. 37 38 * **`app_update()`**: 39 * Se ejecuta continuamente dentro del bucle `while(1)` de `main.c`. 40 * Es activado por un "tick" del sistema (la variable `g_app_tick_cnt` se 41 vuelve mayor que cero). 42 * Dentro de un bucle `while`, procesa todos los ticks pendientes. En cada 43 pasada: 1. Mide el tiempo de ejecución de la función `_update` de cada 44 tarea (`task_sensor_update`, `task_menu_update`) utilizando un contador de 45 ciclos de hardware (DWT). 2. Suma estos tiempos para obtener el tiempo de 46 ejecución total del ciclo (`g_app_runtime_us`). 3. Compara el tiempo de 47 ejecución de la tarea actual con el `WCET` almacenado y lo actualiza si el 48 tiempo actual es mayor. 49 50 * **`HAL_SYSTICK_Callback()`**: 51 * Esta función es la rutina de servicio de interrupción (ISR) del `SysTick`. 52 Se ejecuta automáticamente cada 1 milisegundo. 53 * Incrementa los contadores de tick para la aplicación principal 54 (`g_app_tick_cnt`) y para cada tarea específica (`g_task_sensor_tick_cnt`, 55 `g_task_menu_tick_cnt`). 56 57 #### **3. `task_sensor.c` (Tarea de Lectura de Botones)** Gestiona la lectura de 58 los botones físicos, implementando un filtro antirrebote (debounce) por 59 software. 60 61 * **`task_sensor_init()`**: Inicializa las variables de la tarea y muestra 62 mensajes de log. 63 * **`task_sensor_update()`**: Se activa periódicamente gracias a 64 `g_task_sensor_tick_cnt` y ejecuta la máquina de estados. 65 * **`task_sensor_statechart()`**: 66 * Implementa una máquina de estados de 4 etapas (`UP`, `FALLING`, `DOWN`, 67 `RISING`) para cada botón. 68 * Cuando se presiona un botón, no reacciona al instante. Entra en el estado 69 `FALLING` y espera un tiempo (`tick_max`). Si el botón sigue presionado 70 después de ese tiempo, se valida la pulsación y se genera un evento (ej. 71 `EV_MEN_ENT_ACTIVE`). 72 * Los eventos se envían a la tarea del menú mediante la función 73 `put_event_task_menu()`. 74 75 #### **4. `task_menu.c` (Tarea de Lógica de Menú)** Controla la lógica de la 76 interfaz de usuario y actualiza la pantalla LCD. 77 78 * **`task_menu_init()`**: Inicializa la pantalla LCD y muestra un mensaje de 79 bienvenida. También inicializa sus propias variables y la cola de eventos. 80 * **`task_menu_update()`**: Se activa periódicamente y ejecuta la máquina de 81 estados del menú. 82 * **`task_menu_statechart()`**: 83 * Revisa si hay eventos pendientes en la cola (enviados por `task_sensor`). 84 * Procesa los eventos para cambiar entre sus estados (`ST_MEN_XX_IDLE`, 85 `ST_MEN_XX_ACTIVE`). 86 * En el estado `ACTIVE`, decrementa un temporizador. Cuando este llega a 87 cero, actualiza un contador en la pantalla LCD. Esto crea una 88 actualización periódica en el display. 89 90 --- 91 92 ### **Impacto de `LOGGER_INFO()` en la Evolución de Variables** 93 94 El uso de `LOGGER_INFO()` tiene un **impacto muy significativo y negativo** en 95 el rendimiento del sistema y, por lo tanto, en las variables que lo miden. La 96 razón principal es que la comunicación por semihosting es **extremadamente 97 lenta** en comparación con la velocidad de ejecución normal del 98 microcontrolador. 99 100 #### **Nota sobre `g_task_test_tick_cnt`** Esta variable **no existe** en el 101 código fuente proporcionado. Es probable que sea un error y se refiera a una de 102 las variables de tick existentes: `g_app_tick_cnt`, `g_task_sensor_tick_cnt` o 103 `g_task_menu_tick_cnt`. El impacto principal sobre estas es que la 104 deshabilitación de interrupciones por parte de `LOGGER_INFO` puede introducir 105 "jitter" (variabilidad en el tiempo de respuesta a la interrupción del 106 `SysTick`), haciendo que el sistema sea menos predecible. 107 108 #### **`g_app_runtime_us` (Tiempo de Ejecución del Ciclo)** 109 * **Unidad de medida**: Microsegundos ($µs$). 110 * **Evolución**: 111 * **Sin `LOGGER_INFO()`**: En un ciclo normal de `app_update`, 112 `g_app_runtime_us` mediría solo el tiempo de la lógica de las tareas (leer 113 pines, actualizar máquinas de estado), que sería de unas pocas decenas de 114 microsegundos. 115 * **Con `LOGGER_INFO()`**: Cada vez que se llama a `LOGGER_INFO` 116 (especialmente durante `app_init`), el tiempo de ejecución se dispara. La 117 operación de `printf` sobre semihosting puede tardar **varios 118 milisegundos**. Como `app.c` mide el tiempo de ejecución de las funciones 119 `_init` y `_update` que contienen estos logs, el valor de 120 `g_app_runtime_us` reflejará este enorme tiempo. 121 * **Impacto**: `g_app_runtime_us` tendrá valores **extremadamente altos y 122 variables**, del orden de **miles de microsegundos (milisegundos)** en 123 lugar de decenas, cada vez que una tarea imprima un log. Esto falsea por 124 completo la métrica de carga de la CPU. 125 126 #### **`task_dta_list[index].WCET` (Tiempo de Ejecución de Peor Caso)** 127 * **Unidad de medida**: Microsegundos ($µs$). 128 * **Evolución**: 129 * **Inicialización (`app_init`)**: Las funciones `task_sensor_init` y 130 `task_menu_init` hacen un uso intensivo de `LOGGER_INFO`. Dado que el 131 `WCET` se mide también durante la inicialización, este se establecerá 132 inmediatamente en un valor **muy alto** (múltiples milisegundos) debido al 133 tiempo que tarda la consola de depuración en procesar los mensajes. 134 * **Ejecución (`app_update`)**: El `WCET` representa el tiempo máximo que ha 135 tardado una tarea en ejecutarse. Debido a los logs en la inicialización, 136 este valor ya será muy grande desde el principio. Durante la ejecución 137 normal, la lógica de las tareas es rápida, por lo que el `WCET` 138 probablemente no se actualizará, a menos que se llame a `LOGGER_INFO` de 139 nuevo dentro de `app_update`. 140 * **Impacto**: El `WCET` medido **no reflejará el tiempo de ejecución de la 141 lógica real de la tarea, sino el tiempo de la operación de E/S de 142 depuración**. Esto hace que la métrica `WCET` sea inútil para el análisis 143 de tiempo real, ya que el código de depuración no estaría presente en una 144 versión final del producto. El valor será del orden de **miles de 145 microsegundos**.
