comparison onewire.c @ 0:8705acff2494

lots of stuff
author Matt Johnston <matt@ucc.asn.au>
date Sat, 01 Jun 2013 01:38:42 +0800
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:8705acff2494
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