1 #include "config.h"
2 #include "i2c.h"
3
4 #include <util/delay.h>
5
6 #include "io.h"
7 #include "debug.h"
8
9 /*
10 - Reset bus on failure (lack of ACK, etc)
11 - Clock stretching
12 - In pull-up mode, much code was commented out to ever avoid driving the bus (for a fleeting moment) as this was visible on the scope as short peaks (instead the line will briefly go Hi Z).
13 */
14
15 volatile bool _i2c_disable_ack_check = false;
16
17 // FIXME: Follow magic numbers should be in a struct that is passed into each function
18
19 #define I2C_DEFAULT_RETRY_DELAY 1 // us MAGIC
20 #define I2C_DEFAULT_MAX_ACK_RETRIES 10 // * I2C_DEFAULT_RETRY_DELAY us
21
22 #define I2C_DEFAULT_BUS_WAIT 10 // us MAGIC
23 #define I2C_DEFAULT_MAX_BUS_RETRIES 10
24
25 #define I2C_DEFAULT_SCL_LOW_PERIOD 2 // 1.3 us
26 #define I2C_DEFAULT_SCL_HIGH_PERIOD 1 // 0.6 us
27 #define I2C_DEFAULT_BUS_FREE_TIME 2 // 1.3 us
28 #define I2C_DEFAULT_STOP_TIME 1 // 0.6 us
29
30 #define I2C_DELAY _delay_us // _delay_ms
31
_i2c_start_ex(io_pin_t sda,io_pin_t scl,bool pull_up)32 static bool _i2c_start_ex(io_pin_t sda, io_pin_t scl, bool pull_up)
33 {
34 // Assumes: SDA/SCL are both inputs
35
36 uint8_t retries = I2C_DEFAULT_MAX_BUS_RETRIES;
37 while ((io_test_pin(sda) == false) || (io_test_pin(scl) == false))
38 {
39 I2C_DELAY(I2C_DEFAULT_BUS_WAIT);
40 if (retries-- == 0)
41 {
42 debug_log("I2C:S1");
43 return false;
44 }
45 }
46
47 // START condition
48 // if (pull_up == false)
49 io_clear_pin(sda); // Set LOW before switching to output
50 io_output_pin(sda);
51 // if (pull_up)
52 // io_clear_pin(sda);
53 I2C_DELAY(I2C_DEFAULT_SCL_LOW_PERIOD); // Thd, sta
54
55 retries = I2C_DEFAULT_MAX_BUS_RETRIES;
56 while (io_test_pin(scl) == false) // SCL should remain high
57 {
58 I2C_DELAY(I2C_DEFAULT_BUS_WAIT);
59 if (retries-- == 0)
60 {
61 io_input_pin(sda);
62 debug_log_ex("I2C:S2", false);
63 debug_log_hex(scl);
64 return false;
65 }
66 }
67
68 // if (pull_up == false)
69 io_clear_pin(scl);
70 io_output_pin(scl);
71 // if (pull_up)
72 // io_clear_pin(scl);
73 I2C_DELAY(I2C_DEFAULT_SCL_LOW_PERIOD / 2); // MAGIC
74
75 return true;
76 }
77
_i2c_stop_ex(io_pin_t sda,io_pin_t scl,bool pull_up)78 static bool _i2c_stop_ex(io_pin_t sda, io_pin_t scl, bool pull_up)
79 {
80 // Assumes:
81 // SCL is output & LOW
82 // SDA is input (Hi-Z, or pull-up enabled)
83
84 // Assuming pull-up already enabled
85 //if (pull_up)
86 // io_set_pin(sda);
87
88 bool result = true;
89
90 // SDA should be HIGH after ACK has been clocked away
91 // bool skip_drive = false;
92 uint8_t retries = 0;
93 while (io_test_pin(sda) == false)
94 {
95 if (retries == I2C_DEFAULT_MAX_ACK_RETRIES)
96 {
97 debug_log_ex("I2C:STP ", false);
98 debug_log_hex(sda);
99 debug_blink_rev(4);
100
101 // skip_drive = true;
102 result = false;
103 break; // SDA is being held low?!
104 }
105
106 ++retries;
107 I2C_DELAY(I2C_DEFAULT_RETRY_DELAY);
108 }
109
110 // STOP condition
111 // if ((pull_up == false) || (skip_drive))
112 io_clear_pin(sda); // Don't tri-state if internal pull-up is used
113 // //else
114 // // Pin will now be driven, but having checked SDA is HIGH above means slave's SDA should be Open Collector (i.e. it won't blow up)
115 io_output_pin(sda); // Drive LOW
116 // if (pull_up)
117 // io_clear_pin(sda);
118
119 ///////////////////////////////////
120
121 // if (pull_up)
122 // io_set_pin(scl); // Don't tri-state if internal pull-up is used. Line will be driven, but assuming this is the only master on the clock line (i.e. no one else will pull it low).
123 io_input_pin(scl);
124 if (pull_up)
125 io_set_pin(scl);
126 I2C_DELAY(I2C_DEFAULT_STOP_TIME);
127
128 ///////////////////////////////////
129
130 // if ((pull_up) && (skip_drive == false))
131 // io_set_pin(sda); // Don't tri-state if internal pull-up is used
132 io_input_pin(sda);
133 // if ((pull_up) && (skip_drive))
134 io_set_pin(sda);
135 I2C_DELAY(I2C_DEFAULT_BUS_FREE_TIME);
136
137 return result;
138 }
139 /*
140 static void _i2c_stop(io_pin_t sda, io_pin_t scl)
141 {
142 _i2c_stop_ex(sda, scl, false);
143 }
144 *//*
145 static void _i2c_abort_safe_ex(io_pin_t pin, bool pull_up)
146 {
147 if (io_is_output(pin))
148 {
149 if (io_is_pin_set(pin)) // This is bad - hope no slave is pulling down the line
150 {
151 io_input_pin(pin); // Pull-up already enabled
152
153 if (pull_up == false)
154 io_clear_pin(pin); // Doing this after changing direction ensures the line is not brought down
155 }
156 else // Currently pulling line down
157 {
158 io_input_pin(pin); // Hi-Z
159
160 if (pull_up) // There will be a moment where the line will float (better than driving the line though...)
161 {
162 io_set_pin(pin);
163 }
164 }
165 }
166 else // Already an input
167 {
168 if (pull_up)
169 {
170 io_set_pin(pin); // Enable pull-ups
171 }
172 else
173 {
174 io_clear_pin(pin); // Disable pull-ups
175 }
176 }
177
178 // Normally: pin will be Hi-Z input
179 // With internal pull-up: pin will be input with pull-up enabled
180 }
181 */
_i2c_abort_safe(io_pin_t pin,bool pull_up)182 static void _i2c_abort_safe(io_pin_t pin, bool pull_up)
183 {
184 if (pull_up == false)
185 io_clear_pin(pin); // Should never be output/HIGH, could be input/<was outputting HIGH> so disable pull-ups
186
187 io_input_pin(pin);
188
189 if (pull_up)
190 io_set_pin(pin); // Enable pull-up
191 }
192
_i2c_abort_ex(io_pin_t sda,io_pin_t scl,bool pull_up)193 static void _i2c_abort_ex(io_pin_t sda, io_pin_t scl, bool pull_up)
194 {
195 /* if (pull_up == false)
196 {
197 io_clear_pin(sda);
198 io_clear_pin(scl);
199 }
200
201 io_input_pin(scl);
202 io_input_pin(sda);
203
204 if (pull_up)
205 {
206 io_set_pin(sda);
207 io_set_pin(scl);
208 }
209 */
210 _i2c_abort_safe(scl, pull_up);
211 _i2c_abort_safe(sda, pull_up);
212
213 //_i2c_abort_safe_ex(scl, pull_up);
214 //_i2c_abort_safe_ex(sda, pull_up);
215 }
216 /*
217 static void _i2c_abort(io_pin_t sda, io_pin_t scl)
218 {
219 _i2c_abort_ex(sda, scl, false);
220 }
221 */
_i2c_write_byte_ex(io_pin_t sda,io_pin_t scl,uint8_t value,bool pull_up)222 static bool _i2c_write_byte_ex(io_pin_t sda, io_pin_t scl, uint8_t value, bool pull_up)
223 {
224 // Assumes:
225 // SDA output is LOW
226 // SCL output is LOW
227
228 for (uint8_t i = 0; i < 8; ++i)
229 {
230 bool b = ((value & (0x01 << (7 - i))) != 0x00); // MSB first
231
232 if (b)
233 {
234 if (pull_up)
235 {
236 // io_set_pin(sda); // This is bad (will drive line for a moment), but more stable than letting line float
237 io_input_pin(sda);
238 io_set_pin(sda);
239 }
240 else
241 io_input_pin(sda); // Release HIGH
242
243 if (io_test_pin(sda) == false)
244 {
245 debug_log("I2C:WR ");
246 debug_log_hex(sda);
247 debug_blink_rev(1);
248 return false;
249 }
250 }
251 else
252 {
253 if (pull_up)
254 {
255 // if (io_is_output(sda))
256 io_clear_pin(sda);
257 // else
258 // {
259 io_output_pin(sda); // [This is bad (will drive line for a moment), but more stable than letting line float]
260 // io_clear_pin(sda);
261 // }
262 }
263 else
264 {
265 io_enable_pin(sda, false);
266 io_output_pin(sda); // Drive LOW
267 }
268 }
269
270 ///////////////////////////////
271
272 io_input_pin(scl); // Release HIGH
273 if (pull_up)
274 io_set_pin(scl);
275 I2C_DELAY(I2C_DEFAULT_SCL_HIGH_PERIOD);
276 #ifdef I2C_ALLOW_CLOCK_STRETCH
277 uint8_t retries = I2C_DEFAULT_MAX_BUS_RETRIES;
278 while (io_test_pin(scl) == false) // Clock stretch requested?
279 {
280 I2C_DELAY(I2C_DEFAULT_BUS_WAIT);
281 if (--retries == 0)
282 {
283 io_input_pin(sda); // Release HIGH
284 if (pull_up)
285 io_set_pin(sda);
286
287 debug_log_ex("I2C:STRTCH ", false);
288 debug_log_hex(scl);
289 debug_blink_rev(2);
290 return false;
291 }
292 }
293 #endif // I2C_ALLOW_CLOCK_STRETCH
294 if (pull_up)
295 io_clear_pin(scl);
296 io_output_pin(scl); // Drive LOW
297 I2C_DELAY(I2C_DEFAULT_SCL_LOW_PERIOD);
298 }
299
300 io_input_pin(sda); // Release HIGH
301 if (pull_up)
302 io_set_pin(sda); // Assuming letting line float won't confuse slave when pulling line LOW for ACK
303 I2C_DELAY(I2C_DEFAULT_SCL_HIGH_PERIOD);
304
305 uint8_t retries = 0;
306 while ((_i2c_disable_ack_check == false) && (io_test_pin(sda)))
307 {
308 if (retries == I2C_DEFAULT_MAX_ACK_RETRIES)
309 {
310 debug_log_ex("I2C:ACK ", false);
311 debug_log_hex_ex(sda, false);
312 debug_log_hex(value);
313 debug_blink_rev(3);
314 return false; // Will abort and not release bus - done by caller
315 }
316
317 ++retries;
318 I2C_DELAY(I2C_DEFAULT_RETRY_DELAY);
319 }
320
321 // Clock away acknowledge
322 // if (pull_up)
323 // io_set_pin(scl);
324 io_input_pin(scl); // Release HIGH
325 if (pull_up)
326 io_set_pin(scl);
327 I2C_DELAY(I2C_DEFAULT_SCL_HIGH_PERIOD);
328
329 if (pull_up)
330 io_clear_pin(scl);
331 io_output_pin(scl); // Drive LOW
332 // if (pull_up)
333 // io_clear_pin(scl);
334 I2C_DELAY(I2C_DEFAULT_SCL_LOW_PERIOD);
335
336 return true;
337 }
338
_i2c_read_byte_ex(io_pin_t sda,io_pin_t scl,uint8_t * value,bool pull_up)339 static bool _i2c_read_byte_ex(io_pin_t sda, io_pin_t scl, uint8_t* value, bool pull_up)
340 {
341 // Assumes:
342 // SDA output is LOW
343 // SCL output is LOW
344
345 io_input_pin(sda);
346 if (pull_up)
347 io_set_pin(sda); // OK to leave line floating for a moment (better not to drive as slave will be pulling it to ground)
348
349 (*value) = 0x00;
350
351 for (uint8_t i = 0; i < 8; ++i)
352 {
353 // if (pull_up)
354 // io_set_pin(scl); // [Not ideal with pull-up]
355 io_input_pin(scl); // Release HIGH
356 if (pull_up)
357 io_set_pin(scl);
358 I2C_DELAY(I2C_DEFAULT_SCL_HIGH_PERIOD);
359 #ifdef I2C_ALLOW_CLOCK_STRETCH
360 uint8_t retries = I2C_DEFAULT_MAX_BUS_RETRIES;
361 while (io_test_pin(scl) == false) // Clock stretch requested?
362 {
363 I2C_DELAY(I2C_DEFAULT_BUS_WAIT);
364 if (--retries == 0)
365 {
366 debug_log_ex("I2C:R ");
367 debug_log_hex(scl);
368 debug_blink_rev(5);
369 return false;
370 }
371 }
372 #endif // I2C_ALLOW_CLOCK_STRETCH
373 (*value) |= ((io_test_pin(sda) ? 0x1 : 0x0) << (7 - i)); // MSB first
374
375 if (pull_up)
376 io_clear_pin(scl);
377 io_output_pin(scl); // Drive LOW (not ideal with pull-up)
378 // if (pull_up)
379 // io_clear_pin(scl);
380 I2C_DELAY(I2C_DEFAULT_SCL_LOW_PERIOD);
381 }
382
383 // Not necessary to ACK since it's only this one byte
384
385 return true;
386 }
387
i2c_read2_ex(io_pin_t sda,io_pin_t scl,uint8_t addr,uint8_t subaddr,uint8_t * value,bool pull_up)388 bool i2c_read2_ex(io_pin_t sda, io_pin_t scl, uint8_t addr, uint8_t subaddr, uint8_t* value, bool pull_up)
389 {
390 if (_i2c_start_ex(sda, scl, pull_up) == false)
391 return false;
392
393 if (_i2c_write_byte_ex(sda, scl, addr & ~0x01, pull_up) == false)
394 {
395 #ifdef I2C_EXTRA_DEBUGGING
396 //debug_log_ex("R21:", false);
397 debug_log("R21");
398 //debug_log_hex(addr);
399 #endif // I2C_EXTRA_DEBUGGING
400 goto i2c_read2_fail;
401 }
402
403 if (_i2c_write_byte_ex(sda, scl, subaddr, pull_up) == false)
404 {
405 #ifdef I2C_EXTRA_DEBUGGING
406 //debug_log_ex("R22:", false);
407 debug_log("R22");
408 //debug_log_hex(subaddr);
409 #endif // I2C_EXTRA_DEBUGGING
410 goto i2c_read2_fail;
411 }
412
413 io_input_pin(scl);
414 if (pull_up)
415 io_set_pin(scl);
416 I2C_DELAY(I2C_DEFAULT_BUS_WAIT);
417
418 if (_i2c_start_ex(sda, scl, pull_up) == false)
419 {
420 return false;
421 }
422
423 if (_i2c_write_byte_ex(sda, scl, addr | 0x01, pull_up) == false)
424 {
425 #ifdef I2C_EXTRA_DEBUGGING
426 //debug_log_ex("R23:", false);
427 debug_log("R23");
428 //debug_log_hex(addr);
429 #endif // I2C_EXTRA_DEBUGGING
430 goto i2c_read2_fail;
431 }
432
433 if (_i2c_read_byte_ex(sda, scl, value, pull_up) == false)
434 {
435 #ifdef I2C_EXTRA_DEBUGGING
436 //debug_log_ex("R24:", false);
437 debug_log("R24");
438 //debug_log_hex(*value);
439 #endif // I2C_EXTRA_DEBUGGING
440 goto i2c_read2_fail;
441 }
442
443 if (_i2c_stop_ex(sda, scl, pull_up) == false)
444 {
445 #ifdef I2C_EXTRA_DEBUGGING
446 debug_log("R25");
447 #endif // I2C_EXTRA_DEBUGGING
448 }
449
450 return true;
451 i2c_read2_fail:
452 _i2c_abort_ex(sda, scl, pull_up);
453 return false;
454 }
455
i2c_write_ex(io_pin_t sda,io_pin_t scl,uint8_t addr,uint8_t subaddr,uint8_t value,bool pull_up)456 bool i2c_write_ex(io_pin_t sda, io_pin_t scl, uint8_t addr, uint8_t subaddr, uint8_t value, bool pull_up)
457 {
458 if (_i2c_start_ex(sda, scl, pull_up) == false)
459 return false;
460
461 if (_i2c_write_byte_ex(sda, scl, addr, pull_up) == false)
462 goto i2c_write_fail;
463
464 if (_i2c_write_byte_ex(sda, scl, subaddr, pull_up) == false)
465 goto i2c_write_fail;
466
467 if (_i2c_write_byte_ex(sda, scl, value, pull_up) == false)
468 goto i2c_write_fail;
469
470 _i2c_stop_ex(sda, scl, pull_up);
471
472 return true;
473 i2c_write_fail:
474 _i2c_abort_ex(sda, scl, pull_up);
475 return false;
476 }
477
i2c_write(io_pin_t sda,io_pin_t scl,uint8_t addr,uint8_t subaddr,uint8_t value)478 bool i2c_write(io_pin_t sda, io_pin_t scl, uint8_t addr, uint8_t subaddr, uint8_t value)
479 {
480 return i2c_write_ex(sda, scl, addr, subaddr, value, false);
481 }
482
i2c_read_ex(io_pin_t sda,io_pin_t scl,uint8_t addr,uint8_t subaddr,uint8_t * value,bool pull_up)483 bool i2c_read_ex(io_pin_t sda, io_pin_t scl, uint8_t addr, uint8_t subaddr, uint8_t* value, bool pull_up)
484 {
485 if (_i2c_start_ex(sda, scl, pull_up) == false)
486 return false;
487
488 if (_i2c_write_byte_ex(sda, scl, addr, pull_up) == false)
489 goto i2c_read_fail;
490
491 if (_i2c_write_byte_ex(sda, scl, subaddr, pull_up) == false)
492 goto i2c_read_fail;
493
494 if (_i2c_read_byte_ex(sda, scl, value, pull_up) == false)
495 goto i2c_read_fail;
496
497 _i2c_stop_ex(sda, scl, pull_up);
498
499 return true;
500 i2c_read_fail:
501 _i2c_abort_ex(sda, scl, pull_up);
502 return false;
503 }
504
i2c_read(io_pin_t sda,io_pin_t scl,uint8_t addr,uint8_t subaddr,uint8_t * value)505 bool i2c_read(io_pin_t sda, io_pin_t scl, uint8_t addr, uint8_t subaddr, uint8_t* value)
506 {
507 return i2c_read_ex(sda, scl, addr, subaddr, value, false);
508 }
509
i2c_init_ex(io_pin_t sda,io_pin_t scl,bool pull_up)510 void i2c_init_ex(io_pin_t sda, io_pin_t scl, bool pull_up)
511 {
512 _i2c_abort_ex(sda, scl, pull_up);
513 }
514
i2c_init(io_pin_t sda,io_pin_t scl)515 void i2c_init(io_pin_t sda, io_pin_t scl)
516 {
517 i2c_init_ex(sda, scl, false);
518 }
519