furi_hal_i2c.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #include <furi_hal_i2c.h>
  2. #include <furi_hal_delay.h>
  3. #include <furi_hal_version.h>
  4. #include <stm32wbxx_ll_i2c.h>
  5. #include <stm32wbxx_ll_gpio.h>
  6. #include <stm32wbxx_ll_cortex.h>
  7. #include <furi.h>
  8. #define TAG "FuriHalI2C"
  9. void furi_hal_i2c_init() {
  10. furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
  11. furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit);
  12. FURI_LOG_I(TAG, "Init OK");
  13. }
  14. void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
  15. // Lock bus access
  16. handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
  17. // Ensuree that no active handle set
  18. furi_check(handle->bus->current_handle == NULL);
  19. // Set current handle
  20. handle->bus->current_handle = handle;
  21. // Activate bus
  22. handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
  23. // Activate handle
  24. handle->callback(handle, FuriHalI2cBusHandleEventActivate);
  25. }
  26. void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
  27. // Ensure that current handle is our handle
  28. furi_check(handle->bus->current_handle == handle);
  29. // Deactivate handle
  30. handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
  31. // Deactivate bus
  32. handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
  33. // Reset current handle
  34. handle->bus->current_handle = NULL;
  35. // Unlock bus
  36. handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
  37. }
  38. bool furi_hal_i2c_tx(
  39. FuriHalI2cBusHandle* handle,
  40. uint8_t address,
  41. const uint8_t* data,
  42. uint8_t size,
  43. uint32_t timeout) {
  44. furi_check(handle->bus->current_handle == handle);
  45. furi_assert(timeout > 0);
  46. bool ret = true;
  47. uint32_t timeout_tick = furi_hal_get_tick() + timeout;
  48. do {
  49. while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) {
  50. if(furi_hal_get_tick() >= timeout_tick) {
  51. ret = false;
  52. break;
  53. }
  54. }
  55. if(!ret) {
  56. break;
  57. }
  58. LL_I2C_HandleTransfer(
  59. handle->bus->i2c,
  60. address,
  61. LL_I2C_ADDRSLAVE_7BIT,
  62. size,
  63. LL_I2C_MODE_AUTOEND,
  64. LL_I2C_GENERATE_START_WRITE);
  65. while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
  66. if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
  67. LL_I2C_TransmitData8(handle->bus->i2c, (*data));
  68. data++;
  69. size--;
  70. }
  71. if(furi_hal_get_tick() >= timeout_tick) {
  72. ret = false;
  73. break;
  74. }
  75. }
  76. LL_I2C_ClearFlag_STOP(handle->bus->i2c);
  77. } while(0);
  78. return ret;
  79. }
  80. bool furi_hal_i2c_rx(
  81. FuriHalI2cBusHandle* handle,
  82. uint8_t address,
  83. uint8_t* data,
  84. uint8_t size,
  85. uint32_t timeout) {
  86. furi_check(handle->bus->current_handle == handle);
  87. furi_assert(timeout > 0);
  88. bool ret = true;
  89. uint32_t timeout_tick = furi_hal_get_tick() + timeout;
  90. do {
  91. while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) {
  92. if(furi_hal_get_tick() >= timeout_tick) {
  93. ret = false;
  94. break;
  95. }
  96. }
  97. if(!ret) {
  98. break;
  99. }
  100. LL_I2C_HandleTransfer(
  101. handle->bus->i2c,
  102. address,
  103. LL_I2C_ADDRSLAVE_7BIT,
  104. size,
  105. LL_I2C_MODE_AUTOEND,
  106. LL_I2C_GENERATE_START_READ);
  107. while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
  108. if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
  109. *data = LL_I2C_ReceiveData8(handle->bus->i2c);
  110. data++;
  111. size--;
  112. }
  113. if(furi_hal_get_tick() >= timeout_tick) {
  114. ret = false;
  115. break;
  116. }
  117. }
  118. LL_I2C_ClearFlag_STOP(handle->bus->i2c);
  119. } while(0);
  120. return ret;
  121. }
  122. bool furi_hal_i2c_trx(
  123. FuriHalI2cBusHandle* handle,
  124. uint8_t address,
  125. const uint8_t* tx_data,
  126. uint8_t tx_size,
  127. uint8_t* rx_data,
  128. uint8_t rx_size,
  129. uint32_t timeout) {
  130. if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
  131. furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
  132. return true;
  133. } else {
  134. return false;
  135. }
  136. }
  137. bool furi_hal_i2c_is_device_ready(FuriHalI2cBusHandle* handle, uint8_t i2c_addr, uint32_t timeout) {
  138. furi_check(handle);
  139. furi_check(handle->bus->current_handle == handle);
  140. furi_assert(timeout > 0);
  141. bool ret = true;
  142. uint32_t timeout_tick = furi_hal_get_tick() + timeout;
  143. do {
  144. while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) {
  145. if(furi_hal_get_tick() >= timeout_tick) {
  146. return false;
  147. }
  148. }
  149. handle->bus->i2c->CR2 =
  150. ((((uint32_t)(i2c_addr) & (I2C_CR2_SADD)) | (I2C_CR2_START) | (I2C_CR2_AUTOEND)) &
  151. (~I2C_CR2_RD_WRN));
  152. while((!LL_I2C_IsActiveFlag_NACK(handle->bus->i2c)) &&
  153. (!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c))) {
  154. if(furi_hal_get_tick() >= timeout_tick) {
  155. return false;
  156. }
  157. }
  158. if(LL_I2C_IsActiveFlag_NACK(handle->bus->i2c)) {
  159. while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c)) {
  160. if(furi_hal_get_tick() >= timeout_tick) {
  161. return false;
  162. }
  163. }
  164. LL_I2C_ClearFlag_NACK(handle->bus->i2c);
  165. // Clear STOP Flag generated by autoend
  166. LL_I2C_ClearFlag_STOP(handle->bus->i2c);
  167. // Generate actual STOP
  168. LL_I2C_GenerateStopCondition(handle->bus->i2c);
  169. ret = false;
  170. }
  171. while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c)) {
  172. if(furi_hal_get_tick() >= timeout_tick) {
  173. return false;
  174. }
  175. }
  176. LL_I2C_ClearFlag_STOP(handle->bus->i2c);
  177. } while(0);
  178. return ret;
  179. }
  180. bool furi_hal_i2c_read_reg_8(
  181. FuriHalI2cBusHandle* handle,
  182. uint8_t i2c_addr,
  183. uint8_t reg_addr,
  184. uint8_t* data,
  185. uint32_t timeout) {
  186. furi_check(handle);
  187. return furi_hal_i2c_trx(handle, i2c_addr, &reg_addr, 1, data, 1, timeout);
  188. }
  189. bool furi_hal_i2c_read_reg_16(
  190. FuriHalI2cBusHandle* handle,
  191. uint8_t i2c_addr,
  192. uint8_t reg_addr,
  193. uint16_t* data,
  194. uint32_t timeout) {
  195. furi_check(handle);
  196. uint8_t reg_data[2];
  197. bool ret = furi_hal_i2c_trx(handle, i2c_addr, &reg_addr, 1, reg_data, 2, timeout);
  198. *data = (reg_data[0] << 8) | (reg_data[1]);
  199. return ret;
  200. }
  201. bool furi_hal_i2c_read_mem(
  202. FuriHalI2cBusHandle* handle,
  203. uint8_t i2c_addr,
  204. uint8_t mem_addr,
  205. uint8_t* data,
  206. uint8_t len,
  207. uint32_t timeout) {
  208. furi_check(handle);
  209. return furi_hal_i2c_trx(handle, i2c_addr, &mem_addr, 1, data, len, timeout);
  210. }
  211. bool furi_hal_i2c_write_reg_8(
  212. FuriHalI2cBusHandle* handle,
  213. uint8_t i2c_addr,
  214. uint8_t reg_addr,
  215. uint8_t data,
  216. uint32_t timeout) {
  217. furi_check(handle);
  218. uint8_t tx_data[2];
  219. tx_data[0] = reg_addr;
  220. tx_data[1] = data;
  221. return furi_hal_i2c_tx(handle, i2c_addr, (const uint8_t*)&tx_data, 2, timeout);
  222. }
  223. bool furi_hal_i2c_write_reg_16(
  224. FuriHalI2cBusHandle* handle,
  225. uint8_t i2c_addr,
  226. uint8_t reg_addr,
  227. uint16_t data,
  228. uint32_t timeout) {
  229. furi_check(handle);
  230. uint8_t tx_data[3];
  231. tx_data[0] = reg_addr;
  232. tx_data[1] = (data >> 8) & 0xFF;
  233. tx_data[2] = data & 0xFF;
  234. return furi_hal_i2c_tx(handle, i2c_addr, (const uint8_t*)&tx_data, 3, timeout);
  235. }
  236. bool furi_hal_i2c_write_mem(
  237. FuriHalI2cBusHandle* handle,
  238. uint8_t i2c_addr,
  239. uint8_t mem_addr,
  240. uint8_t* data,
  241. uint8_t len,
  242. uint32_t timeout) {
  243. furi_check(handle);
  244. furi_check(handle->bus->current_handle == handle);
  245. furi_assert(timeout > 0);
  246. bool ret = true;
  247. uint8_t size = len + 1;
  248. uint32_t timeout_tick = furi_hal_get_tick() + timeout;
  249. do {
  250. while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) {
  251. if(furi_hal_get_tick() >= timeout_tick) {
  252. ret = false;
  253. break;
  254. }
  255. }
  256. if(!ret) {
  257. break;
  258. }
  259. LL_I2C_HandleTransfer(
  260. handle->bus->i2c,
  261. i2c_addr,
  262. LL_I2C_ADDRSLAVE_7BIT,
  263. size,
  264. LL_I2C_MODE_AUTOEND,
  265. LL_I2C_GENERATE_START_WRITE);
  266. while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
  267. if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
  268. if(size == len + 1) {
  269. LL_I2C_TransmitData8(handle->bus->i2c, mem_addr);
  270. } else {
  271. LL_I2C_TransmitData8(handle->bus->i2c, (*data));
  272. data++;
  273. }
  274. size--;
  275. }
  276. if(furi_hal_get_tick() >= timeout_tick) {
  277. ret = false;
  278. break;
  279. }
  280. }
  281. LL_I2C_ClearFlag_STOP(handle->bus->i2c);
  282. } while(0);
  283. return ret;
  284. }