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
firmware-nucleo/App/Src/ds18b20.c (10023B)
   1 /*
   2  * Copyright (c) 2026 Martin Javier Klöckner <mklockner@fi.uba.ar>
   3  *
   4  * See file `LICENSE` for full details
   5  */
   6 
   7 #include <stdbool.h>
   8 
   9 #include "main.h"
  10 #include "systick.h"
  11 #include "ds18b20.h"
  12 #include "stm32f1xx_ll_usart.h"
  13 #include "logger.h"
  14 
  15 #define DS18B20_SKIP_ROM_CMD                   0xCC
  16 #define DS18B20_CONVERT_T_CMD                  0x44
  17 #define DS18B20_READ_SCRATCHPAD_CMD            0xBE
  18 #define DS18B20_WRITE_SCRATCHPAD_CMD           0x4E
  19 #define DS18B20_WRITE_SCRATCHPAD_TO_EEPROM_CMD 0x48
  20 
  21 #define G_DS18B20_RESOLUTION_BITS 9
  22 #define G_DS18B20_CONV_TIME_MS    100ul // ~100ms for 9 bit resolution
  23 #define G_DS18B20_TICK_INI        0ul
  24 #define G_RESET_BAUDRATE          9600
  25 
  26 // TODO: Handle temp sensor not responding with 115200. Idea: Use first 115200
  27 //       until the sensor no longer responds, in thta case try with different
  28 //       speeds, such as 96500.
  29 #define G_DATA_BAUDRATE        96500
  30 
  31 #define G_DS18B20_ASYNC_QUEUE_LEN    256
  32 #define G_DS18B20_ASYNC_RESET_DEL_MS 100ul
  33 
  34 // Private data structures definition
  35 typedef enum {
  36     DS18B20_QUEUE_BYTE_TX,
  37     DS18B20_QUEUE_BYTE_RX,
  38     DS18B20_QUEUE_READ_LSB,
  39     DS18B20_QUEUE_READ_MSB,
  40     DS18B20_QUEUE_SET_BAUD_SLOW,
  41     DS18B20_QUEUE_SET_BAUD_FAST,
  42     DS18B20_QUEUE_RESET,
  43     DS18B20_QUEUE_DELAY,
  44 } ds18b20_data_type_e;
  45 
  46 typedef struct {
  47     ds18b20_data_type_e type;
  48     uint16_t data;
  49 } ds18b20_data_t;
  50 
  51 static struct {
  52     uint8_t head;
  53     uint8_t tail;
  54     uint8_t count;
  55     ds18b20_data_t queue[G_DS18B20_ASYNC_QUEUE_LEN];
  56 } ds18b20_async_queue;
  57 
  58 // Public variables
  59 bool b_ds18b20_dma_tx_done, b_ds18b20_dma_rx_done;
  60 
  61 // Private global variables
  62 static uint32_t g_ds18b20_tick;
  63 static uint16_t g_ds18b20_temp, g_ds18b20_update_count;
  64 static uint8_t g_temp_lsb, g_temp_msb;
  65 static uint8_t g_ds18b20_tx_buffer[8], g_ds18b20_rx_buffer[8];
  66 static bool b_ds18b20_rx_data_processed, b_ds18b20_async_temp_ready;
  67 
  68 // Private functions declaration
  69 //// Blocking calls
  70 static bool ds18b20_reset(void);
  71 static void ds18b20_write(uint8_t data);
  72 static void ds18b20_set_resolution(uint8_t resolution);
  73 static uint8_t ds18b20_get_rx_byte(void);
  74 static void ds18b20_byte_to_array_of_bytes(uint8_t byte, uint8_t *array);
  75 //// Asynchronous calls
  76 static void ds18b20_dma_write(ds18b20_data_t data);
  77 static void ds18b20_async_reset(void);
  78 static void ds18b20_async_enqueue(ds18b20_data_t data);
  79 static ds18b20_data_t ds18b20_async_dequeue(void);
  80 static ds18b20_data_t ds18b20_async_queue_tail(void);
  81 
  82 static bool ds18b20_reset(void)
  83 {
  84     uint8_t data = 0xF0;
  85 
  86     __HAL_UART_DISABLE(&huart1);
  87     LL_USART_SetBaudRate(USART1, HAL_RCC_GetPCLK2Freq(), G_RESET_BAUDRATE);
  88     __HAL_UART_ENABLE(&huart1);
  89 
  90     HAL_UART_Transmit(&huart1, &data, 1, 100);
  91     if ((HAL_UART_Receive(&huart1, &data, 1, 100) != HAL_OK) || (data == 0xF0))
  92     {
  93         // Initialization failed
  94         LOGGER_ERROR("Couldn't read temperature sensor");
  95         return true;
  96     }
  97 
  98     __HAL_UART_DISABLE(&huart1);
  99     LL_USART_SetBaudRate(USART1, HAL_RCC_GetPCLK2Freq(), G_DATA_BAUDRATE);
 100     __HAL_UART_ENABLE(&huart1);
 101     return false;
 102 }
 103 
 104 static void ds18b20_set_resolution(uint8_t resolution)
 105 {
 106     uint8_t config;
 107 
 108     switch(resolution)
 109     {
 110         case 9:  config = 0x1F; break;
 111         case 10: config = 0x3F; break;
 112         case 11: config = 0x5F; break;
 113         case 12: config = 0x7F; break;
 114         default: config = 0x7F;
 115     }
 116 
 117     ds18b20_reset();
 118     ds18b20_write(DS18B20_SKIP_ROM_CMD);
 119     ds18b20_write(DS18B20_WRITE_SCRATCHPAD_CMD);
 120 
 121     ds18b20_write(0x00); // Alarm TH byte
 122     ds18b20_write(0x00); // Alarm TL byte
 123     ds18b20_write(config);
 124 
 125     ds18b20_reset();
 126     ds18b20_write(DS18B20_SKIP_ROM_CMD);
 127     ds18b20_write(DS18B20_WRITE_SCRATCHPAD_TO_EEPROM_CMD);
 128 }
 129 
 130 void ds18b20_init(void)
 131 {
 132     if (ds18b20_reset() == 0)
 133     {
 134         LOGGER_INFO("Temperature sensor initialized successfully");
 135     }
 136     ds18b20_set_resolution(G_DS18B20_RESOLUTION_BITS);
 137 
 138     g_ds18b20_tick = G_DS18B20_TICK_INI;
 139     g_ds18b20_update_count = 0;
 140     g_temp_lsb = g_temp_msb = 0xFF;
 141 
 142     b_ds18b20_dma_tx_done = true;
 143     b_ds18b20_dma_rx_done = true;
 144     b_ds18b20_rx_data_processed = true;
 145     b_ds18b20_async_temp_ready = false;
 146     ds18b20_async_queue.head = 0;
 147     ds18b20_async_queue.tail = 0;
 148     ds18b20_async_queue.count = 0;
 149 }
 150 
 151 static void ds18b20_write(uint8_t data)
 152 {
 153     uint8_t buffer[8];
 154     ds18b20_byte_to_array_of_bytes(data, buffer);
 155     HAL_UART_Transmit(&huart1, buffer, 8, 100);
 156 }
 157 
 158 static void ds18b20_async_reset(void)
 159 {
 160     ds18b20_async_enqueue((ds18b20_data_t){DS18B20_QUEUE_SET_BAUD_SLOW});
 161     ds18b20_async_enqueue((ds18b20_data_t){DS18B20_QUEUE_RESET});
 162     ds18b20_async_enqueue((ds18b20_data_t){DS18B20_QUEUE_SET_BAUD_FAST});
 163 }
 164 
 165 static void ds18b20_dma_write(ds18b20_data_t data)
 166 {
 167     switch (data.type)
 168     {
 169         case DS18B20_QUEUE_BYTE_TX:
 170             ds18b20_byte_to_array_of_bytes(data.data, g_ds18b20_tx_buffer);
 171             b_ds18b20_dma_tx_done = false;
 172             HAL_UART_Transmit_DMA(&huart1, g_ds18b20_tx_buffer, 8);
 173         break;
 174 
 175         case DS18B20_QUEUE_BYTE_RX:
 176             memset(g_ds18b20_rx_buffer, 0, sizeof(g_ds18b20_rx_buffer));
 177             b_ds18b20_dma_rx_done = false;
 178             HAL_UARTEx_ReceiveToIdle_DMA(&huart1, g_ds18b20_rx_buffer, 8);
 179         break;
 180 
 181         case DS18B20_QUEUE_READ_LSB:
 182         case DS18B20_QUEUE_READ_MSB:
 183             b_ds18b20_dma_tx_done = false;
 184             b_ds18b20_dma_rx_done = false;
 185             b_ds18b20_rx_data_processed = false;
 186             memset(g_ds18b20_rx_buffer, 0, sizeof(g_ds18b20_rx_buffer));
 187             ds18b20_byte_to_array_of_bytes(0xFF, g_ds18b20_tx_buffer);
 188 
 189             HAL_UARTEx_ReceiveToIdle_DMA(&huart1, g_ds18b20_rx_buffer, 8);
 190             HAL_UART_Transmit_DMA(&huart1, g_ds18b20_tx_buffer, 8);
 191         break;
 192 
 193         case DS18B20_QUEUE_DELAY:
 194             g_ds18b20_tick = data.data;
 195         break;
 196 
 197         case DS18B20_QUEUE_SET_BAUD_SLOW:
 198             __HAL_UART_DISABLE(&huart1);
 199             LL_USART_SetBaudRate(USART1, HAL_RCC_GetPCLK2Freq(), G_RESET_BAUDRATE);
 200             __HAL_UART_ENABLE(&huart1);
 201         break;
 202 
 203         case DS18B20_QUEUE_SET_BAUD_FAST:
 204             __HAL_UART_DISABLE(&huart1);
 205             LL_USART_SetBaudRate(USART1, HAL_RCC_GetPCLK2Freq(), G_DATA_BAUDRATE);
 206             __HAL_UART_ENABLE(&huart1);
 207         break;
 208 
 209         case DS18B20_QUEUE_RESET:
 210             b_ds18b20_dma_tx_done = false;
 211             b_ds18b20_dma_rx_done = true;
 212             b_ds18b20_rx_data_processed = false;
 213             memset(g_ds18b20_rx_buffer, 0, sizeof(g_ds18b20_rx_buffer));
 214             g_ds18b20_tx_buffer[0] = 0xF0;
 215             HAL_UARTEx_ReceiveToIdle_DMA(&huart1, g_ds18b20_rx_buffer, 1);
 216             HAL_UART_Transmit_DMA(&huart1, g_ds18b20_tx_buffer, 1);
 217         break;
 218 
 219         default: break;
 220     }
 221 }
 222 
 223 static void ds18b20_byte_to_array_of_bytes(uint8_t byte, uint8_t *array)
 224 {
 225     for (uint8_t i = 0; i < 8; ++i)
 226     {
 227         array[i] = ((byte & (1 << i)) ? 0xFF : 0x00);
 228     }
 229 }
 230 
 231 static uint8_t ds18b20_get_rx_byte(void)
 232 {
 233     uint8_t received_value = 0;
 234 
 235     for (uint8_t i = 0; i < 8; ++i)
 236     {
 237         received_value |= (((g_ds18b20_rx_buffer[i] == 0xFF) ? 1 : 0) << i);
 238     }
 239 
 240     return received_value;
 241 }
 242 
 243 void ds18b20_async_tick(void)
 244 {
 245     if (!b_ds18b20_rx_data_processed)
 246     {
 247         b_ds18b20_rx_data_processed = true;
 248         switch(ds18b20_async_queue_tail().type)
 249         {
 250             case DS18B20_QUEUE_READ_LSB:
 251                 g_temp_lsb = ds18b20_get_rx_byte();
 252             break;
 253             case DS18B20_QUEUE_READ_MSB:
 254                 g_temp_msb = ds18b20_get_rx_byte();
 255                 g_ds18b20_temp = ((g_temp_msb << 8) | g_temp_lsb) / 16;
 256                 b_ds18b20_async_temp_ready = true;
 257                 g_ds18b20_update_count++;
 258             break;
 259             case DS18B20_QUEUE_RESET:
 260                 // TODO: Read presence byte
 261             break;
 262             default: break;
 263         }
 264     }
 265     else
 266     {
 267         if (0 < g_ds18b20_tick)
 268         {
 269             g_ds18b20_tick--;
 270         }
 271         else
 272         {
 273             if ((0 != ds18b20_async_queue.count)
 274                     && b_ds18b20_dma_tx_done
 275                     && b_ds18b20_dma_rx_done)
 276             {
 277                 ds18b20_dma_write(ds18b20_async_dequeue());
 278             }
 279         }
 280     }
 281 }
 282 
 283 void ds18b20_async_read_temp(void)
 284 {
 285     b_ds18b20_async_temp_ready = false;
 286 
 287     ds18b20_async_reset();
 288     ds18b20_async_enqueue((ds18b20_data_t){
 289             DS18B20_QUEUE_BYTE_TX, DS18B20_SKIP_ROM_CMD});
 290     ds18b20_async_enqueue((ds18b20_data_t){
 291             DS18B20_QUEUE_BYTE_TX, DS18B20_CONVERT_T_CMD});
 292     ds18b20_async_enqueue((ds18b20_data_t){
 293             DS18B20_QUEUE_DELAY, G_DS18B20_CONV_TIME_MS});
 294 
 295     ds18b20_async_reset();
 296     ds18b20_async_enqueue((ds18b20_data_t){
 297             DS18B20_QUEUE_BYTE_TX, DS18B20_SKIP_ROM_CMD});
 298     ds18b20_async_enqueue((ds18b20_data_t){
 299             DS18B20_QUEUE_BYTE_TX, DS18B20_READ_SCRATCHPAD_CMD});
 300     ds18b20_async_enqueue((ds18b20_data_t){DS18B20_QUEUE_READ_LSB});
 301     ds18b20_async_enqueue((ds18b20_data_t){DS18B20_QUEUE_READ_MSB});
 302 }
 303 
 304 bool ds18b20_async_temp_ready(void)
 305 {
 306     return b_ds18b20_async_temp_ready;
 307 }
 308 
 309 int16_t ds18b20_async_get_temp(void)
 310 {
 311     return g_ds18b20_temp;
 312 }
 313 
 314 static void ds18b20_async_enqueue(ds18b20_data_t data)
 315 {
 316     ds18b20_async_queue.count++;
 317     ds18b20_async_queue.queue[ds18b20_async_queue.head++] = data;
 318 }
 319 
 320 #if 0
 321 static ds18b20_data_t ds18b20_async_dequeue(void)
 322 {
 323     ds18b20_async_queue.count--;
 324     ds18b20_data_t ret = ds18b20_async_queue.queue[ds18b20_async_queue.tail];
 325 
 326     if ((DS18B20_QUEUE_READ_LSB != ret.type) || (DS18B20_QUEUE_READ_LSB != ret.type))
 327     {
 328         ds18b20_async_queue.tail++;
 329     }
 330 
 331     return res;
 332 }
 333 #endif
 334 
 335 static ds18b20_data_t ds18b20_async_dequeue(void)
 336 {
 337     ds18b20_async_queue.count--;
 338     return ds18b20_async_queue.queue[ds18b20_async_queue.tail++];
 339 }
 340 
 341 static ds18b20_data_t ds18b20_async_queue_tail(void)
 342 {
 343     return ds18b20_async_queue.queue[(ds18b20_async_queue.tail) - 1];
 344 }