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 }
