0
|
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 }
|