-
Notifications
You must be signed in to change notification settings - Fork 0
/
owi_lowlevel.c
186 lines (151 loc) · 4.59 KB
/
owi_lowlevel.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
* Program: Multitherm - A multiple DS18x20 thermometer control and logging device
* File Name: owilowlevel.c
* Purpose: Port level bit-banging funtions to access a Dallas Semiconductor 1-Wire bus
*
* Description:
* Port level access to Dallas 1-Wire bus. These functions ARE device
* speed/timing dependent and have been adjusted to match timings present
* in AN126
*
* Based on Dallas Semiconductor Application Note AN126
* "1-Wire Communication Through Software"
* Based on code by Peter Dannegger and Martin Thomas
*
* Programmer: Tom Blough
* Host System: ATMega16L tested with both internal RC osc at 8MHz
* and external 8MHz crystal
* Date Created: 2007/09/20
* Revision: $WCREV$ $WCDATE$
* Modifications:
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "owi_lowlevel.h"
#include "owi_defs.h"
#include "delay.h"
/* This function initializes the 1-Wire bus(es) by releasing it and
* waiting until any presence sinals are finished.
*/
extern void owi_init()
{
OWI_RELEASE_BUS();
// The first rising edge can be interpreted by a slave as the end of a
// Reset pulse. Delay for the required reset recovery time (H) to be
// sure that the real reset is interpreted correctly.
delay_us( OWI_DELAY_H);
}
/* Generates the waveform for transmission of a Reset pulse on the
* 1-Wire(R) bus and listens for presence signals.
*
* returns OWI_BUS_OK if presence signal was detected or OWI_BUS_ERROR
* if no devices present or bus error exists
*/
extern uint8_t owi_reset()
{
uint8_t sreg, b;
// first part is long delay with significant timing leeway so
// don't disable interrupts until after
OWI_PULL_BUS_LOW();
delay_us( OWI_DELAY_H + 12);
sreg = SREG;
cli(); // disable interrupts
OWI_RELEASE_BUS(); // allow bus high
delay_us( OWI_DELAY_I);
b = ~OWI_GET_IN();
SREG = sreg; // restore interrupts
// another long delay without max so re-enable interrupts before
delay_us( OWI_DELAY_J);
// check to see if the bus is stull pulled low (shorted?)
return b & OWI_GET_IN();
}
/* write or read a single bit from the bus
* note that owi_bit_io( b) is the same as owi_bit_wr( b)
* and b = owi_bit_io( 0x01) is the same as b = owi_bit_rd();
*/
extern uint8_t owi_bit_io( uint8_t b)
{
uint8_t sreg;
sreg = SREG;
cli();
// attention pulse
OWI_PULL_BUS_LOW(); // drive bus low
// delay_us( OWI_DELAY_A);
//delay_us( 1); //code was too long - replace with inline assembler delays
DELAY_1US();
DELAY_1US();
DELAY_1US();
DELAY_1US();
// if writing 1 (or reading), stop pulling low data period
if( b)
OWI_RELEASE_BUS(); // allow bus high
// response wait
//delay_us( OWI_DELAY_E);
delay_us( 1);
b = OWI_GET_IN(); // sample at end of response wait
delay_us( OWI_DELAY_F - OWI_DELAY_D - 3); // wait for rest of R/W time slot
// recovery time
OWI_RELEASE_BUS(); // allow bus high if we were reading or writing 0, else we were already there
// delay_us( OWI_DELAY_D);
//delay_us( 1); // code was too long - replace with assembler delays
DELAY_1US();
DELAY_1US();
SREG = sreg; // sei();
return b;
}
/* individual bit write and read functions are only needed for debugging and delay testing
* normally we can use the combiner IO function to write and read a bit at the same time.
* to reduce code size if not needed, comment out the OWI_LL_DEBUG definition in the header file.
*/
#ifdef OWI_LL_DEBUG
// write a single bit to the 1-Wire bus
extern void owi_bit_wr( uint8_t b)
{
uint8_t sreg;
sreg = SREG; // stop interrupts to maintain timing
cli();
// do attention pulse
OWI_PULL_BUS_LOW();
// delay_us( OWI_DELAY_A);
// delay_us( 1) code was too long - replace with inline assembler delays
DELAY_1US();
DELAY_1US();
DELAY_1US();
DELAY_1US();
// if writing 1, stop pulling low data period
if( b)
OWI_RELEASE_BUS();
// data period
delay_us( OWI_DELAY_B - OWI_DELAY_D - 4);
OWI_RELEASE_BUS();
// recovery time
// delay_us( OWI_DELAY_D);
// delay_us( 1) code was too long - replace with assembler delays
DELAY_1US();
DELAY_1US();
SREG = sreg; // sei();
}
//read a single bit from the 1-Wire bus
extern uint8_t owi_bit_rd()
{
uint8_t sreg, b;
sreg = SREG;
cli();
// attention pulse
OWI_PULL_BUS_LOW();
// delay_us( OWI_DELAY_A);
//delay_us( 1); // code was too long - replace with inline assembler delays
DELAY_1US();
DELAY_1US();
DELAY_1US();
DELAY_1US();
// stop pulling low for data period
OWI_RELEASE_BUS();
//delay_us( OWI_DELAY_E);
delay_us( 1);
b = OWI_GET_IN(); // sample at end of response wait
delay_us( OWI_DELAY_F - 11); // wait for rest of time slot
SREG = sreg; // sei();
return b;
}
#endif // OWI_DEBUG