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 3482a2cce4b4715c4c2bdf287152fa7f24bd5f07
parent fb48410853668478a318f34fb326e41320af08f4
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date:   Sun, 22 Mar 2026 12:24:46 -0300

Mover funciones `DS18B20_` de `task_temp_sensor.*` a archivos `ds18b20.*`

Diffstat:
Mfirmware/.cproject | 10+++++++++-
Mfirmware/Core/Inc/main.h | 2--
Mfirmware/Core/Src/main.c | 6------
Mfirmware/Core/Src/stm32f1xx_hal_msp.c | 4++--
Mfirmware/app/inc/app.h | 1-
Afirmware/app/inc/ds18b20.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfirmware/app/inc/task_menu_attribute.h | 1+
Mfirmware/app/inc/task_temp_sensor_attribute.h | 43+------------------------------------------
Mfirmware/app/src/app.c | 2--
Afirmware/app/src/ds18b20.c | 268+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mfirmware/app/src/task_menu.c | 67+++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mfirmware/app/src/task_temp_sensor.c | 273+------------------------------------------------------------------------------
Mfirmware/tdse-tf_3-02.ioc | 37++++++++++++++++++-------------------
13 files changed, 414 insertions(+), 365 deletions(-)
diff --git a/firmware/.cproject b/firmware/.cproject
@@ -23,6 +23,7 @@
                             <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board.1578684016" name="Board" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board" useByScannerDiscovery="false" value="NUCLEO-F103RB" valueType="string"/>
                             <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults.137200207" name="Defaults" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults" useByScannerDiscovery="false" value="com.st.stm32cube.ide.common.services.build.inputs.revA.1.0.6 || Debug || true || Executable || com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain.value.workspace || NUCLEO-F103RB || 0 || 0 || arm-none-eabi- || ${gnu_tools_for_stm32_compiler_path} || ../Drivers/CMSIS/Device/ST/STM32F1xx/Include | ../Drivers/CMSIS/Include | ../Core/Inc | ../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy | ../Drivers/STM32F1xx_HAL_Driver/Inc ||  ||  || USE_HAL_DRIVER | STM32F103xB ||  || Drivers | Core/Startup | Core ||  ||  || ${workspace_loc:/${ProjName}/STM32F103RBTX_FLASH.ld} || true || NonSecure ||  || secure_nsclib.o ||  || None ||  ||  || " valueType="string"/>
                             <option id="com.st.stm32cube.ide.mcu.debug.option.cpuclock.718213595" name="Cpu clock frequence" superClass="com.st.stm32cube.ide.mcu.debug.option.cpuclock" useByScannerDiscovery="false" value="64" valueType="string"/>
+                            <option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.nanoprintffloat.1243536684" name="Use float with printf from newlib-nano (-u _printf_float)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.nanoprintffloat" useByScannerDiscovery="false" value="false" valueType="boolean"/>
                             <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform.1359183697" isAbstract="false" osList="all" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform"/>
                             <builder buildPath="${workspace_loc:/tdse-tp2_01-model_integration}/Debug" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder.1277475106" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder"/>
                             <tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.1808103261" name="MCU/MPU GCC Assembler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler">
@@ -337,5 +338,12 @@
             <autodiscovery enabled="false" problemReportingEnabled="true" selectedProfileId=""/>
         </scannerConfigBuildInfo>
     </storageModule>
-    <storageModule moduleId="refreshScope"/>
+    <storageModule moduleId="refreshScope" versionNumber="2">
+        <configuration configurationName="Debug">
+            <resource resourceType="PROJECT" workspacePath="/tdse-tf_3-02"/>
+        </configuration>
+        <configuration configurationName="Release">
+            <resource resourceType="PROJECT" workspacePath="/tdse-tf_3-02"/>
+        </configuration>
+    </storageModule>
 </cproject>
 \ No newline at end of file
diff --git a/firmware/Core/Inc/main.h b/firmware/Core/Inc/main.h
@@ -75,8 +75,6 @@ void Error_Handler(void);
 #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
 #define TMS_GPIO_Port GPIOA
 #define TCK_Pin GPIO_PIN_14
diff --git a/firmware/Core/Src/main.c b/firmware/Core/Src/main.c
@@ -314,12 +314,6 @@ static void MX_GPIO_Init(void)
   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;
diff --git a/firmware/Core/Src/stm32f1xx_hal_msp.c b/firmware/Core/Src/stm32f1xx_hal_msp.c
@@ -119,7 +119,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
     hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
     hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
     hdma_usart1_rx.Init.Mode = DMA_NORMAL;
