| 1 | /* $Id: ds1wire.h,v 1.2 2010/03/23 07:57:04 simimeie Exp $ |
| 2 | * Basic operations for dallas / maxim 1wire bus |
| 3 | * (C) Michael "Fox" Meier 2009 |
| 4 | */ |
| 5 | |
| 6 | #ifndef __DS1WIRE_H__ |
| 7 | #define __DS1WIRE_H__ |
| 8 | |
| 9 | #include <util/delay.h> |
| 10 | |
| 11 | /* This macro is redundant after powerup, as all bits zero is the default |
| 12 | * state after powerup. */ |
| 13 | #define ds1wire_init(port, bit) {\ |
| 14 | DDR##port &= (uint8_t)~(_BV(bit)); /* Do not actively drive the bus */ \ |
| 15 | PORT##port &= (uint8_t)~(_BV(bit)); /* Always output a 0, so we just need to change */ \ |
| 16 | /* the DDR register to pull the bus low. */ \ |
| 17 | } |
| 18 | |
| 19 | /* Reset the 1 wire bus. Works by driving it low for > 480 us. |
| 20 | * we do 500 to make sure. |
| 21 | * We then read the presence pulse 60 us after releasing the bus, |
| 22 | * and wait for another 420+1 us for the bus to become free. |
| 23 | * Returns 1 if there was a presence pulse, and 0 otherwise. |
| 24 | * takes about 981 usec to execute. |
| 25 | */ |
| 26 | #define ds1wire_reset(port, bit) \ |
| 27 | __ds1wire_reset(&DDR##port, &PIN##port, _BV(bit)) |
| 28 | |
| 29 | static inline uint8_t __ds1wire_reset(volatile uint8_t * ddr, volatile uint8_t * pin, uint8_t bv) { |
| 30 | uint8_t ret; |
| 31 | *ddr |= bv; /* drive the bus low */ |
| 32 | _delay_ms(0.50); |
| 33 | *ddr &= (uint8_t)~bv; /* release the bus */ |
| 34 | _delay_us(60.0); |
| 35 | ret = ((*pin & bv) == 0); |
| 36 | _delay_ms(0.421); |
| 37 | return ret; |
| 38 | } |
| 39 | |
| 40 | /* Actively pull down the 1 wire bus. For hard resetting parasite powered |
| 41 | * probes that have gone bonkers. */ |
| 42 | #define ds1wire_pulldown(port, bit) {\ |
| 43 | PORT##port &= (uint8_t)~(_BV(bit)); /* Output 0 (sucking away the current from the pullup) */ \ |
| 44 | DDR##port |= _BV(bit); /* Actively drive the bus */ \ |
| 45 | } |
| 46 | |
| 47 | /* Read a bit from the 1 wire bus. takes 61 usec to execute. */ |
| 48 | #define ds1wire_read(port, bit) \ |
| 49 | __ds1wire_read(&DDR##port, &PIN##port, _BV(bit)) |
| 50 | |
| 51 | static inline uint8_t __ds1wire_read(volatile uint8_t * ddr, volatile uint8_t * pin, uint8_t bv) { |
| 52 | uint8_t ret; |
| 53 | *ddr |= bv; /* drive the bus low */ |
| 54 | _delay_us(5.0); /* everything > 1 us should suffice, more to be sure. */ |
| 55 | *ddr &= (uint8_t)~bv; /* release the bus */ |
| 56 | _delay_us(6.0); /* Wait for the probe to pull the bus */ |
| 57 | ret = ((*pin & bv) != 0); |
| 58 | _delay_us(50.0); /* after that the bus is free again */ |
| 59 | return ret; |
| 60 | } |
| 61 | |
| 62 | /* Sends a 0 bit to the 1 wire bus. takes 61 usec to execute. */ |
| 63 | #define ds1wire_send0(port, bit) {\ |
| 64 | DDR##port |= _BV(bit); /* pull low */ \ |
| 65 | _delay_us(60.0); /* worst case timing */ \ |
| 66 | DDR##port &= (uint8_t)~_BV(bit); /* release */ \ |
| 67 | _delay_us(1.0); /* bus is free again after that */ \ |
| 68 | } |
| 69 | |
| 70 | /* Sends a 1 bit to the 1 wire bus. takes 61 usec to execute. */ |
| 71 | #define ds1wire_send1(port, bit) {\ |
| 72 | DDR##port |= _BV(bit); /* pull low */ \ |
| 73 | _delay_us(10.0); /* everything > 1 us should suffice, try to be close to 15 us. */ \ |
| 74 | DDR##port &= (uint8_t)~_BV(bit); /* release */ \ |
| 75 | _delay_us(51.0); /* bus is free again after that */ \ |
| 76 | } |
| 77 | |
| 78 | /* Enable power for parasite powered probes. Warning: You must |
| 79 | * not forget to call parasitepoweroff after some time! */ |
| 80 | #define ds1wire_parasitepoweron(port, bit) { \ |
| 81 | PORT##port |= _BV(bit); \ |
| 82 | DDR##port |= _BV(bit); \ |
| 83 | } |
| 84 | |
| 85 | /* Disable power for parasite powered probes. */ |
| 86 | #define ds1wire_parasitepoweroff(port, bit) \ |
| 87 | ds1wire_init(port, bit) |
| 88 | |
| 89 | static inline uint8_t ds1wire_calccrc8(uint8_t shiftreg, uint8_t data) |
| 90 | { |
| 91 | uint8_t i; |
| 92 | for (i = 0; i < 8; i++) { |
| 93 | /* XOR LSB of shiftreg with LSB of data */ |
| 94 | uint8_t feedback = (shiftreg & 0x01) ^ (data & 0x01); |
| 95 | shiftreg >>= 1; /* first position in shiftreg now is 0 - important for below! */ |
| 96 | if (feedback == 1) { |
| 97 | shiftreg = shiftreg ^ 0x8C; /* binary 10001100 */ |
| 98 | } |
| 99 | data >>= 1; |
| 100 | } |
| 101 | return shiftreg; |
| 102 | } |
| 103 | |
| 104 | #endif /* __DS1WIRE_H__ */ |