comparison 1wire.c @ 0:3879f487b661

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