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 }