furi_hal_i2c.c 9.2 KB

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