i2c.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. uint8_t i2c_xfer(uint8_t addr, const uint8_t *w, uint8_t wlen, uint8_t *r, uint8_t rlen)
  91. {
  92. uint8_t st = I2C_OK;
  93. bus_err = false;
  94. if (!(PIND & SDA_M) || !(PIND & SCL_M)) {
  95. if (i2c_recover() != I2C_OK) return I2C_BUS_ERR;
  96. }
  97. if (wlen || !rlen) {
  98. start();
  99. if (!wr(addr << 1)) { st = I2C_NACK_ADDR; goto done; }
  100. for (uint8_t i = 0; i < wlen; i++)
  101. if (!wr(w[i])) { st = I2C_NACK_DATA; goto done; }
  102. }
  103. if (rlen) {
  104. start(); /* (repeated) START */
  105. if (!wr((addr << 1) | 1)) { st = I2C_NACK_ADDR; goto done; }
  106. for (uint8_t i = 0; i < rlen; i++)
  107. r[i] = rd(i < rlen - 1);
  108. }
  109. done:
  110. stop();
  111. return bus_err ? I2C_BUS_ERR : st;
  112. }