1 |
786 |
skrzyp |
//==========================================================================
|
2 |
|
|
//
|
3 |
|
|
// i2c.cxx
|
4 |
|
|
//
|
5 |
|
|
// Generic API for accessing devices attached to an I2C bus
|
6 |
|
|
//
|
7 |
|
|
//==========================================================================
|
8 |
|
|
// ####ECOSGPLCOPYRIGHTBEGIN####
|
9 |
|
|
// -------------------------------------------
|
10 |
|
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
11 |
|
|
// Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc.
|
12 |
|
|
//
|
13 |
|
|
// eCos is free software; you can redistribute it and/or modify it under
|
14 |
|
|
// the terms of the GNU General Public License as published by the Free
|
15 |
|
|
// Software Foundation; either version 2 or (at your option) any later
|
16 |
|
|
// version.
|
17 |
|
|
//
|
18 |
|
|
// eCos is distributed in the hope that it will be useful, but WITHOUT
|
19 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
20 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
21 |
|
|
// for more details.
|
22 |
|
|
//
|
23 |
|
|
// You should have received a copy of the GNU General Public License
|
24 |
|
|
// along with eCos; if not, write to the Free Software Foundation, Inc.,
|
25 |
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
26 |
|
|
//
|
27 |
|
|
// As a special exception, if other files instantiate templates or use
|
28 |
|
|
// macros or inline functions from this file, or you compile this file
|
29 |
|
|
// and link it with other works to produce a work based on this file,
|
30 |
|
|
// this file does not by itself cause the resulting work to be covered by
|
31 |
|
|
// the GNU General Public License. However the source code for this file
|
32 |
|
|
// must still be made available in accordance with section (3) of the GNU
|
33 |
|
|
// General Public License v2.
|
34 |
|
|
//
|
35 |
|
|
// This exception does not invalidate any other reasons why a work based
|
36 |
|
|
// on this file might be covered by the GNU General Public License.
|
37 |
|
|
// -------------------------------------------
|
38 |
|
|
// ####ECOSGPLCOPYRIGHTEND####
|
39 |
|
|
//==========================================================================
|
40 |
|
|
//###DESCRIPTIONBEGIN####
|
41 |
|
|
//
|
42 |
|
|
// Author(s): bartv
|
43 |
|
|
// Date: 2004-10-05
|
44 |
|
|
//
|
45 |
|
|
//###DESCRIPTIONEND####
|
46 |
|
|
//========================================================================
|
47 |
|
|
|
48 |
|
|
#include <pkgconf/infra.h>
|
49 |
|
|
#include <pkgconf/io_i2c.h>
|
50 |
|
|
#include <cyg/infra/cyg_ass.h>
|
51 |
|
|
#include <cyg/infra/cyg_type.h>
|
52 |
|
|
#include <cyg/infra/diag.h>
|
53 |
|
|
#include <cyg/io/i2c.h>
|
54 |
|
|
#include <cyg/hal/hal_io.h>
|
55 |
|
|
#include <cyg/hal/hal_intr.h>
|
56 |
|
|
#include <cyg/hal/hal_diag.h>
|
57 |
|
|
|
58 |
|
|
// ----------------------------------------------------------------------------
|
59 |
|
|
// Static initialization.
|
60 |
|
|
//
|
61 |
|
|
// This is somewhat tricky. There is a strong argument for leaving the
|
62 |
|
|
// initialization to the platform HAL since with most I2C buses that
|
63 |
|
|
// code will be straightforward. However that would mean that the
|
64 |
|
|
// cyg_i2c_bus structure(s) and associated code would always get
|
65 |
|
|
// linked in, even if the application does not use any i2c devices.
|
66 |
|
|
// Instead to get the maximum benefit of linker garbage collection
|
67 |
|
|
// initialization is handled by the generic I2C code, using the usual
|
68 |
|
|
// dummy C++ object with a prioritized constructor. There is a dummy
|
69 |
|
|
// references to this object from the transaction end function. The
|
70 |
|
|
// result should be that if the application uses any I2C functionality
|
71 |
|
|
// then all required code and data should get included, otherwise it
|
72 |
|
|
// will all be elided.
|
73 |
|
|
//
|
74 |
|
|
// All I2C buses are kept in a table, so that the init code can
|
75 |
|
|
// iterate through each one.
|
76 |
|
|
|
77 |
|
|
CYG_HAL_TABLE_BEGIN(cyg_i2c_buses, i2c_buses);
|
78 |
|
|
CYG_HAL_TABLE_END(cyg_i2c_buses_end, i2c_buses);
|
79 |
|
|
|
80 |
|
|
class cyg_i2c_init {
|
81 |
|
|
public:
|
82 |
|
|
cyg_uint8 i2c_dummy;
|
83 |
|
|
cyg_i2c_init();
|
84 |
|
|
};
|
85 |
|
|
|
86 |
|
|
static cyg_i2c_init cyg_i2c_init_object CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_BUS_I2C);
|
87 |
|
|
|
88 |
|
|
cyg_i2c_init::cyg_i2c_init()
|
89 |
|
|
{
|
90 |
|
|
cyg_i2c_bus* bus;
|
91 |
|
|
|
92 |
|
|
cyg_i2c_init_object.i2c_dummy = 0;
|
93 |
|
|
for (bus = &(cyg_i2c_buses[0]); bus != &cyg_i2c_buses_end; bus++) {
|
94 |
|
|
cyg_drv_mutex_init(&(bus->i2c_lock));
|
95 |
|
|
#ifdef CYGDBG_USE_ASSERTS
|
96 |
|
|
bus->i2c_current_device = (const cyg_i2c_device*) 0;
|
97 |
|
|
#endif
|
98 |
|
|
if ((void (*)(cyg_i2c_bus*))0 != bus->i2c_init_fn) {
|
99 |
|
|
(*bus->i2c_init_fn)(bus);
|
100 |
|
|
}
|
101 |
|
|
}
|
102 |
|
|
}
|
103 |
|
|
|
104 |
|
|
// ----------------------------------------------------------------------------
|
105 |
|
|
// The main exported routines just operate in terms of the transaction ones.
|
106 |
|
|
|
107 |
|
|
extern "C" cyg_uint32
|
108 |
|
|
cyg_i2c_tx(const cyg_i2c_device* dev, const cyg_uint8* buf, cyg_uint32 count)
|
109 |
|
|
{
|
110 |
|
|
cyg_uint32 result;
|
111 |
|
|
cyg_i2c_transaction_begin(dev);
|
112 |
|
|
result = cyg_i2c_transaction_tx(dev, true, buf, count, true);
|
113 |
|
|
cyg_i2c_transaction_end(dev);
|
114 |
|
|
return result;
|
115 |
|
|
}
|
116 |
|
|
|
117 |
|
|
extern "C" cyg_uint32
|
118 |
|
|
cyg_i2c_rx(const cyg_i2c_device* dev, cyg_uint8* buf, cyg_uint32 count)
|
119 |
|
|
{
|
120 |
|
|
cyg_uint32 result;
|
121 |
|
|
cyg_i2c_transaction_begin(dev);
|
122 |
|
|
result = cyg_i2c_transaction_rx(dev, true, buf, count, true, true);
|
123 |
|
|
cyg_i2c_transaction_end(dev);
|
124 |
|
|
return result;
|
125 |
|
|
}
|
126 |
|
|
|
127 |
|
|
// Transaction begin/end relate to the per-bus locking. There does not
|
128 |
|
|
// seem to be any need to interact with the hardware at this point.
|
129 |
|
|
extern "C" void
|
130 |
|
|
cyg_i2c_transaction_begin(const cyg_i2c_device* dev)
|
131 |
|
|
{
|
132 |
|
|
cyg_i2c_bus* bus;
|
133 |
|
|
|
134 |
|
|
CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
|
135 |
|
|
bus = dev->i2c_bus;
|
136 |
|
|
CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
|
137 |
|
|
|
138 |
|
|
while (! cyg_drv_mutex_lock(&(bus->i2c_lock)));
|
139 |
|
|
#ifdef CYGDBG_USE_ASSERTS
|
140 |
|
|
bus->i2c_current_device = dev;
|
141 |
|
|
#endif
|
142 |
|
|
// All done, return with the bus locked.
|
143 |
|
|
}
|
144 |
|
|
|
145 |
|
|
extern "C" cyg_bool
|
146 |
|
|
cyg_i2c_transaction_begin_nb(const cyg_i2c_device* dev)
|
147 |
|
|
{
|
148 |
|
|
cyg_bool result = false;
|
149 |
|
|
cyg_i2c_bus* bus;
|
150 |
|
|
|
151 |
|
|
CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
|
152 |
|
|
bus = dev->i2c_bus;
|
153 |
|
|
CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
|
154 |
|
|
|
155 |
|
|
if (cyg_drv_mutex_trylock(&(bus->i2c_lock))) {
|
156 |
|
|
#ifdef CYGDBG_USE_ASSERTS
|
157 |
|
|
bus->i2c_current_device = dev;
|
158 |
|
|
#endif
|
159 |
|
|
result = true;
|
160 |
|
|
}
|
161 |
|
|
|
162 |
|
|
return result;
|
163 |
|
|
}
|
164 |
|
|
|
165 |
|
|
extern "C" void
|
166 |
|
|
cyg_i2c_transaction_end(const cyg_i2c_device* dev)
|
167 |
|
|
{
|
168 |
|
|
cyg_i2c_bus* bus;
|
169 |
|
|
|
170 |
|
|
CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
|
171 |
|
|
bus = dev->i2c_bus;
|
172 |
|
|
CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
|
173 |
|
|
CYG_PRECONDITION(bus->i2c_current_device == dev, "I2C transaction end requested without claiming the bus");
|
174 |
|
|
|
175 |
|
|
cyg_drv_mutex_unlock(&(bus->i2c_lock));
|
176 |
|
|
#ifdef CYGDBG_USE_ASSERTS
|
177 |
|
|
bus->i2c_current_device = (const cyg_i2c_device*)0;
|
178 |
|
|
#endif
|
179 |
|
|
// Avoid problems with linker garbage collection
|
180 |
|
|
cyg_i2c_init_object.i2c_dummy = 0;
|
181 |
|
|
}
|
182 |
|
|
|
183 |
|
|
// The I/O operations just indirect through the per-bus function pointers
|
184 |
|
|
extern "C" cyg_uint32
|
185 |
|
|
cyg_i2c_transaction_tx(const cyg_i2c_device* dev, cyg_bool start, const cyg_uint8* buf, cyg_uint32 count, cyg_bool stop)
|
186 |
|
|
{
|
187 |
|
|
cyg_i2c_bus* bus;
|
188 |
|
|
cyg_uint32 result;
|
189 |
|
|
|
190 |
|
|
CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
|
191 |
|
|
bus = dev->i2c_bus;
|
192 |
|
|
CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
|
193 |
|
|
CYG_PRECONDITION(bus->i2c_current_device == dev, "I2C transaction end requested without claiming the bus");
|
194 |
|
|
CYG_CHECK_FUNC_PTR(bus->i2c_tx_fn, "I2C bus has not provided a tx function");
|
195 |
|
|
|
196 |
|
|
result = (*(bus->i2c_tx_fn))(dev, start, buf, count, stop);
|
197 |
|
|
return result;
|
198 |
|
|
}
|
199 |
|
|
|
200 |
|
|
extern "C" cyg_uint32
|
201 |
|
|
cyg_i2c_transaction_rx(const cyg_i2c_device* dev, cyg_bool start, cyg_uint8* buf, cyg_uint32 count, cyg_bool nak, cyg_bool stop)
|
202 |
|
|
{
|
203 |
|
|
cyg_i2c_bus* bus;
|
204 |
|
|
cyg_uint32 result;
|
205 |
|
|
|
206 |
|
|
CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
|
207 |
|
|
bus = dev->i2c_bus;
|
208 |
|
|
CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
|
209 |
|
|
CYG_PRECONDITION(bus->i2c_current_device == dev, "I2C transaction end requested without claiming the bus");
|
210 |
|
|
CYG_CHECK_FUNC_PTR(bus->i2c_rx_fn, "I2C bus has not provided an rx function");
|
211 |
|
|
|
212 |
|
|
result = (*(bus->i2c_rx_fn))(dev, start, buf, count, nak, stop);
|
213 |
|
|
return result;
|
214 |
|
|
}
|
215 |
|
|
|
216 |
|
|
extern "C" void
|
217 |
|
|
cyg_i2c_transaction_stop(const cyg_i2c_device* dev)
|
218 |
|
|
{
|
219 |
|
|
cyg_i2c_bus* bus;
|
220 |
|
|
|
221 |
|
|
CYG_CHECK_DATA_PTR(dev, "valid I2C device pointer required");
|
222 |
|
|
bus = dev->i2c_bus;
|
223 |
|
|
CYG_CHECK_DATA_PTR(bus, "I2C device does not point at a valid bus structure");
|
224 |
|
|
CYG_PRECONDITION(bus->i2c_current_device == dev, "I2C transaction end requested without claiming the bus");
|
225 |
|
|
CYG_CHECK_FUNC_PTR(bus->i2c_stop_fn, "I2C bus has not provided a stop function");
|
226 |
|
|
|
227 |
|
|
(*(bus->i2c_stop_fn))(dev);
|
228 |
|
|
}
|
229 |
|
|
|
230 |
|
|
// ----------------------------------------------------------------------------
|
231 |
|
|
// The bit-banging support
|
232 |
|
|
//
|
233 |
|
|
// Optional debug support, useful while sorting out the platform-specific
|
234 |
|
|
// bitbang function.
|
235 |
|
|
#if 1
|
236 |
|
|
# define DEBUG(_format_, ...)
|
237 |
|
|
#else
|
238 |
|
|
# define DEBUG(_format_, ...) diag_printf(_format_, ## __VA_ARGS__)
|
239 |
|
|
#endif
|
240 |
|
|
|
241 |
|
|
|
242 |
|
|
// Initialization calls into the h/w specific bit-bang function to set
|
243 |
|
|
// up the GPIO pins and to set both SCL and SDA as outputs and high.
|
244 |
|
|
|
245 |
|
|
extern "C" void
|
246 |
|
|
cyg_i2c_bitbang_init(cyg_i2c_bus* mash)
|
247 |
|
|
{
|
248 |
|
|
cyg_i2c_bitbang_fn banger = (cyg_i2c_bitbang_fn)(mash->i2c_extra);
|
249 |
|
|
CYG_CHECK_FUNC_PTR(banger, "bitbanged i2c bus has not provided a bitbang function");
|
250 |
|
|
|
251 |
|
|
DEBUG("i2c bitbang init\n");
|
252 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_INIT);
|
253 |
|
|
}
|
254 |
|
|
|
255 |
|
|
// Send a single byte out of the bus and get back the acknowledgement.
|
256 |
|
|
// This may be the addressing byte or a data byte.
|
257 |
|
|
// Preconditions:
|
258 |
|
|
// SCL output low. The previous operation has completed, the
|
259 |
|
|
// acknowledgement bit has been received and processed.
|
260 |
|
|
// None of the devices should be driving the bus.
|
261 |
|
|
// SDA output, indeterminate value.
|
262 |
|
|
// Postconditions:
|
263 |
|
|
// SCL output low, the acknowledgement has been received.
|
264 |
|
|
// SDA may be left as an input or an output, depending on the
|
265 |
|
|
// last argument
|
266 |
|
|
//
|
267 |
|
|
// The return value is the acknowledge bit, i.e. 0 for ack, 1 for
|
268 |
|
|
// nak.
|
269 |
|
|
|
270 |
|
|
static cyg_bool
|
271 |
|
|
cyg_i2c_bitbang_send_byte(cyg_i2c_bus* mash, const cyg_i2c_device* dev, cyg_uint32 delay, cyg_uint8 data, cyg_bool leave_as_input)
|
272 |
|
|
{
|
273 |
|
|
cyg_i2c_bitbang_fn banger = (cyg_i2c_bitbang_fn)(mash->i2c_extra);
|
274 |
|
|
cyg_uint8 mask;
|
275 |
|
|
cyg_bool result;
|
276 |
|
|
|
277 |
|
|
DEBUG("i2c bitbang send_byte %02x, leave_as_input %d\n", data, leave_as_input);
|
278 |
|
|
|
279 |
|
|
for (mask = 0x0080; 0x00 != mask; ) {
|
280 |
|
|
// Transfer the next bit of data
|
281 |
|
|
(*banger)(mash, (0 != (data & mask)) ? CYG_I2C_BITBANG_SDA_HIGH : CYG_I2C_BITBANG_SDA_LOW);
|
282 |
|
|
mask = mask >> 1;
|
283 |
|
|
// We should now be able to just set the clock high and wait
|
284 |
|
|
// for the delay period. However if the device is having
|
285 |
|
|
// difficulty keeping up then it may perform clock stretching,
|
286 |
|
|
// basically keeping the clock low for a period of time.
|
287 |
|
|
// SCL_CLOCKSTRETCH means set the clock high, then wait
|
288 |
|
|
// until it really has gone high.
|
289 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_HIGH_CLOCKSTRETCH);
|
290 |
|
|
// The device is now busy sampling the bit.
|
291 |
|
|
HAL_DELAY_US(delay);
|
292 |
|
|
// Unless this was the last bit, just drop the clock. If it is
|
293 |
|
|
// the last bit switch SDA to an input as well.
|
294 |
|
|
(*banger)(mash, (0 != mask) ? CYG_I2C_BITBANG_SCL_LOW : CYG_I2C_BITBANG_SCL_LOW_SDA_INPUT);
|
295 |
|
|
HAL_DELAY_US(delay);
|
296 |
|
|
}
|
297 |
|
|
// The last bit has been sent, SCL is low, and SDA has been turned
|
298 |
|
|
// into an input. The device should be placing the acknowledge bit
|
299 |
|
|
// onto SDA. Reading the acknowledge bit still needs a clock cycle.
|
300 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_HIGH);
|
301 |
|
|
HAL_DELAY_US(delay);
|
302 |
|
|
result = (*banger)(mash, CYG_I2C_BITBANG_SDA_READ);
|
303 |
|
|
DEBUG("i2c bitbang send_byte, got ack %d\n", result);
|
304 |
|
|
|
305 |
|
|
// Drop SCL again, and leave SDA as either an input or an output
|
306 |
|
|
// depending on the calling code's requirements and whether or not
|
307 |
|
|
// the device ack'd.
|
308 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_LOW);
|
309 |
|
|
HAL_DELAY_US(delay);
|
310 |
|
|
if ((1 == result) || !leave_as_input) {
|
311 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SDA_OUTPUT);
|
312 |
|
|
}
|
313 |
|
|
|
314 |
|
|
return result;
|
315 |
|
|
}
|
316 |
|
|
|
317 |
|
|
// Read a single byte from the bus and generate an ack/nak.
|
318 |
|
|
// Preconditions:
|
319 |
|
|
// SCL output low. The previous operation has completed.
|
320 |
|
|
// The device should have placed the data on the bus.
|
321 |
|
|
// SDA input
|
322 |
|
|
// Postconditions:
|
323 |
|
|
// SCL output low. The acknowledgement has been sent.
|
324 |
|
|
// SDA may be left as an input or an output, depending on
|
325 |
|
|
// whether or not this is the last byte in a transfer.
|
326 |
|
|
// For the last byte we want to send a nak.
|
327 |
|
|
//
|
328 |
|
|
// The result is the byte read.
|
329 |
|
|
|
330 |
|
|
static cyg_uint8
|
331 |
|
|
cyg_i2c_bitbang_read_byte(cyg_i2c_bus* mash, const cyg_i2c_device* dev, cyg_uint32 delay, cyg_bool nak)
|
332 |
|
|
{
|
333 |
|
|
cyg_i2c_bitbang_fn banger = (cyg_i2c_bitbang_fn)(mash->i2c_extra);
|
334 |
|
|
cyg_uint32 i;
|
335 |
|
|
cyg_uint8 result = 0;
|
336 |
|
|
|
337 |
|
|
DEBUG("i2c bitbang read_byte, nak %d\n", nak);
|
338 |
|
|
|
339 |
|
|
for (i = 0; i < 8; i++) {
|
340 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_HIGH);
|
341 |
|
|
HAL_DELAY_US(delay);
|
342 |
|
|
result = result << 1;
|
343 |
|
|
if (0 != (*banger)(mash, CYG_I2C_BITBANG_SDA_READ)) {
|
344 |
|
|
result |= 0x01;
|
345 |
|
|
}
|
346 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_LOW);
|
347 |
|
|
HAL_DELAY_US(delay);
|
348 |
|
|
}
|
349 |
|
|
// We have read the last bit. SDA is still an input, SCL is low.
|
350 |
|
|
// We need to switch SDA to an output and send the ack/nak
|
351 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SDA_OUTPUT);
|
352 |
|
|
(*banger)(mash, nak ? CYG_I2C_BITBANG_SDA_HIGH : CYG_I2C_BITBANG_SDA_LOW);
|
353 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_HIGH);
|
354 |
|
|
HAL_DELAY_US(delay);
|
355 |
|
|
(*banger)(mash, nak ? CYG_I2C_BITBANG_SCL_LOW : CYG_I2C_BITBANG_SCL_LOW_SDA_INPUT);
|
356 |
|
|
HAL_DELAY_US(delay);
|
357 |
|
|
|
358 |
|
|
DEBUG("i2c bitbang read_byte, result %02x\n", result);
|
359 |
|
|
return result;
|
360 |
|
|
}
|
361 |
|
|
|
362 |
|
|
// Generate a start condition.
|
363 |
|
|
//
|
364 |
|
|
// Preconditions:
|
365 |
|
|
// SCL output, indeterminate
|
366 |
|
|
// SDA output, indeterminate
|
367 |
|
|
// Postconditions:
|
368 |
|
|
// SCL output low
|
369 |
|
|
// SDA output low
|
370 |
|
|
//
|
371 |
|
|
// At the start of a transaction we know that both SCL and SDA will be
|
372 |
|
|
// high, but for a repeated start
|
373 |
|
|
static void
|
374 |
|
|
cyg_i2c_bitbang_send_start(cyg_i2c_bus* mash, cyg_uint32 delay)
|
375 |
|
|
{
|
376 |
|
|
cyg_i2c_bitbang_fn banger = (cyg_i2c_bitbang_fn)(mash->i2c_extra);
|
377 |
|
|
|
378 |
|
|
DEBUG("i2c bitbang, generating start\n");
|
379 |
|
|
// First get both SCL and SDA back into a known state
|
380 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SDA_HIGH);
|
381 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_HIGH);
|
382 |
|
|
HAL_DELAY_US(delay);
|
383 |
|
|
// A start condition involves dropping SDA while SCL stays high.
|
384 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SDA_LOW);
|
385 |
|
|
// Make sure that all devices have seen the start condition and
|
386 |
|
|
// reacted
|
387 |
|
|
HAL_DELAY_US(delay);
|
388 |
|
|
// Drop the clock, so that we can send the address/direction byte
|
389 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_LOW);
|
390 |
|
|
HAL_DELAY_US(delay);
|
391 |
|
|
}
|
392 |
|
|
|
393 |
|
|
// Generate a stop condition
|
394 |
|
|
// Preconditions:
|
395 |
|
|
// SCL output, low
|
396 |
|
|
// SDA output, indeterminate
|
397 |
|
|
// Postconditions:
|
398 |
|
|
// SCL output, high
|
399 |
|
|
// SDA output, high
|
400 |
|
|
static void
|
401 |
|
|
cyg_i2c_bitbang_send_stop(cyg_i2c_bus* mash, cyg_uint32 delay)
|
402 |
|
|
{
|
403 |
|
|
cyg_i2c_bitbang_fn banger = (cyg_i2c_bitbang_fn)(mash->i2c_extra);
|
404 |
|
|
|
405 |
|
|
DEBUG("i2c bitbang, generating stop\n");
|
406 |
|
|
// We need SDA low, then we can generate the stop signal
|
407 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SDA_LOW);
|
408 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SCL_HIGH);
|
409 |
|
|
HAL_DELAY_US(delay);
|
410 |
|
|
(*banger)(mash, CYG_I2C_BITBANG_SDA_HIGH);
|
411 |
|
|
// Ensure that the minimum delay between stop and start is observed
|
412 |
|
|
HAL_DELAY_US(delay);
|
413 |
|
|
}
|
414 |
|
|
|
415 |
|
|
// A full transfer to a given device, within in a transaction.
|
416 |
|
|
extern "C" cyg_uint32
|
417 |
|
|
cyg_i2c_bitbang_tx(const cyg_i2c_device* dev, cyg_bool send_start, const cyg_uint8* buf, cyg_uint32 count, cyg_bool send_stop)
|
418 |
|
|
{
|
419 |
|
|
cyg_uint32 result = 0;
|
420 |
|
|
// The bit-bang code works in terms of us delays rather than ns
|
421 |
|
|
cyg_uint32 delay = (0 == dev->i2c_delay) ? 1 : (dev->i2c_delay + 1999) / 2000;
|
422 |
|
|
|
423 |
|
|
CYG_CHECK_DATA_PTR(buf, "i2c tx operation requested but no data supplied");
|
424 |
|
|
CYG_PRECONDITION(count > 0, "at least one byte should be sent");
|
425 |
|
|
|
426 |
|
|
DEBUG("i2c bitbang tx, dev %08x, addr %02x, delay %d, send_start %d, buf %08x, count %d, send_stop %d\n",
|
427 |
|
|
dev, dev->i2c_address, delay, send_start, buf, count, send_stop);
|
428 |
|
|
|
429 |
|
|
if (send_start) {
|
430 |
|
|
cyg_i2c_bitbang_send_start(dev->i2c_bus, delay);
|
431 |
|
|
|
432 |
|
|
// Now send a single byte, holding the address shifted left and a
|
433 |
|
|
// 0 to indicate a write. A nak indicates that the device has not
|
434 |
|
|
// responded. SDA should stay as an output.
|
435 |
|
|
if (0 != cyg_i2c_bitbang_send_byte(dev->i2c_bus, dev, delay, (dev->i2c_address << 1) | 0x00, false) ) {
|
436 |
|
|
// Get the bus back in a consistent state
|
437 |
|
|
DEBUG("i2 bitbang tx, no device has responded to address %02x\n", dev->i2c_address);
|
438 |
|
|
cyg_i2c_bitbang_send_stop(dev->i2c_bus, delay);
|
439 |
|
|
return 0;
|
440 |
|
|
}
|
441 |
|
|
// The device has ack'd so we can continue sending
|
442 |
|
|
}
|
443 |
|
|
// Send all bytes, unless we receive a nak. SDA should remain an output
|
444 |
|
|
do {
|
445 |
|
|
result += 1;
|
446 |
|
|
if (0 != cyg_i2c_bitbang_send_byte(dev->i2c_bus, dev, delay, buf[result - 1], false)) {
|
447 |
|
|
break;
|
448 |
|
|
}
|
449 |
|
|
} while (result < count);
|
450 |
|
|
|
451 |
|
|
// At this point we have SCL low and SDA an indeterminate output
|
452 |
|
|
if (send_stop) {
|
453 |
|
|
cyg_i2c_bitbang_send_stop(dev->i2c_bus, delay);
|
454 |
|
|
}
|
455 |
|
|
DEBUG("i2c bitbang tx, %d bytes sent out of %d\n", result, count);
|
456 |
|
|
|
457 |
|
|
return result;
|
458 |
|
|
}
|
459 |
|
|
|
460 |
|
|
// A full transfer from a given device. The bus has already been locked
|
461 |
|
|
// by higher-level code. On entry both SDA and SCL should be outputs
|
462 |
|
|
// and both should be high. The same conditions should hold on exit.
|
463 |
|
|
extern "C" cyg_uint32
|
464 |
|
|
cyg_i2c_bitbang_rx(const cyg_i2c_device* dev, cyg_bool send_start, cyg_uint8* buf, cyg_uint32 count, cyg_bool send_nak, cyg_bool send_stop)
|
465 |
|
|
{
|
466 |
|
|
cyg_uint32 result = 0;
|
467 |
|
|
// The bit-bang code works in terms of us delays rather than ns
|
468 |
|
|
cyg_uint32 delay = (0 == dev->i2c_delay) ? 1 : (dev->i2c_delay + 1999) / 2000;
|
469 |
|
|
|
470 |
|
|
DEBUG("i2c bitbang rx, dev %08x, addr %02x, delay %d, send_start %d, buf %08x, count %d, send_nak %d, send_stop %d\n",
|
471 |
|
|
dev, dev->i2c_address, delay, send_start, buf, count, send_nak, send_stop);
|
472 |
|
|
|
473 |
|
|
CYG_CHECK_DATA_PTR(buf, "i2c rx operation requested but no data supplied");
|
474 |
|
|
CYG_PRECONDITION(count > 0, "at least one byte should be sent");
|
475 |
|
|
CYG_PRECONDITION(send_nak || !send_stop, "a stop can only be generated after the receive has been nak'd");
|
476 |
|
|
|
477 |
|
|
if (send_start) {
|
478 |
|
|
cyg_i2c_bitbang_send_start(dev->i2c_bus, delay);
|
479 |
|
|
|
480 |
|
|
// Now send a single byte, holding the address shifted left and a
|
481 |
|
|
// 1 to indicate a read. A nak indicates that the device has not
|
482 |
|
|
// responded. SDA should become an output.
|
483 |
|
|
if (0 != cyg_i2c_bitbang_send_byte(dev->i2c_bus, dev, delay, (dev->i2c_address << 1) | 0x01, true) ) {
|
484 |
|
|
// Get the bus back in a consistent state
|
485 |
|
|
DEBUG("i2c bitbang rx, no device has responded to address %02x\n", dev->i2c_address);
|
486 |
|
|
cyg_i2c_bitbang_send_stop(dev->i2c_bus, delay);
|
487 |
|
|
return 0;
|
488 |
|
|
}
|
489 |
|
|
// The device has ack'd so we can continue sending
|
490 |
|
|
}
|
491 |
|
|
|
492 |
|
|
// The device has ack'd. Read the number of bytes specified. The
|
493 |
|
|
// device cannot stop sending, although it may clock-stretch. For
|
494 |
|
|
// the last byte we usually we want to NAK and SDA should become
|
495 |
|
|
// an input, but if the data stream is variable length with e.g.
|
496 |
|
|
// the first byte indicating the length then we want to support
|
497 |
|
|
// partial reads.
|
498 |
|
|
for (result = 0; result < count; result++) {
|
499 |
|
|
buf[result] = cyg_i2c_bitbang_read_byte(dev->i2c_bus, dev, delay, (send_nak && (result == (count - 1))) ? true : false);
|
500 |
|
|
}
|
501 |
|
|
|
502 |
|
|
// At this point we have SCL low and SDA an indeterminate output
|
503 |
|
|
if (send_stop) {
|
504 |
|
|
cyg_i2c_bitbang_send_stop(dev->i2c_bus, delay);
|
505 |
|
|
}
|
506 |
|
|
|
507 |
|
|
DEBUG("i2c bitbang rx, read %d bytes\n", result);
|
508 |
|
|
return result;
|
509 |
|
|
}
|
510 |
|
|
|
511 |
|
|
extern "C" void
|
512 |
|
|
cyg_i2c_bitbang_stop(const cyg_i2c_device* dev)
|
513 |
|
|
{
|
514 |
|
|
// The bit-bang code works in terms of us delays rather than ns
|
515 |
|
|
cyg_uint32 delay = (0 == dev->i2c_delay) ? 1 : (dev->i2c_delay + 1999) / 2000;
|
516 |
|
|
cyg_i2c_bitbang_send_stop(dev->i2c_bus, delay);
|
517 |
|
|
}
|