| 1 | /* $Id: ds1820.c,v 1.3 2010/07/16 19:31:18 simimeie Exp $ |
| 2 | * USB interface for ds1820 |
| 3 | * This file handles everything that has to do with the temperature probes. |
| 4 | * (C) Michael "Fox" Meier 2009 |
| 5 | */ |
| 6 | |
| 7 | #include "usbdrv/usbdrv.h" |
| 8 | #include "ds1wire.h" |
| 9 | #include "time.h" |
| 10 | |
| 11 | #include "ds1820.h" |
| 12 | |
| 13 | struct probe ds1820probes[DS1820_MAXPROBES]; |
| 14 | |
| 15 | void ds1820init(void) { |
| 16 | ds1wire_init(B, 0); |
| 17 | ds1wire_reset(B, 0); |
| 18 | } |
| 19 | |
| 20 | void ds1820killbus(void) { |
| 21 | ds1wire_pulldown(B, 0); |
| 22 | } |
| 23 | |
| 24 | static void ds1820write(uint8_t val) { |
| 25 | uint8_t i; |
| 26 | for (i = 0; i < 8; i++) { |
| 27 | if (val & 0x01) { |
| 28 | ds1wire_send1(B, 0); |
| 29 | } else { |
| 30 | ds1wire_send0(B, 0); |
| 31 | } |
| 32 | val >>= 1; |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | static uint8_t ds1820read(void) { |
| 37 | uint8_t i; |
| 38 | uint8_t res = 0; |
| 39 | for (i = 0; i < 8; i++) { |
| 40 | res |= ((ds1wire_read(B, 0)) << i); |
| 41 | } |
| 42 | return res; |
| 43 | } |
| 44 | |
| 45 | void ds1820queryprobe(uint8_t probenum) |
| 46 | { |
| 47 | uint8_t i; uint8_t crc = 0; |
| 48 | ds1wire_reset(B, 0); |
| 49 | #ifdef KISS |
| 50 | ds1820write(DS1820_CMD_SKIPROM); /* Skip ROM */ |
| 51 | #else |
| 52 | ds1820write(DS1820_CMD_MATCHROM); /* Match ROM */ |
| 53 | /* Send 64 bit serial */ |
| 54 | ds1820write(ds1820probes[probenum].family); |
| 55 | crc = ds1wire_calccrc8(crc, ds1820probes[probenum].family); |
| 56 | for (i = 0; i < 6; i++) { |
| 57 | ds1820write(ds1820probes[probenum].serial[i]); |
| 58 | crc = ds1wire_calccrc8(crc, ds1820probes[probenum].serial[i]); |
| 59 | } |
| 60 | ds1820write(crc); |
| 61 | #endif /* KISS */ |
| 62 | /* Issue 'start temperature conversion' */ |
| 63 | ds1820write(DS1820_CMD_CONVERTT); |
| 64 | if (ds1820probes[probenum].flags & DS1820FLAG_PARASITE) { |
| 65 | /* Provide parasite power */ |
| 66 | ds1wire_parasitepoweron(B, 0); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | /* Returns 1 on successful update, 0 otherwise */ |
| 71 | uint8_t ds1820updateprobe(uint8_t probenum) |
| 72 | { |
| 73 | uint8_t i; uint8_t crc = 0; uint8_t t1 = 0; uint8_t t2 = 0; |
| 74 | if (ds1820probes[probenum].flags & DS1820FLAG_PARASITE) { |
| 75 | /* No longer provide parasite power */ |
| 76 | ds1wire_parasitepoweroff(B, 0); |
| 77 | } |
| 78 | ds1wire_reset(B, 0); |
| 79 | #ifdef KISS |
| 80 | ds1820write(DS1820_CMD_SKIPROM); /* Skip ROM */ |
| 81 | #else |
| 82 | ds1820write(DS1820_CMD_MATCHROM); /* Match ROM */ |
| 83 | /* Send 64 bit serial */ |
| 84 | ds1820write(ds1820probes[probenum].family); |
| 85 | crc = ds1wire_calccrc8(crc, ds1820probes[probenum].family); |
| 86 | for (i = 0; i < 6; i++) { |
| 87 | ds1820write(ds1820probes[probenum].serial[i]); |
| 88 | crc = ds1wire_calccrc8(crc, ds1820probes[probenum].serial[i]); |
| 89 | } |
| 90 | ds1820write(crc); |
| 91 | #endif /* KISS */ |
| 92 | /* Read Scratchpad */ |
| 93 | ds1820write(DS1820_CMD_READSCRPAD); |
| 94 | crc = 0; |
| 95 | for (i = 0; i < 9; i++) { |
| 96 | uint8_t v = ds1820read(); |
| 97 | if (i == 0) { t1 = v; } |
| 98 | if (i == 1) { t2 = v; } |
| 99 | crc = ds1wire_calccrc8(crc, v); |
| 100 | } |
| 101 | /* For parasite powered probes, reading 0x50 0x05 (85.0 deg) usually |
| 102 | * means the probe has lost power during temperature conversion and |
| 103 | * reset (85.0 is the poweron value of the temperature scratchpad). |
| 104 | * So we filter the value 85.0 for parasite powered probes. This means |
| 105 | * you can never use parasite powered probes for temperatures in this |
| 106 | * range. */ |
| 107 | if ((crc == 0) |
| 108 | && (((ds1820probes[probenum].flags & DS1820FLAG_PARASITE) == 0) |
| 109 | || (t1 != 0x50) || (t2 != 0x05))) { |
| 110 | ds1820probes[probenum].lastts = gettime(); |
| 111 | ds1820probes[probenum].lasttemp[0] = t1; |
| 112 | ds1820probes[probenum].lasttemp[1] = t2; |
| 113 | return 1; |
| 114 | } else { |
| 115 | return 0; |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | /* This is going to be a tough one: |
| 120 | * Scan the bus to find all probes. |
| 121 | */ |
| 122 | void ds1820scan(void) { |
| 123 | #ifdef KISS |
| 124 | ds1wire_reset(B, 0); |
| 125 | ds1820probes[0].flags |= DS1820FLAG_SLOTINUSE; |
| 126 | ds1820write(DS1820_CMD_SKIPROM); /* Skip ROM */ |
| 127 | ds1820write(DS1820_CMD_READPOWER); /* Read power supply */ |
| 128 | if (ds1wire_read(B, 0) == 0) { /* Parasite powered probes return 0 */ |
| 129 | ds1820probes[0].flags |= DS1820FLAG_PARASITE; |
| 130 | } else { |
| 131 | ds1820probes[0].flags &= ~DS1820FLAG_PARASITE; |
| 132 | } |
| 133 | #else /* KISS */ |
| 134 | uint8_t lastserialfound[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
| 135 | int8_t lastcolwith0 = -1; |
| 136 | int8_t prevcolwith0; |
| 137 | int8_t i; |
| 138 | uint8_t j; |
| 139 | for (i = 0; i < DS1820_MAXPROBES; i++) { /* Clear list of probes */ |
| 140 | ds1820probes[i].flags = 0; |
| 141 | } |
| 142 | do { |
| 143 | ds1wire_reset(B, 0); |
| 144 | prevcolwith0 = lastcolwith0; |
| 145 | lastcolwith0 = -1; |
| 146 | /* Send scan command */ |
| 147 | ds1820write(DS1820_CMD_SEARCHROM); |
| 148 | for (i = 0; i < 64; i++) { |
| 149 | uint8_t val1 = ds1wire_read(B, 0); |
| 150 | uint8_t val2 = ds1wire_read(B, 0); |
| 151 | if (val1 == val2) { /* Collission */ |
| 152 | if (val1 == 1) { /* and thus val2 is 1 too */ |
| 153 | /* Nothing matched on the bus! This is actually pretty fatal! */ |
| 154 | /* Try to get out alive. Send all 0. */ |
| 155 | ds1wire_send0(B, 0); lastcolwith0 = -1; |
| 156 | } else { /* Both 0 */ |
| 157 | /* Was that where we stopped last time? */ |
| 158 | if (prevcolwith0 == i) { /* Send a 1 this time */ |
| 159 | ds1wire_send1(B, 0); |
| 160 | lastserialfound[i >> 3] |= _BV(i & 0x07); |
| 161 | } else { |
| 162 | lastcolwith0 = i; |
| 163 | ds1wire_send0(B, 0); |
| 164 | lastserialfound[i >> 3] &= (uint8_t)~_BV(i & 0x07); |
| 165 | } |
| 166 | } |
| 167 | } else { /* val1 != val2 */ |
| 168 | if (val1 == 0) { /* Was a 0, so select that */ |
| 169 | ds1wire_send0(B, 0); |
| 170 | lastserialfound[i >> 3] &= (uint8_t)~_BV(i & 0x07); |
| 171 | } else { /* Was a 1 */ |
| 172 | ds1wire_send1(B, 0); |
| 173 | lastserialfound[i >> 3] |= _BV(i & 0x07); |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | /* lastserialfound now contains the serial of the last probe we found, |
| 178 | * AND that probe is selected. */ |
| 179 | /* Check CRC of serial number. */ |
| 180 | j = 0; /* Used as CRC here */ |
| 181 | for (i = 0; i < 8; i++) { |
| 182 | j = ds1wire_calccrc8(j, lastserialfound[i]); |
| 183 | } |
| 184 | if (j == 0) { /* CRC of serial number OK! */ |
| 185 | for (i = 0; i < DS1820_MAXPROBES; i++) { |
| 186 | if ((ds1820probes[i].flags & DS1820FLAG_SLOTINUSE) == 0) { |
| 187 | /* Empty slot, use it. */ |
| 188 | break; |
| 189 | } |
| 190 | } |
| 191 | if (i == DS1820_MAXPROBES) { /* No match. Overwrite last entry. */ |
| 192 | i = DS1820_MAXPROBES - 1; |
| 193 | } |
| 194 | ds1820probes[i].flags |= DS1820FLAG_SLOTINUSE; |
| 195 | ds1820probes[i].family = lastserialfound[0]; |
| 196 | for (j = 0; j < 6; j++) { |
| 197 | ds1820probes[i].serial[j] = lastserialfound[j+1]; |
| 198 | } |
| 199 | ds1820probes[i].lastts = 0; |
| 200 | ds1820probes[i].lasttemp[0] = 0; |
| 201 | ds1820probes[i].lasttemp[1] = 0; |
| 202 | /* Find out if the probe is parasite powered or not. */ |
| 203 | ds1820write(DS1820_CMD_READPOWER); /* Read power supply */ |
| 204 | if (ds1wire_read(B, 0) == 0) { /* Parasite powered probes return 0 */ |
| 205 | ds1820probes[i].flags |= DS1820FLAG_PARASITE; |
| 206 | } else { |
| 207 | ds1820probes[i].flags &= ~DS1820FLAG_PARASITE; |
| 208 | } |
| 209 | } |
| 210 | } while (lastcolwith0 >= 0); |
| 211 | #endif /* KISS */ |
| 212 | } |