tdse-tp2_04-model_integration

Index Commits Files Refs README
README.md (12187B)
   1 # Taller de Sistemas Embebidos
   2 
   3 En este proyecto se implementa una aplicación para la placa STM32
   4 [Nucleo-F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html). Esta
   5 aplicación es de tipo no bloqueante y [dirigida por
   6 eventos](https://es.wikipedia.org/wiki/Programaci%C3%B3n_dirigida_por_eventos),
   7 ademas se actualiza en cada milisegundo. A su vez esta aplicación incluye 3
   8 tareas `task_sensor`, `task_system` y `task_actuator` las cuales se modelan
   9 mediante maquinas de estado.
  10 
  11 ## Estructura del proyecto
  12 
  13 Para el proyecto se utiliza la IDE de STM:
  14 [STM32CubeIDE](https://www.st.com/en/development-tools/stm32cubeide.html). Una
  15 vista de árbol nivel 3 (desde la raíz del directorio) se muestra a continuación.
  16 
  17 ```console
  18 .
  19 |-- app
  20 |   |-- inc
  21 |   |   |-- app.h
  22 |   |   |-- board.h
  23 |   |   |-- dwt.h
  24 |   |   |-- logger.h
  25 |   |   |-- systick.h
  26 |   |   |-- task_actuator_attribute.h
  27 |   |   |-- task_actuator.h
  28 |   |   |-- task_actuator_interface.h
  29 |   |   |-- task_sensor_attribute.h
  30 |   |   |-- task_sensor.h
  31 |   |   |-- task_system_attribute.h
  32 |   |   |-- task_system.h
  33 |   |   `-- task_system_interface.h
  34 |   |-- src
  35 |   |   |-- app.c
  36 |   |   |-- logger.c
  37 |   |   |-- systick.c
  38 |   |   |-- task_actuator.c
  39 |   |   |-- task_actuator_interface.c
  40 |   |   |-- task_sensor.c
  41 |   |   |-- task_system.c
  42 |   |   `-- task_system_interface.c
  43 |   |-- app.txt
  44 |   |-- readme.txt
  45 |   |-- task_actuator.png
  46 |   |-- task_actuator.txt
  47 |   |-- task_sensor.png
  48 |   |-- task_sensor.txt
  49 |   |-- task_system.png
  50 |   `-- task_system.txt
  51 |-- Core
  52 |   |-- Inc
  53 |   |   |-- main.h
  54 |   |   |-- stm32f1xx_hal_conf.h
  55 |   |   `-- stm32f1xx_it.h
  56 |   |-- Src
  57 |   |   |-- main.c
  58 |   |   |-- stm32f1xx_hal_msp.c
  59 |   |   |-- stm32f1xx_it.c
  60 |   |   |-- syscalls.c
  61 |   |   |-- sysmem.c
  62 |   |   `-- system_stm32f1xx.c
  63 |   `-- Startup
  64 |       `-- startup_stm32f103rbtx.s
  65 |-- Drivers
  66 |   |-- CMSIS
  67 |   |   |-- Device
  68 |   |   |-- Include
  69 |   |   `-- LICENSE.txt
  70 |   `-- STM32F1xx_HAL_Driver
  71 |       |-- Inc
  72 |       |-- Src
  73 |       `-- LICENSE.txt
  74 |-- README.md
  75 |-- STM32F103RBTX_FLASH.ld
  76 `-- tdse-tp2_01-model_integration.ioc
  77 
  78 15 directories, 44 files
  79 ```
  80 
  81 ### Archivo `Core/Startup/startup_stm32f103rbtx.s`
  82 
  83 Este archivo está escrito en arm assembly y se ejecuta al inicializar el
  84 microcontrolador, el propósito es inicializar los registros principales (como el
  85 stack pointer o el program counter) la memoria y periféricos, para finalmente
  86 transferir el control a la aplicación principal, cuyo punto de entrada es la
  87 función `main` (definida en el archivo `Core/Src/main.c`) esto se puede ver en
  88 la linea 100 del archivo de inicialización, en la cual se ejecuta una
  89 instrucción `bl` (branch with link) y luego el símbolo `main`. El único tipo de
  90 dato utilizado es `word` que representa una variable de 4 bytes (o 32 bits).
  91 
  92 ### Archivo `Core/Src/main.c`
  93 
  94 El archivo `main.c` es un archivo escrito en C que contiene el punto de entrada
  95 del programa principal, este punto de entrada es invocado al momento de
  96 inicializar el microcontrolador, como se mencionó previamente. El patrón de
  97 diseño de este archivo es procedural, ya que la ejecución del programa se lleva
  98 a cabo mediante la invocación de diferentes funciones o subrutinas.
  99 
 100 Los métodos que se encuentran en este archivo además de la (función principal
 101 `main`) son: `initialise_monitor_handles`, `HAL_Init`, `SystemClock_Config`,
 102 `MX_GPIO_Init`, `MX_USART2_UART_Init`, `app_init`, `app_update` y
 103 `Error_Handler`.
 104 
 105 La función o método `initialise_monitor_handles` se encarga de inicializar o
 106 configurar como se manipula la entrada y salida, por ejemplo con `printf` al
 107 momento de depurar el código, en particular se utiliza el protocolo UART para
 108 comunicarse con la computadora, es por esto que se inicializa con la función
 109 `MX_USART2_UART_Init`.
 110 
 111 La función `SystemClock_Config` como se indica en el nombre configura los
 112 relojes internos del microprocesador, como ser las fuentes y los pre-escaladores
 113 de los buses y los timers. La velocidad del microprocesador se almacena en la
 114 variable global `SystemCoreClock`, esta variable se debe actualizar si se cambia
 115 la velocidad del microprocesador.
 116 
 117 Cuando se ejecuta la función `HAL_Init` se inicializa los estados internos de la
 118 librería HAL (Hardware Abstraction Layer) lo que incluye el timer `SysTick`,
 119 cuyo estado se almacena en la estructura global del mismo nombre. `SysTick` se
 120 utiliza para generar una interrupción por cada milisegundo, para esto cuenta
 121 desde `SystemCoreClock/1000` hasta 0, por ejemplo, para una frecuencia de 64MHz,
 122 el el timer cuenta desde 64000 hasta 0, lo que produce una interrupción exacta
 123 por milisegundo.
 124 
 125 La función `Error_Handler` se ejecuta en caso de error pero no tiene una
 126 funcionalidad definida. Por ultimo en la función `main` se inicializa la
 127 aplicación con `app_init` y en cada ciclo se actualiza el estado de la
 128 aplicación con `app_update`.
 129 
 130 ### Archivo `app/src/app.c`
 131 
 132 En este archivo se definen las funciones `app_init` y `app_update` que se
 133 invocan en la función `main`, y se define el callback `HAL_SYSTICK_Callback`,
 134 este ultimo es una función que previamente ya estaba definida pero de manera
 135 débil en la librería HAL, y se inicializa al momento de invocar `HAL_Init`, esta
 136 función se ejecuta cada 1 milisegundo debido a una interrupción generada por un
 137 timer. El callback se define de manera tal de incrementar el contador global de
 138 ticks de la aplicación `g_app_tick_cnt` y el interno de cada tarea
 139 `g_task_*_tick_cnt`, de esta manera, cada vez que el contador de cada tarea y de
 140 la aplicación dejan de ser nulos (en cada milisegundo) la aplicación y las
 141 tareas se deben actualizar.
 142 
 143 Cada vez que se ejecutan las tareas se mide el tiempo de ejecución contando los
 144 microsegundos que se tarde en ejecutar esa tarea, el peor de los tiempos de
 145 ejecución se guarda en el dato `WCET` de cada tarea. La aplicación también lleva
 146 un registro del tiempo de ejecución en microsegundos que se tarda en ejecutar
 147 todas las tareas, y resulta de la suma del tiempo de ejecución cada tarea, el
 148 resultado se guarda en la variable global `g_app_runtime_us`, esta variable se
 149 actualiza en cada ejecución de las tareas, ademas se ha agregado la variable
 150 `g_app_WCET_us` en la cual se guarda el peor tiempo de ejecución de todas las
 151 tareas desde que se inicio el microcontrolador.
 152 
 153 Analizando la evolución de la variable `g_app_WCET_us` se ha detectado el
 154 impacto de imprimir texto en la consola con `LOGGER_INFO` en el tiempo de
 155 ejecución de la aplicación, así como analizando el dato `WCET` de cada tarea.
 156 Sin impresión el tiempo aproximado de ejecución de una tarea es menor a 10 us,
 157 mientras que utilizando `LOGGER_INFO` el tiempo se incrementa 95 ms
 158 aproximadamente, esto hace que el peor tiempo de ejecución de la aplicación se
 159 incremente de 13 us a 106 us.
 160 
 161 ### Archivo `app/src/task_sensor.c`
 162 
 163 En este archivo se implementa las funciones del modelo sensor, el cual se
 164 modela, como multiples botones, utilizando una maquina de estados por cada uno.
 165 
 166 Las subrutinas que se presentan son `task_sensor_init`, `task_sensor_update` y
 167 `task_sensor_statechart`. La primera `task_sensor_init` se invoca por única vez
 168 al iniciar la tarea (cuando se invoca `app_init`) e inicializa las variables de
 169 todas las maquinas de estados de modelo sensor disponibles (definidas en
 170 `task_sensor_cfg_list` y `task_sensor_dta_list`). Las ultimas dos subrutinas
 171 `task_sensor_update` y `task_sensor_statechart` se invocan continuamente en el
 172 superloop, al invocar `app_update`, en particular en `app_update` se llama a
 173 `task_sensor_update` y esta internamente invoca la función
 174 `task_sensor_statechart`, la cual actualiza el estado de cada una de la maquina
 175 de estados disponibles del modelo `task_sensor`.
 176 
 177 ### Archivo `app/src/task_sensor_attribute.h`
 178 
 179 En este archivo se describen los atributos de la maquina de estados del modelo
 180 sensor, como son los eventos que recibe y los estados posibles, también se
 181 definen las estructuras que representan esta maquina de estados, de manera tal
 182 de poder representar multiples sensores.
 183 
 184 ### Archivo `app/task_sensor.png`
 185 
 186 En este archivo se presenta el diagrama de estados completo de la maquina de
 187 estados que representa al sensor. Por ser un diagrama de estados se muestran
 188 todos los posibles estados, como también el inicial, y como cambian estos al
 189 recibir eventos.
 190 
 191 ![](app/task_sensor.png)
 192 
 193 ### Archivo `app/src/task_system.c`
 194 
 195 En este archivo se implementa las funciones del modelo system, el cual se
 196 modela, como una única maquina de estados.
 197 
 198 Las subrutinas que se presentan son `task_system_init`, `task_system_update` y
 199 `task_system_statechart`. La primera `task_system_init` se invoca por única vez
 200 al iniciar la tarea (cuando se invoca `app_init`) e inicializa las variables de
 201 la maquina de estados del modelo system (definidas en la instancia de la
 202 estructura `task_system_dta_t`, `task_system_dta`). Las ultimas dos subrutinas
 203 `task_system_update` y `task_system_statechart` se invocan continuamente en el
 204 superloop, al invocar `app_update`, en particular en `app_update` se llama a
 205 `task_system_update` y esta internamente invoca la función
 206 `task_system_statechart`, la cual actualiza el estado de la maquina de estados
 207 del modelo system de acuerdo al estado en que este y los eventos que se reciben.
 208 
 209 ### Archivo `app/src/task_system_attribute.h`
 210 
 211 En este archivo se describen los atributos de la maquina de estados del modelo
 212 system, como son los eventos que recibe y los estados posibles, también se
 213 definen las estructuras que representan esta maquina de estados.
 214 
 215 ### Archivo `app/src/task_system_interface.h`
 216 
 217 En este archivo se define una serie de subrutinas para interactuar con el modelo
 218 system, de manera de enviar y recibir eventos, por ejemplo recibir eventos del
 219 modelo system y enviar eventos al modelo actuator.
 220 
 221 Las subrutinas que se definen son `init_queue_event_task_system`,
 222 `put_event_task_system`, `task_system_ev_t get_event_task_system` y
 223 `any_event_task_system`.
 224 
 225 ### Archivo `app/task_system.png`
 226 
 227 En este archivo se presenta el diagrama de estados completo de la maquina de
 228 estados que representa al sistema. Por ser un diagrama de estados se muestran
 229 todos los posibles estados, incluyendo el estado inicial, y como cambian estos
 230 al recibir eventos.
 231 
 232 ![](app/task_system.png)
 233 
 234 ### Archivo `app/src/task_actuator.c`
 235 
 236 En este archivo se implementa las funciones del modelo actuator, el cual se
 237 modela, como una única maquina de estados.
 238 
 239 Las subrutinas que se presentan son `task_actuator_init`, `task_actuator_update` y
 240 `task_actuator_statechart`. La primera `task_actuator_init` se invoca por única vez
 241 al iniciar la tarea (cuando se invoca `app_init`) e inicializa las variables de
 242 todas las maquinas de estados de modelo actuator (definidas en la lista de instancias de la
 243 estructura `task_actuator_dta_t`, `task_actuator_dta_list`). Las ultimas dos
 244 subrutinas `task_actuator_update` y `task_actuator_statechart` se invocan
 245 continuamente en el superloop, al invocar `app_update`, en particular en
 246 `app_update` se llama a `task_actuator_update` y esta internamente invoca la
 247 función `task_actuator_statechart`, la cual actualiza el estado de la maquina de
 248 estados de cada uno de las instancias de modelo actuator de acuerdo al estado en
 249 que este y los eventos que recibe.
 250 
 251 ### Archivo `app/src/task_actuator_attribute.h`
 252 
 253 En este archivo se describen los atributos de la maquina de estados del modelo
 254 actuator, como son los eventos que recibe y los estados posibles, también se
 255 definen las estructuras que representan esta maquina de estados.
 256 
 257 ### Archivo `app/src/task_actuator_interface.h`
 258 
 259 En este archivo se define una subrutina para interactuar con el modelo
 260 actuator `put_event_task_actuator`, esta subrutina tiene como único fin enviar
 261 eventos al modelo actuator, por ejemplo desde el modelo system. 
 262 
 263 ### Archivo `app/task_actuator.png`
 264 
 265 En este archivo se presenta el diagrama de estados completo de la maquina de
 266 estados que representa al actuador. Por ser un diagrama de estados se muestran
 267 todos los posibles estados, incluyendo el estado inicial, y como cambian estos
 268 al recibir eventos.
 269 
 270 ![](app/task_actuator.png)