hal_i2c.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /*
  2. ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. /*
  14. Concepts and parts of this file have been contributed by Uladzimir Pylinsky
  15. aka barthess.
  16. */
  17. /**
  18. * @file i2c.c
  19. * @brief I2C Driver code.
  20. *
  21. * @addtogroup I2C
  22. * @{
  23. */
  24. #include "hal.h"
  25. #if (HAL_USE_I2C == TRUE) || defined(__DOXYGEN__)
  26. /*===========================================================================*/
  27. /* Driver local definitions. */
  28. /*===========================================================================*/
  29. /*===========================================================================*/
  30. /* Driver exported variables. */
  31. /*===========================================================================*/
  32. /*===========================================================================*/
  33. /* Driver local variables and types. */
  34. /*===========================================================================*/
  35. /*===========================================================================*/
  36. /* Driver local functions. */
  37. /*===========================================================================*/
  38. /*===========================================================================*/
  39. /* Driver exported functions. */
  40. /*===========================================================================*/
  41. /**
  42. * @brief I2C Driver initialization.
  43. * @note This function is implicitly invoked by @p halInit(), there is
  44. * no need to explicitly initialize the driver.
  45. *
  46. * @init
  47. */
  48. void i2cInit(void) {
  49. i2c_lld_init();
  50. }
  51. /**
  52. * @brief Initializes the standard part of a @p I2CDriver structure.
  53. *
  54. * @param[out] i2cp pointer to the @p I2CDriver object
  55. *
  56. * @init
  57. */
  58. void i2cObjectInit(I2CDriver *i2cp) {
  59. i2cp->state = I2C_STOP;
  60. i2cp->config = NULL;
  61. #if I2C_USE_MUTUAL_EXCLUSION == TRUE
  62. #if CH_CFG_USE_MUTEXES
  63. osalMutexObjectInit(&i2cp->mutex);
  64. #else
  65. osalSemObjectInit(&i2cp->semaphore, 1);
  66. #endif /* CH_CFG_USE_MUTEXES */
  67. #endif /* I2C_USE_MUTUAL_EXCLUSION */
  68. #if defined(I2C_DRIVER_EXT_INIT_HOOK)
  69. I2C_DRIVER_EXT_INIT_HOOK(i2cp);
  70. #endif
  71. }
  72. /**
  73. * @brief Configures and activates the I2C peripheral.
  74. *
  75. * @param[in] i2cp pointer to the @p I2CDriver object
  76. * @param[in] config pointer to the @p I2CConfig object
  77. *
  78. * @api
  79. */
  80. void i2cStart(I2CDriver *i2cp, const I2CConfig *config) {
  81. osalDbgCheck((i2cp != NULL) && (config != NULL));
  82. osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
  83. (i2cp->state == I2C_LOCKED), "invalid state");
  84. osalSysLock();
  85. i2cp->config = config;
  86. i2c_lld_start(i2cp);
  87. i2cp->state = I2C_READY;
  88. osalSysUnlock();
  89. }
  90. /**
  91. * @brief Deactivates the I2C peripheral.
  92. *
  93. * @param[in] i2cp pointer to the @p I2CDriver object
  94. *
  95. * @api
  96. */
  97. void i2cStop(I2CDriver *i2cp) {
  98. osalDbgCheck(i2cp != NULL);
  99. osalDbgAssert((i2cp->state == I2C_STOP) || (i2cp->state == I2C_READY) ||
  100. (i2cp->state == I2C_LOCKED), "invalid state");
  101. osalSysLock();
  102. i2c_lld_stop(i2cp);
  103. i2cp->state = I2C_STOP;
  104. osalSysUnlock();
  105. }
  106. /**
  107. * @brief Returns the errors mask associated to the previous operation.
  108. *
  109. * @param[in] i2cp pointer to the @p I2CDriver object
  110. * @return The errors mask.
  111. *
  112. * @api
  113. */
  114. i2cflags_t i2cGetErrors(I2CDriver *i2cp) {
  115. osalDbgCheck(i2cp != NULL);
  116. return i2c_lld_get_errors(i2cp);
  117. }
  118. /**
  119. * @brief Sends data via the I2C bus.
  120. * @details Function designed to realize "read-through-write" transfer
  121. * paradigm. If you want transmit data without any further read,
  122. * than set @b rxbytes field to 0.
  123. *
  124. * @param[in] i2cp pointer to the @p I2CDriver object
  125. * @param[in] addr slave device address (7 bits) without R/W bit
  126. * @param[in] txbuf pointer to transmit buffer
  127. * @param[in] txbytes number of bytes to be transmitted
  128. * @param[out] rxbuf pointer to receive buffer
  129. * @param[in] rxbytes number of bytes to be received, set it to 0 if
  130. * you want transmit only
  131. * @param[in] timeout the number of ticks before the operation timeouts,
  132. * the following special values are allowed:
  133. * - @a TIME_INFINITE no timeout.
  134. * .
  135. *
  136. * @return The operation status.
  137. * @retval MSG_OK if the function succeeded.
  138. * @retval MSG_RESET if one or more I2C errors occurred, the errors can
  139. * be retrieved using @p i2cGetErrors().
  140. * @retval MSG_TIMEOUT if a timeout occurred before operation end.
  141. *
  142. * @api
  143. */
  144. msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp,
  145. i2caddr_t addr,
  146. const uint8_t *txbuf,
  147. size_t txbytes,
  148. uint8_t *rxbuf,
  149. size_t rxbytes,
  150. systime_t timeout) {
  151. msg_t rdymsg;
  152. osalDbgCheck((i2cp != NULL) && (addr != 0U) &&
  153. (txbytes > 0U) && (txbuf != NULL) &&
  154. ((rxbytes == 0U) || ((rxbytes > 0U) && (rxbuf != NULL))) &&
  155. (timeout != TIME_IMMEDIATE));
  156. osalDbgAssert(i2cp->state == I2C_READY, "not ready");
  157. osalSysLock();
  158. i2cp->errors = I2C_NO_ERROR;
  159. i2cp->state = I2C_ACTIVE_TX;
  160. rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes,
  161. rxbuf, rxbytes, timeout);
  162. if (rdymsg == MSG_TIMEOUT) {
  163. i2cp->state = I2C_LOCKED;
  164. }
  165. else {
  166. i2cp->state = I2C_READY;
  167. }
  168. osalSysUnlock();
  169. return rdymsg;
  170. }
  171. /**
  172. * @brief Receives data from the I2C bus.
  173. *
  174. * @param[in] i2cp pointer to the @p I2CDriver object
  175. * @param[in] addr slave device address (7 bits) without R/W bit
  176. * @param[out] rxbuf pointer to receive buffer
  177. * @param[in] rxbytes number of bytes to be received
  178. * @param[in] timeout the number of ticks before the operation timeouts,
  179. * the following special values are allowed:
  180. * - @a TIME_INFINITE no timeout.
  181. * .
  182. *
  183. * @return The operation status.
  184. * @retval MSG_OK if the function succeeded.
  185. * @retval MSG_RESET if one or more I2C errors occurred, the errors can
  186. * be retrieved using @p i2cGetErrors().
  187. * @retval MSG_TIMEOUT if a timeout occurred before operation end.
  188. *
  189. * @api
  190. */
  191. msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp,
  192. i2caddr_t addr,
  193. uint8_t *rxbuf,
  194. size_t rxbytes,
  195. systime_t timeout){
  196. msg_t rdymsg;
  197. osalDbgCheck((i2cp != NULL) && (addr != 0U) &&
  198. (rxbytes > 0U) && (rxbuf != NULL) &&
  199. (timeout != TIME_IMMEDIATE));
  200. osalDbgAssert(i2cp->state == I2C_READY, "not ready");
  201. osalSysLock();
  202. i2cp->errors = I2C_NO_ERROR;
  203. i2cp->state = I2C_ACTIVE_RX;
  204. rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout);
  205. if (rdymsg == MSG_TIMEOUT) {
  206. i2cp->state = I2C_LOCKED;
  207. }
  208. else {
  209. i2cp->state = I2C_READY;
  210. }
  211. osalSysUnlock();
  212. return rdymsg;
  213. }
  214. #if HAL_USE_I2C_LOCK /* I2C slave mode support */
  215. /**
  216. * @brief Lock I2C bus at the beginning of the next message sent
  217. *
  218. * @param[in] i2cp pointer to the @p I2CDriver object
  219. * @param[in] lockDuration max number of ticks to hold bus locked
  220. * - @a TIME_INFINITE no timeout.
  221. * - @a TIME_IMMEDIATE unlock the bus immediately
  222. * .
  223. *
  224. * @api
  225. */
  226. void i2cLock(I2CDriver *i2cp, systime_t lockDuration)
  227. {
  228. chDbgCheck((i2cp != NULL), "i2cLock");
  229. chSysLock();
  230. i2c_lld_lock(i2cp, lockDuration);
  231. chSysUnlock();
  232. }
  233. /**
  234. * @brief Unlock I2C bus after the end of the next transaction
  235. *
  236. * @param[in] i2cp pointer to the @p I2CDriver object
  237. *
  238. * @api
  239. **/
  240. void i2cUnlock(I2CDriver *i2cp)
  241. {
  242. chDbgCheck((i2cp != NULL), "i2cUnlock");
  243. chSysLock();
  244. i2c_lld_unlock(i2cp);
  245. chSysUnlock();
  246. }
  247. #endif
  248. #if HAL_USE_I2C_SLAVE /* I2C slave mode support */
  249. /**
  250. * @brief Reconfigure I2C channel to respond to indicated address
  251. * in addition to those already matched
  252. *
  253. * @param[in] i2cp pointer to the @p I2CDriver object
  254. * @param[in] i2cadr I2C network address
  255. *
  256. * @return Length of message OR the type of event received
  257. * @retval I2C_OK Success
  258. * @retval I2C_ERROR Cannot match address in addition of those already
  259. *
  260. * @details MatchAddress calls are cumulative.
  261. * Specify address zero to match I2C "all call"
  262. * Does not support 10-bit addressing.
  263. *
  264. * @api
  265. **/
  266. msg_t i2cMatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr)
  267. {
  268. osalDbgCheck((i2cp != NULL));
  269. chSysLock();
  270. msg_t result = i2c_lld_matchAddress(i2cp, i2cadr);
  271. chSysUnlock();
  272. return result;
  273. }
  274. /**
  275. * @brief Configure to ignore messages directed to the given i2cadr
  276. *
  277. * @param[in] i2cp pointer to the @p I2CDriver object
  278. * @param[in] i2cadr I2C bus address
  279. * - @a 0 matches "all call"
  280. * .
  281. * @details A message being transferred that has already matched the
  282. * specified address will continue being processed.
  283. * Requests to unmatch an address that is not currently being matched
  284. * are ignored.
  285. *
  286. * @api
  287. */
  288. void i2cUnmatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr)
  289. {
  290. osalDbgCheck((i2cp != NULL));
  291. chSysLock();
  292. i2c_lld_unmatchAddress(i2cp, i2cadr);
  293. chSysUnlock();
  294. }
  295. /**
  296. * @brief Reconfigure I2C channel to no longer match any address
  297. *
  298. * @param[in] i2cp pointer to the @p I2CDriver object
  299. *
  300. * @details Causes all subsequent messages to be ignored.
  301. * A message being transferred that has already matched a
  302. * slave address will continue being processed.
  303. *
  304. * @api
  305. **/
  306. void i2cUnmatchAll(I2CDriver *i2cp)
  307. {
  308. osalDbgCheck((i2cp != NULL));
  309. chSysLock();
  310. i2c_lld_unmatchAll(i2cp);
  311. chSysUnlock();
  312. }
  313. /**
  314. * @brief Configure callbacks & buffers for message reception & query reply
  315. *
  316. * @param[in] i2cp pointer to the @p I2CDriver object
  317. * @param[in] rxMsg @p I2CSlaveMsg struct for processing subsequent messages
  318. * @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
  319. *
  320. * @details Must be called from a thread
  321. * Call i2cMatchAddress() after this to start processing
  322. * Enabling match addresses before installing handler callbacks can
  323. * result in locking the I2C bus when a master accesses those
  324. * unconfigured slave addresses
  325. *
  326. * @api
  327. */
  328. void i2cSlaveConfigure(I2CDriver *i2cp,
  329. const I2CSlaveMsg *rxMsg, const I2CSlaveMsg *replyMsg)
  330. {
  331. osalDbgCheck((i2cp != NULL));
  332. chSysLock();
  333. i2c_lld_slaveReceive(i2cp, rxMsg);
  334. i2c_lld_slaveReply(i2cp, replyMsg);
  335. chSysUnlock();
  336. }
  337. /**
  338. * @brief Configure callbacks & buffers for query reply
  339. *
  340. * @param[in] i2cp pointer to the @p I2CDriver object
  341. * @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
  342. *
  343. * @details Call i2cMatchAddress() after this to start processing
  344. * Enabling match addresses before installing handler callbacks can
  345. * result in locking the I2C bus when a master accesses those
  346. * unconfigured slave addresses
  347. *
  348. * @api
  349. */
  350. void i2cSlaveReceive(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg)
  351. {
  352. osalDbgCheck((i2cp != NULL && rxMsg != NULL));
  353. chSysLock();
  354. i2c_lld_slaveReceive(i2cp, rxMsg);
  355. chSysUnlock();
  356. }
  357. /**
  358. * @brief Configure callbacks & buffers for query reply
  359. *
  360. * @param[in] i2cp pointer to the @p I2CDriver object
  361. * @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
  362. *
  363. * @details Call i2cMatchAddress() after this to start processing
  364. * Enabling match addresses before installing handler callbacks can
  365. * result in locking the I2C bus when a master accesses those
  366. * unconfigured slave addresses
  367. *
  368. * @api
  369. */
  370. void i2cSlaveReply(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg)
  371. {
  372. osalDbgCheck((i2cp != NULL && replyMsg != NULL));
  373. chSysLock();
  374. i2c_lld_slaveReply(i2cp, replyMsg);
  375. chSysUnlock();
  376. }
  377. #endif /* HAL_USE_I2C_SLAVE */
  378. #if I2C_USE_MUTUAL_EXCLUSION == TRUE || defined(__DOXYGEN__)
  379. /**
  380. * @brief Gains exclusive access to the I2C bus.
  381. * @details This function tries to gain ownership to the I2C bus, if the bus
  382. * is already being used then the invoking thread is queued.
  383. * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
  384. * must be enabled.
  385. *
  386. * @param[in] i2cp pointer to the @p I2CDriver object
  387. *
  388. * @api
  389. */
  390. void i2cAcquireBus(I2CDriver *i2cp) {
  391. osalDbgCheck(i2cp != NULL);
  392. #if CH_CFG_USE_MUTEXES
  393. osalMutexLock(&i2cp->mutex);
  394. #elif CH_CFG_USE_SEMAPHORES
  395. osalSemWait(&i2cp->semaphore);
  396. #endif /* CH_CFG_USE_MUTEXES */
  397. }
  398. /**
  399. * @brief Releases exclusive access to the I2C bus.
  400. * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION
  401. * must be enabled.
  402. *
  403. * @param[in] i2cp pointer to the @p I2CDriver object
  404. *
  405. * @api
  406. */
  407. void i2cReleaseBus(I2CDriver *i2cp) {
  408. osalDbgCheck(i2cp != NULL);
  409. #if CH_CFG_USE_MUTEXES
  410. osalMutexUnlock(&i2cp->mutex);
  411. #elif CH_CFG_USE_SEMAPHORES
  412. osalSemSignal(&i2cp->semaphore);
  413. #endif /* CH_CFG_USE_MUTEXES */
  414. }
  415. #endif /* I2C_USE_MUTUAL_EXCLUSION == TRUE */
  416. #endif /* HAL_USE_I2C == TRUE */
  417. /** @} */