1 // DS18B20 Temperature Sensor
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>
12 static volatile u32 ds_dma_buffer;
24 #define DEBUG debug_printf
26 #define DEBUG(xxx, ...) do { } while (0)
30 #define DEBUG2 debug_printf
32 #define DEBUG2(xxx, ...) do { } while (0)
35 // Current temperature
36 int ds_current_temp = DS_TEMP_UNKNOWN;
38 // Auxiliary functions which are missing from libopencm3
39 static inline bool timer_is_counter_enabled(u32 timer)
41 return TIM_CR1(timer) & TIM_CR1_CEN;
44 static inline void timer_enable_dma_cc1(u32 timer)
46 TIM_DIER(timer) |= TIM_DIER_CC1DE;
49 static inline void timer_disable_dma_cc1(u32 timer)
51 TIM_DIER(timer) &= ~TIM_DIER_CC1DE;
54 static bool ds_reset(void)
56 DEBUG2("DS18B20: Reset\n");
57 timer_disable_counter(DS_TIMER);
58 timer_one_shot_mode(DS_TIMER);
60 // DMA for reading pin state
61 ds_dma_buffer = 0xdeadbeef;
62 dma_set_memory_address(DS_DMA, DS_DMA_CH, (u32) &ds_dma_buffer);
63 dma_set_peripheral_address(DS_DMA, DS_DMA_CH, (u32) &GPIO_IDR(DS_GPIO));
64 dma_set_number_of_data(DS_DMA, DS_DMA_CH, 1);
65 dma_enable_channel(DS_DMA, DS_DMA_CH);
67 // CC1 is used to drive the DMA (read line state at specified time)
68 timer_disable_oc_output(DS_TIMER, TIM_OC1);
69 timer_set_oc_mode(DS_TIMER, TIM_OC1, TIM_OCM_FROZEN);
70 timer_set_oc_value(DS_TIMER, TIM_OC1, 560);
71 timer_set_dma_on_compare_event(DS_TIMER);
72 timer_enable_dma_cc1(DS_TIMER);
74 // CC2 is used to generate pulses (return line to idle state at specified time)
75 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
76 timer_enable_oc_output(DS_TIMER, TIM_OC2);
77 timer_set_oc_value(DS_TIMER, TIM_OC2, 480);
78 timer_set_oc_polarity_low(DS_TIMER, TIM_OC2);
80 // Set timer period to the length of the whole transaction (1 ms)
81 timer_set_period(DS_TIMER, 999);
83 // Pull line down and start timer
84 cm_disable_interrupts();
85 timer_enable_counter(DS_TIMER);
86 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
87 cm_enable_interrupts();
89 // Wait until the timer expires
90 while (timer_is_counter_enabled(DS_TIMER))
92 // Counter is automatically disabled at the end of cycle
95 timer_disable_dma_cc1(DS_TIMER);
96 dma_disable_channel(DS_DMA, DS_DMA_CH);
98 DEBUG2("Init DMA: %08x [%u] (%u remains)\n",
100 !!(ds_dma_buffer & GPIO7),
101 dma_get_number_of_data(DS_DMA, DS_DMA_CH));
103 // Did the device respond?
104 if (ds_dma_buffer & GPIO7) {
105 DEBUG("DS18B20: Initialization failed\n");
111 static void ds_send_byte(byte b)
113 DEBUG2("DS write: %02x\n", b);
114 timer_set_period(DS_TIMER, 99); // Each write slot takes 100 μs
115 for (uint m = 1; m < 0x100; m <<= 1) {
116 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
117 timer_set_oc_value(DS_TIMER, TIM_OC2, ((b & m) ? 3 : 89)); // 1: 3μs pulse, 0: 89μs pulse
118 cm_disable_interrupts();
119 // XXX: On STM32F1, we must configure the OC channel _after_ we enable the counter,
120 // otherwise OC triggers immediately. Reasons?
121 timer_enable_counter(DS_TIMER);
122 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
123 cm_enable_interrupts();
124 while (timer_is_counter_enabled(DS_TIMER))
129 static byte ds_recv_byte(void)
131 timer_set_period(DS_TIMER, 79); // Each read slot takes 80μs
132 timer_set_oc_value(DS_TIMER, TIM_OC2, 2); // Generate 2μs pulse to start read slot
133 timer_set_oc_value(DS_TIMER, TIM_OC1, 8); // Sample data 8μs after start of slot
134 timer_enable_dma_cc1(DS_TIMER);
137 for (uint m = 1; m < 0x100; m <<= 1) {
138 ds_dma_buffer = 0xdeadbeef;
139 dma_set_number_of_data(DS_DMA, DS_DMA_CH, 1);
140 dma_enable_channel(DS_DMA, DS_DMA_CH);
141 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
142 cm_disable_interrupts();
143 timer_enable_counter(DS_TIMER);
144 timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
145 cm_enable_interrupts();
146 while (timer_is_counter_enabled(DS_TIMER))
148 // DEBUG2("XXX %08x\n", ds_dma_buffer);
149 if (ds_dma_buffer & GPIO7)
151 dma_disable_channel(DS_DMA, DS_DMA_CH);
154 timer_disable_dma_cc1(DS_TIMER);
155 DEBUG2("DS read: %02x\n", out);
159 static byte ds_buf[10];
161 static bool ds_recv_block(uint n)
164 for (uint i = 0; i < n; i++) {
165 uint b = ds_recv_byte();
166 // DEBUG("%02x ", b);
168 for (uint j = 0; j < 8; j++) {
169 uint k = (b & 1) ^ (crc >> 7);
170 crc = (crc << 1) & 0xff;
178 DEBUG("DS18B20: Invalid CRC %02x\n", crc);
186 DEBUG("DS18B20: Init\n");
188 dma_set_read_from_peripheral(DS_DMA, DS_DMA_CH);
189 dma_set_priority(DS_DMA, DS_DMA_CH, DMA_CCR_PL_VERY_HIGH);
190 dma_disable_peripheral_increment_mode(DS_DMA, DS_DMA_CH);
191 dma_enable_memory_increment_mode(DS_DMA, DS_DMA_CH);
192 dma_set_peripheral_size(DS_DMA, DS_DMA_CH, DMA_CCR_PSIZE_16BIT);
193 dma_set_memory_size(DS_DMA, DS_DMA_CH, DMA_CCR_MSIZE_16BIT);
195 timer_set_prescaler(DS_TIMER, 71); // 1 tick = 1 μs
196 timer_set_mode(DS_TIMER, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
197 timer_disable_preload(DS_TIMER);
199 gpio_set_mode(DS_GPIO, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO7);
207 // FIXME: Configure precision
212 static byte ds_running;
213 static byte ds_timeout;
218 ds_current_temp = DS_TEMP_UNKNOWN;
227 if (ds_recv_byte() != 0xff) {
229 ds_current_temp = DS_TEMP_UNKNOWN;
231 DEBUG("DS18B20: Timeout\n");
239 ds_current_temp = DS_TEMP_UNKNOWN;
244 if (!ds_recv_block(9)) {
245 ds_current_temp = DS_TEMP_UNKNOWN;
248 int t = (int16_t) (ds_buf[0] | (ds_buf[1] << 8));
251 DEBUG("DS18B20: %d.%03d degC\n", t / 1000, t % 1000);