-    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
+    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
     if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
     {
       Error_Handler();
@@ -135,7 +135,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
     hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
     hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
     hdma_usart1_tx.Init.Mode = DMA_NORMAL;
-    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
+    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
     if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
     {
       Error_Handler();
diff --git a/firmware/app/inc/app.h b/firmware/app/inc/app.h
@@ -12,7 +12,6 @@
 extern "C" {
 #endif
 
-extern uint32_t g_app_cnt;
 extern uint32_t g_app_runtime_us;
 extern uint32_t g_app_WCET_us;
 extern volatile uint32_t g_app_tick_cnt;
diff --git a/firmware/app/inc/ds18b20.h b/firmware/app/inc/ds18b20.h
@@ -0,0 +1,65 @@
+/*
+ * 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
+ */
+
+#ifndef _DS18B20_H_
+#define _DS18B20_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* DS18B20 Non Blocking State Machine - Transition Table
+ *
+ * +------------------------------+-------+------------------------+------------------------------+---------------------------+
+ * | Current state                | Event | [Guard]                | Next state                   | Actions                   |
+ * +==============================+=======+========================+==============================+===========================+
+ * |                              |       | [tick == 0]            | ST_DS18B20_BUSY_WAITING_CONV | Send start conversion cmd |
+ * + ST_DS18B20_READY             +-------+------------------------+------------------------------+---------------------------+
+ * |                              |       |                        | ST_DS18B20_READY             | tick--                    |
+ * +------------------------------+-------+------------------------+------------------------------+---------------------------+
+ * |                              |       | [tick == 0]            | ST_DS18B20_BUSY_WAITING_DMA  | Transmit/Receive DMA      |
+ * |                              |       |                        |                              | tick = DMA_TIMEOUT_MAX    |
+ * |                              |       |                        |                              | Data_LSB = 1              |
+ * | ST_DS18B20_BUSY_WAITING_CONV +-------+------------------------+------------------------------+---------------------------+
+ * |                              |       |                        | ST_DS18B20_BUSY_WAITING_CONV | tick--                    |
+ * |                              |       |                        |                              |                           |
+ * +------------------------------+-------+------------------------+------------------------------+---------------------------+
+ * |                              |       | [tick == 0]            | ST_DS18B20_READY             | tick = TEMP_PERIOD        |
+ * |                              |       |                        |                              |                           |
+ * | ST_DS18B20_BUSY_WAITING_DMA  +-------+------------------------+------------------------------+---------------------------+
+ * |                              |       | [tick != 0 &&          | ST_DS18B20_BUSY_WAITING_DMA  | tick--                    |
+ * |                              |       |  Received_data == 0]   |                              |                           |
+ * +                              +-------+------------------------+------------------------------+---------------------------+
+ * |                              |       | [tick != 0 &&          | ST_DS18B20_BUSY_WAITING_DMA  | tick = DMA_TIMEOUT_MAX    |
+ * |                              |       |  Received_data == 1 && |                              | Data_LSB = 0              |
+ * |                              |       |   Data_LSB == 1]       |                              | Save received LSB data    |
+ * |                              +-------+------------------------+------------------------------+---------------------------+
+ * |                              |       | [tick != 0 &&          | ST_DS18B20_READY             | tick = TEMP_PERIOD        |
+ * |                              |       |  Received_data == 0 && |                              | Save received MSB data    |
+ * |                              |       |   Data_LSB == 0]       |                              |                           |
+ * +------------------------------+-------+------------------------+------------------------------+---------------------------+
+ *
+ *
+ */
+
+typedef enum {
+    ST_DS18B20_READY,
+    ST_DS18B20_BUSY_WAITING_CONV,
+    ST_DS18B20_BUSY_WAITING_DMA
+} DS18B20_st_t;
+
+void DS18B20_Init(void);
+void DS18B20_Update(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DS18B20_H_ */
diff --git a/firmware/app/inc/task_menu_attribute.h b/firmware/app/inc/task_menu_attribute.h
@@ -34,6 +34,7 @@ typedef enum {
     EV_MEN_NEX_ACTIVE,
     EV_MEN_ESC_IDLE,
     EV_MEN_ESC_ACTIVE,
+    EV_MEN_DISPLAY_UPDATE,
     EV_MEN_INACTIVE_TIMEOUT
 } task_menu_ev_t;
 
diff --git a/firmware/app/inc/task_temp_sensor_attribute.h b/firmware/app/inc/task_temp_sensor_attribute.h
@@ -11,47 +11,6 @@
 extern "C" {
 #endif
 
-/* DS18B20 Non Blocking State Machine - Transition Table
- *
- * +------------------------------+-------+------------------------+------------------------------+---------------------------+
- * | Current state                | Event | [Guard]                | Next state                   | Actions                   |
- * +==============================+=======+========================+==============================+===========================+
- * |                              |       | [tick == 0]            | ST_DS18B20_BUSY_WAITING_CONV | Send start conversion cmd |
- * + ST_DS18B20_READY             +-------+------------------------+------------------------------+---------------------------+
- * |                              |       |                        | ST_DS18B20_READY             | tick--                    |
- * +------------------------------+-------+------------------------+------------------------------+---------------------------+
- * |                              |       | [tick == 0]            | ST_DS18B20_BUSY_WAITING_DMA  | Transmit/Receive DMA      |
- * |                              |       |                        |                              | tick = DMA_TIMEOUT_MAX    |
- * |                              |       |                        |                              | Data_LSB = 1              |
- * | ST_DS18B20_BUSY_WAITING_CONV +-------+------------------------+------------------------------+---------------------------+
- * |                              |       |                        | ST_DS18B20_BUSY_WAITING_CONV | tick--                    |
- * |                              |       |                        |                              |                           |
- * +------------------------------+-------+------------------------+------------------------------+---------------------------+
- * |                              |       | [tick == 0]            | ST_DS18B20_READY             | tick = TEMP_PERIOD        |
- * |                              |       |                        |                              |                           |
- * | ST_DS18B20_BUSY_WAITING_DMA  +-------+------------------------+------------------------------+---------------------------+
- * |                              |       | [tick != 0 &&          | ST_DS18B20_BUSY_WAITING_DMA  | tick--                    |
- * |                              |       |  Received_data == 0]   |                              |                           |
- * +                              +-------+------------------------+------------------------------+---------------------------+
- * |                              |       | [tick != 0 &&          | ST_DS18B20_BUSY_WAITING_DMA  | tick = DMA_TIMEOUT_MAX    |
- * |                              |       |  Received_data == 1 && |                              | Data_LSB = 0              |
- * |                              |       |   Data_LSB == 1]       |                              | Save received LSB data    |
- * |                              +-------+------------------------+------------------------------+---------------------------+
- * |                              |       | [tick != 0 &&          | ST_DS18B20_READY             | tick = TEMP_PERIOD        |
- * |                              |       |  Received_data == 0 && |                              | Save received MSB data    |
- * |                              |       |   Data_LSB == 0]       |                              |                           |
- * +------------------------------+-------+------------------------+------------------------------+---------------------------+
- *
- *
- */
-
-typedef enum {
-    ST_DS18B20_READY,
-    ST_DS18B20_BUSY_WAITING_CONV,
-    ST_DS18B20_BUSY_WAITING_DMA
-} DS18B20_st_t;
-
-/* Identifier of Task Sensor */
 typedef enum {
     ID_DS18B20_A,
 } task_temp_sensor_id_t;
@@ -62,7 +21,7 @@ typedef struct {
 
 typedef struct {
     uint32_t tick;
-    DS18B20_st_t state;
+    // task_temp_sensor_st_t state;
     // task_temp_sensor_ev_t event;
 } task_temp_sensor_dta_t;
 
diff --git a/firmware/app/src/app.c b/firmware/app/src/app.c
@@ -44,7 +44,6 @@ const task_cfg_t task_cfg_list[] = {
 
 #define TASK_QTY (sizeof(task_cfg_list)/sizeof(task_cfg_t))
 
-uint32_t g_app_cnt;
 uint32_t g_app_runtime_us;
 uint32_t g_app_WCET_us; // Worst case execution time historically
 
@@ -92,7 +91,6 @@ void app_update(void)
 
     while (b_time_update_required)
     {
-        g_app_cnt++;
         g_app_runtime_us = 0;
 
         for (index = 0; TASK_QTY > index; index++)
diff --git a/firmware/app/src/ds18b20.c b/firmware/app/src/ds18b20.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
+ *
+ * See file `LICENSE` for full details
+ */
+
+#include <stdbool.h>
+
+#include "main.h"
+#include "systick.h"
+#include "ds18b20.h"
+#include "stm32f1xx_ll_usart.h"
+#include "logger.h"
+
+#include "task_menu_attribute.h"
+#include "task_menu_interface.h"
+
+#define G_DS18B20_CONV_TIME_MS   180ul // ~188ms for 10 bit resolution
+#define G_DS18B20_DMA_TIMEOUT_MS 50ul
+#define G_TEMP_PERIOD_MS         1000ul
+
+// Private global variables
+volatile bool b_DS18B20_Received_data;
+static uint8_t g_DS18B20_Received_data_buffer[8];
+const uint8_t g_buffer[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+static bool b_DS18B20_Received_data_LSB;
+DS18B20_st_t g_DS18B20_state;
+uint32_t g_DS18B20_tick;
+uint16_t g_DS18B20_temp;
+
+uint8_t Temp_LSB, Temp_MSB;
+
+// Public global variables
+uint16_t g_DS18B20_update_count;
+uint16_t g_DS18B20_DMA_error_count;
+
+// Private functions declaration
+void DS18B20_Write(uint8_t data);
+void DS18B20_Read_temp(void);
+uint8_t DS18B20_Read(void);
+uint8_t DS18B20_Reset(void);
+
+uint8_t DS18B20_Reset(void)
+{
+    uint8_t data = 0xF0;
+
+    __HAL_UART_DISABLE(&huart1);
+    LL_USART_SetBaudRate(USART1, HAL_RCC_GetPCLK2Freq(), 9600);
+    __HAL_UART_ENABLE(&huart1);
+    HAL_UART_Transmit(&huart1, &data, 1, 100);
+
+    if ((HAL_UART_Receive(&huart1, &data, 1, 100) != HAL_OK) || (data == 0xF0))
+    {
+        // initialization failed
+        LOGGER_ERROR("Couldn't read temperature sensor");
+        return 1;
+    }
+
+    __HAL_UART_DISABLE(&huart1);
+    LL_USART_SetBaudRate(USART1, HAL_RCC_GetPCLK2Freq(), 115200);
+    __HAL_UART_ENABLE(&huart1);
+    return 0;
+}
+
+void DS18B20_SetResolution(uint8_t resolution)
+{
+    uint8_t config;
+
+    switch(resolution)
+    {
+        case 9:  config = 0x1F; break;
+        case 10: config = 0x3F; break;
+        case 11: config = 0x5F; break;
+        case 12: config = 0x7F; break;
+        default: config = 0x7F;
+    }
+
+    DS18B20_Reset();
+    DS18B20_Write(0xCC); // Send 'Skip ROM' command
+    DS18B20_Write(0x4E); // Send 'write scratchpad' command
+
+    DS18B20_Write(0x00); // TH
+    DS18B20_Write(0x00); // TL
+    DS18B20_Write(config);
+
+    DS18B20_Reset();
+    DS18B20_Write(0xCC); // Skip ROM
+    DS18B20_Write(0x48); // Write scratchpad to EEPROM
+}
+
+void DS18B20_Init(void)
+{
+    if (DS18B20_Reset() == 0)
+    {
+        LOGGER_INFO("Temperature sensor initialized successfully");
+    }
+    DS18B20_SetResolution(9);
+    g_DS18B20_state = ST_DS18B20_READY;
+    g_DS18B20_tick = G_TEMP_PERIOD_MS;
+    g_DS18B20_update_count = 0;
+    g_DS18B20_DMA_error_count = 0;
+
+    Temp_LSB = Temp_MSB = 0xFF;
+}
+
+void DS18B20_Write(uint8_t data)
+{
+    uint8_t buffer[8];
+
+    for (uint8_t i = 0; i < 8; ++i)
+    {
+        if (data & (1 << i))
+        {
+            buffer[i] = 0xFF;
+        }
+        else
+        {
+            buffer[i] = 0x00;
+        }
+    }
+
+    // This is a blocking call and can wait at most 100ms
+    // TODO: convert to non-blocking call using DMA
+    HAL_UART_Transmit(&huart1, buffer, 8, 100);
+}
+
+void DS18B20_Start_conv(void)
+{
+    // Send start temp conversion command
+    // the sensor needs 96ms to 750ms to complete temp conversion depending on
+    // resolution
+    DS18B20_Reset();
+    DS18B20_Write(0xCC); // Send 'Skip ROM' command
+    DS18B20_Write(0x44); // Send 'Convert T' command
+}
+
+static uint8_t l_DS18B20_DMA_error_count = 0;
+void DS18B20_Update(void)
+{
+    switch (g_DS18B20_state)
+    {
+        case ST_DS18B20_READY:
+            if (0 == g_DS18B20_tick)
+            {
+                DS18B20_Start_conv();
+                g_DS18B20_state = ST_DS18B20_BUSY_WAITING_CONV;
+                g_DS18B20_tick = G_DS18B20_CONV_TIME_MS;
+                l_DS18B20_DMA_error_count = 0;
+            }
+            else
+            {
+                g_DS18B20_tick--;
+            }
+            break;
+        case ST_DS18B20_BUSY_WAITING_CONV:
+            if (0 == g_DS18B20_tick)
+            {
+                DS18B20_Reset();
+                DS18B20_Write(0xCC); // Send 'Skip ROM' command
+                DS18B20_Write(0xBE); // Send 'read scratchpad' command
+
+                HAL_UART_Transmit_DMA(&huart1, g_buffer, 8);
+                HAL_UART_Receive_DMA(&huart1, g_DS18B20_Received_data_buffer, 8);
+
+                b_DS18B20_Received_data_LSB = true;
+                g_DS18B20_state = ST_DS18B20_BUSY_WAITING_DMA;
+                g_DS18B20_tick = G_DS18B20_DMA_TIMEOUT_MS;
+            }
+            else
+            {
+                g_DS18B20_tick--;
+            }
+
+            break;
+
+        case ST_DS18B20_BUSY_WAITING_DMA:
+            // Process received byte if any
+            if (true == b_DS18B20_Received_data)
+            {
+                b_DS18B20_Received_data = false;
+
+                uint8_t received_value = 0;
+                for (uint8_t i = 0; i < 8; ++i)
+                {
+                    if (g_DS18B20_Received_data_buffer[i] == 0xFF)
+                    {
+                        received_value |= (1 << i);
+                    }
+                }
+
+                if (true == b_DS18B20_Received_data_LSB)
+                {
+                    b_DS18B20_Received_data_LSB = false;
+                    // LSB
+                    // g_DS18B20_temp = (0x00FF & received_value);
+                    Temp_LSB = received_value;
+                    g_DS18B20_tick = G_DS18B20_DMA_TIMEOUT_MS;
+
+                    HAL_UART_Transmit_DMA(&huart1, g_buffer, 8);
+                    HAL_UART_Receive_DMA(&huart1, g_DS18B20_Received_data_buffer, 8);
+                }
+                else
+                {
+                    // MSB
+                    // g_DS18B20_temp = ((g_DS18B20_temp | (0xFF00 & (received_value << 8))) / 16.0);
+                    Temp_MSB = received_value;
+                    g_DS18B20_temp = ((Temp_MSB << 8) | Temp_LSB) / 16;
+                    g_DS18B20_state = ST_DS18B20_READY;
+                    g_DS18B20_tick = G_TEMP_PERIOD_MS;
+
+                    g_DS18B20_update_count++;
+                    put_event_task_menu(EV_MEN_DISPLAY_UPDATE);
+                }
+            }
+            else if (0 == g_DS18B20_tick) // Error handling
+            {
+                if (0 == l_DS18B20_DMA_error_count)
+                {
+                    // Try again readying scratchpad (only once)
+                    g_DS18B20_DMA_error_count++;
+                    l_DS18B20_DMA_error_count++;
+                    put_event_task_menu(EV_MEN_DISPLAY_UPDATE);
+
+                    /*
+                    HAL_UART_DMAStop(&huart1);
+                    __HAL_UART_DISABLE(&huart1);
+                    __HAL_UART_CLEAR_PEFLAG(&huart1);
+                    __HAL_UART_CLEAR_FEFLAG(&huart1);
+                    __HAL_UART_CLEAR_NEFLAG(&huart1);
+                    __HAL_UART_CLEAR_OREFLAG(&huart1);
+                    __HAL_UART_ENABLE(&huart1);
+                    memset(g_DS18B20_Received_data_buffer, 0, sizeof(g_DS18B20_Received_data_buffer));
+
+                    HAL_UART_Transmit_DMA(&huart1, g_buffer, 8);
+                    HAL_UART_Receive_DMA(&huart1, g_DS18B20_Received_data_buffer, 8);
+
+                    g_DS18B20_tick = G_DS18B20_DMA_TIMEOUT_MS;
+                    */
+
+                    g_DS18B20_state = ST_DS18B20_BUSY_WAITING_CONV;
+                }
+                else
+                {
+                    // DMA Timeout, start conversion again
+                    __HAL_UART_DISABLE(&huart1);
+                    __HAL_UART_ENABLE(&huart1);
+                    g_DS18B20_state = ST_DS18B20_READY;
+                    g_DS18B20_tick = G_TEMP_PERIOD_MS;
+                }
+            }
+            else
+            {
+                g_DS18B20_tick--;
+            }
+
+            break;
+
+        default: break;
+    }
+}
+
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
+{
+    if (huart->Instance == USART1)
+    {
+        b_DS18B20_Received_data = true;
+    }
+}
diff --git a/firmware/app/src/task_menu.c b/firmware/app/src/task_menu.c
@@ -18,12 +18,13 @@
 #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
+#define G_TASK_MEN_CNT_INI         0ul
+#define G_TASK_MEN_TICK_CNT_INI    0ul
+
+#define G_TASK_MEN_UPDATE_RATE_INI 0ul
 
 task_menu_dta_t task_menu_dta = {
-    DEL_MEN_XX_MIN, ST_MEN_IDLE, EV_MEN_ENT_IDLE, false
+    G_TASK_MEN_UPDATE_RATE_INI, ST_MEN_IDLE, EV_MEN_ENT_IDLE, false
 };
 
 #define MENU_DTA_QTY (sizeof(task_menu_dta)/sizeof(task_menu_dta_t))
@@ -44,12 +45,15 @@ task_menu_st_t g_menu_prev_state;
 uint32_t g_task_menu_cnt;
 volatile uint32_t g_task_menu_tick_cnt;
 
+// External variables
+extern uint16_t g_DS18B20_temp;
+extern uint16_t g_DS18B20_update_count;
+extern uint16_t g_DS18B20_DMA_error_count;
+
 // 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`...");
 
@@ -59,9 +63,8 @@ void task_menu_init(void *parameters)
 
     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->state = ST_MEN_IDLE;
+    g_menu_prev_state = ST_MEN_IDLE;
 
     p_task_menu_dta->event = EV_MEN_ENT_IDLE;
     p_task_menu_dta->event_flag = false;
@@ -116,6 +119,20 @@ void menu_set_state(task_menu_st_t new_state)
     g_display_update = true;
 }
 
+int count_digits(int n) {
+    int count = 0;
+
+    if (n == 0) return 1;
+    if (n < 0) n = -n;
+
+    while (n > 0) {
+        n /= 10;
+        count++;
+    }
+
+    return count;
+}
+
 void task_menu_statechart(void)
 {
     task_menu_dta_t *p_task_menu_dta;
@@ -129,7 +146,6 @@ void task_menu_statechart(void)
         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))
@@ -141,14 +157,6 @@ void task_menu_statechart(void)
     {
         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;
@@ -159,16 +167,35 @@ void task_menu_statechart(void)
                     case EV_MEN_ESC_ACTIVE:
                         menu_set_state(ST_MEN_IDLE);
                         break;
+                    case EV_MEN_DISPLAY_UPDATE:
+                        g_display_update = true;
+                        break;
                     default:
-                    break;
+                        break;
                 }
             }
 
+            if (g_display_update)
+            {
+                g_display_update = false;
+                display_clear();
+                uint8_t temp_digits = count_digits(g_DS18B20_temp);
+                snprintf(menu_row_str, 20, "%-*d%cC%*d",
+                        temp_digits, g_DS18B20_temp, 0xDF,
+                        16-temp_digits-2, g_DS18B20_update_count);
+                display_write_string(menu_row_str);
+
+                display_set_cursor_pos(16-4, 1);
+                memset(menu_row_str, '\0', sizeof(menu_row_str));
+                snprintf(menu_row_str, 20, "%4d", g_DS18B20_DMA_error_count);
+                display_write_string(menu_row_str);
+            }
+
         break;
 
         default:
 
-            p_task_menu_dta->tick  = DEL_MEN_XX_MIN;
+            p_task_menu_dta->tick  = G_TASK_MEN_UPDATE_RATE_INI;
             p_task_menu_dta->state = ST_MEN_IDLE;
             p_task_menu_dta->event = EV_MEN_ENT_IDLE;
             p_task_menu_dta->event_flag  = false;
diff --git a/firmware/app/src/task_temp_sensor.c b/firmware/app/src/task_temp_sensor.c
@@ -15,281 +15,15 @@
 #include "task_temp_sensor.h"
 #include "logger.h"
 
-#define G_TASK_SEN_TICK_CNT_INI  0ul
-#define G_DS18B20_CONV_TIME_MS   180ul // ~188ms for 10 bit resolution
-#define G_DS18B20_DMA_TIMEOUT_MS 2000ul
-#define G_TEMP_PERIOD_MS         1000ul
+#include "ds18b20.h"
 
-// local global variables
-volatile bool b_DS18B20_Received_data;
-uint8_t g_DS18B20_Received_data_buffer[8];
-float g_DS18B20_temp;
+#define G_TASK_SEN_TICK_CNT_INI  0ul
 
-DS18B20_st_t g_DS18B20_state;
 uint32_t g_task_temp_sensor_tick;
 
-uint8_t Temp_LSB;
-uint8_t Temp_MSB;
-static const uint8_t buffer[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-static bool b_DS18B20_Received_data_LSB;
-
 // this variable is incremented by 1 on every ms by HAL_SysTick
 volatile uint32_t g_task_temp_sensor_tick_cnt;
 
-// private functions declaration
-void UART1_SetBaud(uint32_t baud);
-void DS18B20_Write(uint8_t data);
-void DS18B20_Read_temp(void);
-void DS18B20_Read_temp_non_blocking(void);
-void DS18B20_Init(void);
-uint8_t DS18B20_Read(void);
-uint8_t DS18B20_Reset(void);
-
-void UART1_SetBaud(uint32_t baud)
-{
-    huart1.Instance = USART1;
-    huart1.Init.BaudRate = baud;
-    huart1.Init.WordLength = UART_WORDLENGTH_8B;
-    huart1.Init.StopBits = UART_STOPBITS_1;
-    huart1.Init.Parity = UART_PARITY_NONE;
-    huart1.Init.Mode = UART_MODE_TX_RX;
-    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
-    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
-    if (HAL_HalfDuplex_Init(&huart1) != HAL_OK)
-    {
-        Error_Handler();
-    };
-}
-
-uint8_t DS18B20_Reset(void)
-{
-    uint8_t data = 0xF0;
-    UART1_SetBaud(9600);
-    HAL_UART_Transmit(&huart1, &data, 1, 10);
-
-    if ((HAL_UART_Receive(&huart1, &data, 1, 10) != HAL_OK) || (data == 0xF0))
-    {
-        // initialization failed
-        LOGGER_ERROR("Couldn't read temperature sensor");
-        return 1;
-    }
-
-    UART1_SetBaud(115200);
-    return 0;
-}
-
-void DS18B20_SetResolution(uint8_t resolution)
-{
-    uint8_t config;
-
-    switch(resolution)
-    {
-        case 9:  config = 0x1F; break;
-        case 10: config = 0x3F; break;
-        case 11: config = 0x5F; break;
-        case 12: config = 0x7F; break;
-        default: config = 0x7F;
-    }
-
-    DS18B20_Reset();
-    DS18B20_Write(0xCC); // Send 'Skip ROM' command
-    DS18B20_Write(0x4E); // Send 'write scratchpad' command
-
-    DS18B20_Write(0x00); // TH
-    DS18B20_Write(0x00); // TL
-    DS18B20_Write(config);
-
-    DS18B20_Reset();
-
-    DS18B20_Write(0xCC); // Skip ROM
-    DS18B20_Write(0x48); // Write scratchpad to EEPROM
-}
-
-void DS18B20_Init(void)
-{
-    if (DS18B20_Reset() == 0)
-    {
-        LOGGER_INFO("Temperature sensor initialized successfully");
-    }
-    DS18B20_SetResolution(10);
-    g_DS18B20_state = ST_DS18B20_READY;
-    g_task_temp_sensor_tick = G_TEMP_PERIOD_MS;
-}
-
-void DS18B20_Write(uint8_t data)
-{
-    uint8_t buffer[8];
-
-    for (uint8_t i = 0; i < 8; ++i)
-    {
-        if (data & (1 << i))
-        {
-            buffer[i] = 0xFF;
-        }
-        else
-        {
-            buffer[i] = 0x00;
-        }
-    }
-
-    // This is a blocking call and can wait at most 100ms
-    // TODO: convert to non-blocking call using DMA
-    HAL_UART_Transmit(&huart1, buffer, 8, 10);
-}
-
-// Blocking version
-uint8_t DS18B20_Read(void)
-{
-    uint8_t buffer[8];
-    uint8_t received_value = 0;
-
-    for (uint8_t i = 0; i < 8; ++i)
-    {
-        buffer[i] = 0xFF;
-    }
-
-    HAL_UART_Transmit_DMA(&huart1, buffer, 8);
-    HAL_UART_Receive_DMA(&huart1, g_DS18B20_Received_data_buffer, 8);
-
-    while(b_DS18B20_Received_data == false)
-        ;
-
-    b_DS18B20_Received_data = false;
-
-    for (uint8_t i = 0; i < 8; ++i)
-    {
-        if (g_DS18B20_Received_data_buffer[i] == 0xFF)
-        {
-            received_value |= (1 << i);
-        }
-    }
-
-    return received_value;
-}
-
-void DS18B20_Read_temp(void)
-{
-    DS18B20_Reset();
-    DS18B20_Write(0xCC); // Send 'Skip ROM' command
-    DS18B20_Write(0x44); // Send 'Convert T' command
-
-    DS18B20_Reset();
-    DS18B20_Write(0xCC); // Send 'Skip ROM' command
-    DS18B20_Write(0xBE); // Send 'read scratchpad' command
-
-    Temp_LSB = DS18B20_Read();
-    Temp_MSB = DS18B20_Read();
-
-    uint16_t temp = (Temp_MSB << 8) | Temp_LSB;
-    g_DS18B20_temp = (float) temp / 16.0;
-}
-
-void DS18B20_Read_temp_non_blocking(void)
-{
-    switch (g_DS18B20_state)
-    {
-        case ST_DS18B20_READY:
-            if (0 == g_task_temp_sensor_tick)
-            {
-                // Send start temp conversion command
-                // this needs 96ms to 750ms depending on resolution
-                DS18B20_Reset();
-                DS18B20_Write(0xCC); // Send 'Skip ROM' command
-                DS18B20_Write(0x44); // Send 'Convert T' command
-
-                g_DS18B20_state = ST_DS18B20_BUSY_WAITING_CONV;
-                g_task_temp_sensor_tick = G_DS18B20_CONV_TIME_MS;
-            }
-            else
-            {
-                g_task_temp_sensor_tick--;
-            }
-            break;
-
-        case ST_DS18B20_BUSY_WAITING_CONV:
-            if (0 == g_task_temp_sensor_tick)
-            {
-                DS18B20_Reset();
-                DS18B20_Write(0xCC); // Send 'Skip ROM' command
-                DS18B20_Write(0xBE); // Send 'read scratchpad' command
-
-                if (HAL_OK == HAL_UART_Transmit_DMA(&huart1, buffer, 8))
-                {
-                    if (HAL_OK == HAL_UART_Receive_DMA(&huart1, g_DS18B20_Received_data_buffer, 8))
-                    {
-                        b_DS18B20_Received_data_LSB = true;
-                        g_DS18B20_state = ST_DS18B20_BUSY_WAITING_DMA;
-                        g_task_temp_sensor_tick = G_DS18B20_DMA_TIMEOUT_MS;
-                    }
-                }
-            }
-            else
-            {
-                g_task_temp_sensor_tick--;
-            }
-
-            break;
-
-        case ST_DS18B20_BUSY_WAITING_DMA:
-
-            if (0 == g_task_temp_sensor_tick)
-            {
-                // DMA Timeout, reset conversion
-                g_DS18B20_state = ST_DS18B20_READY;
-                g_task_temp_sensor_tick = G_TEMP_PERIOD_MS;
-                break;
-            }
-            else
-            {
-                g_task_temp_sensor_tick--;
-            }
-
-            if (true == b_DS18B20_Received_data)
-            {
-                b_DS18B20_Received_data = false;
-
-                uint8_t received_value = 0;
-                for (uint8_t i = 0; i < 8; ++i)
-                {
-                    if (g_DS18B20_Received_data_buffer[i] == 0xFF)
-                    {
-                        received_value |= (1 << i);
-                    }
-                }
-
-                if (true == b_DS18B20_Received_data_LSB)
-                {
-                    if (HAL_OK == HAL_UART_Transmit_DMA(&huart1, buffer, 8))
-                    {
-                        if (HAL_OK == HAL_UART_Receive_DMA(&huart1, g_DS18B20_Received_data_buffer, 8))
-                        {
-                            b_DS18B20_Received_data_LSB = false;
-                            Temp_LSB = received_value;
-                            g_task_temp_sensor_tick = G_DS18B20_DMA_TIMEOUT_MS;
-                        }
-                    }
-                }
-                else
-                {
-                    Temp_MSB = received_value;
-                    uint16_t temp = ((Temp_MSB << 8) | Temp_LSB);
-                    g_DS18B20_temp = (float) temp / 16.0;
-                    g_DS18B20_state = ST_DS18B20_READY;
-                    g_task_temp_sensor_tick = G_TEMP_PERIOD_MS;
-                }
-            }
-
-            break;
-
-        default: break;
-    }
-}
-
-void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
-{
-    b_DS18B20_Received_data = true;
-}
-
 void task_temp_sensor_init(void *parameters)
 {
     LOGGER_INFO("Initializing `task_temp_sensor`...");
@@ -314,8 +48,6 @@ void task_temp_sensor_update(void *parameters)
 
     while (b_time_update_required)
     {
-        DS18B20_Read_temp_non_blocking();
-
         __asm("CPSID i");
         if (G_TASK_SEN_TICK_CNT_INI < g_task_temp_sensor_tick_cnt)
         {
@@ -328,5 +60,6 @@ void task_temp_sensor_update(void *parameters)
         }
         __asm("CPSIE i");
 
+        DS18B20_Update();
     }
 }
diff --git a/firmware/tdse-tf_3-02.ioc b/firmware/tdse-tf_3-02.ioc
@@ -12,7 +12,7 @@ Dma.USART1_RX.0.MemInc=DMA_MINC_ENABLE
 Dma.USART1_RX.0.Mode=DMA_NORMAL
 Dma.USART1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
 Dma.USART1_RX.0.PeriphInc=DMA_PINC_DISABLE
-Dma.USART1_RX.0.Priority=DMA_PRIORITY_LOW
+Dma.USART1_RX.0.Priority=DMA_PRIORITY_VERY_HIGH
 Dma.USART1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
 Dma.USART1_TX.1.Direction=DMA_MEMORY_TO_PERIPH
 Dma.USART1_TX.1.Instance=DMA1_Channel4
@@ -21,9 +21,10 @@ Dma.USART1_TX.1.MemInc=DMA_MINC_ENABLE
 Dma.USART1_TX.1.Mode=DMA_NORMAL
 Dma.USART1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
 Dma.USART1_TX.1.PeriphInc=DMA_PINC_DISABLE
-Dma.USART1_TX.1.Priority=DMA_PRIORITY_LOW
+Dma.USART1_TX.1.Priority=DMA_PRIORITY_VERY_HIGH
 Dma.USART1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
 File.Version=6
+GPIO.groupedBy=Group By Peripherals
 KeepUserPlacement=false
 Mcu.CPN=STM32F103RBT6
 Mcu.Family=STM32F1
@@ -40,18 +41,17 @@ Mcu.Pin0=PC13-TAMPER-RTC
 Mcu.Pin1=PC14-OSC32_IN
 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.Pin12=PA9
+Mcu.Pin13=PA13
+Mcu.Pin14=PA14
+Mcu.Pin15=PB3
+Mcu.Pin16=PB4
+Mcu.Pin17=PB5
+Mcu.Pin18=PB6
+Mcu.Pin19=PB8
 Mcu.Pin2=PC15-OSC32_OUT
-Mcu.Pin20=PB8
-Mcu.Pin21=PB9
-Mcu.Pin22=VP_SYS_VS_Systick
+Mcu.Pin20=PB9
+Mcu.Pin21=VP_SYS_VS_Systick
 Mcu.Pin3=PD0-OSC_IN
 Mcu.Pin4=PD1-OSC_OUT
 Mcu.Pin5=PA2
@@ -59,7 +59,7 @@ Mcu.Pin6=PA3
 Mcu.Pin7=PA5
 Mcu.Pin8=PA6
 Mcu.Pin9=PA7
-Mcu.PinsNb=23
+Mcu.PinsNb=22
 Mcu.ThirdPartyNb=0
 Mcu.UserConstants=
 Mcu.UserName=STM32F103RBTx
@@ -123,10 +123,8 @@ 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
-PA8.Signal=GPIO_Input
+PA9.GPIOParameters=GPIO_Mode
+PA9.GPIO_Mode=GPIO_MODE_AF_OD
 PA9.Mode=Half_duplex(single_wire_mode)
 PA9.Signal=USART1_TX
 PB10.GPIOParameters=GPIO_PuPd,GPIO_Label
@@ -245,8 +243,9 @@ RCC.VCOOutput2Freq_Value=4000000
 SH.GPXTI13.0=GPIO_EXTI13
 SH.GPXTI13.ConfNb=1
 USART1.BaudRate=115200
-USART1.IPParameters=VirtualMode,BaudRate
+USART1.IPParameters=VirtualMode,BaudRate,WordLength
 USART1.VirtualMode=VM_ASYNC
+USART1.WordLength=WORDLENGTH_8B
 USART2.IPParameters=VirtualMode
 USART2.VirtualMode=VM_ASYNC
 VP_SYS_VS_Systick.Mode=SysTick