Taller de Sistemas Embebidos
En este proyecto se implementa una aplicación para la placa STM32
Nucleo-F103RB. Esta
aplicación es de tipo no bloqueante y dirigida por
eventos,
ademas se actualiza en cada milisegundo. A su vez esta aplicación incluye 3
tareas task_sensor, task_system y task_actuator las cuales se modelan
mediante maquinas de estado.
Estructura del proyecto
Para el proyecto se utiliza la IDE de STM: STM32CubeIDE. Una vista de árbol nivel 3 (desde la raíz del directorio) se muestra a continuación.
.
|-- app
| |-- inc
| | |-- app.h
| | |-- board.h
| | |-- dwt.h
| | |-- logger.h
| | |-- systick.h
| | |-- task_actuator_attribute.h
| | |-- task_actuator.h
| | |-- task_actuator_interface.h
| | |-- task_sensor_attribute.h
| | |-- task_sensor.h
| | |-- task_system_attribute.h
| | |-- task_system.h
| | `-- task_system_interface.h
| |-- src
| | |-- app.c
| | |-- logger.c
| | |-- systick.c
| | |-- task_actuator.c
| | |-- task_actuator_interface.c
| | |-- task_sensor.c
| | |-- task_system.c
| | `-- task_system_interface.c
| |-- app.txt
| |-- readme.txt
| |-- task_actuator.png
| |-- task_actuator.txt
| |-- task_sensor.png
| |-- task_sensor.txt
| |-- task_system.png
| `-- task_system.txt
|-- Core
| |-- Inc
| | |-- main.h
| | |-- stm32f1xx_hal_conf.h
| | `-- stm32f1xx_it.h
| |-- Src
| | |-- main.c
| | |-- stm32f1xx_hal_msp.c
| | |-- stm32f1xx_it.c
| | |-- syscalls.c
| | |-- sysmem.c
| | `-- system_stm32f1xx.c
| `-- Startup
| `-- startup_stm32f103rbtx.s
|-- Drivers
| |-- CMSIS
| | |-- Device
| | |-- Include
| | `-- LICENSE.txt
| `-- STM32F1xx_HAL_Driver
| |-- Inc
| |-- Src
| `-- LICENSE.txt
|-- README.md
|-- STM32F103RBTX_FLASH.ld
`-- tdse-tp2_01-model_integration.ioc
15 directories, 44 files
Archivo Core/Startup/startup_stm32f103rbtx.s
Este archivo está escrito en arm assembly y se ejecuta al inicializar el
microcontrolador, el propósito es inicializar los registros principales (como el
stack pointer o el program counter) la memoria y periféricos, para finalmente
transferir el control a la aplicación principal, cuyo punto de entrada es la
función main (definida en el archivo Core/Src/main.c) esto se puede ver en
la linea 100 del archivo de inicialización, en la cual se ejecuta una
instrucción bl (branch with link) y luego el símbolo main. El único tipo de
dato utilizado es word que representa una variable de 4 bytes (o 32 bits).
Archivo Core/Src/main.c
El archivo main.c es un archivo escrito en C que contiene el punto de entrada
del programa principal, este punto de entrada es invocado al momento de
inicializar el microcontrolador, como se mencionó previamente. El patrón de
diseño de este archivo es procedural, ya que la ejecución del programa se lleva
a cabo mediante la invocación de diferentes funciones o subrutinas.
Los métodos que se encuentran en este archivo además de la (función principal
main) son: initialise_monitor_handles, HAL_Init, SystemClock_Config,
MX_GPIO_Init, MX_USART2_UART_Init, app_init, app_update y
Error_Handler.
La función o método initialise_monitor_handles se encarga de inicializar o
configurar como se manipula la entrada y salida, por ejemplo con printf al
momento de depurar el código, en particular se utiliza el protocolo UART para
comunicarse con la computadora, es por esto que se inicializa con la función
MX_USART2_UART_Init.
La función SystemClock_Config como se indica en el nombre configura los
relojes internos del microprocesador, como ser las fuentes y los pre-escaladores
de los buses y los timers. La velocidad del microprocesador se almacena en la
variable global SystemCoreClock, esta variable se debe actualizar si se cambia
la velocidad del microprocesador.
Cuando se ejecuta la función HAL_Init se inicializa los estados internos de la
librería HAL (Hardware Abstraction Layer) lo que incluye el timer SysTick,
cuyo estado se almacena en la estructura global del mismo nombre. SysTick se
utiliza para generar una interrupción por cada milisegundo, para esto cuenta
desde SystemCoreClock/1000 hasta 0, por ejemplo, para una frecuencia de 64MHz,
el el timer cuenta desde 64000 hasta 0, lo que produce una interrupción exacta
por milisegundo.
La función Error_Handler se ejecuta en caso de error pero no tiene una
funcionalidad definida. Por ultimo en la función main se inicializa la
aplicación con app_init y en cada ciclo se actualiza el estado de la
aplicación con app_update.
Archivo app/src/app.c
En este archivo se definen las funciones app_init y app_update que se
invocan en la función main, y se define el callback HAL_SYSTICK_Callback,
este ultimo es una función que previamente ya estaba definida pero de manera
débil en la librería HAL, y se inicializa al momento de invocar HAL_Init, esta
función se ejecuta cada 1 milisegundo debido a una interrupción generada por un
timer. El callback se define de manera tal de incrementar el contador global de
ticks de la aplicación g_app_tick_cnt y el interno de cada tarea
g_task_*_tick_cnt, de esta manera, cada vez que el contador de cada tarea y de
la aplicación dejan de ser nulos (en cada milisegundo) la aplicación y las
tareas se deben actualizar.
Cada vez que se ejecutan las tareas se mide el tiempo de ejecución contando los
microsegundos que se tarde en ejecutar esa tarea, el peor de los tiempos de
ejecución se guarda en el dato WCET de cada tarea. La aplicación también lleva
un registro del tiempo de ejecución en microsegundos que se tarda en ejecutar
todas las tareas, y resulta de la suma del tiempo de ejecución cada tarea, el
resultado se guarda en la variable global g_app_runtime_us, esta variable se
actualiza en cada ejecución de las tareas, ademas se ha agregado la variable
g_app_WCET_us en la cual se guarda el peor tiempo de ejecución de todas las
tareas desde que se inicio el microcontrolador.
Analizando la evolución de la variable g_app_WCET_us se ha detectado el
impacto de imprimir texto en la consola con LOGGER_INFO en el tiempo de
ejecución de la aplicación, así como analizando el dato WCET de cada tarea.
Sin impresión el tiempo aproximado de ejecución de una tarea es menor a 10 us,
mientras que utilizando LOGGER_INFO el tiempo se incrementa 95 ms
aproximadamente, esto hace que el peor tiempo de ejecución de la aplicación se
incremente de 13 us a 106 us.
Archivo app/src/task_sensor.c
En este archivo se implementa las funciones del modelo sensor, el cual se modela, como multiples botones, utilizando una maquina de estados por cada uno.
Las subrutinas que se presentan son task_sensor_init, task_sensor_update y
task_sensor_statechart. La primera task_sensor_init se invoca por única vez
al iniciar la tarea (cuando se invoca app_init) e inicializa las variables de
todas las maquinas de estados de modelo sensor disponibles (definidas en
task_sensor_cfg_list y task_sensor_dta_list). Las ultimas dos subrutinas
task_sensor_update y task_sensor_statechart se invocan continuamente en el
superloop, al invocar app_update, en particular en app_update se llama a
task_sensor_update y esta internamente invoca la función
task_sensor_statechart, la cual actualiza el estado de cada una de la maquina
de estados disponibles del modelo task_sensor.
Archivo app/src/task_sensor_attribute.h
En este archivo se describen los atributos de la maquina de estados del modelo sensor, como son los eventos que recibe y los estados posibles, también se definen las estructuras que representan esta maquina de estados, de manera tal de poder representar multiples sensores.
Archivo app/task_sensor.png
En este archivo se presenta el diagrama de estados completo de la maquina de estados que representa al sensor. Por ser un diagrama de estados se muestran todos los posibles estados, como también el inicial, y como cambian estos al recibir eventos.

Archivo app/src/task_system.c
En este archivo se implementa las funciones del modelo system, el cual se modela, como una única maquina de estados.
Las subrutinas que se presentan son task_system_init, task_system_update y
task_system_statechart. La primera task_system_init se invoca por única vez
al iniciar la tarea (cuando se invoca app_init) e inicializa las variables de
la maquina de estados del modelo system (definidas en la instancia de la
estructura task_system_dta_t, task_system_dta). Las ultimas dos subrutinas
task_system_update y task_system_statechart se invocan continuamente en el
superloop, al invocar app_update, en particular en app_update se llama a
task_system_update y esta internamente invoca la función
task_system_statechart, la cual actualiza el estado de la maquina de estados
del modelo system de acuerdo al estado en que este y los eventos que se reciben.
Archivo app/src/task_system_attribute.h
En este archivo se describen los atributos de la maquina de estados del modelo system, como son los eventos que recibe y los estados posibles, también se definen las estructuras que representan esta maquina de estados.
Archivo app/src/task_system_interface.h
En este archivo se define una serie de subrutinas para interactuar con el modelo system, de manera de enviar y recibir eventos, por ejemplo recibir eventos del modelo system y enviar eventos al modelo actuator.
Las subrutinas que se definen son init_queue_event_task_system,
put_event_task_system, task_system_ev_t get_event_task_system y
any_event_task_system.
Archivo app/task_system.png
En este archivo se presenta el diagrama de estados completo de la maquina de estados que representa al sistema. Por ser un diagrama de estados se muestran todos los posibles estados, incluyendo el estado inicial, y como cambian estos al recibir eventos.

Archivo app/src/task_actuator.c
En este archivo se implementa las funciones del modelo actuator, el cual se modela, como una única maquina de estados.
Las subrutinas que se presentan son task_actuator_init, task_actuator_update y
task_actuator_statechart. La primera task_actuator_init se invoca por única vez
al iniciar la tarea (cuando se invoca app_init) e inicializa las variables de
todas las maquinas de estados de modelo actuator (definidas en la lista de instancias de la
estructura task_actuator_dta_t, task_actuator_dta_list). Las ultimas dos
subrutinas task_actuator_update y task_actuator_statechart se invocan
continuamente en el superloop, al invocar app_update, en particular en
app_update se llama a task_actuator_update y esta internamente invoca la
función task_actuator_statechart, la cual actualiza el estado de la maquina de
estados de cada uno de las instancias de modelo actuator de acuerdo al estado en
que este y los eventos que recibe.
Archivo app/src/task_actuator_attribute.h
En este archivo se describen los atributos de la maquina de estados del modelo actuator, como son los eventos que recibe y los estados posibles, también se definen las estructuras que representan esta maquina de estados.
Archivo app/src/task_actuator_interface.h
En este archivo se define una subrutina para interactuar con el modelo
actuator put_event_task_actuator, esta subrutina tiene como único fin enviar
eventos al modelo actuator, por ejemplo desde el modelo system.
Archivo app/task_actuator.png
En este archivo se presenta el diagrama de estados completo de la maquina de estados que representa al actuador. Por ser un diagrama de estados se muestran todos los posibles estados, incluyendo el estado inicial, y como cambian estos al recibir eventos.

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  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  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 
