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 2068d6e7d5126387f761357f57dcd6b450dbb27e
parent d34bdf709422b8ebd9b4aa6ef23d4d875e5826c1
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date:   Sun,  3 May 2026 21:00:11 -0300

Gestionar error cuando el display no responde

Para esto se cuenta un tiempo (100 ms) desde que se envió el ultimo
byte. Si no se obtiene respuesta en ese tiempo se asume error. En esta
situación se reinicia el periférico I2C y se limpian todos los errores,
por ultimo se retransmite el ultimo byte enviado al display.

Diffstat:
Mfirmware-nucleo/App/Src/display_i2c.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 65 insertions(+), 6 deletions(-)
diff --git a/firmware-nucleo/App/Src/display_i2c.c b/firmware-nucleo/App/Src/display_i2c.c
@@ -16,7 +16,6 @@
 #define DISPLAY_I2C_ADDRESS        0x27
 #define DISPLAY_ASYNC_QUEUE_LEN    256
 #define DISPLAY_ASYNC_CLEAR_DEL_MS 2ul
-#define DISPLAY_TICK_CNT_INI       0ul
 
 #define DISPLAY_CMD_CLEAR_DISPLAY   0b00000001
 #define DISPLAY_CMD_SET_CURSOR_HOME 0b00000010
@@ -41,6 +40,8 @@
 #define DISPLAY_CMD_DISPLAY_CONTROL_CURSOR_OFF  0b00000000
 #define DISPLAY_CMD_DISPLAY_CONTROL_BLINK_ON    0b00000001
 #define DISPLAY_CMD_DISPLAY_CONTROL_BLINK_OFF   0b00000000
+#define DISPLAY_TICK_CNT_INI_MS     0ul
+#define DISPLAY_TICK_DMA_TIMEOUT_MS 100ul
 
 #define DISPLAY_LINE1_FIRST_CHAR_ADDR 0
 #define DISPLAY_LINE2_FIRST_CHAR_ADDR 64
@@ -67,9 +68,10 @@ typedef struct {
 } display_async_queue_t;
 
 static bool b_display_i2c_dma_done;
-static uint32_t g_display_i2c_tick;
+static uint32_t g_display_i2c_tick, g_display_i2c_dma_tick;
 static uint8_t async_buffer[4];
 static display_async_queue_t display_async_queue;
+static display_data_t curr_tx_data;
 
 // Private functions declaration
 static void display_i2c_send_cmd(uint8_t cmd);
@@ -77,6 +79,8 @@ static void display_i2c_send_data(uint8_t data);
 static void display_i2c_async_write(display_data_t data);
 static void display_i2c_async_enqueue(display_data_t data);
 static display_data_t display_i2c_async_dequeue(void);
+void display_i2c_recover(void);
+uint8_t display_i2c_is_stuck(void);
 
 // Public functions definition
 void display_i2c_init(void)
@@ -126,7 +130,8 @@ void display_i2c_init(void)
     HAL_Delay(2);
 
     b_display_i2c_dma_done = true;
-    g_display_i2c_tick = DISPLAY_TICK_CNT_INI;
+    g_display_i2c_tick = DISPLAY_TICK_CNT_INI_MS;
+    g_display_i2c_dma_tick = DISPLAY_TICK_CNT_INI_MS;
 
     display_async_queue.head = 0;
     display_async_queue.tail = 0;
@@ -209,8 +214,30 @@ void display_i2c_async_tick(void)
     {
         if ((display_async_queue.count != 0) && b_display_i2c_dma_done)
         {
-            display_i2c_async_write(display_i2c_async_dequeue());
-        } 
+            curr_tx_data = display_i2c_async_dequeue();
+            display_i2c_async_write(curr_tx_data);
+        }
+    }
+
+    if (false == b_display_i2c_dma_done)
+    {
+        if (0 < g_display_i2c_dma_tick)
+        {
+            g_display_i2c_dma_tick--;
+        }
+        else
+        {
+            // DMA timeout. Assume error. Try to recover i2c peripheral and
+            // send again last sent byte.
+            //
+            // TODO: report the error in some way if there are repeated losses.
+
+            if (display_i2c_is_stuck())
+            {
+                display_i2c_recover();
+            }
+
+            display_i2c_async_write(curr_tx_data);
     }
 }
 
@@ -227,7 +254,7 @@ static void display_i2c_send_cmd(uint8_t cmd)
     buffer[2] = data_l | 0x0C;
     buffer[3] = data_l | 0x08;
 
-    HAL_I2C_Master_Transmit(&hi2c1, DISPLAY_I2C_ADDRESS<<1, (uint8_t*)buffer, 4, 100);
+    HAL_I2C_Master_Transmit(&hi2c1, DISPLAY_I2C_ADDRESS<<1, buffer, 4, 100);
 }
 
 static void display_i2c_send_data(uint8_t data)
@@ -281,6 +308,7 @@ static void display_i2c_async_write(display_data_t data)
     {
         HAL_I2C_Master_Transmit_DMA(&hi2c1, DISPLAY_I2C_ADDRESS<<1, async_buffer, 4);
         b_display_i2c_dma_done = false;
+        g_display_i2c_dma_tick = DISPLAY_TICK_DMA_TIMEOUT_MS;
     }
 }
 
@@ -300,3 +328,34 @@ static display_data_t display_i2c_async_dequeue(void)
     display_async_queue.count--;
     return display_async_queue.queue[display_async_queue.tail++];
 }
+
+uint8_t display_i2c_is_stuck(void)
+{
+    if ((hi2c1.Instance->SR1 & I2C_SR1_AF) ||
+        (hi2c1.Instance->SR2 & I2C_SR2_BUSY) ||
+        (DMA1_Channel6->CCR & DMA_CCR_EN) ||
+        (hi2c1.State != HAL_I2C_STATE_READY))
+    {
+        return 1;
+    }
+
+    return 0;
+}
+
+
+void display_i2c_recover(void)
+{
+    HAL_DMA_Abort(hi2c1.hdmatx);
+
+    HAL_I2C_DeInit(&hi2c1);
+
+    __HAL_RCC_I2C1_FORCE_RESET();
+    __HAL_RCC_I2C1_RELEASE_RESET();
+
+    __HAL_UNLOCK(&hi2c1);
+    hi2c1.State = HAL_I2C_STATE_READY;
+
+    systick_delay_us(200);
+
+    HAL_I2C_Init(&hi2c1);
+}