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. De estas 3 tareas en esta instancia solo se ha 10 implementado la maquina de estados de la primera `task_sensor`, de las restantes 11 solo se ha implementado lo suficiente como para que la aplicación se ejecute sin 12 errores. 13 14 ## Estructura del proyecto 15 16 Para el proyecto se utiliza la IDE de STM: 17 [STM32CubeIDE](https://www.st.com/en/development-tools/stm32cubeide.html). Una 18 vista de árbol nivel 3 (desde la raíz del directorio) se muestra a continuación. 19 20 ```console 21 . 22 |-- app 23 | |-- inc 24 | | |-- app.h 25 | | |-- board.h 26 | | |-- dwt.h 27 | | |-- logger.h 28 | | |-- systick.h 29 | | |-- task_actuator_attribute.h 30 | | |-- task_actuator.h 31 | | |-- task_actuator_interface.h 32 | | |-- task_sensor_attribute.h 33 | | |-- task_sensor.h 34 | | |-- task_system_attribute.h 35 | | |-- task_system.h 36 | | `-- task_system_interface.h 37 | |-- src 38 | | |-- app.c 39 | | |-- logger.c 40 | | |-- systick.c 41 | | |-- task_actuator.c 42 | | |-- task_actuator_interface.c 43 | | |-- task_sensor.c 44 | | |-- task_system.c 45 | | `-- task_system_interface.c 46 | |-- app.txt 47 | |-- readme.txt 48 | |-- task_actuator.png 49 | |-- task_actuator.txt 50 | |-- task_sensor.png 51 | |-- task_sensor.txt 52 | |-- task_system.png 53 | `-- task_system.txt 54 |-- Core 55 | |-- Inc 56 | | |-- main.h 57 | | |-- stm32f1xx_hal_conf.h 58 | | `-- stm32f1xx_it.h 59 | |-- Src 60 | | |-- main.c 61 | | |-- stm32f1xx_hal_msp.c 62 | | |-- stm32f1xx_it.c 63 | | |-- syscalls.c 64 | | |-- sysmem.c 65 | | `-- system_stm32f1xx.c 66 | `-- Startup 67 | `-- startup_stm32f103rbtx.s 68 |-- Drivers 69 | |-- CMSIS 70 | | |-- Device 71 | | |-- Include 72 | | `-- LICENSE.txt 73 | `-- STM32F1xx_HAL_Driver 74 | |-- Inc 75 | |-- Src 76 | `-- LICENSE.txt 77 |-- README.md 78 |-- STM32F103RBTX_FLASH.ld 79 `-- tdse-tp2_01-model_integration.ioc 80 81 15 directories, 44 files 82 ``` 83 84 ### Archivo `Core/Startup/startup_stm32f103rbtx.s` 85 86 Este archivo está escrito en arm assembly y se ejecuta al inicializar el 87 microcontrolador, el propósito es inicializar los registros principales (como el 88 stack pointer o el program counter) la memoria y periféricos, para finalmente 89 transferir el control a la aplicación principal, cuyo punto de entrada es la 90 función `main` (definida en el archivo `Core/Src/main.c`) esto se puede ver en 91 la linea 100 del archivo de inicialización, en la cual se ejecuta una 92 instrucción `bl` (branch with link) y luego el símbolo `main`. El único tipo de 93 dato utilizado es `word` que representa una variable de 4 bytes (o 32 bits). 94 95 ### Archivo `Core/Src/main.c` 96 97 El archivo `main.c` es un archivo escrito en C que contiene el punto de entrada 98 del programa principal, este punto de entrada es invocado al momento de 99 inicializar el microcontrolador, como se mencionó previamente. El patrón de 100 diseño de este archivo es procedural, ya que la ejecución del programa se lleva 101 a cabo mediante la invocación de diferentes funciones o subrutinas. 102 103 Las funciones o subrutinas que se encuentran en este archivo además de la 104 (función principal `main`) son: `initialise_monitor_handles`, `HAL_Init`, 105 `SystemClock_Config`, `MX_GPIO_Init`, `MX_USART2_UART_Init`, `app_init`, 106 `app_update` y `Error_Handler`. 107 108 La función `initialise_monitor_handles` se encarga de inicializar o configurar 109 como se manipula la entrada y salida, por ejemplo con `printf` al momento de 110 depurar el código, en particular se utiliza el protocolo UART para comunicarse 111 con la computadora, es por esto que se inicializa con la función 112 `MX_USART2_UART_Init`. 113 114 La función `SystemClock_Config` como se indica en el nombre configura los 115 relojes internos del microprocesador, como ser las fuentes y los pre-escaladores 116 de los buses y los timers. La velocidad del microprocesador se almacena en la 117 variable global `SystemCoreClock`, esta variable se debe actualizar si se cambia 118 la velocidad del microprocesador. 119 120 Cuando se ejecuta la función `HAL_Init` se inicializa los estados internos de la 121 librería HAL (Hardware Abstraction Layer) lo que incluye el timer `SysTick`, 122 cuyo estado se almacena en la estructura global del mismo nombre. `SysTick` se 123 utiliza para generar una interrupción por cada milisegundo, para esto cuenta 124 desde `SystemCoreClock/1000` hasta 0, por ejemplo, para una frecuencia de 64MHz, 125 el el timer cuenta desde 64000 hasta 0, lo que produce una interrupción exacta 126 por milisegundo. 127 128 La función `Error_Handler` se ejecuta en caso de error pero no tiene una 129 funcionalidad definida. Por ultimo en la función `main` se inicializa la 130 aplicación con `app_init` y en cada ciclo se actualiza el estado de la 131 aplicación con `app_update`. 132 133 ### Archivo `app/src/app.c` 134 135 En este archivo se definen las funciones `app_init` y `app_update` que se 136 invocan en la función `main`, y se define el callback `HAL_SYSTICK_Callback`, 137 este ultimo es una función que previamente ya estaba definida pero de manera 138 débil en la librería HAL, y se inicializa al momento de invocar `HAL_Init`, esta 139 función se ejecuta cada 1 milisegundo debido a una interrupción generada por un 140 timer. El callback se define de manera tal de incrementar el contador global de 141 ticks de la aplicación `g_app_tick_cnt` y el interno de cada tarea 142 `g_task_*_tick_cnt`, de esta manera, cada vez que el contador de cada tarea y de 143 la aplicación dejan de ser nulos (en cada milisegundo) la aplicación y las 144 tareas se deben actualizar. 145 146 Cada vez que se ejecutan las tareas se mide el tiempo de ejecución contando los 147 microsegundos que se tarde en ejecutar esa tarea, el peor de los tiempos de 148 ejecución se guarda en el dato `WCET` de cada tarea. La aplicación también lleva 149 un registro del tiempo de ejecución en microsegundos que se tarda en ejecutar 150 todas las tareas, y resulta de la suma del tiempo de ejecución cada tarea, el 151 resultado se guarda en la variable global `g_app_runtime_us`, esta variable se 152 actualiza en cada ejecución de las tareas, ademas se ha agregado la variable 153 `g_app_WCET_us` en la cual se guarda el peor tiempo de ejecución de todas las 154 tareas desde que se inicio el microcontrolador. 155 156 Analizando la evolución de la variable `g_app_WCET_us` se ha detectado el 157 impacto de imprimir texto en la consola con `LOGGER_INFO` en el tiempo de 158 ejecución de la aplicación, así como analizando el dato `WCET` de cada tarea. 159 Sin impresión el tiempo aproximado de ejecución de una tarea es menor a 10 us, 160 mientras que utilizando `LOGGER_INFO` el tiempo se incrementa 95 ms 161 aproximadamente, esto hace que el peor tiempo de ejecución de la aplicación se 162 incremente de 13 us a 106 us. 163 164 ### Archivo `app/src/task_sensor.c` 165 166 En este archivo se implementa las funciones del modelo sensor, el cual se 167 modela, en esta instancia como un único botón, utilizando una maquina de estados. 168 169 Las subrutinas que se presentan son `task_sensor_init`, `task_sensor_update` y 170 `task_sensor_statechart`. La primera `task_sensor_init` se invoca por única vez 171 al iniciar la tarea (cuando se invoca `app_init`) e inicializa las variables de 172 todas las maquinas de estados de modelo sensor disponibles (ya que pueden haber 173 multiples, definidas en `task_sensor_cfg_list` y `task_sensor_dta_list`). Las 174 ultimas dos subrutinas `task_sensor_update` y `task_sensor_statechart` se 175 invocan continuamente en el superloop, al invocar `app_update`, en particular en 176 `app_update` se llama a `task_sensor_update` y esta internamente invoca la 177 función `task_sensor_statechart`, la cual actualiza el estado de cada una de la 178 maquina de estados disponibles del modelo `task_sensor`. 179 180 ### Archivo `app/src/task_sensor_attribute.h` 181 182 En este archivo se describen los atributos de la maquina de estados del modelo 183 sensor, como son los eventos que recibe y los estados posibles, también se 184 definen las estructuras que representan esta maquina de estados, de manera tal 185 de poder representar multiples sensores. 186 187 ### Archivo `app/task_sensor.png` 188 189 En este archivo se presenta el diagrama de estados completo de la maquina de 190 estados que representa al sensor. Por ser un diagrama de estados se muestran 191 todos los posibles estados, como también el inicial, y como cambian estos al 192 recibir eventos. 193 194 
