tdse-tf_3-02

Controlador PID para derretidor de miel con control local via botones y remoto via WiFi
Index Commits Files Refs Submodules README
commit fb48410853668478a318f34fb326e41320af08f4
parent 42285ecbb1797194e5151185da17a976f9eef4f9
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date:   Thu, 19 Mar 2026 00:05:56 -0300

Agregar tarea `task_menu` y archivos `display.*`

Diffstat:
Mfirmware/.cproject | 1+
Mfirmware/Core/Inc/main.h | 12++++++++++++
Mfirmware/Core/Src/main.c | 29++++++++++++++++++++++++++++-
Afirmware/app/inc/display.h | 28++++++++++++++++++++++++++++
Mfirmware/app/inc/task_buttons.h | 1+
Afirmware/app/inc/task_menu.h | 27+++++++++++++++++++++++++++
Afirmware/app/inc/task_menu_attribute.h | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afirmware/app/inc/task_menu_interface.h | 25+++++++++++++++++++++++++
Mfirmware/app/inc/task_system_attribute.h | 10+++++++++-
Mfirmware/app/src/app.c | 6+++++-
Afirmware/app/src/display.c | 346+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfirmware/app/src/task_buttons.c | 40++++++++++++++++++----------------------
Afirmware/app/src/task_menu.c | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afirmware/app/src/task_menu_interface.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfirmware/app/src/task_system.c | 4----
Mfirmware/app/src/task_system_interface.c | 138+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mfirmware/tdse-tf_3-02.ioc | 62++++++++++++++++++++++++++++++++++++++++++++++++++------------
17 files changed, 935 insertions(+), 107 deletions(-)
diff --git a/firmware/.cproject b/firmware/.cproject
@@ -337,4 +337,5 @@
             <autodiscovery enabled="false" problemReportingEnabled="true" selectedProfileId=""/>
         </scannerConfigBuildInfo>
     </storageModule>
+    <storageModule moduleId="refreshScope"/>
 </cproject>
 \ No newline at end of file
diff --git a/firmware/Core/Inc/main.h b/firmware/Core/Inc/main.h
@@ -67,8 +67,14 @@ void Error_Handler(void);
 #define USART_RX_GPIO_Port GPIOA
 #define LD2_Pin GPIO_PIN_5
 #define LD2_GPIO_Port GPIOA
+#define D7_Pin GPIO_PIN_6
+#define D7_GPIO_Port GPIOA
+#define D6_Pin GPIO_PIN_7
+#define D6_GPIO_Port GPIOA
 #define BTN_B_Pin GPIO_PIN_10
 #define BTN_B_GPIO_Port GPIOB
+#define D4_Pin GPIO_PIN_7
+#define D4_GPIO_Port GPIOC
 #define BUZZER_Pin GPIO_PIN_8
 #define BUZZER_GPIO_Port GPIOA
 #define TMS_Pin GPIO_PIN_13
@@ -81,6 +87,12 @@ void Error_Handler(void);
 #define BTN_C_GPIO_Port GPIOB
 #define BTN_D_Pin GPIO_PIN_5
 #define BTN_D_GPIO_Port GPIOB
+#define D5_Pin GPIO_PIN_6
+#define D5_GPIO_Port GPIOB
+#define D9_Pin GPIO_PIN_8
+#define D9_GPIO_Port GPIOB
+#define D8_Pin GPIO_PIN_9
+#define D8_GPIO_Port GPIOB
 
 /* USER CODE BEGIN Private defines */
 
diff --git a/firmware/Core/Src/main.c b/firmware/Core/Src/main.c
@@ -273,7 +273,13 @@ static void MX_GPIO_Init(void)
   __HAL_RCC_GPIOB_CLK_ENABLE();
 
   /*Configure GPIO pin Output Level */
