dev_soft_i2c.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-07-30 sp-cai first version
  9. */
  10. #include <rtdevice.h>
  11. #ifdef RT_USING_SOFT_I2C
  12. #if !defined(RT_USING_SOFT_I2C0) &&\
  13. !defined(RT_USING_SOFT_I2C1) && !defined(RT_USING_SOFT_I2C2) &&\
  14. !defined(RT_USING_SOFT_I2C3) && !defined(RT_USING_SOFT_I2C4) &&\
  15. !defined(RT_USING_SOFT_I2C5) && !defined(RT_USING_SOFT_I2C6) &&\
  16. !defined(RT_USING_SOFT_I2C7) && !defined(RT_USING_SOFT_I2C8)
  17. #error "Please define at least one RT_USING_SOFT_I2Cx"
  18. /*
  19. This driver can be disabled at:
  20. menuconfig -> RT-Thread Components -> Device Drivers -> Using I2C device drivers
  21. */
  22. #endif
  23. #define DBG_ENABLE
  24. #define DBG_TAG "I2C_S"
  25. #ifdef RT_I2C_BITOPS_DEBUG
  26. #define DBG_LEVEL DBG_LOG
  27. #endif
  28. #include <rtdbg.h>
  29. /* i2c config class */
  30. struct soft_i2c_config
  31. {
  32. rt_base_t scl_pin;
  33. rt_base_t sda_pin;
  34. const char *bus_name;
  35. rt_uint16_t timing_delay; /* scl and sda line delay */
  36. rt_uint16_t timing_timeout; /* in tick */
  37. };
  38. /* i2c dirver class */
  39. struct rt_soft_i2c
  40. {
  41. struct rt_i2c_bus_device i2c_bus;
  42. struct rt_i2c_bit_ops ops;
  43. };
  44. struct soft_i2c_config i2c_cfg[] =
  45. {
  46. #ifdef RT_USING_SOFT_I2C0
  47. {
  48. .scl_pin = RT_SOFT_I2C0_SCL_PIN,
  49. .sda_pin = RT_SOFT_I2C0_SDA_PIN,
  50. .bus_name = RT_SOFT_I2C0_BUS_NAME,
  51. .timing_delay = RT_SOFT_I2C0_TIMING_DELAY,
  52. .timing_timeout = RT_SOFT_I2C0_TIMING_TIMEOUT,
  53. },
  54. #endif //RT_USING_SOFT_I2C0
  55. #ifdef RT_USING_SOFT_I2C1
  56. {
  57. .scl_pin = RT_SOFT_I2C1_SCL_PIN,
  58. .sda_pin = RT_SOFT_I2C1_SDA_PIN,
  59. .bus_name = RT_SOFT_I2C1_BUS_NAME,
  60. .timing_delay = RT_SOFT_I2C1_TIMING_DELAY,
  61. .timing_timeout = RT_SOFT_I2C1_TIMING_TIMEOUT,
  62. },
  63. #endif //RT_USING_SOFT_I2C1
  64. #ifdef RT_USING_SOFT_I2C2
  65. {
  66. .scl_pin = RT_SOFT_I2C2_SCL_PIN,
  67. .sda_pin = RT_SOFT_I2C2_SDA_PIN,
  68. .bus_name = RT_SOFT_I2C2_BUS_NAME,
  69. .timing_delay = RT_SOFT_I2C2_TIMING_DELAY,
  70. .timing_timeout = RT_SOFT_I2C2_TIMING_TIMEOUT,
  71. },
  72. #endif //RT_USING_SOFT_I2C2
  73. #ifdef RT_USING_SOFT_I2C3
  74. {
  75. .scl_pin = RT_SOFT_I2C3_SCL_PIN,
  76. .sda_pin = RT_SOFT_I2C3_SDA_PIN,
  77. .bus_name = RT_SOFT_I2C3_BUS_NAME,
  78. .timing_delay = RT_SOFT_I2C3_TIMING_DELAY,
  79. .timing_timeout = RT_SOFT_I2C3_TIMING_TIMEOUT,
  80. },
  81. #endif //RT_USING_SOFT_I2C3
  82. #ifdef RT_USING_SOFT_I2C4
  83. {
  84. .scl_pin = RT_SOFT_I2C4_SCL_PIN,
  85. .sda_pin = RT_SOFT_I2C4_SDA_PIN,
  86. .bus_name = RT_SOFT_I2C4_BUS_NAME,
  87. .timing_delay = RT_SOFT_I2C4_TIMING_DELAY,
  88. .timing_timeout = RT_SOFT_I2C4_TIMING_TIMEOUT,
  89. },
  90. #endif //RT_USING_SOFT_I2C4
  91. #ifdef RT_USING_SOFT_I2C5
  92. {
  93. .scl_pin = RT_SOFT_I2C5_SCL_PIN,
  94. .sda_pin = RT_SOFT_I2C5_SDA_PIN,
  95. .bus_name = RT_SOFT_I2C5_BUS_NAME,
  96. .timing_delay = RT_SOFT_I2C5_TIMING_DELAY,
  97. .timing_timeout = RT_SOFT_I2C5_TIMING_TIMEOUT,
  98. },
  99. #endif //RT_USING_SOFT_I2C5
  100. #ifdef RT_USING_SOFT_I2C6
  101. {
  102. .scl_pin = RT_SOFT_I2C6_SCL_PIN,
  103. .sda_pin = RT_SOFT_I2C6_SDA_PIN,
  104. .bus_name = RT_SOFT_I2C6_BUS_NAME,
  105. .timing_delay = RT_SOFT_I2C6_TIMING_DELAY,
  106. .timing_timeout = RT_SOFT_I2C6_TIMING_TIMEOUT,
  107. },
  108. #endif //RT_USING_SOFT_I2C6
  109. #ifdef RT_USING_SOFT_I2C7
  110. {
  111. .scl_pin = RT_SOFT_I2C7_SCL_PIN,
  112. .sda_pin = RT_SOFT_I2C7_SDA_PIN,
  113. .bus_name = RT_SOFT_I2C7_BUS_NAME,
  114. .timing_delay = RT_SOFT_I2C7_TIMING_DELAY,
  115. .timing_timeout = RT_SOFT_I2C7_TIMING_TIMEOUT,
  116. },
  117. #endif //RT_USING_SOFT_I2C7
  118. #ifdef RT_USING_SOFT_I2C8
  119. {
  120. .scl_pin = RT_SOFT_I2C8_SCL_PIN,
  121. .sda_pin = RT_SOFT_I2C8_SDA_PIN,
  122. .bus_name = RT_SOFT_I2C8_BUS_NAME,
  123. .timing_delay = RT_SOFT_I2C8_TIMING_DELAY,
  124. .timing_timeout = RT_SOFT_I2C8_TIMING_TIMEOUT,
  125. },
  126. #endif //RT_USING_SOFT_I2C8
  127. };
  128. static struct rt_soft_i2c i2c_bus_obj[sizeof(i2c_cfg) / sizeof(i2c_cfg[0])] =
  129. { 0 };
  130. /**
  131. * This function initializes the i2c pin.
  132. * @param i2c config class.
  133. */
  134. static void pin_init(const struct soft_i2c_config *cfg)
  135. {
  136. rt_pin_mode(cfg->scl_pin, PIN_MODE_OUTPUT_OD);
  137. rt_pin_mode(cfg->sda_pin, PIN_MODE_OUTPUT_OD);
  138. rt_pin_write(cfg->scl_pin, PIN_HIGH);
  139. rt_pin_write(cfg->sda_pin, PIN_HIGH);
  140. }
  141. /**
  142. * This function sets the sda pin.
  143. * @param i2c config class.
  144. * @param The sda pin state.
  145. */
  146. static void set_sda(void *cfg, rt_int32_t value)
  147. {
  148. rt_pin_write(((const struct soft_i2c_config*)cfg)->sda_pin, value);
  149. }
  150. /**
  151. * This function sets the scl pin.
  152. * @param i2c config class.
  153. * @param The sda pin state.
  154. */
  155. static void set_scl(void *cfg, rt_int32_t value)
  156. {
  157. rt_pin_write(((const struct soft_i2c_config*)cfg)->scl_pin, value);
  158. }
  159. /**
  160. * This function gets the sda pin state.
  161. * @param i2c config class.
  162. */
  163. static rt_int32_t get_sda(void *cfg)
  164. {
  165. return rt_pin_read(((const struct soft_i2c_config*)cfg)->sda_pin);
  166. }
  167. /**
  168. * This function gets the scl pin state.
  169. * @param i2c config class.
  170. */
  171. static rt_int32_t get_scl(void *cfg)
  172. {
  173. return rt_pin_read(((const struct soft_i2c_config*)cfg)->scl_pin);
  174. }
  175. static const struct rt_i2c_bit_ops soft_i2c_ops =
  176. {
  177. .set_sda = set_sda,
  178. .set_scl = set_scl,
  179. .get_sda = get_sda,
  180. .get_scl = get_scl,
  181. .udelay = rt_hw_us_delay,
  182. };
  183. /**
  184. * if i2c is locked, this function will unlock it
  185. *
  186. * @param i2c config class.
  187. *
  188. * @return RT_EOK indicates successful unlock.
  189. */
  190. static rt_err_t i2c_bus_unlock(const struct soft_i2c_config *cfg)
  191. {
  192. rt_ubase_t i = 0;
  193. if(PIN_LOW == rt_pin_read(cfg->sda_pin))
  194. {
  195. while(i++ < 9)
  196. {
  197. rt_pin_write(cfg->scl_pin, PIN_HIGH);
  198. rt_hw_us_delay(cfg->timing_delay);
  199. rt_pin_write(cfg->scl_pin, PIN_LOW);
  200. rt_hw_us_delay(cfg->timing_delay);
  201. }
  202. }
  203. if(PIN_LOW == rt_pin_read(cfg->sda_pin))
  204. {
  205. return -RT_ERROR;
  206. }
  207. return RT_EOK;
  208. }
  209. /* I2C initialization function */
  210. int rt_soft_i2c_init(void)
  211. {
  212. int err = RT_EOK;
  213. struct rt_soft_i2c *obj;
  214. int i;
  215. for(i = 0; i < sizeof(i2c_bus_obj) / sizeof(i2c_bus_obj[0]); i++)
  216. {
  217. struct soft_i2c_config *cfg = &i2c_cfg[i];
  218. pin_init(cfg);
  219. obj = &i2c_bus_obj[i];
  220. obj->ops = soft_i2c_ops;
  221. obj->ops.data = cfg;
  222. obj->i2c_bus.priv = &obj->ops;
  223. obj->ops.delay_us = cfg->timing_delay;
  224. obj->ops.timeout = cfg->timing_timeout;
  225. if(rt_i2c_bit_add_bus(&obj->i2c_bus, cfg->bus_name) == RT_EOK)
  226. {
  227. i2c_bus_unlock(cfg);
  228. LOG_D("Software simulation %s init done"
  229. ", SCL pin: 0x%02X, SDA pin: 0x%02X"
  230. , cfg->bus_name
  231. , cfg->scl_pin
  232. , cfg->sda_pin
  233. );
  234. }
  235. else
  236. {
  237. err++;
  238. LOG_E("Software simulation %s init fail"
  239. ", SCL pin: 0x%02X, SDA pin: 0x%02X"
  240. , cfg->bus_name
  241. , cfg->scl_pin
  242. , cfg->sda_pin
  243. );
  244. }
  245. }
  246. return err;
  247. }
  248. INIT_PREV_EXPORT(rt_soft_i2c_init);
  249. #endif // RT_USING_SOFT_I2C