i2c.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #include <avr/io.h>
  2. #include <util/delay_basic.h>
  3. #include <stdbool.h>
  4. #include "i2c.h"
  5. #define SCL_BIT PD3
  6. #define SDA_BIT PD2
  7. #define SCL_M (1 << SCL_BIT)
  8. #define SDA_M (1 << SDA_BIT)
  9. /* Open drain: PORT bits stay 0, DDR=1 drives low, DDR=0 releases (pull-up). */
  10. #define SDA_LOW() (DDRD |= SDA_M)
  11. #define SDA_HIGH() (DDRD &= ~SDA_M)
  12. #define SCL_LOW() (DDRD |= SCL_M)
  13. #define SCL_HIGH() (DDRD &= ~SCL_M)
  14. static uint8_t dly = 4; /* default ~400 kHz at 16 MHz - verify with a scope */
  15. static bool bus_err;
  16. static inline void d(void) { if (dly) _delay_loop_1(dly); }
  17. void i2c_set_delay(uint8_t v) { dly = v; }
  18. void i2c_init(void)
  19. {
  20. PORTD &= ~(SCL_M | SDA_M);
  21. DDRD &= ~(SCL_M | SDA_M);
  22. }
  23. static void scl_release(void) /* release SCL and honour clock stretching */
  24. {
  25. SCL_HIGH();
  26. if (!(PIND & SCL_M)) {
  27. uint16_t t = 0; /* ~16 ms max */
  28. while (!(PIND & SCL_M)) if (--t == 0) { bus_err = true; break; }
  29. }
  30. }
  31. static void start(void)
  32. {
  33. SDA_HIGH(); d();
  34. scl_release(); d();
  35. SDA_LOW(); d();
  36. SCL_LOW();
  37. }
  38. static void stop(void)
  39. {
  40. SDA_LOW(); d();
  41. scl_release(); d();
  42. SDA_HIGH(); d();
  43. }
  44. static bool wr(uint8_t b) /* returns true on ACK */
  45. {
  46. for (uint8_t i = 0; i < 8; i++) {
  47. if (b & 0x80) SDA_HIGH(); else SDA_LOW();
  48. b <<= 1;
  49. d(); scl_release(); d(); SCL_LOW();
  50. }
  51. SDA_HIGH();
  52. d(); scl_release(); d();
  53. bool ack = !(PIND & SDA_M);
  54. SCL_LOW();
  55. return ack;
  56. }
  57. static uint8_t rd(bool ack)
  58. {
  59. uint8_t v = 0;
  60. SDA_HIGH();
  61. for (uint8_t i = 0; i < 8; i++) {
  62. d(); scl_release(); d();
  63. v = (v << 1) | ((PIND & SDA_M) ? 1 : 0);
  64. SCL_LOW();
  65. }
  66. if (ack) SDA_LOW(); else SDA_HIGH();
  67. d(); scl_release(); d(); SCL_LOW();
  68. SDA_HIGH();
  69. return v;
  70. }
  71. /* Diagnostic: optionally enable weak internal pull-ups, return bit0=SCL, bit1=SDA levels */
  72. uint8_t i2c_lines(uint8_t pullup)
  73. {
  74. if (pullup) PORTD |= (SCL_M | SDA_M); else PORTD &= ~(SCL_M | SDA_M);
  75. DDRD &= ~(SCL_M | SDA_M);
  76. d(); d();
  77. uint8_t p = PIND;
  78. return ((p & SCL_M) ? 1 : 0) | ((p & SDA_M) ? 2 : 0);
  79. }
  80. uint8_t i2c_recover(void)
  81. {
  82. bus_err = false;
  83. for (uint8_t i = 0; i < 9 && !(PIND & SDA_M); i++) {
  84. SCL_LOW(); d(); d();
  85. scl_release(); d(); d();
  86. }
  87. stop();
  88. return (bus_err || !(PIND & SDA_M) || !(PIND & SCL_M)) ? I2C_BUS_ERR : I2C_OK;
  89. }
  90. /* ---- split-phase API (one transaction spread over several USB requests) ---- */
  91. uint8_t i2c_start(uint8_t addr_rw, bool repeated)
  92. {
  93. if (!repeated) {
  94. bus_err = false;
  95. if (!(PIND & SDA_M) || !(PIND & SCL_M)) {
  96. if (i2c_recover() != I2C_OK) return I2C_BUS_ERR;
  97. }
  98. }
  99. start();
  100. bool ack = wr(addr_rw);
  101. if (bus_err) return I2C_BUS_ERR;
  102. return ack ? I2C_OK : I2C_NACK_ADDR;
  103. }
  104. uint8_t i2c_write(uint8_t b)
  105. {
  106. bool ack = wr(b);
  107. if (bus_err) return I2C_BUS_ERR;
  108. return ack ? I2C_OK : I2C_NACK_DATA;
  109. }
  110. uint8_t i2c_read(bool ack) { return rd(ack); }
  111. bool i2c_bus_error(void) { return bus_err; }
  112. void i2c_stop(void) { stop(); }
  113. uint8_t i2c_xfer(uint8_t addr, const uint8_t *w, uint8_t wlen, uint8_t *r, uint8_t rlen)
  114. {
  115. uint8_t st = I2C_OK;
  116. bus_err = false;
  117. if (!(PIND & SDA_M) || !(PIND & SCL_M)) {
  118. if (i2c_recover() != I2C_OK) return I2C_BUS_ERR;
  119. }
  120. if (wlen || !rlen) {
  121. start();
  122. if (!wr(addr << 1)) { st = I2C_NACK_ADDR; goto done; }
  123. for (uint8_t i = 0; i < wlen; i++)
  124. if (!wr(w[i])) { st = I2C_NACK_DATA; goto done; }
  125. }
  126. if (rlen) {
  127. start(); /* (repeated) START */
  128. if (!wr((addr << 1) | 1)) { st = I2C_NACK_ADDR; goto done; }
  129. for (uint8_t i = 0; i < rlen; i++)
  130. r[i] = rd(i < rlen - 1);
  131. }
  132. done:
  133. stop();
  134. return bus_err ? I2C_BUS_ERR : st;
  135. }