comparison 1wire.c @ 13:96c345d304af

Add 1wire code. 1wire.c, 1wire.h and 1wire-config.h are copied avr-lib.
author Daniel O'Connor <darius@dons.net.au>
date Wed, 08 Feb 2012 10:37:22 +1030
parents
children 969bb070b181
comparison
equal deleted inserted replaced
12:093bc0c3b1cc 13:96c345d304af
1 /*
2 * Various 1 wire routines
3 * Search routine is copied from the Dallas owpd library with mods
4 * available from here http://www.ibutton.com/software/1wire/wirekit.html
5 *
6 * $Id$
7 *
8 * Copyright (c) 2004
9 * Daniel O'Connor <darius@dons.net.au>. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * No user servicable parts inside
35 *
36 * Modify 1wire-config.h
37 */
38
39 #include <stdio.h>
40 #include <stdint.h>
41 #include "1wire-config.h"
42 #include "1wire.h"
43
44 static uint8_t OW_LastDevice = 0;
45 static uint8_t OW_LastDiscrepancy = 0;
46 static uint8_t OW_LastFamilyDiscrepancy = 0;
47
48 const PROGMEM char *OWProgROM_Status[] = {
49 "OK",
50 "no HW support",
51 "Invalid params",
52 "module missing/broken"
53 };
54
55 /*-----------------------------------------------------------------------------
56 * Configure the IO port as we need
57 */
58 void
59 OWInit(void) {
60 OWBUSINIT();
61 OWSETBUSHIGH();
62 }
63
64 /*-----------------------------------------------------------------------------
65 * Generate a 1-Wire reset, return 0 if presence pulse was found, 1 if it
66 * wasn't, or 2 if the line appears to be being held low.
67 *
68 * (NOTE: Does not handle alarm presence from DS2404/DS1994)
69 */
70 uint8_t
71 OWTouchReset(void) {
72 uint8_t i;
73
74 OWDELAY_G;
75
76 /* Check the bus isn't being held low (ie it's broken) Do it after
77 * the delay so we guarantee we don't see a slave from a previous
78 * comms attempt
79 */
80 #if 1
81 OWSETREAD();
82 if(OWREADBUS() == 0)
83 return 2;
84 #endif
85
86 OWSETBUSLOW();
87 OWDELAY_H;
88 OWSETBUSHIGH();
89 OWDELAY_I;
90
91 OWSETREAD();
92 i = OWREADBUS();
93
94 OWDELAY_J;
95 return(i);
96 }
97
98 /*-----------------------------------------------------------------------------
99 * Send a 1-wire write bit.
100 */
101 void
102 OWWriteBit(uint8_t bit) {
103 OWDELAY_I;
104
105 if (bit) {
106 OWSETBUSLOW();
107 OWDELAY_A;
108 OWSETBUSHIGH();
109 OWDELAY_B;
110 } else {
111 OWSETBUSLOW();
112 OWDELAY_C;
113 OWSETBUSHIGH();
114 OWDELAY_D;
115 }
116 }
117
118 /*-----------------------------------------------------------------------------
119 * Read a bit from the 1-wire bus and return it.
120 */
121 uint8_t
122 OWReadBit(void) {
123 uint8_t i;
124
125 OWDELAY_I;
126
127 OWSETBUSLOW();
128 OWDELAY_A;
129 OWSETBUSHIGH();
130 OWDELAY_E;
131 OWSETREAD();
132 i = OWREADBUS();
133 OWDELAY_F;
134 return(i);
135 }
136
137 /*-----------------------------------------------------------------------------
138 * Write a byte to the 1-wire bus
139 */
140 void
141 OWWriteByte(uint8_t data) {
142 uint8_t i;
143
144 /* Send LSB first */
145 for (i = 0; i < 8; i++) {
146 OWWriteBit(data & 0x01);
147 data >>= 1;
148 }
149 }
150
151 /*-----------------------------------------------------------------------------
152 * Read a byte from the 1-wire bus
153 */
154 uint8_t
155 OWReadByte(void) {
156 int i, result = 0;
157
158 for (i = 0; i < 8; i++) {
159 result >>= 1;
160 if (OWReadBit())
161 result |= 0x80;
162 }
163 return(result);
164 }
165
166 /*-----------------------------------------------------------------------------
167 * Write a 1-wire data byte and return the sampled result.
168 */
169 uint8_t
170 OWTouchByte(uint8_t data) {
171 uint8_t i, result = 0;
172
173 for (i = 0; i < 8; i++) {
174 result >>= 1;
175
176 /* If sending a 1 then read a bit, otherwise write a 0 */
177 if (data & 0x01) {
178 if (OWReadBit())
179 result |= 0x80;
180 } else
181 OWWriteBit(0);
182
183 data >>= 1;
184 }
185
186 return(result);
187 }
188
189 /*-----------------------------------------------------------------------------
190 * Write a block of bytes to the 1-wire bus and return the sampled result in
191 * the same buffer
192 */
193 void
194 OWBlock(uint8_t *data, int len) {
195 int i;
196
197 for (i = 0; i < len; i++)
198 data[i] = OWTouchByte(data[i]);
199 }
200
201
202 /*-----------------------------------------------------------------------------
203 * Send a 1 wire command to a device, or all if no ROM ID provided
204 */
205 void
206 OWSendCmd(uint8_t *ROM, uint8_t cmd) {
207 uint8_t i;
208
209 OWTouchReset();
210
211 if (ROM == NULL)
212 OWWriteByte(OW_SKIP_ROM_CMD);
213 else {
214 OWWriteByte(OW_MATCH_ROM_CMD);
215 for (i = 0; i < 8; i++)
216 OWWriteByte(ROM[i]);
217 }
218 OWWriteByte(cmd);
219 }
220
221 /*-----------------------------------------------------------------------------
222 * Search algorithm from App note 187 (and 162)
223 *
224 * OWFirst/OWNext return..
225 * 1 when something is found,
226 * 0 no more modules
227 * -1 if no presence pulse,
228 * -2 if bad CRC,
229 * -3 if bad wiring.
230 */
231 uint8_t
232 OWFirst(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only) {
233 /* Reset state */
234 OW_LastDiscrepancy = 0;
235 OW_LastDevice = 0;
236 OW_LastFamilyDiscrepancy = 0;
237
238 /* Go looking */
239 return (OWNext(ROM, do_reset, alarm_only));
240 }
241
242 /* Returns 1 when something is found, 0 if nothing left */
243 uint8_t
244 OWNext(uint8_t *ROM, uint8_t do_reset, uint8_t alarm_only) {
245 uint8_t bit_test, search_direction, bit_number;
246 uint8_t last_zero, rom_byte_number, rom_byte_mask;
247 uint8_t lastcrc8, crcaccum;
248 int8_t next_result;
249
250 /* Init for search */
251 bit_number = 1;
252 last_zero = 0;
253 rom_byte_number = 0;
254 rom_byte_mask = 1;
255 next_result = OW_NOMODULES;
256 lastcrc8 = 0;
257 crcaccum = 0;
258
259 /* if the last call was not the last one */
260 if (!OW_LastDevice) {
261 /* check if reset first is requested */
262 if (do_reset) {
263 /* reset the 1-wire
264 * if there are no parts on 1-wire, return 0 */
265 OWPUTSP(PSTR("Resetting\r\n"));
266 switch (OWTouchReset()) {
267 case 0:
268 OWPUTSP(PSTR("Found device(s)\r\n"));
269 break;
270
271 case 1:
272 /* reset the search */
273 OW_LastDiscrepancy = 0;
274 OW_LastFamilyDiscrepancy = 0;
275 OWPUTSP(PSTR("No devices on bus\r\n"));
276 return OW_NOPRESENCE;
277 break;
278
279 case 2:
280 /* reset the search */
281 OW_LastDiscrepancy = 0;
282 OW_LastFamilyDiscrepancy = 0;
283 OWPUTSP(PSTR("Bus appears to be being held low\r\n"));
284 return OW_BADWIRE;
285 break;
286
287 }
288 }
289
290 /* If finding alarming devices issue a different command */
291 if (alarm_only)
292 OWWriteByte(OW_SEARCH_ALRM_CMD); /* issue the alarming search command */
293 else
294 OWWriteByte(OW_SEARCH_ROM_CMD); /* issue the search command */
295
296 /* pause before beginning the search */
297 OWDELAY_I;
298 OWDELAY_I;
299 OWDELAY_I;
300
301 /* loop to do the search */
302 do {
303 /* read a bit and its compliment */
304 bit_test = OWReadBit() << 1;
305 bit_test |= OWReadBit();
306
307 OWPRINTFP(PSTR("bit_test = %d\r\n"), bit_test);
308
309 /* check for no devices on 1-wire */
310 if (bit_test == 3) {
311 OWPRINTFP(PSTR("bit_test = %d\r\n"), bit_test);
312 return(OW_BADWIRE);
313 }
314 else {
315 /* all devices coupled have 0 or 1 */
316 if (bit_test > 0)
317 search_direction = !(bit_test & 0x01); /* bit write value for search */
318 else {
319 /* if this discrepancy is before the Last Discrepancy
320 * on a previous OWNext then pick the same as last time */
321 if (bit_number < OW_LastDiscrepancy)
322 search_direction = ((ROM[rom_byte_number] & rom_byte_mask) > 0);
323 else
324 /* if equal to last pick 1, if not then pick 0 */
325 search_direction = (bit_number == OW_LastDiscrepancy);
326
327 /* if 0 was picked then record its position in LastZero */
328 if (search_direction == 0) {
329 last_zero = bit_number;
330
331 /* check for Last discrepancy in family */
332 if (last_zero < 9)
333 OW_LastFamilyDiscrepancy = last_zero;
334 }
335 }
336
337 /* set or clear the bit in the ROM byte rom_byte_number
338 * with mask rom_byte_mask */
339 if (search_direction == 1)
340 ROM[rom_byte_number] |= rom_byte_mask;
341 else
342 ROM[rom_byte_number] &= ~rom_byte_mask;
343
344 /* serial number search direction write bit */
345 OWWriteBit(search_direction);
346
347 /* increment the byte counter bit_number
348 * and shift the mask rom_byte_mask */
349 bit_number++;
350 rom_byte_mask <<= 1;
351
352 /* if the mask is 0 then go to new ROM byte rom_byte_number
353 * and reset mask */
354 if (rom_byte_mask == 0) {
355 OWCRC(ROM[rom_byte_number], &crcaccum); /* accumulate the CRC */
356 lastcrc8 = crcaccum;
357
358 rom_byte_number++;
359 rom_byte_mask = 1;
360 }
361 }
362 } while (rom_byte_number < 8); /* loop until through all ROM bytes 0-7 */
363
364 /* if the search was successful then */
365 if (!(bit_number < 65) || lastcrc8) {
366 if (lastcrc8) {
367 OWPRINTFP(PSTR("Bad CRC (%d)\r\n"), lastcrc8);
368 next_result = OW_BADCRC;
369 } else {
370 /* search successful so set LastDiscrepancy,LastDevice,next_result */
371 OW_LastDiscrepancy = last_zero;
372 OW_LastDevice = (OW_LastDiscrepancy == 0);
373 OWPRINTFP(PSTR("Last device = %d\r\n"), OW_LastDevice);
374 next_result = OW_FOUND;
375 }
376 }
377 }
378
379 /* if no device found then reset counters so next 'next' will be
380 * like a first */
381 if (next_result != OW_FOUND || ROM[0] == 0) {
382 OW_LastDiscrepancy = 0;
383 OW_LastDevice = 0;
384 OW_LastFamilyDiscrepancy = 0;
385 }
386
387 if (next_result == OW_FOUND && ROM[0] == 0x00)
388 next_result = OW_BADWIRE;
389
390 return next_result;
391
392 }
393
394 uint8_t PROGMEM dscrc_table[] = {
395 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
396 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
397 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
398 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
399 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
400 219, 133,103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
401 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
402 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
403 140,210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113,147, 205,
404 17, 79, 173, 243, 112, 46, 204, 146, 211,141, 111, 49, 178, 236, 14, 80,
405 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82,176, 238,
406 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
407 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
408 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
409 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
410 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
411 };
412
413 /*-----------------------------------------------------------------------------
414 * Update *crc based on the value of x
415 */
416 void
417 OWCRC(uint8_t x, uint8_t *crc) {
418 *crc = pgm_read_byte(&dscrc_table[(*crc) ^ x]);
419 }
420
421 /*-----------------------------------------------------------------------------
422 * Program a DS2502's memory
423 *
424 * Arguments
425 * ROM - ROM ID (or NULL to send SKIP_ROM)
426 * start - Start address (bytes)
427 * len - Length of data to write
428 * data - Data to write
429 * exact - If true, only accept exact matches for programming,
430 * otherwise only ensure the bits we requested were
431 * programmed [to 0]
432 * status - If true program status rather than memory
433 *
434 * Returns..
435 * 0 if all is OK
436 * 1 if the programming is not possible
437 * 2 if the parameters were invalid
438 * 3 if the DS2502 didn't respond appropriately (also happens if the
439 * module doesn't exist)
440 */
441 #if defined(OWSETVPPON) && defined(OWSETVPPOFF)
442 uint8_t
443 OWProgROM(uint8_t *ROM, uint8_t start, uint8_t len, uint8_t *data, uint8_t exact, uint8_t status) {
444 uint8_t crc, i, tmp;
445
446 /* Stupid programmer detection */
447 if (status) {
448 if (start + len > 3)
449 return(2);
450 } else {
451 if (start + len > 127)
452 return(2);
453 }
454
455 if (len < 1)
456 return(2);
457
458 OWDELAY_I;
459 if (OWTouchReset() != 0) {
460 cons_putsP(PSTR("No presence pulse\r\n"));
461 return(3);
462 }
463
464 crc = 0;
465
466 /* Send the command */
467 if (status) {
468 OWSendCmd(ROM, OW_WRITE_STATUS);
469 OWCRC(OW_WRITE_STATUS, &crc);
470 } else {
471 OWSendCmd(ROM, OW_WRITE_MEMORY);
472 OWCRC(OW_WRITE_MEMORY, &crc);
473 }
474
475 /* And the start address
476 * (2 bytes even though one would do)
477 */
478 OWWriteByte(start);
479 OWCRC(start, &crc);
480
481 OWWriteByte(0x00);
482 OWCRC(0x00, &crc);
483
484 for (i = 0; i < len; i++) {
485 cons_putsP(PSTR("Programming "));
486 cons_puts_hex(data[i]);
487 cons_putsP(PSTR(" to "));
488 cons_puts_hex(start + i);
489 cons_putsP(PSTR("\r\n"));
490
491 OWWriteByte(data[i]);
492 OWCRC(data[i], &crc);
493
494 tmp = OWReadByte();
495
496 if (crc != tmp) {
497 cons_putsP(PSTR("CRC mismatch "));
498 cons_puts_hex(crc);
499 cons_putsP(PSTR(" vs "));
500 cons_puts_hex(tmp);
501 cons_putsP(PSTR("\r\n"));
502
503 OWTouchReset();
504 return(3);
505 }
506
507 OWSETVPPON();
508 OWDELAY_H;
509 OWSETVPPOFF();
510
511 tmp = OWReadByte();
512
513 /* Check the bits we turned off are off */
514 /*
515 for (i = 0; i < 8; i++)
516 if (!(data[i] & 1 << i) && (tmp & 1 << i))
517 return(-3);
518 */
519 if ((!data[i] & tmp) != 0) {
520 cons_putsP(PSTR("Readback mismatch "));
521 cons_puts_hex(data[i]);
522 cons_putsP(PSTR(" vs "));
523 cons_puts_hex(data[i]);
524 cons_putsP(PSTR("\r\n"));
525
526 OWTouchReset();
527 return(3);
528 }
529
530 /* The DS2502 loads it's CRC register with the address of the
531 * next byte */
532 crc = 0;
533 OWCRC(start + i + 1, &crc);
534 }
535
536 return(0);
537 }
538 #else
539 uint8_t
540 OWProgROM(uint8_t *ROM __attribute((unused)), uint8_t start __attribute((unused)), uint8_t len __attribute((unused)), uint8_t *data __attribute((unused)), uint8_t exact __attribute((unused)), uint8_t status __attribute((unused))) {
541 return(1);
542 }
543 #endif
544
545 /*
546 * OWGetTemp
547 *
548 * Get the temperature from a 1wire bus module
549 *
550 * Returns temperature in hundredths of a degree or OW_TEMP_xxx on
551 * error.
552 */
553 int16_t
554 OWGetTemp(uint8_t *ROM) {
555 int8_t i;
556 uint8_t crc, buf[9];
557 int16_t temp;
558 int16_t tfrac;
559
560 if (ROM[0] != OW_FAMILY_TEMP)
561 return OW_TEMP_WRONG_FAM;
562
563 OWSendCmd(ROM, OW_CONVERTT_CMD);
564
565 i = 0;
566
567 /* Wait for the conversion */
568 while (OWReadBit() == 0)
569 i = 1;
570
571 /* Check that we talked to a module and it did something */
572 if (i == 0) {
573 return OW_TEMP_NO_ROM;
574 }
575
576 OWSendCmd(ROM, OW_RD_SCR_CMD);
577 crc = 0;
578 for (i = 0; i < 8; i++) {
579 buf[i] = OWReadByte();
580 OWCRC(buf[i], &crc);
581 }
582 buf[i] = OWReadByte();
583 if (crc != buf[8])
584 return OW_TEMP_CRC_ERR;
585 temp = buf[0];
586 if (buf[1] & 0x80)
587 temp -= 256;
588
589 /* Chop off 0.5 degree bit */
590 temp >>= 1;
591
592 /* Calulate the fractional remainder */
593 tfrac = buf[7] - buf[6];
594
595 /* Work in 100'th of degreess to save on floats */
596 tfrac *= (int16_t)100;
597
598 /* Divide by count */
599 tfrac /= buf[7];
600
601 /* Subtract 0.25 deg from temp */
602 tfrac += 75;
603 if (tfrac < 100)
604 temp--;
605 else
606 tfrac -= 100;
607
608 i = temp;
609 temp *= 100;
610 temp += tfrac;
611
612 return(temp);
613 }
614
615 /*
616 * OWTempStatusStr
617 *
618 * Return a string for each OW_TEMP_xxx error code
619 *
620 * shrt = 1 returns short strings
621 *
622 */
623 const char *
624 OWTempStatusStr(int16_t val, uint8_t shrt) {
625 if (val > OW_TEMP_BADVAL) {
626 if (shrt)
627 return PSTR("OK");
628 else
629 return PSTR("OK");
630 }
631
632 switch (val) {
633 case OW_TEMP_WRONG_FAM:
634 if (shrt)
635 return PSTR("WrFam");
636 else
637 return PSTR("Wrong family");
638 break;
639 case OW_TEMP_CRC_ERR:
640 if (shrt)
641 return PSTR("CRCErr");
642 else
643 return PSTR("CRC Error");
644 break;
645 case OW_TEMP_NO_ROM:
646 if (shrt)
647 return PSTR("NoROM");
648 else
649 return PSTR("ROM did not reply");
650 break;
651 default:
652 if (shrt)
653 return PSTR("???");
654 else
655 return PSTR("Unknown error code");
656 break;
657 }
658 }