| 1 | /* Dallas 1-Wire bus routines */ |
| 2 | |
| 3 | #if defined(__XC) |
| 4 | #include <xc.h> /* XC8 General Include File */ |
| 5 | #elif defined(HI_TECH_C) |
| 6 | #include <htc.h> /* HiTech General Include File */ |
| 7 | #endif |
| 8 | |
| 9 | #include <stdint.h> /* For uint8_t definition */ |
| 10 | #include <stdbool.h> /* For true/false definition */ |
| 11 | |
| 12 | #include "system.h" |
| 13 | #include "user.h" |
| 14 | #include "onewire.h" |
| 15 | |
| 16 | // fast way, macros |
| 17 | #define OWLOW { PORTAbits.RA5 = 0; TRISAbits.TRISA5 = 0; } |
| 18 | #define OWHIGH { PORTAbits.RA5 = 1; TRISAbits.TRISA5 = 0; } |
| 19 | #define OWTRI { TRISAbits.TRISA5 = 1; } |
| 20 | #define OWREAD (PORTAbits.RA5) |
| 21 | |
| 22 | |
| 23 | // slow way, causes a function call |
| 24 | inline void drive_OW_low(void) |
| 25 | { |
| 26 | PORTAbits.RA5 = 0; |
| 27 | TRISAbits.TRISA5 = 0; |
| 28 | } |
| 29 | |
| 30 | inline void drive_OW_high(void) |
| 31 | { |
| 32 | PORTAbits.RA5 = 1; |
| 33 | TRISAbits.TRISA5 = 0; |
| 34 | } |
| 35 | |
| 36 | inline void float_OW(void) |
| 37 | { |
| 38 | TRISAbits.TRISA5 = 1; |
| 39 | } |
| 40 | |
| 41 | inline bool read_OW(void) |
| 42 | { |
| 43 | TRISAbits.TRISA5 = 1; |
| 44 | return PORTAbits.RA5; |
| 45 | } |
| 46 | |
| 47 | |
| 48 | /* start the 1-Wire bus |
| 49 | * |
| 50 | */ |
| 51 | void OW_start(void) |
| 52 | { |
| 53 | //drive_OW_high(); |
| 54 | float_OW(); |
| 55 | } |
| 56 | |
| 57 | /* reset the bus, test for presence signal */ |
| 58 | bool OW_reset(void) |
| 59 | { |
| 60 | bool presence = 0; |
| 61 | |
| 62 | OWLOW; //drive_OW_low(); |
| 63 | DelayUs(250); |
| 64 | DelayUs(250); |
| 65 | OWTRI; //float_OW(); // let it float high |
| 66 | DelayUs(70); |
| 67 | presence = OWREAD; //read_OW(); // now sample |
| 68 | DelayUs(215); |
| 69 | DelayUs(215); |
| 70 | |
| 71 | return ! presence; |
| 72 | } |
| 73 | |
| 74 | void OW_write_bit(bool val) |
| 75 | { |
| 76 | #if 0 // Maxim dev note 2420 |
| 77 | drive_OW_low(); |
| 78 | DelayUs(3); |
| 79 | if (val) float_OW(); |
| 80 | DelayUs(60); |
| 81 | float_OW(); |
| 82 | DelayUs(2); |
| 83 | #else |
| 84 | OWLOW; |
| 85 | NOP(); |
| 86 | NOP(); |
| 87 | // NOP(); // doc one for other delays |
| 88 | if (val) OWTRI; |
| 89 | DelayUs(60); |
| 90 | OWTRI; |
| 91 | NOP(); |
| 92 | NOP(); |
| 93 | #endif |
| 94 | } |
| 95 | |
| 96 | bool OW_read_bit() |
| 97 | { |
| 98 | bool val; |
| 99 | #if 0 /* Maxim dev note 2420 */ |
| 100 | drive_OW_low(); |
| 101 | DelayUs(6); |
| 102 | float_OW(); |
| 103 | DelayUs(4); |
| 104 | val = read_OW(); |
| 105 | DelayUs(50); |
| 106 | #else |
| 107 | OWLOW; |
| 108 | // NOP(); |
| 109 | NOP(); |
| 110 | NOP(); |
| 111 | NOP(); |
| 112 | NOP(); |
| 113 | NOP(); |
| 114 | OWTRI; |
| 115 | // NOP(); |
| 116 | NOP(); |
| 117 | NOP(); |
| 118 | NOP(); |
| 119 | val = read_OW(); |
| 120 | DelayUs(50); |
| 121 | |
| 122 | #endif |
| 123 | return val; |
| 124 | } |
| 125 | |
| 126 | void OW_write_byte(unsigned char byte) |
| 127 | { |
| 128 | for (char i=8; i!=0; i--) |
| 129 | { |
| 130 | OW_write_bit( byte & 0x01 ); |
| 131 | byte >>= 1; |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | unsigned char OW_read_byte(void) |
| 136 | { |
| 137 | unsigned char byte = 0; |
| 138 | for (char i=8; i!=0; i--) |
| 139 | { |
| 140 | byte >>= 1; |
| 141 | if (OW_read_bit()) |
| 142 | byte |= 0x80; |
| 143 | |
| 144 | } |
| 145 | return byte; |
| 146 | } |
| 147 | |
| 148 | static const unsigned char dscrc_table[] = { |
| 149 | 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, |
| 150 | 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, |
| 151 | 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, |
| 152 | 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, |
| 153 | 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, |
| 154 | 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, |
| 155 | 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, |
| 156 | 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, |
| 157 | 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, |
| 158 | 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, |
| 159 | 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, |
| 160 | 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, |
| 161 | 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, |
| 162 | 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, |
| 163 | 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, |
| 164 | 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53 |
| 165 | }; |
| 166 | |
| 167 | unsigned char romid[8]; |
| 168 | char LastDiscrepancy = 0; |
| 169 | char LastFamilyDiscrepancy = 0; |
| 170 | char LastDeviceFlag = false; |
| 171 | unsigned char crc8; |
| 172 | |
| 173 | static unsigned char docrc8(unsigned char value) |
| 174 | { |
| 175 | crc8 = dscrc_table[crc8 ^ value]; |
| 176 | return crc8; |
| 177 | } |
| 178 | |
| 179 | /* enumerate the devices */ |
| 180 | bool OW_search() |
| 181 | { |
| 182 | char id_bit_number = 1; |
| 183 | char last_zero = 0; |
| 184 | char rom_byte_number = 0; |
| 185 | char search_result = 0; |
| 186 | unsigned char rom_byte_mask = 1; |
| 187 | unsigned char search_direction; |
| 188 | |
| 189 | crc8 = 0; |
| 190 | |
| 191 | // do not interrupt us |
| 192 | int_disable(); |
| 193 | |
| 194 | // if the last call was not the last one |
| 195 | if (!LastDeviceFlag) { |
| 196 | if (!OW_reset()) |
| 197 | { |
| 198 | msg_write("Reset said nothing there.\r\n"); |
| 199 | // reset the search |
| 200 | LastDiscrepancy = 0; |
| 201 | LastDeviceFlag = 0; |
| 202 | LastFamilyDiscrepancy = 0; |
| 203 | int_enable(); |
| 204 | return 0; |
| 205 | } |
| 206 | |
| 207 | // issue the search command |
| 208 | OW_write_byte(0xF0); |
| 209 | |
| 210 | // loop to do the search |
| 211 | do { |
| 212 | // read a bit and its complement |
| 213 | bool id_bit = OW_read_bit(); |
| 214 | DelayUs(6); |
| 215 | bool cmp_id_bit = OW_read_bit(); |
| 216 | |
| 217 | // check for no devices on bus |
| 218 | if (id_bit && cmp_id_bit) { |
| 219 | break; |
| 220 | } |
| 221 | |
| 222 | if (id_bit != cmp_id_bit) { |
| 223 | // all devices have a 0 here, or they all have a 1 |
| 224 | search_direction = id_bit; |
| 225 | } else { |
| 226 | // both bits zero, so both 0 and 1 exist |
| 227 | |
| 228 | // if this discrepancy is before the Last Discrepancy |
| 229 | // on a previous next then pick the same as last time |
| 230 | if (id_bit_number < LastDiscrepancy) { |
| 231 | search_direction = ((romid[rom_byte_number] & rom_byte_mask) > 0); |
| 232 | } else { |
| 233 | // if equal to last pick 1, if not then pick 0 |
| 234 | search_direction = (id_bit_number == LastDiscrepancy); |
| 235 | } |
| 236 | |
| 237 | // if 0 was picked then record its position in LastZero |
| 238 | if (search_direction == 0) |
| 239 | { |
| 240 | last_zero = id_bit_number; |
| 241 | // check for last discrepancy in family |
| 242 | if (last_zero < 9) |
| 243 | LastFamilyDiscrepancy = last_zero; |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | // set or clear the bit in the ROM byte rom_byte_number |
| 248 | // with mask rom_byte_mask |
| 249 | if (search_direction == 1) |
| 250 | romid[rom_byte_number] |= rom_byte_mask; |
| 251 | else |
| 252 | romid[rom_byte_number] &= ~rom_byte_mask; |
| 253 | |
| 254 | // serial number search direction write bit |
| 255 | OW_write_bit(search_direction); |
| 256 | |
| 257 | // increment the byte counter id_bit_number |
| 258 | // and shift the mask rom_byte_mask |
| 259 | id_bit_number++; |
| 260 | rom_byte_mask <<= 1; |
| 261 | |
| 262 | // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask |
| 263 | if (rom_byte_mask == 0) |
| 264 | { |
| 265 | docrc8(romid[rom_byte_number]); // accumulate the CRC |
| 266 | rom_byte_number++; |
| 267 | rom_byte_mask = 1; |
| 268 | } |
| 269 | } while (rom_byte_number < 8); // loop until all rom bytes 0-7 |
| 270 | } // end of not-last-device |
| 271 | |
| 272 | // if the search was succesful then |
| 273 | if (!(id_bit_number < 65 || crc8 != 0)) |
| 274 | { |
| 275 | // search successful |
| 276 | LastDiscrepancy = last_zero; |
| 277 | |
| 278 | // check for last device |
| 279 | if (LastDiscrepancy == 0) |
| 280 | LastDeviceFlag = true; |
| 281 | |
| 282 | search_result = true; |
| 283 | } |
| 284 | |
| 285 | if (!search_result || !romid[0]) |
| 286 | { |
| 287 | LastDiscrepancy = 0; |
| 288 | LastDeviceFlag = false; |
| 289 | LastFamilyDiscrepancy = 0; |
| 290 | search_result = false; |
| 291 | } |
| 292 | |
| 293 | int_enable(); |
| 294 | return search_result; |
| 295 | } |
| 296 | |
| 297 | |
| 298 | void OW_search_init() |
| 299 | { |
| 300 | LastDiscrepancy = 0; |
| 301 | LastDeviceFlag = false; |
| 302 | LastFamilyDiscrepancy = 0; |
| 303 | |
| 304 | for (int j=0; j<8; j++) romid[j]=0; |
| 305 | } |
| 306 | |
| 307 | |
| 308 | /* ask the (lone) device for its Serial number */ |
| 309 | void OW_identify() |
| 310 | { |
| 311 | int_disable(); |
| 312 | OW_reset(); |
| 313 | // read ROM command |
| 314 | OW_write_byte(0x33); |
| 315 | for (int j=0; j<8; j++) |
| 316 | romid[j] = OW_read_byte(); |
| 317 | int_enable(); |
| 318 | } |
| 319 | |
| 320 | /* is anyone parasite powered ? */ |
| 321 | bool OW_parasite(void) |
| 322 | { |
| 323 | int_disable(); |
| 324 | OW_reset(); |
| 325 | OW_write_byte(0xCC); // skip the rom command |
| 326 | OW_write_byte(0xB4); // are you parasite powered ? |
| 327 | bool no = OW_read_bit(); |
| 328 | int_enable(); |
| 329 | return !no; |
| 330 | } |
| 331 | |
| 332 | /* select a specific device, |
| 333 | * if family==0 select all devices (skip rom) |
| 334 | */ |
| 335 | static void OW_select_id(void) |
| 336 | { |
| 337 | if (romid[0] == 0) { |
| 338 | OW_write_byte(0xCC); // all devices for now |
| 339 | } else { |
| 340 | OW_write_byte(0x55); // match rom |
| 341 | for (int8_t j=0; j<8; j++) { |
| 342 | OW_write_byte(romid[j]); |
| 343 | } |
| 344 | } |
| 345 | } |
| 346 | |
| 347 | |
| 348 | /* read a memory block eg scratchpad 0xBE */ |
| 349 | void OW_read_block(uint8_t code, uint8_t * data, uint8_t len) |
| 350 | { |
| 351 | int_disable(); |
| 352 | OW_reset(); |
| 353 | OW_select_id(); |
| 354 | OW_write_byte(code); |
| 355 | for (int8_t j=0; j<len; j++) |
| 356 | data[j] = OW_read_byte(); |
| 357 | int_enable(); |
| 358 | } |
| 359 | |
| 360 | /* write a memory block to device, eg scratchpad 0x4E */ |
| 361 | void OW_write_block(uint8_t code, uint8_t * data, uint8_t len) |
| 362 | { |
| 363 | int_disable(); |
| 364 | OW_reset(); |
| 365 | OW_select_id(); |
| 366 | OW_write_byte(code); |
| 367 | for (int8_t j=0; j<len; j++) { |
| 368 | OW_write_byte(data[j]); |
| 369 | } |
| 370 | int_enable(); |
| 371 | } |
| 372 | |
| 373 | |
| 374 | // perform temperature conversion |
| 375 | void OW_convert() |
| 376 | { |
| 377 | // first see if anyone is parasitic |
| 378 | bool para = OW_parasite(); |
| 379 | |
| 380 | int_disable(); |
| 381 | OW_reset(); // all command start with reset |
| 382 | OW_select_id(); |
| 383 | //OW_write_byte(0xCC); // all devices |
| 384 | OW_write_byte(0x44); // convert |
| 385 | if (para) { |
| 386 | // hard high for 750mS |
| 387 | OWHIGH; |
| 388 | DelayUs(250000); |
| 389 | DelayUs(250000); |
| 390 | DelayUs(250000); |
| 391 | DelayUs(250000); |
| 392 | } else { |
| 393 | // keep polling until its done |
| 394 | // device will reply with 0 'pull low' whilst convert in progress |
| 395 | do { |
| 396 | DelayUs(1000); |
| 397 | } while (!OW_read_bit()); |
| 398 | } |
| 399 | int_enable(); |
| 400 | } |
| 401 | |
| 402 | /* Available commands :- |
| 403 | * 33h - read rom (sends 8 bytes) |
| 404 | * 55h - match rom (reads 8 bytes) |
| 405 | * F0h - search rom (enumeration mode) |
| 406 | * ECh - alarm search |
| 407 | * CC - skip rom command |
| 408 | * |
| 409 | * followed by.... |
| 410 | * 44h - convert temperature |
| 411 | * 48h - copy scratchpad -> eeprom |
| 412 | * 4Eh - write scratchpad (send 3 bytes ) |
| 413 | * BEh - read scratchpad ( 8 bytes + crc) |
| 414 | * B8h - recall EEPROM -> scratchpad |
| 415 | * B4h - read power supply (read 1 bit) |
| 416 | */ |