Mercurial > ~darius > hgwebdir.cgi > avr
comparison 1wire.c @ 0:ffeab3c04e83
Initial revision
author | darius |
---|---|
date | Sun, 11 Jul 2004 00:45:50 +0930 |
parents | |
children | f9a085a0ba93 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:ffeab3c04e83 |
---|---|
1 /* | |
2 * Various 1 wire routines | |
3 * Search routine is copied from the Dallas owpd library with mods. | |
4 * | |
5 * Copyright (c) 2004 | |
6 * Daniel O'Connor <darius@dons.net.au>. All rights reserved. | |
7 * | |
8 * Redistribution and use in source and binary forms, with or without | |
9 * modification, are permitted provided that the following conditions | |
10 * are met: | |
11 * 1. Redistributions of source code must retain the above copyright | |
12 * notice, this list of conditions and the following disclaimer. | |
13 * 2. Redistributions in binary form must reproduce the above copyright | |
14 * notice, this list of conditions and the following disclaimer in the | |
15 * documentation and/or other materials provided with the distribution. | |
16 * | |
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | |
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
27 * SUCH DAMAGE. | |
28 */ | |
29 | |
30 #include <stdio.h> | |
31 #include <avr/io.h> | |
32 #include <avr/pgmspace.h> | |
33 | |
34 #include "1wire.h" | |
35 | |
36 void uart_putsP(const char *addr); | |
37 void uart_puts(const char *addr); | |
38 void uart_getc(); | |
39 int uart_putc(char c); | |
40 | |
41 static uint8_t OW_LastDevice = 0; | |
42 static uint8_t OW_LastDiscrepancy = 0; | |
43 static uint8_t OW_LastFamilyDiscrepancy = 0; | |
44 | |
45 static void | |
46 OWdelay(void) { | |
47 asm volatile ( | |
48 "ldi r21, 50\n\t" | |
49 "_OWdelay:\n\t" | |
50 "nop\n\t" | |
51 "nop\n\t" | |
52 "nop\n\t" | |
53 "nop\n\t" | |
54 "nop\n\t" | |
55 "nop\n\t" | |
56 "nop\n\t" | |
57 "nop\n\t" | |
58 "nop\n\t" | |
59 "nop\n\t" | |
60 "nop\n\t" | |
61 "nop\n\t" | |
62 "nop\n\t" | |
63 "dec r21\n\t" | |
64 "brne _OWdelay\n\t" | |
65 ::: "r21"); | |
66 } | |
67 | |
68 /*----------------------------------------------------------------------------- | |
69 * Generate a 1-Wire reset, return 1 if no presence detect was found, | |
70 * return 0 otherwise. | |
71 * (NOTE: Does not handle alarm presence from DS2404/DS1994) | |
72 */ | |
73 int | |
74 OWTouchReset(void) { | |
75 uint8_t result; | |
76 | |
77 asm volatile ( | |
78 /* Delay G (0 usec) */ | |
79 "\n\t" | |
80 /* Drive bus low */ | |
81 "cbi %[out], %[opin]\n\t" | |
82 "sbi %[ddr], %[opin]\n\t" | |
83 /* Delay H (480 usec) */ | |
84 "ldi r21, 120\n\t" | |
85 "loopH:\n\t" | |
86 "nop\n\t" | |
87 "nop\n\t" | |
88 "nop\n\t" | |
89 "nop\n\t" | |
90 "nop\n\t" | |
91 "nop\n\t" | |
92 "nop\n\t" | |
93 "nop\n\t" | |
94 "nop\n\t" | |
95 "nop\n\t" | |
96 "nop\n\t" | |
97 "nop\n\t" | |
98 "nop\n\t" | |
99 "dec r21\n\t" | |
100 "brne loopH\n\t" | |
101 /* Release bus */ | |
102 "cbi %[ddr], %[opin]\n\t" | |
103 /* Delay I (70 usec) */ | |
104 "ldi r21, 35\n\t" | |
105 "loopI:\n\t" | |
106 "nop\n\t" | |
107 "nop\n\t" | |
108 "nop\n\t" | |
109 "nop\n\t" | |
110 "nop\n\t" | |
111 "dec r21\n\t" | |
112 "brne loopI\n\t" | |
113 /* Sample for presense */ | |
114 "ldi %[result], 0\n\t" | |
115 "sbi %[ddr], 1\n\t" | |
116 "sbi %[out], 1\n\t" | |
117 /* 1 == no presence */ | |
118 "sbic %[in], %[ipin]\n\t" | |
119 "ldi %[result], 1\n\t" | |
120 "cbi %[out], 1\n\t" | |
121 | |
122 : [result] "=r" (result) /* Outputs */ | |
123 : [out] "I" (_SFR_IO_ADDR(OWIREOUTPORT)), /* Inputs */ | |
124 [ddr] "I" (_SFR_IO_ADDR(OWIREDDR)), | |
125 [opin] "I" (OWIREOUTPIN), | |
126 [in] "I" (_SFR_IO_ADDR(OWIREINPORT)), | |
127 [ipin] "I" (OWIREINPIN) | |
128 : "r21"); /* Clobbers */ | |
129 | |
130 return(result); | |
131 } | |
132 | |
133 /*----------------------------------------------------------------------------- | |
134 * Send a 1-wire write bit. | |
135 */ | |
136 void | |
137 OWWriteBit(int bit) { | |
138 OWdelay(); | |
139 if (bit) { | |
140 asm volatile ( | |
141 /* Drive bus low */ | |
142 "cbi %[out], %[pin]\n\t" | |
143 "sbi %[ddr], %[pin]\n\t" | |
144 /* Delay A (6 usec) */ | |
145 "ldi r21, 1\n\t" | |
146 "loopA:\n\t" | |
147 "nop\n\t" | |
148 "dec r21\n\t" | |
149 "brne loopA\n\t" | |
150 /* Release bus */ | |
151 "cbi %[ddr], %[pin]\n\t" | |
152 /* Delay B (64 usec) */ | |
153 "ldi r21, 32\n\t" | |
154 "loopB:\n\t" | |
155 "nop\n\t" | |
156 "nop\n\t" | |
157 "nop\n\t" | |
158 "nop\n\t" | |
159 "nop\n\t" | |
160 "dec r21\n\t" | |
161 "brne loopB\n\t" | |
162 : /* Outputs */ | |
163 : [out] "I" (_SFR_IO_ADDR(OWIREOUTPORT)), /* Inputs */ | |
164 [ddr] "I" (_SFR_IO_ADDR(OWIREDDR)), | |
165 [pin] "I" (OWIREOUTPIN) | |
166 : "r21"); /* Clobbers */ | |
167 } else { | |
168 asm volatile ( | |
169 /* Drive bus low */ | |
170 "cbi %[out], %[pin]\n\t" | |
171 "sbi %[ddr], %[pin]\n\t" | |
172 /* Delay C (60 usec) */ | |
173 "ldi r21, 30\n\t" | |
174 "loopC:\n\t" | |
175 "nop\n\t" | |
176 "nop\n\t" | |
177 "nop\n\t" | |
178 "nop\n\t" | |
179 "nop\n\t" | |
180 "dec r21\n\t" | |
181 "brne loopC\n\t" | |
182 /* Release bus */ | |
183 "cbi %[ddr], %[pin]\n\t" | |
184 /* Delay D (10 usec) */ | |
185 "ldi r21, 9\n\t" | |
186 "loopD:\n\t" | |
187 "nop\n\t" | |
188 "dec r21\n\t" | |
189 "brne loopD\n\t" | |
190 : /* Outputs */ | |
191 : [out] "I" (_SFR_IO_ADDR(OWIREOUTPORT)), /* Inputs */ | |
192 [ddr] "I" (_SFR_IO_ADDR(OWIREDDR)), | |
193 [pin] "I" (OWIREOUTPIN) | |
194 : "r21"); /* Clobbers */ | |
195 } | |
196 } | |
197 | |
198 /*----------------------------------------------------------------------------- | |
199 * Read a bit from the 1-wire bus and return it. | |
200 */ | |
201 int | |
202 OWReadBit(void) { | |
203 uint8_t result; | |
204 | |
205 OWdelay(); | |
206 | |
207 asm volatile ( | |
208 /* Drive bus low */ | |
209 "cbi %[out], %[opin]\n\t" | |
210 "sbi %[ddr], %[opin]\n\t" | |
211 /* Delay A (6 usec) */ | |
212 "ldi r21, 1\n\t" | |
213 "loopA1:\n\t" | |
214 "dec r21\n\t" | |
215 "brne loopA1\n\t" | |
216 /* Release bus */ | |
217 "cbi %[ddr], %[opin]\n\t" | |
218 /* Delay E (9 usec) */ | |
219 "ldi r21, 8\n\t" | |
220 "loopE:\n\t" | |
221 "nop\n\t" | |
222 "dec r21\n\t" | |
223 "brne loopE\n\t" | |
224 /* Sample */ | |
225 "ldi %[res], 0\n\t" | |
226 "sbic %[in], %[ipin]\n\t" | |
227 "ldi %[res], 1\n\t" | |
228 | |
229 /* Delay F (55 usec) */ | |
230 "ldi r21, 27\n\t" | |
231 "loopF:\n\t" | |
232 "nop\n\t" | |
233 "nop\n\t" | |
234 "nop\n\t" | |
235 "nop\n\t" | |
236 "nop\n\t" | |
237 "nop\n\t" | |
238 "nop\n\t" | |
239 "nop\n\t" | |
240 "nop\n\t" | |
241 "nop\n\t" | |
242 "nop\n\t" | |
243 "nop\n\t" | |
244 "nop\n\t" | |
245 "dec r21\n\t" | |
246 "brne loopF\n\t" | |
247 | |
248 : [res] "=r" (result) /* Outputs */ | |
249 : [out] "I" (_SFR_IO_ADDR(OWIREOUTPORT)), /* Inputs */ | |
250 [ddr] "I" (_SFR_IO_ADDR(OWIREDDR)), | |
251 [opin] "I" (OWIREOUTPIN), | |
252 [in] "I" (_SFR_IO_ADDR(OWIREINPORT)), | |
253 [ipin] "I" (OWIREINPIN) | |
254 : "r21"); /* Clobbers */ | |
255 | |
256 return(result); | |
257 } | |
258 | |
259 /*----------------------------------------------------------------------------- | |
260 * Write a byte to the 1-wire bus | |
261 */ | |
262 void | |
263 OWWriteByte(uint8_t data) { | |
264 int i; | |
265 | |
266 /* Send LSB first */ | |
267 for (i = 0; i < 8; i++) { | |
268 OWWriteBit(data & 0x01); | |
269 data >>= 1; | |
270 } | |
271 } | |
272 | |
273 /*----------------------------------------------------------------------------- | |
274 * Read a byte from the 1-wire bus | |
275 */ | |
276 int | |
277 OWReadByte(void) { | |
278 int i, result = 0; | |
279 | |
280 for (i = 0; i < 8; i++) { | |
281 result >>= 1; | |
282 if (OWReadBit()) | |
283 result |= 0x80; | |
284 } | |
285 return(result); | |
286 } | |
287 | |
288 /*----------------------------------------------------------------------------- | |
289 * Write a 1-wire data byte and return the sampled result. | |
290 */ | |
291 int | |
292 OWTouchByte(uint8_t data) { | |
293 int i, result = 0; | |
294 | |
295 for (i = 0; i < 8; i++) { | |
296 result >>= 1; | |
297 | |
298 /* If sending a 1 then read a bit, otherwise write a 0 */ | |
299 if (data & 0x01) { | |
300 if (OWReadBit()) | |
301 result |= 0x80; | |
302 } else | |
303 OWWriteBit(0); | |
304 | |
305 data >>= 1; | |
306 } | |
307 | |
308 return(result); | |
309 } | |
310 | |
311 /*----------------------------------------------------------------------------- | |
312 * Write a block of bytes to the 1-wire bus and return the sampled result in | |
313 * the same buffer | |
314 */ | |
315 void | |
316 OWBlock(uint8_t *data, int len) { | |
317 int i; | |
318 | |
319 for (i = 0; i < len; i++) | |
320 data[i] = OWTouchByte(data[i]); | |
321 } | |
322 | |
323 | |
324 /*----------------------------------------------------------------------------- | |
325 * Send a 1 wire command to a device, or all if no ROM ID provided | |
326 */ | |
327 void | |
328 OWSendCmd(uint8_t *ROM, uint8_t cmd) { | |
329 int i; | |
330 | |
331 OWTouchReset(); | |
332 | |
333 if (ROM == NULL) | |
334 OWWriteByte(OW_SKIP_ROM_CMD); | |
335 else { | |
336 OWWriteByte(OW_MATCH_ROM_CMD); | |
337 for (i = 0; i < 8; i++) | |
338 OWWriteByte(ROM[i]); | |
339 } | |
340 | |
341 OWWriteByte(cmd); | |
342 } | |
343 | |
344 /*----------------------------------------------------------------------------- | |
345 * Search algorithm from App note 187 (and 162) | |
346 * | |
347 * Returns 1 when something is found, 0 if nothing present | |
348 */ | |
349 int | |
350 OWFirst(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only) { | |
351 /* Reset state */ | |
352 OW_LastDiscrepancy = 0; | |
353 OW_LastDevice = 0; | |
354 OW_LastFamilyDiscrepancy = 0; | |
355 | |
356 /* Go looking */ | |
357 return (OWNext(ROM, do_reset, alarm_only)); | |
358 } | |
359 | |
360 /* Returns 1 when something is found, 0 if nothing left */ | |
361 int | |
362 OWNext(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only) { | |
363 uint8_t bit_test, search_direction, bit_number; | |
364 uint8_t last_zero, rom_byte_number, next_result; | |
365 uint8_t rom_byte_mask; | |
366 uint8_t lastcrc8, crcaccum; | |
367 char errstr[30]; | |
368 | |
369 /* Init for search */ | |
370 bit_number = 1; | |
371 last_zero = 0; | |
372 rom_byte_number = 0; | |
373 rom_byte_mask = 1; | |
374 next_result = 0; | |
375 lastcrc8 = 0; | |
376 crcaccum = 0; | |
377 | |
378 /* if the last call was not the last one */ | |
379 if (!OW_LastDevice) { | |
380 /* check if reset first is requested */ | |
381 if (do_reset) { | |
382 /* reset the 1-wire | |
383 * if there are no parts on 1-wire, return 0 */ | |
384 #if OW_DEBUG | |
385 uart_putsP(PSTR("Resetting\n\r")); | |
386 #endif | |
387 if (OWTouchReset()) { | |
388 /* reset the search */ | |
389 OW_LastDiscrepancy = 0; | |
390 OW_LastFamilyDiscrepancy = 0; | |
391 #if OW_DEBUG | |
392 uart_putsP(PSTR("No devices on bus\n\r")); | |
393 #endif | |
394 return 0; | |
395 } | |
396 } | |
397 | |
398 /* If finding alarming devices issue a different command */ | |
399 if (alarm_only) | |
400 OWWriteByte(OW_SEARCH_ALRM_CMD); /* issue the alarming search command */ | |
401 else | |
402 OWWriteByte(OW_SEARCH_ROM_CMD); /* issue the search command */ | |
403 | |
404 /* pause before beginning the search */ | |
405 OWdelay(); | |
406 OWdelay(); | |
407 OWdelay(); | |
408 | |
409 /* loop to do the search */ | |
410 do { | |
411 /* read a bit and its compliment */ | |
412 bit_test = OWReadBit() << 1; | |
413 bit_test |= OWReadBit(); | |
414 | |
415 #if OW_DEBUG | |
416 sprintf_P(errstr, PSTR("bit_test = %d\n\r"), bit_test); | |
417 uart_puts(errstr); | |
418 #endif | |
419 | |
420 /* check for no devices on 1-wire */ | |
421 if (bit_test == 3) { | |
422 sprintf_P(errstr, PSTR("bit_test = %d\n\r"), bit_test); | |
423 uart_puts(errstr); | |
424 break; | |
425 } | |
426 else { | |
427 /* all devices coupled have 0 or 1 */ | |
428 if (bit_test > 0) | |
429 search_direction = !(bit_test & 0x01); /* bit write value for search */ | |
430 else { | |
431 /* if this discrepancy is before the Last Discrepancy | |
432 * on a previous OWNext then pick the same as last time */ | |
433 if (bit_number < OW_LastDiscrepancy) | |
434 search_direction = ((ROM[rom_byte_number] & rom_byte_mask) > 0); | |
435 else | |
436 /* if equal to last pick 1, if not then pick 0 */ | |
437 search_direction = (bit_number == OW_LastDiscrepancy); | |
438 | |
439 /* if 0 was picked then record its position in LastZero */ | |
440 if (search_direction == 0) { | |
441 last_zero = bit_number; | |
442 | |
443 /* check for Last discrepancy in family */ | |
444 if (last_zero < 9) | |
445 OW_LastFamilyDiscrepancy = last_zero; | |
446 } | |
447 } | |
448 | |
449 /* set or clear the bit in the ROM byte rom_byte_number | |
450 * with mask rom_byte_mask */ | |
451 if (search_direction == 1) | |
452 ROM[rom_byte_number] |= rom_byte_mask; | |
453 else | |
454 ROM[rom_byte_number] &= ~rom_byte_mask; | |
455 | |
456 /* serial number search direction write bit */ | |
457 OWWriteBit(search_direction); | |
458 | |
459 /* increment the byte counter bit_number | |
460 * and shift the mask rom_byte_mask */ | |
461 bit_number++; | |
462 rom_byte_mask <<= 1; | |
463 | |
464 /* if the mask is 0 then go to new ROM byte rom_byte_number | |
465 * and reset mask */ | |
466 if (rom_byte_mask == 0) { | |
467 OWCRC(ROM[rom_byte_number], &crcaccum); /* accumulate the CRC */ | |
468 lastcrc8 = crcaccum; | |
469 | |
470 rom_byte_number++; | |
471 rom_byte_mask = 1; | |
472 } | |
473 } | |
474 } while (rom_byte_number < 8); /* loop until through all ROM bytes 0-7 */ | |
475 | |
476 /* if the search was successful then */ | |
477 if (!(bit_number < 65) || lastcrc8) { | |
478 if (lastcrc8) { | |
479 sprintf_P(errstr, PSTR("Bad CRC (%d)\n\r"), lastcrc8); | |
480 uart_puts(errstr); | |
481 next_result = 0; | |
482 } else { | |
483 /* search successful so set LastDiscrepancy,LastDevice,next_result */ | |
484 OW_LastDiscrepancy = last_zero; | |
485 OW_LastDevice = (OW_LastDiscrepancy == 0); | |
486 #if OW_DEBUG | |
487 sprintf_P(errstr, PSTR("Last device = %d\n\r"), OW_LastDevice); | |
488 uart_puts(errstr); | |
489 #endif | |
490 next_result = 1; | |
491 } | |
492 } | |
493 } | |
494 | |
495 /* if no device found then reset counters so next 'next' will be | |
496 * like a first */ | |
497 if (!next_result || !ROM[0]) { | |
498 OW_LastDiscrepancy = 0; | |
499 OW_LastDevice = 0; | |
500 OW_LastFamilyDiscrepancy = 0; | |
501 next_result = 0; | |
502 } | |
503 | |
504 return next_result; | |
505 | |
506 } | |
507 | |
508 uint8_t PROGMEM dscrc_table[] = { | |
509 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, | |
510 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, | |
511 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, | |
512 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, | |
513 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, | |
514 219, 133,103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, | |
515 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, | |
516 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, | |
517 140,210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113,147, 205, | |
518 17, 79, 173, 243, 112, 46, 204, 146, 211,141, 111, 49, 178, 236, 14, 80, | |
519 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82,176, 238, | |
520 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, | |
521 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, | |
522 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, | |
523 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, | |
524 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 | |
525 }; | |
526 | |
527 void | |
528 OWCRC(uint8_t x, uint8_t *crc) { | |
529 *crc = pgm_read_byte(&dscrc_table[(*crc) ^ x]); | |
530 } |