api-spi.h 3.4 KB

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