Commit | Line | Data |
---|---|---|
93ac315e MPM |
1 | /* $Id: ds1820.c,v 1.3 2010/07/16 19:31:18 simimeie Exp $ |
2 | * USB interface for ds1820 | |
3 | * This file handles everything that has to do with the temperature probes. | |
4 | * (C) Michael "Fox" Meier 2009 | |
5 | */ | |
6 | ||
7 | #include "usbdrv/usbdrv.h" | |
8 | #include "ds1wire.h" | |
9 | #include "time.h" | |
10 | ||
11 | #include "ds1820.h" | |
12 | ||
13 | struct probe ds1820probes[DS1820_MAXPROBES]; | |
14 | ||
15 | void ds1820init(void) { | |
16 | ds1wire_init(B, 0); | |
17 | ds1wire_reset(B, 0); | |
18 | } | |
19 | ||
20 | void ds1820killbus(void) { | |
21 | ds1wire_pulldown(B, 0); | |
22 | } | |
23 | ||
24 | static void ds1820write(uint8_t val) { | |
25 | uint8_t i; | |
26 | for (i = 0; i < 8; i++) { | |
27 | if (val & 0x01) { | |
28 | ds1wire_send1(B, 0); | |
29 | } else { | |
30 | ds1wire_send0(B, 0); | |
31 | } | |
32 | val >>= 1; | |
33 | } | |
34 | } | |
35 | ||
36 | static uint8_t ds1820read(void) { | |
37 | uint8_t i; | |
38 | uint8_t res = 0; | |
39 | for (i = 0; i < 8; i++) { | |
40 | res |= ((ds1wire_read(B, 0)) << i); | |
41 | } | |
42 | return res; | |
43 | } | |
44 | ||
45 | void ds1820queryprobe(uint8_t probenum) | |
46 | { | |
47 | uint8_t i; uint8_t crc = 0; | |
48 | ds1wire_reset(B, 0); | |
49 | #ifdef KISS | |
50 | ds1820write(DS1820_CMD_SKIPROM); /* Skip ROM */ | |
51 | #else | |
52 | ds1820write(DS1820_CMD_MATCHROM); /* Match ROM */ | |
53 | /* Send 64 bit serial */ | |
54 | ds1820write(ds1820probes[probenum].family); | |
55 | crc = ds1wire_calccrc8(crc, ds1820probes[probenum].family); | |
56 | for (i = 0; i < 6; i++) { | |
57 | ds1820write(ds1820probes[probenum].serial[i]); | |
58 | crc = ds1wire_calccrc8(crc, ds1820probes[probenum].serial[i]); | |
59 | } | |
60 | ds1820write(crc); | |
61 | #endif /* KISS */ | |
62 | /* Issue 'start temperature conversion' */ | |
63 | ds1820write(DS1820_CMD_CONVERTT); | |
64 | if (ds1820probes[probenum].flags & DS1820FLAG_PARASITE) { | |
65 | /* Provide parasite power */ | |
66 | ds1wire_parasitepoweron(B, 0); | |
67 | } | |
68 | } | |
69 | ||
70 | /* Returns 1 on successful update, 0 otherwise */ | |
71 | uint8_t ds1820updateprobe(uint8_t probenum) | |
72 | { | |
73 | uint8_t i; uint8_t crc = 0; uint8_t t1 = 0; uint8_t t2 = 0; | |
74 | if (ds1820probes[probenum].flags & DS1820FLAG_PARASITE) { | |
75 | /* No longer provide parasite power */ | |
76 | ds1wire_parasitepoweroff(B, 0); | |
77 | } | |
78 | ds1wire_reset(B, 0); | |
79 | #ifdef KISS | |
80 | ds1820write(DS1820_CMD_SKIPROM); /* Skip ROM */ | |
81 | #else | |
82 | ds1820write(DS1820_CMD_MATCHROM); /* Match ROM */ | |
83 | /* Send 64 bit serial */ | |
84 | ds1820write(ds1820probes[probenum].family); | |
85 | crc = ds1wire_calccrc8(crc, ds1820probes[probenum].family); | |
86 | for (i = 0; i < 6; i++) { | |
87 | ds1820write(ds1820probes[probenum].serial[i]); | |
88 | crc = ds1wire_calccrc8(crc, ds1820probes[probenum].serial[i]); | |
89 | } | |
90 | ds1820write(crc); | |
91 | #endif /* KISS */ | |
92 | /* Read Scratchpad */ | |
93 | ds1820write(DS1820_CMD_READSCRPAD); | |
94 | crc = 0; | |
95 | for (i = 0; i < 9; i++) { | |
96 | uint8_t v = ds1820read(); | |
97 | if (i == 0) { t1 = v; } | |
98 | if (i == 1) { t2 = v; } | |
99 | crc = ds1wire_calccrc8(crc, v); | |
100 | } | |
101 | /* For parasite powered probes, reading 0x50 0x05 (85.0 deg) usually | |
102 | * means the probe has lost power during temperature conversion and | |
103 | * reset (85.0 is the poweron value of the temperature scratchpad). | |
104 | * So we filter the value 85.0 for parasite powered probes. This means | |
105 | * you can never use parasite powered probes for temperatures in this | |
106 | * range. */ | |
107 | if ((crc == 0) | |
108 | && (((ds1820probes[probenum].flags & DS1820FLAG_PARASITE) == 0) | |
109 | || (t1 != 0x50) || (t2 != 0x05))) { | |
110 | ds1820probes[probenum].lastts = gettime(); | |
111 | ds1820probes[probenum].lasttemp[0] = t1; | |
112 | ds1820probes[probenum].lasttemp[1] = t2; | |
113 | return 1; | |
114 | } else { | |
115 | return 0; | |
116 | } | |
117 | } | |
118 | ||
119 | /* This is going to be a tough one: | |
120 | * Scan the bus to find all probes. | |
121 | */ | |
122 | void ds1820scan(void) { | |
123 | #ifdef KISS | |
124 | ds1wire_reset(B, 0); | |
125 | ds1820probes[0].flags |= DS1820FLAG_SLOTINUSE; | |
126 | ds1820write(DS1820_CMD_SKIPROM); /* Skip ROM */ | |
127 | ds1820write(DS1820_CMD_READPOWER); /* Read power supply */ | |
128 | if (ds1wire_read(B, 0) == 0) { /* Parasite powered probes return 0 */ | |
129 | ds1820probes[0].flags |= DS1820FLAG_PARASITE; | |
130 | } else { | |
131 | ds1820probes[0].flags &= ~DS1820FLAG_PARASITE; | |
132 | } | |
133 | #else /* KISS */ | |
134 | uint8_t lastserialfound[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
135 | int8_t lastcolwith0 = -1; | |
136 | int8_t prevcolwith0; | |
137 | int8_t i; | |
138 | uint8_t j; | |
139 | for (i = 0; i < DS1820_MAXPROBES; i++) { /* Clear list of probes */ | |
140 | ds1820probes[i].flags = 0; | |
141 | } | |
142 | do { | |
143 | ds1wire_reset(B, 0); | |
144 | prevcolwith0 = lastcolwith0; | |
145 | lastcolwith0 = -1; | |
146 | /* Send scan command */ | |
147 | ds1820write(DS1820_CMD_SEARCHROM); | |
148 | for (i = 0; i < 64; i++) { | |
149 | uint8_t val1 = ds1wire_read(B, 0); | |
150 | uint8_t val2 = ds1wire_read(B, 0); | |
151 | if (val1 == val2) { /* Collission */ | |
152 | if (val1 == 1) { /* and thus val2 is 1 too */ | |
153 | /* Nothing matched on the bus! This is actually pretty fatal! */ | |
154 | /* Try to get out alive. Send all 0. */ | |
155 | ds1wire_send0(B, 0); lastcolwith0 = -1; | |
156 | } else { /* Both 0 */ | |
157 | /* Was that where we stopped last time? */ | |
158 | if (prevcolwith0 == i) { /* Send a 1 this time */ | |
159 | ds1wire_send1(B, 0); | |
160 | lastserialfound[i >> 3] |= _BV(i & 0x07); | |
161 | } else { | |
162 | lastcolwith0 = i; | |
163 | ds1wire_send0(B, 0); | |
164 | lastserialfound[i >> 3] &= (uint8_t)~_BV(i & 0x07); | |
165 | } | |
166 | } | |
167 | } else { /* val1 != val2 */ | |
168 | if (val1 == 0) { /* Was a 0, so select that */ | |
169 | ds1wire_send0(B, 0); | |
170 | lastserialfound[i >> 3] &= (uint8_t)~_BV(i & 0x07); | |
171 | } else { /* Was a 1 */ | |
172 | ds1wire_send1(B, 0); | |
173 | lastserialfound[i >> 3] |= _BV(i & 0x07); | |
174 | } | |
175 | } | |
176 | } | |
177 | /* lastserialfound now contains the serial of the last probe we found, | |
178 | * AND that probe is selected. */ | |
179 | /* Check CRC of serial number. */ | |
180 | j = 0; /* Used as CRC here */ | |
181 | for (i = 0; i < 8; i++) { | |
182 | j = ds1wire_calccrc8(j, lastserialfound[i]); | |
183 | } | |
184 | if (j == 0) { /* CRC of serial number OK! */ | |
185 | for (i = 0; i < DS1820_MAXPROBES; i++) { | |
186 | if ((ds1820probes[i].flags & DS1820FLAG_SLOTINUSE) == 0) { | |
187 | /* Empty slot, use it. */ | |
188 | break; | |
189 | } | |
190 | } | |
191 | if (i == DS1820_MAXPROBES) { /* No match. Overwrite last entry. */ | |
192 | i = DS1820_MAXPROBES - 1; | |
193 | } | |
194 | ds1820probes[i].flags |= DS1820FLAG_SLOTINUSE; | |
195 | ds1820probes[i].family = lastserialfound[0]; | |
196 | for (j = 0; j < 6; j++) { | |
197 | ds1820probes[i].serial[j] = lastserialfound[j+1]; | |
198 | } | |
199 | ds1820probes[i].lastts = 0; | |
200 | ds1820probes[i].lasttemp[0] = 0; | |
201 | ds1820probes[i].lasttemp[1] = 0; | |
202 | /* Find out if the probe is parasite powered or not. */ | |
203 | ds1820write(DS1820_CMD_READPOWER); /* Read power supply */ | |
204 | if (ds1wire_read(B, 0) == 0) { /* Parasite powered probes return 0 */ | |
205 | ds1820probes[i].flags |= DS1820FLAG_PARASITE; | |
206 | } else { | |
207 | ds1820probes[i].flags &= ~DS1820FLAG_PARASITE; | |
208 | } | |
209 | } | |
210 | } while (lastcolwith0 >= 0); | |
211 | #endif /* KISS */ | |
212 | } |