]> mj.ucw.cz Git - home-hw.git/commitdiff
SSR: DS18B20
authorMartin Mares <mj@ucw.cz>
Wed, 8 Aug 2018 09:15:54 +0000 (11:15 +0200)
committerMartin Mares <mj@ucw.cz>
Wed, 8 Aug 2018 09:15:54 +0000 (11:15 +0200)
ssr/Inc/app.h
ssr/Inc/util.h
ssr/Makefile
ssr/Src/ds18b20.c [new file with mode: 0644]
ssr/Src/main.c

index 980422d55c2bf2c9c98554046c9d3878c94c16f6..f57ee6dae50bdda562f197145294207bb517c045 100644 (file)
@@ -9,3 +9,7 @@ extern byte tx_packet[64];
 extern volatile byte rx_packet_state, tx_packet_state;
 
 void tx_packet_send(void);
+
+// ds18b20.c
+
+void ds_test(void);
index 3a29fd63c476627d721b7db94d0e22d4bcb274f3..7e37313ad792bc4aada7cd2c23684f1874a5cb02 100644 (file)
@@ -62,8 +62,7 @@ static inline void put_u32_le(byte *p, u32 x)
 // debug.c
 
 #undef DEBUG_SEMIHOSTING
-// #define DEBUG_USART USART1
-#undef DEBUG_USART
+#define DEBUG_USART USART1
 
 void debug_printf(const char *fmt, ...);
 void debug_puts(const char *s);
index c5f919a9377bfc0985849f089c6d5c38cc9a4ce2..53278af209d4b815cfacea1e6ab3f19569812e31 100644 (file)
@@ -56,6 +56,7 @@ Src/main.c \
 Src/debug.c \
 Src/usb.c \
 Src/usbdev.c \
+Src/ds18b20.c \
 /aux/misc/stm/F1-package/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_rcc.c \
 /Src/system_stm32f1xx.c \
 Src/stm32f1xx_it.c \
