1 // DS18B20 Temperature Sensor
7 static volatile u32 ds_dma_buffer;
9 #define DS_PORT THERMO_GPIO_Port
10 #define DS_PIN THERMO_GPIO_Pin
11 #define DS_PIN_MASK (1U << 7) // Unfortunately, this cannot be inferred from the Pin constant
13 #define DS_DMA_CHANNEL LL_DMA_CHANNEL_6
18 #define DEBUG debug_printf
20 #define DEBUG(xxx, ...) do { } while (0)
24 #define DEBUG2 debug_printf
26 #define DEBUG2(xxx, ...) do { } while (0)
29 // Current temperature
30 int ds_current_temp = DS_TEMP_UNKNOWN;
32 static bool ds_reset(void)
34 DEBUG2("DS18B20: Reset\n");
35 LL_TIM_DisableCounter(TIM3);
36 LL_TIM_SetOnePulseMode(TIM3, LL_TIM_ONEPULSEMODE_SINGLE);
38 // DMA for reading pin state
39 ds_dma_buffer = 0xdeadbeef;
40 LL_DMA_SetMemoryAddress(DS_DMA, DS_DMA_CHANNEL, (u32) &ds_dma_buffer);
41 LL_DMA_SetPeriphAddress(DS_DMA, DS_DMA_CHANNEL, (u32) &DS_PORT->IDR);
42 LL_DMA_SetDataLength(DS_DMA, DS_DMA_CHANNEL, 1);
43 LL_DMA_EnableChannel(DS_DMA, DS_DMA_CHANNEL);
45 LL_TIM_OC_InitTypeDef oc;
47 // CC1 is used to drive the DMA (read line state at specified time)
48 LL_TIM_OC_StructInit(&oc);
49 oc.OCMode = LL_TIM_OCMODE_FROZEN;
50 oc.CompareValue = 560;
51 LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH1, &oc);
52 LL_TIM_EnableDMAReq_CC1(TIM3);
53 LL_TIM_CC_SetDMAReqTrigger(TIM3, LL_TIM_CCDMAREQUEST_CC);
55 // CC2 is used to generate pulses (return line to idle state at specified time)
56 LL_TIM_OC_StructInit(&oc);
57 oc.OCMode = LL_TIM_OCMODE_FORCED_ACTIVE;
58 oc.OCState = LL_TIM_OCSTATE_ENABLE;
59 oc.CompareValue = 480;
60 oc.OCPolarity = LL_TIM_OCPOLARITY_LOW;
61 LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH2, &oc);
63 // Set timer period to the length of the whole transaction
64 LL_TIM_SetAutoReload(TIM3, 999);
66 // Pull line down and start timer
67 LL_TIM_EnableCounter(TIM3);
68 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
70 // Wait until the timer expires
71 while (LL_TIM_IsEnabledCounter(TIM3))
73 // Counter is automatically disabled at the end of cycle
76 LL_TIM_DisableDMAReq_CC1(TIM3);
77 LL_DMA_DisableChannel(DS_DMA, DS_DMA_CHANNEL);
79 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));
81 // Did the device respond?
82 if (ds_dma_buffer & DS_PIN_MASK)
84 DEBUG("DS18B20: Initialization failed\n");
91 static void ds_send_byte(byte b)
93 DEBUG2("DS write: %02x\n", b);
94 LL_TIM_SetAutoReload(TIM3, 99); // Each write slot takes 100μs
95 for (uint m=1; m < 0x100; m <<= 1)
97 LL_TIM_OC_SetCompareCH2(TIM3, ((b & m) ? 1 : 89)); // 1: 1μs pulse, 0: 89μs pulse
98 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FORCED_ACTIVE);
100 // XXX: On STM32F1, we must configure the OC channel _after_ we enable the counter,
101 // otherwise OC triggers immediately. Reasons?
102 LL_TIM_EnableCounter(TIM3);
103 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
105 while (LL_TIM_IsEnabledCounter(TIM3))
110 static byte ds_recv_byte(void)
112 LL_TIM_SetAutoReload(TIM3, 79); // Each read slot takes 80μs
113 LL_TIM_OC_SetCompareCH2(TIM3, 1); // Generate 1μs pulse to start read slot
114 LL_TIM_OC_SetCompareCH1(TIM3, 8); // Sample data 8μs after start of slot
115 LL_TIM_EnableDMAReq_CC1(TIM3);
118 for (uint m=1; m < 0x100; m <<= 1)
120 ds_dma_buffer = 0xdeadbeef;
121 LL_DMA_SetDataLength(DS_DMA, DS_DMA_CHANNEL, 1);
122 LL_DMA_EnableChannel(DS_DMA, DS_DMA_CHANNEL);
123 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FORCED_ACTIVE);
125 LL_TIM_EnableCounter(TIM3);
126 LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE);
128 while (LL_TIM_IsEnabledCounter(TIM3))
130 DEBUG2("XXX %08x\n", ds_dma_buffer);
131 if (ds_dma_buffer & DS_PIN_MASK)
133 LL_DMA_DisableChannel(DS_DMA, DS_DMA_CHANNEL);
136 LL_TIM_DisableDMAReq_CC1(TIM3);
137 DEBUG2("DS read: %02x\n", out);
141 static byte ds_buf[10];
143 static bool ds_recv_block(uint n)
146 for (uint i=0; i<n; i++)
148 uint b = ds_recv_byte();
149 // DEBUG("%02x ", b);
151 for (uint j=0; j<8; j++)
153 uint k = (b & 1) ^ (crc >> 7);
154 crc = (crc << 1) & 0xff;
163 DEBUG("DS18B20: Invalid CRC %02x\n", crc);
171 DEBUG("DS18B20: Init\n");
172 NVIC_DisableIRQ(TIM3_IRQn); // One day, we will handle everything from interrupts...
180 // FIXME: Configure precision
185 static byte ds_running;
186 static byte ds_timeout;
193 ds_current_temp = DS_TEMP_UNKNOWN;
204 if (ds_recv_byte() != 0xff)
208 ds_current_temp = DS_TEMP_UNKNOWN;
210 DEBUG("DS18B20: Timeout\n");
219 ds_current_temp = DS_TEMP_UNKNOWN;
224 if (!ds_recv_block(9))
226 ds_current_temp = DS_TEMP_UNKNOWN;
229 int t = (int16_t)(ds_buf[0] | (ds_buf[1] << 8));
232 DEBUG("DS18B20: %d.%03d degC\n", t/1000, t%1000);