api-spi.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #include <furi.h>
  2. #ifdef __cplusplus
  3. extern "C" {
  4. #endif
  5. /*
  6. struct used for handling SPI info.
  7. */
  8. typedef struct {
  9. SPI_HandleTypeDef* spi;
  10. PubSubCallback cb;
  11. void* ctx;
  12. } SpiHandle;
  13. /*
  14. For transmit/receive data use `spi_xfer` function.
  15. * `tx_data` and `rx_data` size must be equal (and equal `len`)
  16. * `cb` called after spi operation is completed, `(NULL, ctx)` passed to callback.
  17. */
  18. bool spi_xfer(
  19. SPI_HandleTypeDef* spi,
  20. uint8_t* tx_data,
  21. uint8_t* rx_data,
  22. size_t len,
  23. PubSubCallback cb,
  24. void* ctx);
  25. /*
  26. Blocking verison:
  27. */
  28. static inline bool
  29. spi_xfer_block(SPI_HandleTypeDef* spi, uint8_t* tx_data, uint8_t* rx_data, size_t len) {
  30. semaphoreInfo s;
  31. osSemaphore block = createSemaphoreStatic(s);
  32. if(!spi_xfer(spi, tx_data, rx_data, len, RELEASE_SEMAPHORE, (void*)block)) {
  33. osReleaseSemaphore(block);
  34. return false;
  35. }
  36. osWaitSemaphore(block);
  37. return false;
  38. }
  39. /*
  40. Common implementation of SPI bus: serial interface + CS pin
  41. */
  42. typedef struct {
  43. GpioPin* cs; ///< CS pin
  44. ValueMutex* spi; ///< <SpiHandle*>
  45. } SpiBus;
  46. /*
  47. For dedicated work with one device there is `SpiDevice` entity.
  48. It contains ValueMutex around SpiBus: after you acquire device
  49. you can acquire spi to work with it (don't forget SPI bus is shared
  50. around many device, release it after every transaction as quick as possible).
  51. */
  52. typedef struct {
  53. ValueMutex* bus; ///< <SpiBus*>
  54. } SpiDevice;
  55. ##SPI IRQ device
  56. /*
  57. Many devices (like CC1101 and NFC) present as SPI bus and IRQ line.
  58. For work with it there is special entity `SpiIrqDevice`.
  59. Use `subscribe_pubsub` for subscribinq to irq events.
  60. */
  61. typedef struct {
  62. ValueMutex* bus; ///< <SpiBus*>
  63. PubSub* irq;
  64. } SpiIrqDevice;
  65. /*
  66. Special implementation of SPI bus: serial interface + CS, Res, D/I lines.
  67. */
  68. typedef struct {
  69. GpioPin* cs; ///< CS pin
  70. GpioPin* res; ///< reset pin
  71. GpioPin* di; ///< D/I pin
  72. ValueMutex* spi; ///< <SPI_HandleTypeDef*>
  73. } DisplayBus;
  74. typedef struct {
  75. ValueMutex* bus; ///< <DisplayBus*>
  76. } DisplayDevice;
  77. /*
  78. # SPI devices (F2)
  79. * `/dev/sdcard` - SD card SPI, `SpiDevice`
  80. * `/dev/cc1101_bus` - Sub-GHz radio (CC1101), `SpiIrqDevice`
  81. * `/dev/nfc` - NFC (ST25R3916), `SpiIrqDevice`
  82. * `/dev/display` - `DisplayDevice`
  83. * `/dev/spiext` - External SPI (warning! Lock PA4, PA5, PA6, PA7)
  84. ### Application example
  85. ```C
  86. // Be careful, this function called from IRQ context
  87. void handle_irq(void* _arg, void* _ctx) {
  88. }
  89. void cc1101_example() {
  90. SpiIrqDevice* cc1101_device = open_input("/dev/cc1101_bus");
  91. if(cc1101_device == NULL) return; // bus not available, critical error
  92. subscribe_pubsub(cc1101_device->irq, handle_irq, NULL);
  93. {
  94. // acquire device as device bus
  95. SpiBus* spi_bus = acquire_mutex(cc1101_device->bus, 0);
  96. if(spi_bus == NULL) {
  97. printf("Device busy\n");
  98. // wait for device
  99. spi_bus = acquire_mutex_block(cc1101_device->bus);
  100. }
  101. // make transaction
  102. uint8_t request[4] = {0xDE, 0xAD, 0xBE, 0xEF};
  103. uint8_t response[4];
  104. {
  105. SPI_HandleTypeDef* spi = acquire_mutex_block(spi_bus->spi);
  106. gpio_write(spi_bus->cs, false);
  107. spi_xfer_block(spi, request, response, 4);
  108. gpio_write(spi_bus->cs, true);
  109. release_mutex(cc1101_device->spi, spi);
  110. }
  111. // release device (device bus)
  112. release_mutex(cc1101_device->bus, spi_bus);
  113. }
  114. }
  115. ```
  116. */
  117. #ifdef __cplusplus
  118. }
  119. #endif