]> mj.ucw.cz Git - home-hw.git/blobdiff - ssr/Src/ds18b20.c
SSR: Temperature measurement over USB
[home-hw.git] / ssr / Src / ds18b20.c
index 0b9b49b00f8d4ebb7a30dffafca0f735a47c7d60..5fa25a129f0ab4249676ea06473694dbffb7b295 100644 (file)
@@ -12,6 +12,7 @@ static volatile u32 ds_dma_buffer;
 #define DS_DMA DMA1
 #define DS_DMA_CHANNEL LL_DMA_CHANNEL_6
 #undef DS_DEBUG
+#undef DS_DEBUG2
 
 #ifdef DS_DEBUG
 #define DEBUG debug_printf
@@ -19,9 +20,18 @@ static volatile u32 ds_dma_buffer;
 #define DEBUG(xxx, ...) do { } while (0)
 #endif
 
-static void ds_reset(void)
+#ifdef DS_DEBUG2
+#define DEBUG2 debug_printf
+#else
+#define DEBUG2(xxx, ...) do { } while (0)
+#endif
+
+// Current temperature
+int ds_current_temp = DS_TEMP_UNKNOWN;
+
+static bool ds_reset(void)
 {
-  DEBUG("DS18B20: Reset\n");
+  DEBUG2("DS18B20: Reset\n");
   LL_TIM_DisableCounter(TIM3);
   LL_TIM_SetOnePulseMode(TIM3, LL_TIM_ONEPULSEMODE_SINGLE);
 
@@ -66,19 +76,32 @@ static void ds_reset(void)
   LL_TIM_DisableDMAReq_CC1(TIM3);
   LL_DMA_DisableChannel(DS_DMA, DS_DMA_CHANNEL);
 
-  DEBUG("Init DMA: %08x [%u] (%u remains)\n", ds_dma_buffer, !!(ds_dma_buffer & DS_PIN_MASK), LL_DMA_GetDataLength(DS_DMA, DS_DMA_CHANNEL));
+  DEBUG2("Init DMA: %08x [%u] (%u remains)\n", ds_dma_buffer, !!(ds_dma_buffer & DS_PIN_MASK), LL_DMA_GetDataLength(DS_DMA, DS_DMA_CHANNEL));
+
+  // Did the device respond?
+  if (ds_dma_buffer & DS_PIN_MASK)
+    {
+      DEBUG("DS18B20: Initialization failed\n");
+      return 0;
+    }
+  else
+    return 1;
 }
 
 static void ds_send_byte(byte b)
 {
-  DEBUG("DS write: %02x\n", b);
+  DEBUG2("DS write: %02x\n", b);
   LL_TIM_SetAutoReload(TIM3, 99);      // Each write slot takes 100μs
   for (uint m=1; m < 0x100; m <<= 1)
     {
       LL_TIM_OC_SetCompareCH2(TIM3, ((b & m) ? 1 : 89));       // 1: 1μs pulse, 0: 89μs pulse
       LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FORCED_ACTIVE);
+      __disable_irq();
+      // XXX: On STM32F1, we must configure the OC channel _after_ we enable the counter,
+      // otherwise OC triggers immediately. Reasons?
       LL_TIM_EnableCounter(TIM3);
       LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
+      __enable_irq();
       while (LL_TIM_IsEnabledCounter(TIM3))
        ;
     }
@@ -98,30 +121,32 @@ static byte ds_recv_byte(void)
       LL_DMA_SetDataLength(DS_DMA, DS_DMA_CHANNEL, 1);
       LL_DMA_EnableChannel(DS_DMA, DS_DMA_CHANNEL);
       LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FORCED_ACTIVE);
+      __disable_irq();
       LL_TIM_EnableCounter(TIM3);
       LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
+      __enable_irq();
       while (LL_TIM_IsEnabledCounter(TIM3))
        ;
-      DEBUG("XXX %08x\n", ds_dma_buffer);
+      DEBUG2("XXX %08x\n", ds_dma_buffer);
       if (ds_dma_buffer & DS_PIN_MASK)
        out |= m;
       LL_DMA_DisableChannel(DS_DMA, DS_DMA_CHANNEL);
     }
 
   LL_TIM_DisableDMAReq_CC1(TIM3);
-  DEBUG("DS read: %02x\n", out);
+  DEBUG2("DS read: %02x\n", out);
   return out;
 }
 
 static byte ds_buf[10];
 
-static int ds_recv_block(uint n)
+static bool ds_recv_block(uint n)
 {
   uint crc = 0;
   for (uint i=0; i<n; i++)
     {
       uint b = ds_recv_byte();
-      // debug_printf("%02x ", b);
+      // DEBUG("%02x ", b);
       ds_buf[i] = b;
       for (uint j=0; j<8; j++)
        {
@@ -132,54 +157,79 @@ static int ds_recv_block(uint n)
          b >>= 1;
        }
     }
-  // debug_printf("\n");
 
   if (crc)
     {
-      debug_printf("WARNING: Invalid CRC %02x\n", crc);
+      DEBUG("DS18B20: Invalid CRC %02x\n", crc);
       return 0;
     }
   return 1;
 }
 
-void ds_test(void)
+void ds_init(void)
 {
-  uint cnt = 0;
-
-  debug_puts("Init\n");
+  DEBUG("DS18B20: Init\n");
   NVIC_DisableIRQ(TIM3_IRQn);  // One day, we will handle everything from interrupts...
 
   // Identify device
-  ds_reset();
+  if (!ds_reset())
+    return;
   ds_send_byte(0x33);
   ds_recv_block(8);
 
   // FIXME: Configure precision
+}
 
-  for (;;)
-    {
-      LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin);
-      // debug_printf("Tick tock: %d\n", cnt);
+void ds_step(void)
+{
+  static byte ds_running;
+  static byte ds_timeout;
 
+  if (!ds_running)
+    {
       // Start measurement
-      ds_reset();
+      if (!ds_reset())
+       {
+         ds_current_temp = DS_TEMP_UNKNOWN;
+         return;
+       }
       ds_send_byte(0xcc);
       ds_send_byte(0x44);
-      while (ds_recv_byte() != 0xff)
-       LL_mDelay(10);
+      ds_running = 1;
+      ds_timeout = 255;
+    }
+  else
+    {
+      // Still running?
+      if (ds_recv_byte() != 0xff)
+       {
+         if (!ds_timeout--)
+           {
+             ds_current_temp = DS_TEMP_UNKNOWN;
+             ds_running = 0;
+             DEBUG("DS18B20: Timeout\n");
+           }
+         return;
+       }
+      ds_running = 0;
 
       // Read scratch pad
-      ds_reset();
+      if (!ds_reset())
+       {
+         ds_current_temp = DS_TEMP_UNKNOWN;
+         return;
+       }
       ds_send_byte(0xcc);
       ds_send_byte(0xbe);
-      ds_recv_block(9);
+      if (!ds_recv_block(9))
+       {
+         ds_current_temp = DS_TEMP_UNKNOWN;
+         return;
+       }
       int t = (int16_t)(ds_buf[0] | (ds_buf[1] << 8));
       t = t*1000/16;
 
-      LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin);
-      debug_printf("Temp: %d.%03d degC\n", t/1000, t%1000);
-
-      LL_mDelay(1000);
-      cnt++;
+      DEBUG("DS18B20: %d.%03d degC\n", t/1000, t%1000);
+      ds_current_temp = t;
     }
 }