1 // DS18B20 Temperature Sensors
6 #include <libopencm3/cm3/cortex.h>
7 #include <libopencm3/stm32/dma.h>
8 #include <libopencm3/stm32/gpio.h>
9 #include <libopencm3/stm32/rcc.h>
10 #include <libopencm3/stm32/timer.h>
13 static volatile u32 ds_dma_buffer;
25 #define DEBUG debug_printf
27 #define DEBUG(xxx, ...) do { } while (0)
31 #define DEBUG2 debug_printf
33 #define DEBUG2(xxx, ...) do { } while (0)
36 // Current temperature
37 int ds_current_temp = DS_TEMP_UNKNOWN;
39 // Auxiliary functions which are missing from libopencm3
40 static inline bool timer_is_counter_enabled(u32 timer)
42 return TIM_CR1(timer) & TIM_CR1_CEN;
45 static inline void timer_enable_dma_cc1(u32 timer)
47 TIM_DIER(timer) |= TIM_DIER_CC1DE;
50 static inline void timer_disable_dma_cc1(u32 timer)
52 TIM_DIER(timer) &= ~TIM_DIER_CC1DE;
55 static bool ds_reset(void)
57 DEBUG2("DS18B20: Reset\n");
58 timer_disable_counter(DS_TIMER);
59 timer_one_shot_mode(DS_TIMER);
61 // DMA for reading pin state
62 ds_dma_buffer = 0xdeadbeef;
63 dma_set_memory_address(DS_DMA, DS_DMA_CH, (u32) &ds_dma_buffer);
64 dma_set_peripheral_address(DS_DMA, DS_DMA_CH, (u32) &GPIO_IDR(DS_GPIO));
65 dma_set_number_of_data(DS_DMA, DS_DMA_CH, 1);
66 dma_enable_channel(DS_DMA, DS_DMA_CH);
68 // CC1 is used to drive the DMA (read line state at specified time)
69 timer_disable_oc_output(DS_TIMER, TIM_OC1);
70 timer_set_oc_mode(DS_TIMER, TIM_OC1, TIM_OCM_FROZEN);
71 timer_set_oc_value(DS_TIMER, TIM_OC1, 560);
72 timer_set_dma_on_compare_event(DS_TIMER);
73 timer_enable_dma_cc1(DS_TIMER);
75 // CC2 is used to generate pulses (return line to idle state at specified time)
76 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
77 timer_enable_oc_output(DS_TIMER, TIM_OC2);
78 timer_set_oc_value(DS_TIMER, TIM_OC2, 480);
79 timer_set_oc_polarity_low(DS_TIMER, TIM_OC2);
81 // Set timer period to the length of the whole transaction (1 ms)
82 timer_set_period(DS_TIMER, 999);
84 // Pull line down and start timer
85 cm_disable_interrupts();
86 timer_enable_counter(DS_TIMER);
87 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
88 cm_enable_interrupts();
90 // Wait until the timer expires
91 while (timer_is_counter_enabled(DS_TIMER))
93 // Counter is automatically disabled at the end of cycle
96 timer_disable_dma_cc1(DS_TIMER);
97 dma_disable_channel(DS_DMA, DS_DMA_CH);
99 DEBUG2("Init DMA: %08x [%u] (%u remains)\n",
101 !!(ds_dma_buffer & GPIO7),
102 dma_get_number_of_data(DS_DMA, DS_DMA_CH));
104 // Did the device respond?
105 if (ds_dma_buffer & GPIO7) {
106 DEBUG("DS18B20: Initialization failed\n");
112 static void ds_send_bit(bool bit)
114 timer_set_period(DS_TIMER, 99); // Each write slot takes 100 μs
115 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
116 timer_set_oc_value(DS_TIMER, TIM_OC2, (bit ? 3 : 89)); // 1: 3μs pulse, 0: 89μs pulse
117 cm_disable_interrupts();
118 // XXX: On STM32F1, we must configure the OC channel _after_ we enable the counter,
119 // otherwise OC triggers immediately. Reasons?
120 timer_enable_counter(DS_TIMER);
121 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
122 cm_enable_interrupts();
123 while (timer_is_counter_enabled(DS_TIMER))
127 static void ds_send_byte(byte b)
129 DEBUG2("DS write: %02x\n", b);
130 for (uint m = 1; m < 0x100; m <<= 1)
134 static bool ds_recv_bit(void)
136 timer_set_period(DS_TIMER, 79); // Each read slot takes 80μs
137 timer_set_oc_value(DS_TIMER, TIM_OC2, 2); // Generate 2μs pulse to start read slot
138 timer_set_oc_value(DS_TIMER, TIM_OC1, 8); // Sample data 8μs after start of slot
139 timer_enable_dma_cc1(DS_TIMER);
141 ds_dma_buffer = 0xdeadbeef;
142 dma_set_number_of_data(DS_DMA, DS_DMA_CH, 1);
143 dma_enable_channel(DS_DMA, DS_DMA_CH);
144 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
145 cm_disable_interrupts();
146 timer_enable_counter(DS_TIMER);
147 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
148 cm_enable_interrupts();
149 while (timer_is_counter_enabled(DS_TIMER))
151 // DEBUG2("XXX %08x\n", ds_dma_buffer);
152 bool out = ds_dma_buffer & GPIO7;
153 dma_disable_channel(DS_DMA, DS_DMA_CH);
155 timer_disable_dma_cc1(DS_TIMER);
160 static byte ds_recv_byte(void)
163 for (uint m = 1; m < 0x100; m <<= 1) {
168 DEBUG2("DS read: %02x\n", out);
172 static byte ds_buf[10];
174 static byte ds_crc_block(uint n)
176 /// XXX: This might be worth optimizing
179 for (uint i = 0; i < n; i++) {
181 for (uint j = 0; j < 8; j++) {
182 uint k = (b & 1) ^ (crc >> 7);
183 crc = (crc << 1) & 0xff;
193 static bool ds_recv_block(uint n)
195 for (uint i = 0; i < n; i++)
196 ds_buf[i] = ds_recv_byte();
198 byte crc = ds_crc_block(n);
200 DEBUG("DS18B20: Invalid CRC %02x\n", crc);
206 struct ds_sensor ds_sensors[DS_NUM_SENSORS];
208 #if DS_NUM_SENSORS == 1
210 static void ds_enumerate(void)
215 ds_send_byte(0x33); // READ_ROM
216 if (!ds_recv_block(8))
219 DEBUG("DS18B20: Found sensor ");
220 for (uint i = 0; i < 8; i++) {
221 DEBUG("%02x", ds_buf[i]);
222 ds_sensors[0].address[i] = ds_buf[i];
229 static void ds_enumerate(void)
232 * The enumeration algorithm roughly follows the one described in the
233 * Book of iButton Standards (Maxim Integrated Application Note 937).
235 * It simulates depth-first search on the trie of all device IDs.
236 * In each pass, it walks the trie from the root and recognizes branching nodes.
238 * The old_choice variable remembers the deepest left branch taken in the
239 * previous pass, new_choice is the same for the current pass.
242 DEBUG("DS18B20: Enumerate\n");
244 uint num_sensors = 0;
250 DEBUG("DS18B20: Enumeration found no sensor\n");
254 ds_send_byte(0xf0); // SEARCH_ROM
256 for (byte i=0; i<64; i++) {
257 bool have_one = ds_recv_bit();
258 bool have_zero = ds_recv_bit();
259 bool old_bit = addr[i/8] & (1U << (i%8));
261 switch (2*have_one + have_zero) {
263 // This should not happen
264 DEBUG("DS18B20: Enumeration failed\n");
278 else if (i > old_choice) {
288 addr[i/8] |= 1U << (i%8);
290 addr[i/8] &= ~(1U << (i%8));
291 ds_send_bit(new_bit);
294 if (num_sensors >= DS_NUM_SENSORS) {
295 DEBUG("DS18B20: Too many sensors\n");
299 DEBUG("DS18B20: Found sensor #%u: ", num_sensors);
300 for (byte i=0; i<8; i++)
301 DEBUG("%02x", addr[i]);
302 if (ds_crc_block(8)) {
303 DEBUG(" - invalid CRC!\n");
304 } else if (ds_buf[0] == 0x28) {
306 memcpy(ds_sensors[num_sensors].address, ds_buf, 8);
309 DEBUG(" - wrong type\n");
312 old_choice = new_choice;
322 DEBUG("DS18B20: Init\n");
324 for (uint i = 0; i < DS_NUM_SENSORS; i++) {
325 memset(ds_sensors[i].address, 0, 8);
326 ds_sensors[i].current_temp = DS_TEMP_UNKNOWN;
329 dma_set_read_from_peripheral(DS_DMA, DS_DMA_CH);
330 dma_set_priority(DS_DMA, DS_DMA_CH, DMA_CCR_PL_VERY_HIGH);
331 dma_disable_peripheral_increment_mode(DS_DMA, DS_DMA_CH);
332 dma_enable_memory_increment_mode(DS_DMA, DS_DMA_CH);
333 dma_set_peripheral_size(DS_DMA, DS_DMA_CH, DMA_CCR_PSIZE_16BIT);
334 dma_set_memory_size(DS_DMA, DS_DMA_CH, DMA_CCR_MSIZE_16BIT);
336 timer_set_prescaler(DS_TIMER, 71); // 1 tick = 1 μs
337 timer_set_mode(DS_TIMER, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
338 timer_disable_preload(DS_TIMER);
340 gpio_set_mode(DS_GPIO, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO7);
344 // FIXME: Configure precision?
347 #if DS_NUM_SENSORS == 1
348 #define ds_current_id 0
350 static byte ds_current_id;
353 static bool ds_activate(void)
356 DEBUG("DS18B20: Reset failed\n");
359 #if DS_NUM_SENSORS == 1
360 ds_send_byte(0xcc); // SKIP_ROM
362 ds_send_byte(0x55); // MATCH_ROM
363 for (uint i = 0; i < 8; i++)
364 ds_send_byte(ds_sensors[ds_current_id].address[i]);
371 static byte ds_running;
372 static byte ds_timeout;
376 #if DS_NUM_SENSORS != 1
377 uint maxn = DS_NUM_SENSORS;
382 if (ds_current_id >= DS_NUM_SENSORS) {
385 } while (!ds_sensors[ds_current_id].address[0]);
387 if (!ds_activate()) {
388 ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
391 ds_send_byte(0x44); // CONVERT_T
396 if (!ds_recv_bit()) {
398 DEBUG("DS18B20 #%u: Timeout\n", ds_current_id);
399 ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
409 ds_send_byte(0xbe); // READ_SCRATCHPAD
410 if (!ds_recv_block(9)) {
411 ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
414 int t = (int16_t) (ds_buf[0] | (ds_buf[1] << 8));
417 DEBUG("DS18B20 #%u: %d.%03d degC\n", ds_current_id, t / 1000, t % 1000);
418 ds_sensors[ds_current_id].current_temp = t;