diff --git a/ssr/Src/ds18b20.c b/ssr/Src/ds18b20.c
new file mode 100644 (file)
index 0000000..d44524d
--- /dev/null
@@ -0,0 +1,185 @@
+// DS18B20 Temperature Sensor
+
+#include "main.h"
+#include "util.h"
+#include "app.h"
+
+static volatile u32 ds_dma_buffer;
+
+#define DS_PORT THERMO_GPIO_Port
+#define DS_PIN THERMO_GPIO_Pin
+#define DS_PIN_MASK (1U << 7)          // Unfortunately, this cannot be inferred from the Pin constant
+#define DS_DMA DMA1
+#define DS_DMA_CHANNEL LL_DMA_CHANNEL_6
+#define DS_DEBUG
+
+#ifdef DS_DEBUG
+#define DEBUG debug_printf
+#else
+#define DEBUG(xxx, ...) do { } while (0)
+#endif
+
+static void ds_reset(void)
+{
+  DEBUG("DS18B20: Reset\n");
+  LL_TIM_DisableCounter(TIM3);
+  LL_TIM_SetOnePulseMode(TIM3, LL_TIM_ONEPULSEMODE_SINGLE);
+
+  // DMA for reading pin state
+  ds_dma_buffer = 0xdeadbeef;
+  LL_DMA_SetMemoryAddress(DS_DMA, DS_DMA_CHANNEL, (u32) &ds_dma_buffer);
+  LL_DMA_SetPeriphAddress(DS_DMA, DS_DMA_CHANNEL, (u32) &DS_PORT->IDR);
+  LL_DMA_SetDataLength(DS_DMA, DS_DMA_CHANNEL, 1);
+  LL_DMA_EnableChannel(DS_DMA, DS_DMA_CHANNEL);
+
+  LL_TIM_OC_InitTypeDef oc;
+
+  // CC1 is used to drive the DMA (read line state at specified time)
+  LL_TIM_OC_StructInit(&oc);
+  oc.OCMode = LL_TIM_OCMODE_FROZEN;
+  oc.CompareValue = 560;
+  LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH1, &oc);
+  LL_TIM_EnableDMAReq_CC1(TIM3);
+  LL_TIM_CC_SetDMAReqTrigger(TIM3, LL_TIM_CCDMAREQUEST_CC);
+
+  // CC2 is used to generate pulses (return line to idle state at specified time)
+  LL_TIM_OC_StructInit(&oc);
+  oc.OCMode = LL_TIM_OCMODE_FORCED_ACTIVE;
+  oc.OCState = LL_TIM_OCSTATE_ENABLE;
+  oc.CompareValue = 480;
+  oc.OCPolarity = LL_TIM_OCPOLARITY_LOW;
+  LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH2, &oc);
+
+  // Set timer period to the length of the whole transaction
+  LL_TIM_SetAutoReload(TIM3, 999);
+
+  // Pull line down and start timer
+  LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
+  LL_TIM_EnableCounter(TIM3);
+
+  // Wait until the timer expires
+  while (LL_TIM_IsEnabledCounter(TIM3))
+    ;
+  // Counter is automatically disabled at the end of cycle
+
+  // Disable DMA
+  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));
+}
+
+static void ds_send_byte(byte b)
+{
+  DEBUG("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);
+      LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
+      LL_TIM_EnableCounter(TIM3);
+      while (LL_TIM_IsEnabledCounter(TIM3))
+       ;
+    }
+}
+
+static byte ds_recv_byte(void)
+{
+  LL_TIM_SetAutoReload(TIM3, 79);      // Each read slot takes 80μs
+  LL_TIM_OC_SetCompareCH2(TIM3, 1);    // Generate 1μs pulse to start read slot
+  LL_TIM_OC_SetCompareCH1(TIM3, 8);    // Sample data 8μs after start of slot
+  LL_TIM_EnableDMAReq_CC1(TIM3);
+
+  uint out = 0;
+  for (uint m=1; m < 0x100; m <<= 1)
+    {
+      ds_dma_buffer = 0xdeadbeef;
+      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);
+      LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
+      LL_TIM_EnableCounter(TIM3);
+      while (LL_TIM_IsEnabledCounter(TIM3))
+       ;
+      debug_printf("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);
+  return out;
+}
+
+static byte ds_buf[10];
+
+static int ds_recv_block(uint n)
+{
+  uint crc = 0;
+  for (uint i=0; i<n; i++)
+    {
+      uint b = ds_recv_byte();
+      ds_buf[i] = b;
+      for (uint j=0; j<8; j++)
+       {
+         uint k = (b & 1) ^ (crc >> 7);
+         crc = (crc << 1) & 0xff;
+         if (k)
+           crc ^= 0x31;
+         b >>= 1;
+       }
+    }
+
+  if (crc)
+    {
+      debug_printf("WARNING: Invalid CRC %02x\n", crc);
+      return 0;
+    }
+  return 1;
+}
+
+void ds_test(void)
+{
+  uint cnt = 0;
+
+  debug_puts("Init\n");
+  NVIC_DisableIRQ(TIM3_IRQn);  // One day, we will handle everything from interrupts...
+
+  // Identify device
+  ds_reset();
+  ds_send_byte(0x33);
+  ds_recv_block(8);
+
+  for(;;);
+
+  // FIXME: Configure precision
+
+  for (;;)
+    {
+      LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin);
+      // debug_printf("Tick tock: %d\n", cnt);
+
+      // Start measurement
+      ds_reset();
+      ds_send_byte(0xcc);
+      ds_send_byte(0x44);
+      while (ds_recv_byte() != 0xff)
+       LL_mDelay(10);
+
+      // Read scratch pad
+      ds_reset();
+      ds_send_byte(0xcc);
+      ds_send_byte(0xbe);
+      ds_recv_block(9);
+      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++;
+    }
+}
index d10eb439d7d7d9e4a840f7fd8f8766d64707d733..419f049201ba92c5d40bd3676e698a2def673fad 100644 (file)
@@ -170,6 +170,8 @@ int main(void)
   LL_TIM_EnableIT_UPDATE(TIM4);
   LL_TIM_GenerateEvent_UPDATE(TIM4);
 
+  ds_test();
+
   /* USER CODE END 2 */
 
   /* Infinite loop */
@@ -337,7 +339,7 @@ static void MX_TIM3_Init(void)
   GPIO_InitStruct.Pin = THERMO_Pin;
   GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
   GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
-  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
+  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
   LL_GPIO_Init(THERMO_GPIO_Port, &GPIO_InitStruct);
 
 }