-  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
+  HAL_GPIO_WritePin(GPIOA, LD2_Pin|D7_Pin|D6_Pin, GPIO_PIN_RESET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(D4_GPIO_Port, D4_Pin, GPIO_PIN_RESET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(GPIOB, D5_Pin|D9_Pin|D8_Pin, GPIO_PIN_RESET);
 
   /*Configure GPIO pin : B1_Pin */
   GPIO_InitStruct.Pin = B1_Pin;
@@ -288,18 +294,39 @@ static void MX_GPIO_Init(void)
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
   HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
 
+  /*Configure GPIO pins : D7_Pin D6_Pin */
+  GPIO_InitStruct.Pin = D7_Pin|D6_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_PULLUP;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
   /*Configure GPIO pins : BTN_B_Pin BTN_C_Pin BTN_D_Pin */
   GPIO_InitStruct.Pin = BTN_B_Pin|BTN_C_Pin|BTN_D_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
   GPIO_InitStruct.Pull = GPIO_PULLUP;
   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
+  /*Configure GPIO pin : D4_Pin */
+  GPIO_InitStruct.Pin = D4_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_PULLUP;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(D4_GPIO_Port, &GPIO_InitStruct);
+
   /*Configure GPIO pin : BUZZER_Pin */
   GPIO_InitStruct.Pin = BUZZER_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   HAL_GPIO_Init(BUZZER_GPIO_Port, &GPIO_InitStruct);
 
+  /*Configure GPIO pins : D5_Pin D9_Pin D8_Pin */
+  GPIO_InitStruct.Pin = D5_Pin|D9_Pin|D8_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_PULLUP;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
   /* EXTI interrupt init*/
   HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
   HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
diff --git a/firmware/app/inc/display.h b/firmware/app/inc/display.h
@@ -0,0 +1,28 @@
+#ifndef _DISPLAY_H_
+#define _DISPLAY_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+     DISPLAY_CONNECTION_GPIO_4BITS,
+     DISPLAY_CONNECTION_GPIO_8BITS,
+} display_connection_t;
+
+typedef struct {
+   display_connection_t connection;
+} display_t;
+
+void display_init(display_connection_t connection);
+void display_set_cursor_pos(uint8_t x, uint8_t y);
+void display_write_string(const char * str);
+void display_clear(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DISPLAY_H_ */
diff --git a/firmware/app/inc/task_buttons.h b/firmware/app/inc/task_buttons.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
  * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
+ * All rights reserved
  *
  * See file `LICENSE` for full details
  */
diff --git a/firmware/app/inc/task_menu.h b/firmware/app/inc/task_menu.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
+ * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
+ *
+ * All rights reserved
+ *
+ * See file `LICENSE` for full details
+ */
+
+#ifndef TASK_INC_TASK_MENU_H_
+#define TASK_INC_TASK_MENU_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint32_t g_task_menu_cnt;
+extern volatile uint32_t g_task_menu_tick_cnt;
+
+extern void task_menu_init(void *parameters);
+extern void task_menu_update(void *parameters);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TASK_INC_TASK_MENU_H_ */
diff --git a/firmware/app/inc/task_menu_attribute.h b/firmware/app/inc/task_menu_attribute.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
+ * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
+ *
+ * All rights reserved
+ *
+ * See file `LICENSE` for full details
+ */
+
+#ifndef TASK_INC_TASK_MENU_ATTRIBUTE_H_
+#define TASK_INC_TASK_MENU_ATTRIBUTE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+* Menu Statechart - State Transition Table
+* 
+* +----------------+-------+---------+-------------+---------+
+* | Current State  | Event | [Guard] | Next State  | Actions |
+* +----------------+-------+---------+-------------+---------+
+* |                |       |         |             |         |
+* | ST_MEN_IDLE    |       |         | ST_MEN_IDLE |         |
+* |                |       |         |             |         |
+* +----------------+-------+---------+-------------+---------+
+*/
+
+/* Events to excite Task Menu */
+typedef enum {
+    EV_MEN_ENT_IDLE,
+    EV_MEN_ENT_ACTIVE,
+    EV_MEN_NEX_IDLE,
+    EV_MEN_NEX_ACTIVE,
+    EV_MEN_ESC_IDLE,
+    EV_MEN_ESC_ACTIVE,
+    EV_MEN_INACTIVE_TIMEOUT
+} task_menu_ev_t;
+
+/* State of Task Menu */
+typedef enum {
+    ST_MEN_IDLE,
+} task_menu_st_t;
+
+typedef struct {
+    uint32_t tick;
+    task_menu_st_t state;
+    task_menu_ev_t event;
+    bool event_flag;
+} task_menu_dta_t;
+
+extern task_menu_dta_t task_menu_dta;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TASK_INC_TASK_MENU_ATTRIBUTE_H_ */
diff --git a/firmware/app/inc/task_menu_interface.h b/firmware/app/inc/task_menu_interface.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
+ * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
+ * All rights reserved
+ *
+ * See file `LICENSE` for full details
+ */
+
+#ifndef TASK_INC_TASK_MENU_INTERFACE_H_
+#define TASK_INC_TASK_MENU_INTERFACE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void init_queue_event_task_menu(void);
+extern void put_event_task_menu(task_menu_ev_t event);
+extern task_menu_ev_t get_event_task_menu(void);
+extern bool any_event_task_menu(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TASK_INC_TASK_MENU_INTERFACE_H_ */
diff --git a/firmware/app/inc/task_system_attribute.h b/firmware/app/inc/task_system_attribute.h
@@ -28,7 +28,15 @@ extern "C" {
  */
 
 typedef enum task_system_ev {
-    EV_SYS_IDLE
+    EV_SYS_IDLE,
+    EV_SYS_BTN_A_IDLE,
+    EV_SYS_BTN_A_ACTIVE,
+    EV_SYS_BTN_B_IDLE,
+    EV_SYS_BTN_B_ACTIVE,
+    EV_SYS_BTN_C_IDLE,
+    EV_SYS_BTN_C_ACTIVE,
+    EV_SYS_BTN_D_IDLE,
+    EV_SYS_BTN_D_ACTIVE,
 } task_system_ev_t;
 
 typedef enum task_system_st {
diff --git a/firmware/app/src/app.c b/firmware/app/src/app.c
@@ -15,6 +15,7 @@
 #include "task_actuator.h"
 #include "task_temp_sensor.h"
 #include "task_buttons.h"
+#include "task_menu.h"
 
 #define G_APP_CNT_INI       0ul
 #define G_APP_TICK_CNT_INI  0ul
@@ -37,7 +38,8 @@ const task_cfg_t task_cfg_list[] = {
     {task_buttons_init,     task_buttons_update,     NULL},
     {task_temp_sensor_init, task_temp_sensor_update, NULL},
     {task_system_init,      task_system_update,      NULL},
-    {task_actuator_init,    task_actuator_update,    NULL}
+    {task_actuator_init,    task_actuator_update,    NULL},
+    {task_menu_init,        task_menu_update,        NULL}
 };
 
 #define TASK_QTY (sizeof(task_cfg_list)/sizeof(task_cfg_t))
@@ -132,8 +134,10 @@ void app_update(void)
 void HAL_SYSTICK_Callback(void)
 {
     g_app_tick_cnt++;
+
     g_task_buttons_tick_cnt++;
     g_task_temp_sensor_tick_cnt++;
     g_task_system_tick_cnt++;
     g_task_actuator_tick_cnt++;
+    g_task_menu_tick_cnt++;
 }
diff --git a/firmware/app/src/display.c b/firmware/app/src/display.c
@@ -0,0 +1,346 @@
+#include "display.h"
+#include "main.h"
+#include <stdbool.h>
+
+// Demo includes
+#include "logger.h"
+#include "dwt.h"
+#include "systick.h"
+
+// Functional states
+#ifndef OFF
+#define OFF    0
+#endif
+#ifndef ON
+#define ON     (!OFF)
+#endif
+
+// Electrical states
+#ifndef LOW
+#define LOW    0
+#endif
+#ifndef HIGH
+#define HIGH   (!LOW)
+#endif
+
+#define DISPLAY_IR_CLEAR_DISPLAY   0b00000001
+#define DISPLAY_IR_SET_CURSOR_HOME 0b00000010
+#define DISPLAY_IR_ENTRY_MODE_SET  0b00000100
+#define DISPLAY_IR_DISPLAY_CONTROL 0b00001000
+#define DISPLAY_IR_FUNCTION_SET    0b00100000
+#define DISPLAY_IR_SET_DDRAM_ADDR  0b10000000
+
+#define DISPLAY_IR_ENTRY_MODE_SET_INCREMENT 0b00000010
+#define DISPLAY_IR_ENTRY_MODE_SET_DECREMENT 0b00000000
+#define DISPLAY_IR_ENTRY_MODE_SET_SHIFT     0b00000001
+#define DISPLAY_IR_ENTRY_MODE_SET_NO_SHIFT  0b00000000
+
+#define DISPLAY_IR_DISPLAY_CONTROL_DISPLAY_ON  0b00000100
+#define DISPLAY_IR_DISPLAY_CONTROL_DISPLAY_OFF 0b00000000
+#define DISPLAY_IR_DISPLAY_CONTROL_CURSOR_ON   0b00000010
+#define DISPLAY_IR_DISPLAY_CONTROL_CURSOR_OFF  0b00000000
+#define DISPLAY_IR_DISPLAY_CONTROL_BLINK_ON    0b00000001
+#define DISPLAY_IR_DISPLAY_CONTROL_BLINK_OFF   0b00000000
+
+#define DISPLAY_IR_FUNCTION_SET_8BITS    0b00010000
+#define DISPLAY_IR_FUNCTION_SET_4BITS    0b00000000
+#define DISPLAY_IR_FUNCTION_SET_2LINES   0b00001000
+#define DISPLAY_IR_FUNCTION_SET_1LINE    0b00000000
+#define DISPLAY_IR_FUNCTION_SET_5x10DOTS 0b00000100
+#define DISPLAY_IR_FUNCTION_SET_5x8DOTS  0b00000000
+
+#define DISPLAY_20x4_LINE1_FIRST_CHARACTER_ADDRESS 0
+#define DISPLAY_20x4_LINE2_FIRST_CHARACTER_ADDRESS 64
+#define DISPLAY_20x4_LINE3_FIRST_CHARACTER_ADDRESS 20
+#define DISPLAY_20x4_LINE4_FIRST_CHARACTER_ADDRESS 84
+
+#define DISPLAY_RS_INSTRUCTION 0
+#define DISPLAY_RS_DATA        1
+
+#define DISPLAY_RW_WRITE 0
+#define DISPLAY_RW_READ  1
+
+#define DISPLAY_PIN_RS  4
+#define DISPLAY_PIN_RW  5
+#define DISPLAY_PIN_EN  6
+#define DISPLAY_PIN_D0  7
+#define DISPLAY_PIN_D1  8
+#define DISPLAY_PIN_D2  9
+#define DISPLAY_PIN_D3 10
+#define DISPLAY_PIN_D4 11
+#define DISPLAY_PIN_D5 12
+#define DISPLAY_PIN_D6 13
+#define DISPLAY_PIN_D7 14
+
+#define DISPLAY_DEL_37US 37ul
+#define DISPLAY_DEL_US 5ul
+
+static display_t display;
+static bool initial_comm_completed;
+
+// Private functions declaration
+static void display_pin_write(uint8_t pin_name, int value);
+static void display_data_bus_write(uint8_t byte);
+static void display_code_write(bool type, uint8_t data_bus);
+
+// Public functions definition
+void display_init(display_connection_t connection)
+{
+    display.connection = connection;
+
+    initial_comm_completed = false;
+
+    HAL_Delay(50);
+
+    display_code_write(DISPLAY_RS_INSTRUCTION,
+                      DISPLAY_IR_FUNCTION_SET |
+                      DISPLAY_IR_FUNCTION_SET_8BITS);
+    HAL_Delay(5);
+
+    display_code_write(DISPLAY_RS_INSTRUCTION,
+                      DISPLAY_IR_FUNCTION_SET |
+                      DISPLAY_IR_FUNCTION_SET_8BITS);
+    HAL_Delay(1);
+
+    display_code_write(DISPLAY_RS_INSTRUCTION,
+                      DISPLAY_IR_FUNCTION_SET |
+                      DISPLAY_IR_FUNCTION_SET_8BITS);
+    HAL_Delay(1);
+
+    switch(display.connection) {
+        case DISPLAY_CONNECTION_GPIO_8BITS:
+            display_code_write(DISPLAY_RS_INSTRUCTION,
+                               DISPLAY_IR_FUNCTION_SET |
+                               DISPLAY_IR_FUNCTION_SET_8BITS |
+                               DISPLAY_IR_FUNCTION_SET_2LINES |
+                               DISPLAY_IR_FUNCTION_SET_5x8DOTS);
+            HAL_Delay(1);
+        break;
+
+        case DISPLAY_CONNECTION_GPIO_4BITS:
+            display_code_write(DISPLAY_RS_INSTRUCTION,
+                               DISPLAY_IR_FUNCTION_SET |
+                               DISPLAY_IR_FUNCTION_SET_4BITS);
+            HAL_Delay(1);
+
+            initial_comm_completed = true;
+
+            display_code_write(DISPLAY_RS_INSTRUCTION,
+                               DISPLAY_IR_FUNCTION_SET |
+                               DISPLAY_IR_FUNCTION_SET_4BITS |
+                               DISPLAY_IR_FUNCTION_SET_2LINES |
+                               DISPLAY_IR_FUNCTION_SET_5x8DOTS);
+            HAL_Delay(1);
+        break;
+    }
+
+    display_code_write(DISPLAY_RS_INSTRUCTION,
+                       DISPLAY_IR_DISPLAY_CONTROL |
+                       DISPLAY_IR_DISPLAY_CONTROL_DISPLAY_OFF |
+                       DISPLAY_IR_DISPLAY_CONTROL_CURSOR_OFF |
+                       DISPLAY_IR_DISPLAY_CONTROL_BLINK_OFF);
+    HAL_Delay(1);
+
+    display_code_write(DISPLAY_RS_INSTRUCTION,
+                       DISPLAY_IR_CLEAR_DISPLAY);
+    HAL_Delay(1);
+
+    display_code_write(DISPLAY_RS_INSTRUCTION,
+                       DISPLAY_IR_ENTRY_MODE_SET |
+                       DISPLAY_IR_ENTRY_MODE_SET_INCREMENT |
+                       DISPLAY_IR_ENTRY_MODE_SET_NO_SHIFT);
+    HAL_Delay(1);
+
+    display_code_write(DISPLAY_RS_INSTRUCTION,
+                       DISPLAY_IR_DISPLAY_CONTROL |
+                       DISPLAY_IR_DISPLAY_CONTROL_DISPLAY_ON |
+                       DISPLAY_IR_DISPLAY_CONTROL_CURSOR_OFF |
+                       DISPLAY_IR_DISPLAY_CONTROL_BLINK_OFF);
+    HAL_Delay(1);
+}
+
+void display_clear(void)
+{
+    display_code_write(DISPLAY_RS_INSTRUCTION, DISPLAY_IR_CLEAR_DISPLAY);
+
+    HAL_Delay(1);
+}
+
+void display_set_cursor_pos(uint8_t x, uint8_t y)
+{
+    switch(y) {
+        case 0:
+            display_code_write(DISPLAY_RS_INSTRUCTION,
+                             DISPLAY_IR_SET_DDRAM_ADDR |
+                             (DISPLAY_20x4_LINE1_FIRST_CHARACTER_ADDRESS + x));
+            //HAL_Delay(1);
+        break;
+
+        case 1:
+            display_code_write(DISPLAY_RS_INSTRUCTION,
+                             DISPLAY_IR_SET_DDRAM_ADDR |
+                             (DISPLAY_20x4_LINE2_FIRST_CHARACTER_ADDRESS + x));
+            //HAL_Delay(1);
+        break;
+
+        case 2:
+            display_code_write(DISPLAY_RS_INSTRUCTION,
+                              DISPLAY_IR_SET_DDRAM_ADDR |
+                              (DISPLAY_20x4_LINE3_FIRST_CHARACTER_ADDRESS + x));
+            //HAL_Delay(1);
+        break;
+
+        case 3:
+            display_code_write(DISPLAY_RS_INSTRUCTION,
+                             DISPLAY_IR_SET_DDRAM_ADDR |
+                             (DISPLAY_20x4_LINE4_FIRST_CHARACTER_ADDRESS + x));
+            //HAL_Delay(1);
+        break;
+    }
+}
+
+void display_write_string(const char *str)
+{
+    while (*str) {
+        display_code_write(DISPLAY_RS_DATA, *str++);
+    }
+}
+
+// Private functions definitions
+static void display_code_write( bool type, uint8_t data_bus )
+{
+    if (type == DISPLAY_RS_INSTRUCTION)
+    {
+        display_pin_write(DISPLAY_PIN_RS, DISPLAY_RS_INSTRUCTION);
+    }
+    else
+    {
+        display_pin_write(DISPLAY_PIN_RS, DISPLAY_RS_DATA);
+    }
+
+    display_pin_write(DISPLAY_PIN_RW, DISPLAY_RW_WRITE);
+    display_data_bus_write(data_bus);
+    systick_delay_us(DISPLAY_DEL_37US);
+}
+
+static void display_pin_write(uint8_t pin_name, int value)
+{
+    switch(display.connection)
+    {
+        /*
+        case DISPLAY_CONNECTION_GPIO_8BITS:
+            switch(pin_name)
+            {
+                case DISPLAY_PIN_D0:
+                    HAL_GPIO_WritePin(D0_GPIO_Port, D0_Pin, value);
+                break;
+                case DISPLAY_PIN_D1:
+                    HAL_GPIO_WritePin(D1_GPIO_Port, D1_Pin, value);
+                break;
+                case DISPLAY_PIN_D2:
+                    HAL_GPIO_WritePin(D2_GPIO_Port, D2_Pin, value);
+                break;
+                case DISPLAY_PIN_D3:
+                    HAL_GPIO_WritePin(D3_GPIO_Port, D3_Pin, value);
+                break;
+                case DISPLAY_PIN_D4:
+                    HAL_GPIO_WritePin(D4_GPIO_Port, D4_Pin, value);
+                break;
+                case DISPLAY_PIN_D5:
+                    HAL_GPIO_WritePin(D5_GPIO_Port, D5_Pin, value);
+                break;
+                case DISPLAY_PIN_D6:
+                    HAL_GPIO_WritePin(D6_GPIO_Port, D6_Pin, value);
+                break;
+                case DISPLAY_PIN_D7:
+                    HAL_GPIO_WritePin(D7_GPIO_Port, D7_Pin, value);
+                break;
+                case DISPLAY_PIN_RS:
+                    HAL_GPIO_WritePin(D8_GPIO_Port, D8_Pin, value);
+                break;
+                case DISPLAY_PIN_EN:
+                    HAL_GPIO_WritePin(D9_GPIO_Port, D9_Pin, value);
+                break;
+                case DISPLAY_PIN_RW:
+                default: 
+                break;
+            }
+        break;
+        */
+
+        case DISPLAY_CONNECTION_GPIO_4BITS:
+            switch(pin_name)
+            {
+                case DISPLAY_PIN_D4: 
+                    HAL_GPIO_WritePin(D4_GPIO_Port, D4_Pin, value);
+                break;
+                case DISPLAY_PIN_D5:
+                    HAL_GPIO_WritePin(D5_GPIO_Port, D5_Pin, value);
+                break;
+                case DISPLAY_PIN_D6:
+                    HAL_GPIO_WritePin(D6_GPIO_Port, D6_Pin, value);
+                break;
+                case DISPLAY_PIN_D7:
+                    HAL_GPIO_WritePin(D7_GPIO_Port, D7_Pin, value);
+                break;
+                case DISPLAY_PIN_RS:
+                    HAL_GPIO_WritePin(D8_GPIO_Port, D8_Pin, value);
+                break;
+                case DISPLAY_PIN_EN:
+                    HAL_GPIO_WritePin(D9_GPIO_Port, D9_Pin, value);
+                break;
+
+                case DISPLAY_PIN_RW:
+                default:
+                break;
+            }
+        default:
+        break;
+    }
+}
+
+static void display_data_bus_write(uint8_t data_bus)
+{
+    display_pin_write(DISPLAY_PIN_EN, OFF);
+    display_pin_write(DISPLAY_PIN_D7, data_bus & 0b10000000);
+    display_pin_write(DISPLAY_PIN_D6, data_bus & 0b01000000);
+    display_pin_write(DISPLAY_PIN_D5, data_bus & 0b00100000);
+    display_pin_write(DISPLAY_PIN_D4, data_bus & 0b00010000);
+
+    switch(display.connection) 
+    {
+        case DISPLAY_CONNECTION_GPIO_8BITS:
+            display_pin_write(DISPLAY_PIN_D3, data_bus & 0b00001000);
+            display_pin_write(DISPLAY_PIN_D2, data_bus & 0b00000100);
+            display_pin_write(DISPLAY_PIN_D1, data_bus & 0b00000010);
+            display_pin_write(DISPLAY_PIN_D0, data_bus & 0b00000001);
+        break;
+
+        case DISPLAY_CONNECTION_GPIO_4BITS:
+            if (true == initial_comm_completed)
+            {
+                display_pin_write(DISPLAY_PIN_EN, ON);
+                //HAL_Delay(1);
+                systick_delay_us(DISPLAY_DEL_US);
+
+                display_pin_write(DISPLAY_PIN_EN, OFF);
+                //HAL_Delay(1);
+                systick_delay_us(DISPLAY_DEL_US);
+
+                display_pin_write(DISPLAY_PIN_D7, data_bus & 0b00001000);
+                display_pin_write(DISPLAY_PIN_D6, data_bus & 0b00000100);
+                display_pin_write(DISPLAY_PIN_D5, data_bus & 0b00000010);
+                display_pin_write(DISPLAY_PIN_D4, data_bus & 0b00000001);
+            }
+        default:
+        break;
+    }
+
+    display_pin_write(DISPLAY_PIN_EN, ON);
+    //HAL_Delay(1);
+    systick_delay_us(DISPLAY_DEL_US);
+
+    display_pin_write(DISPLAY_PIN_EN, OFF);
+    //HAL_Delay(1);
+    systick_delay_us(DISPLAY_DEL_US);
+}
diff --git a/firmware/app/src/task_buttons.c b/firmware/app/src/task_buttons.c
@@ -15,6 +15,8 @@
 #include "task_buttons_attribute.h"
 #include "task_system_attribute.h"
 #include "task_system_interface.h"
+#include "task_menu_attribute.h"
+#include "task_menu_interface.h"
 
 #define G_TASK_SEN_TICK_CNT_INI   0ul
 
@@ -23,10 +25,10 @@
 #define DEL_BTN_XX_MAX          50ul
 
 const task_buttons_cfg_t task_buttons_cfg_list[] = {
-    {ID_BTN_A, BTN_A_GPIO_Port, BTN_A_Pin, BTN_A_PRESSED, DEL_BTN_XX_MAX, EV_SYS_IDLE, EV_SYS_IDLE},
-    {ID_BTN_B, BTN_B_GPIO_Port, BTN_B_Pin, BTN_A_PRESSED, DEL_BTN_XX_MAX, EV_SYS_IDLE, EV_SYS_IDLE},
-    {ID_BTN_C, BTN_C_GPIO_Port, BTN_C_Pin, BTN_A_PRESSED, DEL_BTN_XX_MAX, EV_SYS_IDLE, EV_SYS_IDLE},
-    {ID_BTN_D, BTN_D_GPIO_Port, BTN_D_Pin, BTN_A_PRESSED, DEL_BTN_XX_MAX, EV_SYS_IDLE, EV_SYS_IDLE},
+    {ID_BTN_A, BTN_A_GPIO_Port, BTN_A_Pin, BTN_A_PRESSED, DEL_BTN_XX_MAX, EV_MEN_ENT_ACTIVE, EV_MEN_ENT_IDLE},
+    {ID_BTN_B, BTN_B_GPIO_Port, BTN_B_Pin, BTN_A_PRESSED, DEL_BTN_XX_MAX, EV_MEN_ENT_ACTIVE, EV_MEN_ENT_IDLE},
+    {ID_BTN_C, BTN_C_GPIO_Port, BTN_C_Pin, BTN_A_PRESSED, DEL_BTN_XX_MAX, EV_MEN_NEX_ACTIVE, EV_MEN_NEX_IDLE},
+    {ID_BTN_D, BTN_D_GPIO_Port, BTN_D_Pin, BTN_A_PRESSED, DEL_BTN_XX_MAX, EV_MEN_ESC_ACTIVE, EV_MEN_ESC_IDLE},
 };
 
 #define BUTTONS_CFG_QTY (sizeof(task_buttons_cfg_list)/sizeof(task_buttons_cfg_t))
@@ -43,18 +45,20 @@ task_buttons_dta_t task_buttons_dta_list[] = {
 // this variable is incremented by 1 on every ms by HAL_SysTick
 volatile uint32_t g_task_buttons_tick_cnt;
 
+// Private functions declaration
+void task_buttons_statechart(void);
+
 void task_buttons_init(void *parameters)
 {
-    const task_buttons_cfg_t *p_task_buttons_cfg;
     task_buttons_dta_t *p_task_buttons_dta;
 
     LOGGER_INFO("Initializing `task_buttons`...");
 
     for (uint32_t index = 0; BUTTONS_DTA_QTY > index; index++)
     {
-        p_task_buttons_cfg = &task_buttons_cfg_list[index];
         p_task_buttons_dta = &task_buttons_dta_list[index];
 
+        p_task_buttons_dta->tick = DEL_BTN_XX_MIN;
         p_task_buttons_dta->state = ST_BTN_XX_UP;
         p_task_buttons_dta->event = EV_BTN_XX_UP;
     }
@@ -64,9 +68,6 @@ void task_buttons_init(void *parameters)
 
 void task_buttons_update(void *parameters)
 {
-    const task_buttons_cfg_t *p_task_buttons_cfg;
-    task_buttons_dta_t *p_task_buttons_dta;
-
     bool b_time_update_required = false;
 
     __asm("CPSID i");
@@ -135,9 +136,8 @@ void task_buttons_statechart(void)
                     if (0 == p_task_buttons_dta->tick) {
                         p_task_buttons_dta->state = ST_BTN_XX_UP;
                     }
-
-                    if (p_task_buttons_dta->tick > 0) {
-                        p_task_buttons_dta->state = ST_BTN_XX_FALLING;
+                    else
+                    {
                         p_task_buttons_dta->tick--;
                     }
                 }
@@ -146,10 +146,10 @@ void task_buttons_statechart(void)
                 {
                     if (0 == p_task_buttons_dta->tick) {
                         p_task_buttons_dta->state = ST_BTN_XX_DOWN;
-                        put_event_task_system(p_task_buttons_cfg->signal_down);
+                        put_event_task_menu(p_task_buttons_cfg->signal_down);
                     }
-
-                    if (p_task_buttons_dta->tick > 0) {
+                    else
+                    {
                         p_task_buttons_dta->tick--;
                     }
                 }
@@ -167,11 +167,11 @@ void task_buttons_statechart(void)
                 if (EV_BTN_XX_UP == p_task_buttons_dta->event)
                 {
                     if (0 == p_task_buttons_dta->tick) {
-                        put_event_task_system(p_task_buttons_cfg->signal_up);
+                        put_event_task_menu(p_task_buttons_cfg->signal_up);
                         p_task_buttons_dta->state = ST_BTN_XX_UP;
                     }
-
-                    if (p_task_buttons_dta->tick > 0) {
+                    else
+                    {
                         p_task_buttons_dta->tick--;
                     }
                 }
@@ -181,13 +181,9 @@ void task_buttons_statechart(void)
                     if (0 == p_task_buttons_dta->tick) {
                         p_task_buttons_dta->state = ST_BTN_XX_DOWN;
                     }
-
-                    if (p_task_buttons_dta->tick > 0) {
                         p_task_buttons_dta->tick--;
                     }
-                }
             break;
-
             default: break;
         }
     }
diff --git a/firmware/app/src/task_menu.c b/firmware/app/src/task_menu.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
+ * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
+ *
+ * All rights reserved
+ *
+ * See file `LICENSE` for full details
+ */
+
+#include "main.h"
+
+#include "logger.h"
+#include "dwt.h"
+
+#include "board.h"
+#include "app.h"
+#include "task_menu_attribute.h"
+#include "task_menu_interface.h"
+#include "display.h"
+
+#define G_TASK_MEN_CNT_INI        0ul
+#define G_TASK_MEN_TICK_CNT_INI   0ul
+#define DEL_MEN_XX_MIN            0ul
+
+task_menu_dta_t task_menu_dta = {
+    DEL_MEN_XX_MIN, ST_MEN_IDLE, EV_MEN_ENT_IDLE, false
+};
+
+#define MENU_DTA_QTY (sizeof(task_menu_dta)/sizeof(task_menu_dta_t))
+
+typedef struct {
+    bool power, spin;
+    uint8_t speed;
+} motor_data_t;
+
+// Private functions declaration
+void task_menu_statechart(void);
+
+// Private variables
+bool g_display_update = false;
+task_menu_st_t g_menu_prev_state;
+
+// Public variables
+uint32_t g_task_menu_cnt;
+volatile uint32_t g_task_menu_tick_cnt;
+
+// Public functions
+void task_menu_init(void *parameters)
+{
+    task_menu_dta_t *p_task_menu_dta;
+    task_menu_st_t state;
+    task_menu_ev_t event;
+
+    LOGGER_INFO("Initializing `task_menu`...");
+
+    g_task_menu_cnt = G_TASK_MEN_CNT_INI;
+
+    init_queue_event_task_menu();
+
+    p_task_menu_dta = &task_menu_dta;
+
+    state = ST_MEN_IDLE;
+    p_task_menu_dta->state = state;
+    g_menu_prev_state = state;
+
+    p_task_menu_dta->event = EV_MEN_ENT_IDLE;
+    p_task_menu_dta->event_flag = false;
+
+    display_init(DISPLAY_CONNECTION_GPIO_4BITS);
+    g_display_update = true;
+
+    LOGGER_INFO("Done initializing `task_menu`");
+}
+
+void task_menu_update(void *parameters)
+{
+    bool b_time_update_required = false;
+
+    __asm("CPSID i");
+    if (G_TASK_MEN_TICK_CNT_INI < g_task_menu_tick_cnt)
+    {
+        /* Update Tick Counter */
+        g_task_menu_tick_cnt--;
+        b_time_update_required = true;
+    }
+    __asm("CPSIE i");
+
+    while (b_time_update_required)
+    {
+        g_task_menu_cnt++;
+
+        task_menu_statechart();
+
+        __asm("CPSID i");
+        if (G_TASK_MEN_TICK_CNT_INI < g_task_menu_tick_cnt)
+        {
+            g_task_menu_tick_cnt--;
+            b_time_update_required = true;
+        }
+        else
+        {
+            b_time_update_required = false;
+        }
+        __asm("CPSIE i");
+    }
+}
+
+void menu_set_state(task_menu_st_t new_state)
+{
+    task_menu_dta_t *p_task_menu_dta;
+    p_task_menu_dta = &task_menu_dta;
+
+    g_menu_prev_state = p_task_menu_dta->state;
+    p_task_menu_dta->state = new_state;
+
+    g_display_update = true;
+}
+
+void task_menu_statechart(void)
+{
+    task_menu_dta_t *p_task_menu_dta;
+    char menu_row_str[16 + 4];
+
+    p_task_menu_dta = &task_menu_dta;
+
+    if (true == any_event_task_menu())
+    {
+        p_task_menu_dta->event_flag = true;
+        p_task_menu_dta->event = get_event_task_menu();
+    }
+
+
+    if ((true == p_task_menu_dta->event_flag)
+        && (p_task_menu_dta->event == EV_MEN_INACTIVE_TIMEOUT)
+        && (p_task_menu_dta->state != ST_MEN_IDLE))
+    {
+        menu_set_state(ST_MEN_IDLE);
+    }
+
+    switch (p_task_menu_dta->state)
+    {
+        case ST_MEN_IDLE:
+
+            if (g_display_update)
+            {
+                g_display_update = false;
+                display_clear();
+                sprintf(menu_row_str, "Hello%cC", 0xDF);
+                display_write_string(menu_row_str);
+            }
+
+            if (true == p_task_menu_dta->event_flag)
+            {
+                p_task_menu_dta->event_flag = false;
+                switch (p_task_menu_dta->event)
+                {
+                    case EV_MEN_ENT_ACTIVE:
+                    case EV_MEN_NEX_ACTIVE:
+                    case EV_MEN_ESC_ACTIVE:
+                        menu_set_state(ST_MEN_IDLE);
+                        break;
+                    default:
+                    break;
+                }
+            }
+
+        break;
+
+        default:
+
+            p_task_menu_dta->tick  = DEL_MEN_XX_MIN;
+            p_task_menu_dta->state = ST_MEN_IDLE;
+            p_task_menu_dta->event = EV_MEN_ENT_IDLE;
+            p_task_menu_dta->event_flag  = false;
+            g_display_update = false;
+
+            break;
+    }
+}
diff --git a/firmware/app/src/task_menu_interface.c b/firmware/app/src/task_menu_interface.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
+ * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
+ *
+ * All rights reserved
+ *
+ * See file `LICENSE` for full details
+ */
+
+/* Project includes */
+#include "main.h"
+
+/* Demo includes */
+#include "logger.h"
+#include "dwt.h"
+
+/* Application & Tasks includes */
+#include "board.h"
+#include "app.h"
+#include "task_menu_attribute.h"
+
+#define EVENT_UNDEFINED (255)
+#define MAX_EVENTS      (16)
+
+static struct
+{
+    uint32_t head;
+    uint32_t tail;
+    uint32_t count;
+    task_menu_ev_t queue[MAX_EVENTS];
+} task_menu_event_queue;
+
+// External functions definition
+void init_queue_event_task_menu(void)
+{
+    uint32_t i;
+
+    task_menu_event_queue.head = 0;
+    task_menu_event_queue.tail = 0;
+    task_menu_event_queue.count = 0;
+
+    for (i = 0; i < MAX_EVENTS; i++)
+        task_menu_event_queue.queue[i] = EVENT_UNDEFINED;
+}
+
+void put_event_task_menu(task_menu_ev_t event)
+{
+    task_menu_event_queue.count++;
+    task_menu_event_queue.queue[task_menu_event_queue.head++] = event;
+
+    if (MAX_EVENTS == task_menu_event_queue.head)
+    {
+        task_menu_event_queue.head = 0;
+    }
+}
+
+task_menu_ev_t get_event_task_menu(void)
+{
+    task_menu_ev_t event;
+
+    task_menu_event_queue.count--;
+    event = task_menu_event_queue.queue[task_menu_event_queue.tail];
+    task_menu_event_queue.queue[task_menu_event_queue.tail++] = EVENT_UNDEFINED;
+
+    if (MAX_EVENTS == task_menu_event_queue.tail)
+    {
+        task_menu_event_queue.tail = 0;
+    }
+
+    return event;
+}
+
+bool any_event_task_menu(void)
+{
+    return (task_menu_event_queue.head != task_menu_event_queue.tail);
+}
diff --git a/firmware/app/src/task_system.c b/firmware/app/src/task_system.c
@@ -91,15 +91,11 @@ void task_system_statechart(void)
 {
     task_system_dta_t *p_task_system_dta = &task_system_dta;
 
-    /*
-    // system events unused
-
     if (true == any_event_task_system())
     {
         p_task_system_dta->flag = true;
         p_task_system_dta->event = get_event_task_system();
     }
-    */
 
     switch (p_task_system_dta->state)
     {
diff --git a/firmware/app/src/task_system_interface.c b/firmware/app/src/task_system_interface.c
@@ -1,66 +1,72 @@
-/*
- * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
- * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
- *
- * See file `LICENSE` for full details
- */
-
-#include "main.h"
-
-#include "logger.h"
-#include "dwt.h"
-
-#include "board.h"
-#include "app.h"
-#include "task_system_attribute.h"
-
-#define EVENT_UNDEFINED (255)
-#define MAX_EVENTS      (16)
-
-struct
-{
-    uint32_t head;
-    uint32_t tail;
-    uint32_t count;
-    task_system_ev_t queue[MAX_EVENTS];
-} queue_task_a;
-
-void init_queue_event_task_system(void)
-{
-    uint32_t i;
-
-    queue_task_a.head = 0;
-    queue_task_a.tail = 0;
-    queue_task_a.count = 0;
-
-    for (i = 0; i < MAX_EVENTS; i++)
-        queue_task_a.queue[i] = EVENT_UNDEFINED;
-}
-
-void put_event_task_system(task_system_ev_t event)
-{
-    queue_task_a.count++;
-    queue_task_a.queue[queue_task_a.head++] = event;
-
-    if (MAX_EVENTS == queue_task_a.head)
-        queue_task_a.head = 0;
-}
-
-task_system_ev_t get_event_task_system(void)
-{
-    task_system_ev_t event;
-
-    queue_task_a.count--;
-    event = queue_task_a.queue[queue_task_a.tail];
-    queue_task_a.queue[queue_task_a.tail++] = EVENT_UNDEFINED;
-
-    if (MAX_EVENTS == queue_task_a.tail)
-        queue_task_a.tail = 0;
-
-    return event;
-}
-
-bool any_event_task_system(void)
-{
-    return (queue_task_a.head != queue_task_a.tail);
-}
+/*
+ * Copyright (c) 2023 Juan Manuel Cruz <jcruz@fi.uba.ar> <jcruz@frba.utn.edu.ar>.
+ * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
+ *
+ * See file `LICENSE` for full details
+ */
+
+#include "main.h"
+
+#include "logger.h"
+#include "dwt.h"
+
+#include "board.h"
+#include "app.h"
+#include "task_system_attribute.h"
+
+#define EVENT_UNDEFINED (255)
+#define MAX_EVENTS      (16)
+
+static struct
+{
+    uint32_t head;
+    uint32_t tail;
+    uint32_t count;
+    task_system_ev_t queue[MAX_EVENTS];
+} task_system_event_queue;
+
+void init_queue_event_task_system(void)
+{
+    uint32_t i;
+
+    task_system_event_queue.head = 0;
+    task_system_event_queue.tail = 0;
+    task_system_event_queue.count = 0;
+
+    for (i = 0; i < MAX_EVENTS; i++)
+    {
+        task_system_event_queue.queue[i] = EVENT_UNDEFINED;
+    }
+}
+
+void put_event_task_system(task_system_ev_t event)
+{
+    task_system_event_queue.count++;
+    task_system_event_queue.queue[task_system_event_queue.head++] = event;
+
+    if (MAX_EVENTS == task_system_event_queue.head)
+    {
+        task_system_event_queue.head = 0;
+    }
+}
+
+task_system_ev_t get_event_task_system(void)
+{
+    task_system_ev_t event;
+
+    task_system_event_queue.count--;
+    event = task_system_event_queue.queue[task_system_event_queue.tail];
+    task_system_event_queue.queue[task_system_event_queue.tail++] = EVENT_UNDEFINED;
+
+    if (MAX_EVENTS == task_system_event_queue.tail)
+    {
+        task_system_event_queue.tail = 0;
+    }
+
+    return event;
+}
+
+bool any_event_task_system(void)
+{
+    return (task_system_event_queue.head != task_system_event_queue.tail);
+}
diff --git a/firmware/tdse-tf_3-02.ioc b/firmware/tdse-tf_3-02.ioc
@@ -38,22 +38,28 @@ Mcu.Name=STM32F103R(8-B)Tx
 Mcu.Package=LQFP64
 Mcu.Pin0=PC13-TAMPER-RTC
 Mcu.Pin1=PC14-OSC32_IN
-Mcu.Pin10=PA9
-Mcu.Pin11=PA13
-Mcu.Pin12=PA14
-Mcu.Pin13=PB3
-Mcu.Pin14=PB4
-Mcu.Pin15=PB5
-Mcu.Pin16=VP_SYS_VS_Systick
+Mcu.Pin10=PB10
+Mcu.Pin11=PC7
+Mcu.Pin12=PA8
+Mcu.Pin13=PA9
+Mcu.Pin14=PA13
+Mcu.Pin15=PA14
+Mcu.Pin16=PB3
+Mcu.Pin17=PB4
+Mcu.Pin18=PB5
+Mcu.Pin19=PB6
 Mcu.Pin2=PC15-OSC32_OUT
+Mcu.Pin20=PB8
+Mcu.Pin21=PB9
+Mcu.Pin22=VP_SYS_VS_Systick
 Mcu.Pin3=PD0-OSC_IN
 Mcu.Pin4=PD1-OSC_OUT
 Mcu.Pin5=PA2
 Mcu.Pin6=PA3
 Mcu.Pin7=PA5
-Mcu.Pin8=PB10
-Mcu.Pin9=PA8
-Mcu.PinsNb=17
+Mcu.Pin8=PA6
+Mcu.Pin9=PA7
+Mcu.PinsNb=23
 Mcu.ThirdPartyNb=0
 Mcu.UserConstants=
 Mcu.UserName=STM32F103RBTx
@@ -107,6 +113,16 @@ PA5.GPIO_PuPd=GPIO_NOPULL
 PA5.GPIO_Speed=GPIO_SPEED_FREQ_LOW
 PA5.Locked=true
 PA5.Signal=GPIO_Output
+PA6.GPIOParameters=GPIO_PuPd,GPIO_Label
+PA6.GPIO_Label=D7
+PA6.GPIO_PuPd=GPIO_PULLUP
+PA6.Locked=true
+PA6.Signal=GPIO_Output
+PA7.GPIOParameters=GPIO_PuPd,GPIO_Label
+PA7.GPIO_Label=D6
+PA7.GPIO_PuPd=GPIO_PULLUP
+PA7.Locked=true
+PA7.Signal=GPIO_Output
 PA8.GPIOParameters=GPIO_Label
 PA8.GPIO_Label=BUZZER
 PA8.Locked=true
@@ -132,6 +148,23 @@ PB5.GPIO_Label=BTN_D
 PB5.GPIO_PuPd=GPIO_PULLUP
 PB5.Locked=true
 PB5.Signal=GPIO_Input
+PB6.GPIOParameters=GPIO_PuPd,GPIO_Label
+PB6.GPIO_Label=D5
+PB6.GPIO_PuPd=GPIO_PULLUP
+PB6.Locked=true
+PB6.Signal=GPIO_Output
+PB8.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultOutputPP
+PB8.GPIO_Label=D9
+PB8.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PB8.GPIO_PuPd=GPIO_PULLUP
+PB8.Locked=true
+PB8.Signal=GPIO_Output
+PB9.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultOutputPP
+PB9.GPIO_Label=D8
+PB9.GPIO_ModeDefaultOutputPP=GPIO_MODE_OUTPUT_PP
+PB9.GPIO_PuPd=GPIO_PULLUP
+PB9.Locked=true
+PB9.Signal=GPIO_Output
 PC13-TAMPER-RTC.GPIOParameters=GPIO_PuPd,GPIO_Label
 PC13-TAMPER-RTC.GPIO_Label=B1 [Blue PushButton]
 PC13-TAMPER-RTC.GPIO_PuPd=GPIO_NOPULL
@@ -143,6 +176,11 @@ PC14-OSC32_IN.Signal=RCC_OSC32_IN
 PC15-OSC32_OUT.Locked=true
 PC15-OSC32_OUT.Mode=LSE-External-Oscillator
 PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
+PC7.GPIOParameters=GPIO_PuPd,GPIO_Label
+PC7.GPIO_Label=D4
+PC7.GPIO_PuPd=GPIO_PULLUP
+PC7.Locked=true
+PC7.Signal=GPIO_Output
 PD0-OSC_IN.Locked=true
 PD0-OSC_IN.Mode=HSE-External-Clock-Source
 PD0-OSC_IN.Signal=RCC_OSC_IN
@@ -171,8 +209,8 @@ ProjectManager.MainLocation=Core/Src
 ProjectManager.NoMain=false
 ProjectManager.PreviousToolchain=
 ProjectManager.ProjectBuild=false
-ProjectManager.ProjectFileName=tdse-tf_3-02_sensors.ioc
-ProjectManager.ProjectName=tdse-tf_3-02_sensors
+ProjectManager.ProjectFileName=tdse-tf_3-02.ioc
+ProjectManager.ProjectName=tdse-tf_3-02
 ProjectManager.ProjectStructure=
 ProjectManager.RegisterCallBack=
 ProjectManager.StackSize=0x400