310
|
1 /* |
|
2 Access Dallas 1-Wire Devices with ATMEL AVRs |
|
3 Author of the initial code: Peter Dannegger (danni(at)specs.de) |
|
4 modified by Martin Thomas (mthomas(at)rhrk.uni-kl.de) |
|
5 9/2004 - use of delay.h, optional bus configuration at runtime |
|
6 10/2009 - additional delay in ow_bit_io for recovery |
|
7 5/2010 - timing modifcations, additonal config-values and comments, |
|
8 use of atomic.h macros, internal pull-up support |
|
9 7/2010 - added method to skip recovery time after last bit transfered |
|
10 via ow_command_skip_last_recovery |
|
11 */ |
|
12 |
|
13 |
|
14 #include <avr/io.h> |
|
15 #include <util/delay.h> |
|
16 #include <util/atomic.h> |
|
17 |
|
18 #include "onewire.h" |
|
19 |
|
20 #ifdef OW_ONE_BUS |
|
21 |
|
22 #define OW_GET_IN() ( OW_IN & (1<<OW_PIN)) |
|
23 #define OW_OUT_LOW() ( OW_OUT &= (~(1 << OW_PIN)) ) |
|
24 #define OW_OUT_HIGH() ( OW_OUT |= (1 << OW_PIN) ) |
|
25 #define OW_DIR_IN() ( OW_DDR &= (~(1 << OW_PIN )) ) |
|
26 #define OW_DIR_OUT() ( OW_DDR |= (1 << OW_PIN) ) |
|
27 |
|
28 #else |
|
29 |
|
30 /* set bus-config with ow_set_bus() */ |
|
31 uint8_t OW_PIN_MASK; |
|
32 volatile uint8_t* OW_IN; |
|
33 volatile uint8_t* OW_OUT; |
|
34 volatile uint8_t* OW_DDR; |
|
35 |
|
36 #define OW_GET_IN() ( *OW_IN & OW_PIN_MASK ) |
|
37 #define OW_OUT_LOW() ( *OW_OUT &= (uint8_t) ~OW_PIN_MASK ) |
|
38 #define OW_OUT_HIGH() ( *OW_OUT |= (uint8_t) OW_PIN_MASK ) |
|
39 #define OW_DIR_IN() ( *OW_DDR &= (uint8_t) ~OW_PIN_MASK ) |
|
40 #define OW_DIR_OUT() ( *OW_DDR |= (uint8_t) OW_PIN_MASK ) |
|
41 |
|
42 void ow_set_bus(volatile uint8_t* in, |
|
43 volatile uint8_t* out, |
|
44 volatile uint8_t* ddr, |
|
45 uint8_t pin) |
|
46 { |
|
47 OW_DDR=ddr; |
|
48 OW_OUT=out; |
|
49 OW_IN=in; |
|
50 OW_PIN_MASK = (1 << pin); |
|
51 ow_reset(); |
|
52 } |
|
53 |
|
54 #endif |
|
55 |
|
56 uint8_t ow_input_pin_state() |
|
57 { |
|
58 return OW_GET_IN(); |
|
59 } |
|
60 |
|
61 void ow_parasite_enable(void) |
|
62 { |
|
63 OW_OUT_HIGH(); |
|
64 OW_DIR_OUT(); |
|
65 } |
|
66 |
|
67 void ow_parasite_disable(void) |
|
68 { |
|
69 OW_DIR_IN(); |
|
70 #if (!OW_USE_INTERNAL_PULLUP) |
|
71 OW_OUT_LOW(); |
|
72 #endif |
|
73 } |
|
74 |
|
75 |
|
76 uint8_t ow_reset(void) |
|
77 { |
|
78 uint8_t err; |
|
79 |
|
80 OW_OUT_LOW(); |
|
81 OW_DIR_OUT(); // pull OW-Pin low for 480us |
|
82 _delay_us(480); |
|
83 |
|
84 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { |
|
85 // set Pin as input - wait for clients to pull low |
|
86 OW_DIR_IN(); // input |
|
87 #if OW_USE_INTERNAL_PULLUP |
|
88 OW_OUT_HIGH(); |
|
89 #endif |
|
90 |
|
91 _delay_us(64); // was 66 |
|
92 err = OW_GET_IN(); // no presence detect |
|
93 // if err!=0: nobody pulled to low, still high |
|
94 } |
|
95 |
|
96 // after a delay the clients should release the line |
|
97 // and input-pin gets back to high by pull-up-resistor |
|
98 _delay_us(480 - 64); // was 480-66 |
|
99 if( OW_GET_IN() == 0 ) { |
|
100 err = 1; // short circuit, expected low but got high |
|
101 } |
|
102 |
|
103 return err; |
|
104 } |
|
105 |
|
106 |
|
107 /* Timing issue when using runtime-bus-selection (!OW_ONE_BUS): |
|
108 The master should sample at the end of the 15-slot after initiating |
|
109 the read-time-slot. The variable bus-settings need more |
|
110 cycles than the constant ones so the delays had to be shortened |
|
111 to achive a 15uS overall delay |
|
112 Setting/clearing a bit in I/O Register needs 1 cyle in OW_ONE_BUS |
|
113 but around 14 cyles in configureable bus (us-Delay is 4 cyles per uS) */ |
|
114 static uint8_t ow_bit_io_intern( uint8_t b, uint8_t with_parasite_enable ) |
|
115 { |
|
116 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { |
|
117 #if OW_USE_INTERNAL_PULLUP |
|
118 OW_OUT_LOW(); |
|
119 #endif |
|
120 OW_DIR_OUT(); // drive bus low |
|
121 _delay_us(2); // T_INT > 1usec accoding to timing-diagramm |
|
122 if ( b ) { |
|
123 OW_DIR_IN(); // to write "1" release bus, resistor pulls high |
|
124 #if OW_USE_INTERNAL_PULLUP |
|
125 OW_OUT_HIGH(); |
|
126 #endif |
|
127 } |
|
128 |
|
129 // "Output data from the DS18B20 is valid for 15usec after the falling |
|
130 // edge that initiated the read time slot. Therefore, the master must |
|
131 // release the bus and then sample the bus state within 15ussec from |
|
132 // the start of the slot." |
|
133 _delay_us(15-2-OW_CONF_DELAYOFFSET); |
|
134 |
|
135 if( OW_GET_IN() == 0 ) { |
|
136 b = 0; // sample at end of read-timeslot |
|
137 } |
|
138 |
|
139 _delay_us(60-15-2+OW_CONF_DELAYOFFSET); |
|
140 #if OW_USE_INTERNAL_PULLUP |
|
141 OW_OUT_HIGH(); |
|
142 #endif |
|
143 OW_DIR_IN(); |
|
144 |
|
145 if ( with_parasite_enable ) { |
|
146 ow_parasite_enable(); |
|
147 } |
|
148 |
|
149 } /* ATOMIC_BLOCK */ |
|
150 |
|
151 _delay_us(OW_RECOVERY_TIME); // may be increased for longer wires |
|
152 |
|
153 return b; |
|
154 } |
|
155 |
|
156 uint8_t ow_bit_io( uint8_t b ) |
|
157 { |
|
158 return ow_bit_io_intern( b & 1, 0 ); |
|
159 } |
|
160 |
|
161 uint8_t ow_byte_wr( uint8_t b ) |
|
162 { |
|
163 uint8_t i = 8, j; |
|
164 |
|
165 do { |
|
166 j = ow_bit_io( b & 1 ); |
|
167 b >>= 1; |
|
168 if( j ) { |
|
169 b |= 0x80; |
|
170 } |
|
171 } while( --i ); |
|
172 |
|
173 return b; |
|
174 } |
|
175 |
|
176 uint8_t ow_byte_wr_with_parasite_enable( uint8_t b ) |
|
177 { |
|
178 uint8_t i = 8, j; |
|
179 |
|
180 do { |
|
181 if ( i != 1 ) { |
|
182 j = ow_bit_io_intern( b & 1, 0 ); |
|
183 } else { |
|
184 j = ow_bit_io_intern( b & 1, 1 ); |
|
185 } |
|
186 b >>= 1; |
|
187 if( j ) { |
|
188 b |= 0x80; |
|
189 } |
|
190 } while( --i ); |
|
191 |
|
192 return b; |
|
193 } |
|
194 |
|
195 |
|
196 uint8_t ow_byte_rd( void ) |
|
197 { |
|
198 // read by sending only "1"s, so bus gets released |
|
199 // after the init low-pulse in every slot |
|
200 return ow_byte_wr( 0xFF ); |
|
201 } |
|
202 |
|
203 |
|
204 uint8_t ow_rom_search( uint8_t diff, uint8_t *id ) |
|
205 { |
|
206 uint8_t i, j, next_diff; |
|
207 uint8_t b; |
|
208 |
|
209 if( ow_reset() ) { |
|
210 return OW_PRESENCE_ERR; // error, no device found <--- early exit! |
|
211 } |
|
212 |
|
213 ow_byte_wr( OW_SEARCH_ROM ); // ROM search command |
|
214 next_diff = OW_LAST_DEVICE; // unchanged on last device |
|
215 |
|
216 i = OW_ROMCODE_SIZE * 8; // 8 bytes |
|
217 |
|
218 do { |
|
219 j = 8; // 8 bits |
|
220 do { |
|
221 b = ow_bit_io( 1 ); // read bit |
|
222 if( ow_bit_io( 1 ) ) { // read complement bit |
|
223 if( b ) { // 0b11 |
|
224 return OW_DATA_ERR; // data error <--- early exit! |
|
225 } |
|
226 } |
|
227 else { |
|
228 if( !b ) { // 0b00 = 2 devices |
|
229 if( diff > i || ((*id & 1) && diff != i) ) { |
|
230 b = 1; // now 1 |
|
231 next_diff = i; // next pass 0 |
|
232 } |
|
233 } |
|
234 } |
|
235 ow_bit_io( b ); // write bit |
|
236 *id >>= 1; |
|
237 if( b ) { |
|
238 *id |= 0x80; // store bit |
|
239 } |
|
240 |
|
241 i--; |
|
242 |
|
243 } while( --j ); |
|
244 |
|
245 id++; // next byte |
|
246 |
|
247 } while( i ); |
|
248 |
|
249 return next_diff; // to continue search |
|
250 } |
|
251 |
|
252 |
|
253 static void ow_command_intern( uint8_t command, uint8_t *id, uint8_t with_parasite_enable ) |
|
254 { |
|
255 uint8_t i; |
|
256 |
|
257 ow_reset(); |
|
258 |
|
259 if( id ) { |
|
260 ow_byte_wr( OW_MATCH_ROM ); // to a single device |
|
261 i = OW_ROMCODE_SIZE; |
|
262 do { |
|
263 ow_byte_wr( *id ); |
|
264 id++; |
|
265 } while( --i ); |
|
266 } |
|
267 else { |
|
268 ow_byte_wr( OW_SKIP_ROM ); // to all devices |
|
269 } |
|
270 |
|
271 if ( with_parasite_enable ) { |
|
272 ow_byte_wr_with_parasite_enable( command ); |
|
273 } else { |
|
274 ow_byte_wr( command ); |
|
275 } |
|
276 } |
|
277 |
|
278 void ow_command( uint8_t command, uint8_t *id ) |
|
279 { |
|
280 ow_command_intern( command, id, 0); |
|
281 } |
|
282 |
|
283 void ow_command_with_parasite_enable( uint8_t command, uint8_t *id ) |
|
284 { |
|
285 ow_command_intern( command, id, 1 ); |
|
286 } |
|
287 |