فهرست منبع

[FL-2060] FuriHal: SPI refactoring, flexible bus reconfiguration on fly, same design as i2c. (#853)

* FuriHal: SPI refactoring, flexible bus reconfigration on fly, same desiag as i2c.
* Lib: update CC1101 driver documentation
* FuriHal: update spi symbol names to match naming convention.
あく 4 سال پیش
والد
کامیت
9d27ef8901
36فایلهای تغییر یافته به همراه2059 افزوده شده و 1614 حذف شده
  1. 217 41
      bootloader/targets/f6/furi-hal/furi-hal-spi-config.c
  2. 46 46
      bootloader/targets/f6/furi-hal/furi-hal-spi-config.h
  3. 64 0
      bootloader/targets/f6/furi-hal/furi-hal-spi-types.h
  4. 79 168
      bootloader/targets/f6/furi-hal/furi-hal-spi.c
  5. 0 129
      bootloader/targets/f6/furi-hal/furi-hal-spi.h
  6. 217 41
      bootloader/targets/f7/furi-hal/furi-hal-spi-config.c
  7. 46 46
      bootloader/targets/f7/furi-hal/furi-hal-spi-config.h
  8. 64 0
      bootloader/targets/f7/furi-hal/furi-hal-spi-types.h
  9. 79 168
      bootloader/targets/f7/furi-hal/furi-hal-spi.c
  10. 0 129
      bootloader/targets/f7/furi-hal/furi-hal-spi.h
  11. 102 0
      bootloader/targets/furi-hal-include/furi-hal-spi.h
  12. 5 7
      firmware/targets/f6/fatfs/spi_sd_hal.c
  13. 17 20
      firmware/targets/f6/fatfs/stm32_adafruit_sd.c
  14. 17 9
      firmware/targets/f6/fatfs/user_diskio.c
  15. 3 1
      firmware/targets/f6/furi-hal/furi-hal-sd.c
  16. 180 29
      firmware/targets/f6/furi-hal/furi-hal-spi-config.c
  17. 46 48
      firmware/targets/f6/furi-hal/furi-hal-spi-config.h
  18. 62 0
      firmware/targets/f6/furi-hal/furi-hal-spi-types.h
  19. 67 129
      firmware/targets/f6/furi-hal/furi-hal-spi.c
  20. 66 66
      firmware/targets/f6/furi-hal/furi-hal-subghz.c
  21. 5 7
      firmware/targets/f7/fatfs/spi_sd_hal.c
  22. 17 20
      firmware/targets/f7/fatfs/stm32_adafruit_sd.c
  23. 17 9
      firmware/targets/f7/fatfs/user_diskio.c
  24. 3 1
      firmware/targets/f7/furi-hal/furi-hal-sd.c
  25. 180 29
      firmware/targets/f7/furi-hal/furi-hal-spi-config.c
  26. 46 48
      firmware/targets/f7/furi-hal/furi-hal-spi-config.h
  27. 62 0
      firmware/targets/f7/furi-hal/furi-hal-spi-types.h
  28. 67 129
      firmware/targets/f7/furi-hal/furi-hal-spi.c
  29. 66 66
      firmware/targets/f7/furi-hal/furi-hal-subghz.c
  30. 4 0
      firmware/targets/furi-hal-include/furi-hal-sd.h
  31. 57 75
      firmware/targets/furi-hal-include/furi-hal-spi.h
  32. 1 0
      firmware/targets/furi-hal-include/furi-hal.h
  33. 5 13
      lib/ST25RFAL002/platform.c
  34. 50 66
      lib/drivers/cc1101.c
  35. 99 63
      lib/drivers/cc1101.h
  36. 3 11
      lib/u8g2/u8g2_glue.c

+ 217 - 41
bootloader/targets/f6/furi-hal/furi-hal-spi-config.c

@@ -1,10 +1,9 @@
 #include <furi-hal-spi-config.h>
 #include <furi-hal-spi-config.h>
 #include <furi-hal-resources.h>
 #include <furi-hal-resources.h>
 
 
-#define SPI_R SPI1
-#define SPI_D SPI2
+/* SPI Presets */
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -17,7 +16,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -30,7 +29,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -43,10 +42,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-/**
- * SD Card in fast mode (after init)
- */
-const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -59,10 +55,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-/**
- * SD Card in slow mode (before init)
- */
-const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -75,40 +68,223 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const FuriHalSpiBus spi_r = {
-    .spi = SPI_R,
+/* SPI Buses */
+
+static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
+    if(event == FuriHalSpiBusEventInit) {
+        LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
+        LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
+        bus->current_handle = NULL;
+    } else if(event == FuriHalSpiBusEventDeinit) {
+    } else if(event == FuriHalSpiBusEventLock) {
+    } else if(event == FuriHalSpiBusEventUnlock) {
+    } else if(event == FuriHalSpiBusEventActivate) {
+        LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
+    } else if(event == FuriHalSpiBusEventDeactivate) {
+        LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
+    }
+}
+
+FuriHalSpiBus furi_hal_spi_bus_r = {
+    .spi = SPI1,
+    .callback = furi_hal_spi_bus_r_event_callback,
+};
+
+static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
+    if(event == FuriHalSpiBusEventInit) {
+        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
+        LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
+        bus->current_handle = NULL;
+    } else if(event == FuriHalSpiBusEventDeinit) {
+    } else if(event == FuriHalSpiBusEventLock) {
+    } else if(event == FuriHalSpiBusEventUnlock) {
+    } else if(event == FuriHalSpiBusEventActivate) {
+        LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
+    } else if(event == FuriHalSpiBusEventDeactivate) {
+        LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
+    }
+}
+
+FuriHalSpiBus furi_hal_spi_bus_d = {
+    .spi = SPI2,
+    .callback = furi_hal_spi_bus_d_event_callback,
+};
+
+/* SPI Bus Handles */
+
+inline static void furi_hal_spi_bus_r_handle_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event,
+    const LL_SPI_InitTypeDef* preset) {
+    if(event == FuriHalSpiBusHandleEventInit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    } else if(event == FuriHalSpiBusHandleEventDeinit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+    } else if(event == FuriHalSpiBusHandleEventActivate) {
+        LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
+        LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
+        LL_SPI_Enable(handle->bus->spi);
+
+        hal_gpio_init_ex(
+            handle->miso,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI1);
+        hal_gpio_init_ex(
+            handle->mosi,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI1);
+        hal_gpio_init_ex(
+            handle->sck,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI1);
+
+        hal_gpio_write(handle->cs, false);
+    } else if(event == FuriHalSpiBusHandleEventDeactivate) {
+        hal_gpio_write(handle->cs, true);
+
+        hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+
+        LL_SPI_Disable(handle->bus->spi);
+    }
+}
+
+static void furi_hal_spi_bus_handle_subghz_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_8m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = {
+    .bus = &furi_hal_spi_bus_r,
+    .callback = furi_hal_spi_bus_handle_subghz_event_callback,
+    .miso = &gpio_spi_r_miso,
+    .mosi = &gpio_spi_r_mosi,
+    .sck = &gpio_spi_r_sck,
+    .cs = &gpio_subghz_cs,
+};
+
+static void furi_hal_spi_bus_handle_nfc_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = {
+    .bus = &furi_hal_spi_bus_r,
+    .callback = furi_hal_spi_bus_handle_nfc_event_callback,
     .miso = &gpio_spi_r_miso,
     .miso = &gpio_spi_r_miso,
     .mosi = &gpio_spi_r_mosi,
     .mosi = &gpio_spi_r_mosi,
-    .clk = &gpio_spi_r_sck,
+    .sck = &gpio_spi_r_sck,
+    .cs = &gpio_nfc_cs,
+};
+
+static void furi_hal_spi_bus_handle_external_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = {
+    .bus = &furi_hal_spi_bus_r,
+    .callback = furi_hal_spi_bus_handle_external_event_callback,
+    .miso = &gpio_ext_pa6,
+    .mosi = &gpio_ext_pa7,
+    .sck = &gpio_ext_pb3,
+    .cs = &gpio_ext_pa4,
 };
 };
 
 
-const FuriHalSpiBus spi_d = {
-    .spi = SPI_D,
+inline static void furi_hal_spi_bus_d_handle_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event,
+    const LL_SPI_InitTypeDef* preset) {
+    if(event == FuriHalSpiBusHandleEventInit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
+
+        hal_gpio_init_ex(
+            handle->miso,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI2);
+        hal_gpio_init_ex(
+            handle->mosi,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI2);
+        hal_gpio_init_ex(
+            handle->sck,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI2);
+
+    } else if(event == FuriHalSpiBusHandleEventDeinit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullUp, GpioSpeedLow);
+    } else if(event == FuriHalSpiBusHandleEventActivate) {
+        LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
+        LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
+        LL_SPI_Enable(handle->bus->spi);
+        hal_gpio_write(handle->cs, false);
+    } else if(event == FuriHalSpiBusHandleEventDeactivate) {
+        hal_gpio_write(handle->cs, true);
+        LL_SPI_Disable(handle->bus->spi);
+    }
+}
+
+static void furi_hal_spi_bus_handle_display_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_4m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_display = {
+    .bus = &furi_hal_spi_bus_d,
+    .callback = furi_hal_spi_bus_handle_display_event_callback,
     .miso = &gpio_spi_d_miso,
     .miso = &gpio_spi_d_miso,
     .mosi = &gpio_spi_d_mosi,
     .mosi = &gpio_spi_d_mosi,
-    .clk = &gpio_spi_d_sck,
+    .sck = &gpio_spi_d_sck,
+    .cs = &gpio_display_cs,
 };
 };
 
 
-const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax] = {
-    {
-        .bus = &spi_r,
-        .config = &furi_hal_spi_config_subghz,
-        .chip_select = &gpio_subghz_cs,
-    },
-    {
-        .bus = &spi_d,
-        .config = &furi_hal_spi_config_display,
-        .chip_select = &gpio_display_cs,
-    },
-    {
-        .bus = &spi_d,
-        .config = &furi_hal_spi_config_sd_fast,
-        .chip_select = &gpio_sdcard_cs,
-    },
-    {
-        .bus = &spi_d,
-        .config = &furi_hal_spi_config_sd_slow,
-        .chip_select = &gpio_sdcard_cs,
-    },
-    {.bus = &spi_r, .config = &furi_hal_spi_config_nfc, .chip_select = &gpio_nfc_cs},
+static void furi_hal_spi_bus_handle_sd_fast_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_16m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast = {
+    .bus = &furi_hal_spi_bus_d,
+    .callback = furi_hal_spi_bus_handle_sd_fast_event_callback,
+    .miso = &gpio_spi_d_miso,
+    .mosi = &gpio_spi_d_mosi,
+    .sck = &gpio_spi_d_sck,
+    .cs = &gpio_sdcard_cs,
+};
+
+static void furi_hal_spi_bus_handle_sd_slow_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow = {
+    .bus = &furi_hal_spi_bus_d,
+    .callback = furi_hal_spi_bus_handle_sd_slow_event_callback,
+    .miso = &gpio_spi_d_miso,
+    .mosi = &gpio_spi_d_mosi,
+    .sck = &gpio_spi_d_sck,
+    .cs = &gpio_sdcard_cs,
 };
 };

+ 46 - 46
bootloader/targets/f6/furi-hal/furi-hal-spi-config.h

@@ -1,60 +1,60 @@
 #pragma once
 #pragma once
 
 
-#include <furi-hal-gpio.h>
-#include <stm32wbxx_ll_spi.h>
+#include <furi-hal-spi-types.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_nfc;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_subghz;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_display;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow;
+/** Preset for ST25R916 */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m;
 
 
-/** FURI HAL SPI BUS handler
- * Structure content may change at some point
- */
-typedef struct {
-    const SPI_TypeDef* spi;
-    const GpioPin* miso;
-    const GpioPin* mosi;
-    const GpioPin* clk;
-} FuriHalSpiBus;
-
-/** FURI HAL SPI Device handler
- * Structure content may change at some point
- */
-typedef struct {
-    const FuriHalSpiBus* bus;
-    const LL_SPI_InitTypeDef* config;
-    const GpioPin* chip_select;
-} FuriHalSpiDevice;
-
-/** FURI HAL SPI Standard Device IDs */
-typedef enum {
-    FuriHalSpiDeviceIdSubGhz, /** SubGhz: CC1101, non-standard SPI usage */
-    FuriHalSpiDeviceIdDisplay, /** Display: ERC12864, only have MOSI */
-    FuriHalSpiDeviceIdSdCardFast, /** SDCARD: fast mode, after initialization */
-    FuriHalSpiDeviceIdSdCardSlow, /** SDCARD: slow mode, before initialization */
-    FuriHalSpiDeviceIdNfc, /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */
-
-    FuriHalSpiDeviceIdMax, /** Service Value, do not use */
-} FuriHalSpiDeviceId;
-
-/** Furi Hal Spi Bus R
- * CC1101, Nfc
- */
-extern const FuriHalSpiBus spi_r;
+/** Preset for CC1101 */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m;
+
+/** Preset for ST7567 (Display) */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m;
+
+/** Preset for SdCard in fast mode */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m;
+
+/** Preset for SdCard in slow mode */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m;
 
 
-/** Furi Hal Spi Bus D
- * Display, SdCard
+/** Furi Hal Spi Bus R (Radio: CC1101, Nfc, External)*/
+extern FuriHalSpiBus furi_hal_spi_bus_r;
+
+/** Furi Hal Spi Bus D (Display, SdCard) */
+extern FuriHalSpiBus furi_hal_spi_bus_d;
+
+/** CC1101 on `furi_hal_spi_bus_r` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz;
+
+/** ST25R3916 on `furi_hal_spi_bus_r` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc;
+
+/** External on `furi_hal_spi_bus_r`
+ * Preset: `furi_hal_spi_preset_1edge_low_2m`
+ * 
+ * miso: pa6
+ * mosi: pa7
+ * sck: pb3
+ * cs:  pa4 (software controlled)
+ * 
+ * @warning not initialized by default, call `furi_hal_spi_bus_handle_init` to initialize
+ * Bus pins are floating on inactive state, CS high after initialization
+ * 
  */
  */
-extern const FuriHalSpiBus spi_d;
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_external;
+
+/** ST7567(Display) on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_display;
+
+/** SdCard in fast mode on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast;
 
 
-/** Furi Hal Spi devices */
-extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax];
+/** SdCard in slow mode on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 64 - 0
bootloader/targets/f6/furi-hal/furi-hal-spi-types.h

@@ -0,0 +1,64 @@
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <furi-hal-gpio.h>
+
+#include <stm32wbxx_ll_spi.h>
+#include <stm32wbxx_ll_rcc.h>
+#include <stm32wbxx_ll_bus.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct FuriHalSpiBus FuriHalSpiBus;
+typedef struct FuriHalSpiBusHandle FuriHalSpiBusHandle;
+
+/** FuriHal spi bus states */
+typedef enum {
+    FuriHalSpiBusEventInit, /**< Bus initialization event, called on system start */
+    FuriHalSpiBusEventDeinit, /**< Bus deinitialization event, called on system stop */
+    FuriHalSpiBusEventLock, /**< Bus lock event, called before activation */
+    FuriHalSpiBusEventUnlock, /**< Bus unlock event, called after deactivation */
+    FuriHalSpiBusEventActivate, /**< Bus activation event, called before handle activation */
+    FuriHalSpiBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation  */
+} FuriHalSpiBusEvent;
+
+/** FuriHal spi bus event callback */
+typedef void (*FuriHalSpiBusEventCallback)(FuriHalSpiBus* bus, FuriHalSpiBusEvent event);
+
+/** FuriHal spi bus */
+struct FuriHalSpiBus {
+    SPI_TypeDef* spi;
+    FuriHalSpiBusEventCallback callback;
+    FuriHalSpiBusHandle* current_handle;
+};
+
+/** FuriHal spi handle states */
+typedef enum {
+    FuriHalSpiBusHandleEventInit, /**< Handle init, called on system start, initialize gpio for idle state */
+    FuriHalSpiBusHandleEventDeinit, /**< Handle deinit, called on system stop, deinitialize gpio for default state */
+    FuriHalSpiBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
+    FuriHalSpiBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
+} FuriHalSpiBusHandleEvent;
+
+/** FuriHal spi handle event callback */
+typedef void (*FuriHalSpiBusHandleEventCallback)(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event);
+
+/** FuriHal spi handle */
+struct FuriHalSpiBusHandle {
+    FuriHalSpiBus* bus;
+    FuriHalSpiBusHandleEventCallback callback;
+    const GpioPin* miso;
+    const GpioPin* mosi;
+    const GpioPin* sck;
+    const GpioPin* cs;
+};
+
+#ifdef __cplusplus
+}
+#endif

+ 79 - 168
bootloader/targets/f6/furi-hal/furi-hal-spi.c

@@ -2,239 +2,150 @@
 #include "furi-hal-resources.h"
 #include "furi-hal-resources.h"
 
 
 #include <stdbool.h>
 #include <stdbool.h>
+#include <string.h>
 #include <assert.h>
 #include <assert.h>
 
 
 #include <stm32wbxx_ll_spi.h>
 #include <stm32wbxx_ll_spi.h>
 #include <stm32wbxx_ll_utils.h>
 #include <stm32wbxx_ll_utils.h>
 #include <stm32wbxx_ll_cortex.h>
 #include <stm32wbxx_ll_cortex.h>
 
 
-extern void Enable_SPI(SPI_TypeDef* spi);
-
 void furi_hal_spi_init() {
 void furi_hal_spi_init() {
-    for(size_t i = 0; i < FuriHalSpiDeviceIdMax; ++i) {
-        hal_gpio_write(furi_hal_spi_devices[i].chip_select, true);
-        hal_gpio_init(
-            furi_hal_spi_devices[i].chip_select,
-            GpioModeOutputPushPull,
-            GpioPullNo,
-            GpioSpeedVeryHigh);
-    }
-
-    hal_gpio_init_ex(
-        &gpio_spi_r_miso,
-        GpioModeAltFunctionPushPull,
-        GpioPullNo,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI1);
-    hal_gpio_init_ex(
-        &gpio_spi_r_mosi,
-        GpioModeAltFunctionPushPull,
-        GpioPullNo,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI1);
-    hal_gpio_init_ex(
-        &gpio_spi_r_sck,
-        GpioModeAltFunctionPushPull,
-        GpioPullNo,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI1);
-
-    hal_gpio_init_ex(
-        &gpio_spi_d_miso,
-        GpioModeAltFunctionPushPull,
-        GpioPullUp,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI2);
-    hal_gpio_init_ex(
-        &gpio_spi_d_mosi,
-        GpioModeAltFunctionPushPull,
-        GpioPullUp,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI2);
-    hal_gpio_init_ex(
-        &gpio_spi_d_sck,
-        GpioModeAltFunctionPushPull,
-        GpioPullUp,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI2);
+    furi_hal_spi_bus_init(&furi_hal_spi_bus_r);
+    furi_hal_spi_bus_init(&furi_hal_spi_bus_d);
+
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow);
 }
 }
 
 
-void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus) {
+void furi_hal_spi_bus_init(FuriHalSpiBus* bus) {
     assert(bus);
     assert(bus);
+    bus->callback(bus, FuriHalSpiBusEventInit);
 }
 }
 
 
-void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) {
+void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus) {
     assert(bus);
     assert(bus);
+    bus->callback(bus, FuriHalSpiBusEventDeinit);
 }
 }
 
 
-void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config) {
-    assert(bus);
-    LL_SPI_DeInit((SPI_TypeDef*)bus->spi);
-    LL_SPI_Init((SPI_TypeDef*)bus->spi, (LL_SPI_InitTypeDef*)config);
-    LL_SPI_SetRxFIFOThreshold((SPI_TypeDef*)bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
-    LL_SPI_Enable((SPI_TypeDef*)bus->spi);
+void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle) {
+    assert(handle);
+    handle->callback(handle, FuriHalSpiBusHandleEventInit);
+}
+
+void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle) {
+    assert(handle);
+    handle->callback(handle, FuriHalSpiBusHandleEventDeinit);
+}
+
+void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle) {
+    assert(handle);
+
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventLock);
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventActivate);
+
+    assert(handle->bus->current_handle == NULL);
+
+    handle->bus->current_handle = handle;
+    handle->callback(handle, FuriHalSpiBusHandleEventActivate);
+}
+
+void furi_hal_spi_release(FuriHalSpiBusHandle* handle) {
+    assert(handle);
+    assert(handle->bus->current_handle == handle);
+
+    // Handle event and unset handle
+    handle->callback(handle, FuriHalSpiBusHandleEventDeactivate);
+    handle->bus->current_handle = NULL;
+
+    // Bus events
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventDeactivate);
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventUnlock);
 }
 }
 
 
-void furi_hal_spi_bus_end_txrx(const FuriHalSpiBus* bus, uint32_t timeout) {
-    while(LL_SPI_GetTxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_TX_FIFO_EMPTY)
+static void furi_hal_spi_bus_end_txrx(FuriHalSpiBusHandle* handle, uint32_t timeout) {
+    while(LL_SPI_GetTxFIFOLevel(handle->bus->spi) != LL_SPI_TX_FIFO_EMPTY)
         ;
         ;
-    while(LL_SPI_IsActiveFlag_BSY((SPI_TypeDef*)bus->spi))
+    while(LL_SPI_IsActiveFlag_BSY(handle->bus->spi))
         ;
         ;
-    while(LL_SPI_GetRxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
-        LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
+    while(LL_SPI_GetRxFIFOLevel(handle->bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
+        LL_SPI_ReceiveData8(handle->bus->spi);
     }
     }
 }
 }
 
 
-bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
-    assert(bus);
+bool furi_hal_spi_bus_rx(
+    FuriHalSpiBusHandle* handle,
+    uint8_t* buffer,
+    size_t size,
+    uint32_t timeout) {
+    assert(handle);
+    assert(handle->bus->current_handle == handle);
     assert(buffer);
     assert(buffer);
     assert(size > 0);
     assert(size > 0);
 
 
-    return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout);
+    return furi_hal_spi_bus_trx(handle, buffer, buffer, size, timeout);
 }
 }
 
 
-bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
-    assert(bus);
+bool furi_hal_spi_bus_tx(
+    FuriHalSpiBusHandle* handle,
+    uint8_t* buffer,
+    size_t size,
+    uint32_t timeout) {
+    assert(handle);
+    assert(handle->bus->current_handle == handle);
     assert(buffer);
     assert(buffer);
     assert(size > 0);
     assert(size > 0);
     bool ret = true;
     bool ret = true;
 
 
     while(size > 0) {
     while(size > 0) {
-        if(LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi)) {
-            LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *buffer);
+        if(LL_SPI_IsActiveFlag_TXE(handle->bus->spi)) {
+            LL_SPI_TransmitData8(handle->bus->spi, *buffer);
             buffer++;
             buffer++;
             size--;
             size--;
         }
         }
     }
     }
 
 
-    furi_hal_spi_bus_end_txrx(bus, timeout);
-    LL_SPI_ClearFlag_OVR((SPI_TypeDef*)bus->spi);
+    furi_hal_spi_bus_end_txrx(handle, timeout);
+    LL_SPI_ClearFlag_OVR(handle->bus->spi);
 
 
     return ret;
     return ret;
 }
 }
 
 
 bool furi_hal_spi_bus_trx(
 bool furi_hal_spi_bus_trx(
-    const FuriHalSpiBus* bus,
+    FuriHalSpiBusHandle* handle,
     uint8_t* tx_buffer,
     uint8_t* tx_buffer,
     uint8_t* rx_buffer,
     uint8_t* rx_buffer,
     size_t size,
     size_t size,
     uint32_t timeout) {
     uint32_t timeout) {
-    assert(bus);
+    assert(handle);
+    assert(handle->bus->current_handle == handle);
     assert(tx_buffer);
     assert(tx_buffer);
     assert(rx_buffer);
     assert(rx_buffer);
     assert(size > 0);
     assert(size > 0);
+
     bool ret = true;
     bool ret = true;
     size_t tx_size = size;
     size_t tx_size = size;
     bool tx_allowed = true;
     bool tx_allowed = true;
 
 
     while(size > 0) {
     while(size > 0) {
-        if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi) && tx_allowed) {
-            LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *tx_buffer);
+        if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) {
+            LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
             tx_buffer++;
             tx_buffer++;
             tx_size--;
             tx_size--;
             tx_allowed = false;
             tx_allowed = false;
         }
         }
 
 
-        if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef*)bus->spi)) {
-            *rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
+        if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) {
+            *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
             rx_buffer++;
             rx_buffer++;
             size--;
             size--;
             tx_allowed = true;
             tx_allowed = true;
         }
         }
     }
     }
 
 
-    furi_hal_spi_bus_end_txrx(bus, timeout);
-
-    return ret;
-}
-
-void furi_hal_spi_device_configure(const FuriHalSpiDevice* device) {
-    assert(device);
-    assert(device->config);
-
-    furi_hal_spi_bus_configure(device->bus, device->config);
-}
-
-const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) {
-    assert(device_id < FuriHalSpiDeviceIdMax);
-
-    const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id];
-    assert(device);
-
-    furi_hal_spi_bus_lock(device->bus);
-    furi_hal_spi_device_configure(device);
-
-    return device;
-}
-
-void furi_hal_spi_device_return(const FuriHalSpiDevice* device) {
-    furi_hal_spi_bus_unlock(device->bus);
-}
-
-bool furi_hal_spi_device_rx(
-    const FuriHalSpiDevice* device,
-    uint8_t* buffer,
-    size_t size,
-    uint32_t timeout) {
-    assert(device);
-    assert(buffer);
-    assert(size > 0);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_rx(device->bus, buffer, size, timeout);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
-
-    return ret;
-}
-
-bool furi_hal_spi_device_tx(
-    const FuriHalSpiDevice* device,
-    uint8_t* buffer,
-    size_t size,
-    uint32_t timeout) {
-    assert(device);
-    assert(buffer);
-    assert(size > 0);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_tx(device->bus, buffer, size, timeout);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
-
-    return ret;
-}
-
-bool furi_hal_spi_device_trx(
-    const FuriHalSpiDevice* device,
-    uint8_t* tx_buffer,
-    uint8_t* rx_buffer,
-    size_t size,
-    uint32_t timeout) {
-    assert(device);
-    assert(tx_buffer);
-    assert(rx_buffer);
-    assert(size > 0);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, timeout);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
+    furi_hal_spi_bus_end_txrx(handle, timeout);
 
 
     return ret;
     return ret;
 }
 }

+ 0 - 129
bootloader/targets/f6/furi-hal/furi-hal-spi.h

@@ -1,129 +0,0 @@
-#pragma once
-
-#include "main.h"
-
-#include "furi-hal-spi-config.h"
-#include <furi-hal-gpio.h>
-
-#include <stdbool.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Init SPI API
- */
-void furi_hal_spi_init();
-
-/* Bus Level API */
-
-/** Lock SPI bus
- * Takes bus mutex, if used
- */
-void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
-
-/** Unlock SPI bus
- * Releases BUS mutex, if used
- */
-void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
-
-/**
- * Configure SPI bus
- * @param bus - spi bus handler
- * @param config - spi configuration structure
- */
-void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config);
-
-/** SPI Receive
- * @param bus - spi bus handler
- * @param buffer - receive buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
-
-/** SPI Transmit
- * @param bus - spi bus handler
- * @param buffer - transmit buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
-
-/** SPI Transmit and Receive
- * @param bus - spi bus handlere
- * @param tx_buffer - device handle
- * @param rx_buffer - device handle
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_bus_trx(
-    const FuriHalSpiBus* bus,
-    uint8_t* tx_buffer,
-    uint8_t* rx_buffer,
-    size_t size,
-    uint32_t timeout);
-
-/* Device Level API */
-
-/** Reconfigure SPI bus for device
- * @param device - device description
- */
-void furi_hal_spi_device_configure(const FuriHalSpiDevice* device);
-
-/** Get Device handle
- * And lock access to the corresponding SPI BUS
- * @param device_id - device identifier
- * @return device handle
- */
-const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id);
-
-/** Return Device handle
- * And unlock access to the corresponding SPI BUS
- * @param device - device handle
- */
-void furi_hal_spi_device_return(const FuriHalSpiDevice* device);
-
-/** SPI Recieve
- * @param device - device handle
- * @param buffer - receive buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_device_rx(
-    const FuriHalSpiDevice* device,
-    uint8_t* buffer,
-    size_t size,
-    uint32_t timeout);
-
-/** SPI Transmit
- * @param device - device handle
- * @param buffer - transmit buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_device_tx(
-    const FuriHalSpiDevice* device,
-    uint8_t* buffer,
-    size_t size,
-    uint32_t timeout);
-
-/** SPI Transmit and Receive
- * @param device - device handle
- * @param tx_buffer - device handle
- * @param rx_buffer - device handle
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_device_trx(
-    const FuriHalSpiDevice* device,
-    uint8_t* tx_buffer,
-    uint8_t* rx_buffer,
-    size_t size,
-    uint32_t timeout);
-
-#ifdef __cplusplus
-}
-#endif

+ 217 - 41
bootloader/targets/f7/furi-hal/furi-hal-spi-config.c

@@ -1,10 +1,9 @@
 #include <furi-hal-spi-config.h>
 #include <furi-hal-spi-config.h>
 #include <furi-hal-resources.h>
 #include <furi-hal-resources.h>
 
 
-#define SPI_R SPI1
-#define SPI_D SPI2
+/* SPI Presets */
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -17,7 +16,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -30,7 +29,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -43,10 +42,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-/**
- * SD Card in fast mode (after init)
- */
-const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -59,10 +55,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-/**
- * SD Card in slow mode (before init)
- */
-const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -75,40 +68,223 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const FuriHalSpiBus spi_r = {
-    .spi = SPI_R,
+/* SPI Buses */
+
+static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
+    if(event == FuriHalSpiBusEventInit) {
+        LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
+        LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
+        bus->current_handle = NULL;
+    } else if(event == FuriHalSpiBusEventDeinit) {
+    } else if(event == FuriHalSpiBusEventLock) {
+    } else if(event == FuriHalSpiBusEventUnlock) {
+    } else if(event == FuriHalSpiBusEventActivate) {
+        LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
+    } else if(event == FuriHalSpiBusEventDeactivate) {
+        LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
+    }
+}
+
+FuriHalSpiBus furi_hal_spi_bus_r = {
+    .spi = SPI1,
+    .callback = furi_hal_spi_bus_r_event_callback,
+};
+
+static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
+    if(event == FuriHalSpiBusEventInit) {
+        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
+        LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
+        bus->current_handle = NULL;
+    } else if(event == FuriHalSpiBusEventDeinit) {
+    } else if(event == FuriHalSpiBusEventLock) {
+    } else if(event == FuriHalSpiBusEventUnlock) {
+    } else if(event == FuriHalSpiBusEventActivate) {
+        LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
+    } else if(event == FuriHalSpiBusEventDeactivate) {
+        LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
+    }
+}
+
+FuriHalSpiBus furi_hal_spi_bus_d = {
+    .spi = SPI2,
+    .callback = furi_hal_spi_bus_d_event_callback,
+};
+
+/* SPI Bus Handles */
+
+inline static void furi_hal_spi_bus_r_handle_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event,
+    const LL_SPI_InitTypeDef* preset) {
+    if(event == FuriHalSpiBusHandleEventInit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    } else if(event == FuriHalSpiBusHandleEventDeinit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+    } else if(event == FuriHalSpiBusHandleEventActivate) {
+        LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
+        LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
+        LL_SPI_Enable(handle->bus->spi);
+
+        hal_gpio_init_ex(
+            handle->miso,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI1);
+        hal_gpio_init_ex(
+            handle->mosi,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI1);
+        hal_gpio_init_ex(
+            handle->sck,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI1);
+
+        hal_gpio_write(handle->cs, false);
+    } else if(event == FuriHalSpiBusHandleEventDeactivate) {
+        hal_gpio_write(handle->cs, true);
+
+        hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+
+        LL_SPI_Disable(handle->bus->spi);
+    }
+}
+
+static void furi_hal_spi_bus_handle_subghz_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_8m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = {
+    .bus = &furi_hal_spi_bus_r,
+    .callback = furi_hal_spi_bus_handle_subghz_event_callback,
+    .miso = &gpio_spi_r_miso,
+    .mosi = &gpio_spi_r_mosi,
+    .sck = &gpio_spi_r_sck,
+    .cs = &gpio_subghz_cs,
+};
+
+static void furi_hal_spi_bus_handle_nfc_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = {
+    .bus = &furi_hal_spi_bus_r,
+    .callback = furi_hal_spi_bus_handle_nfc_event_callback,
     .miso = &gpio_spi_r_miso,
     .miso = &gpio_spi_r_miso,
     .mosi = &gpio_spi_r_mosi,
     .mosi = &gpio_spi_r_mosi,
-    .clk = &gpio_spi_r_sck,
+    .sck = &gpio_spi_r_sck,
+    .cs = &gpio_nfc_cs,
+};
+
+static void furi_hal_spi_bus_handle_external_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = {
+    .bus = &furi_hal_spi_bus_r,
+    .callback = furi_hal_spi_bus_handle_external_event_callback,
+    .miso = &gpio_ext_pa6,
+    .mosi = &gpio_ext_pa7,
+    .sck = &gpio_ext_pb3,
+    .cs = &gpio_ext_pa4,
 };
 };
 
 
-const FuriHalSpiBus spi_d = {
-    .spi = SPI_D,
+inline static void furi_hal_spi_bus_d_handle_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event,
+    const LL_SPI_InitTypeDef* preset) {
+    if(event == FuriHalSpiBusHandleEventInit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
+
+        hal_gpio_init_ex(
+            handle->miso,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI2);
+        hal_gpio_init_ex(
+            handle->mosi,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI2);
+        hal_gpio_init_ex(
+            handle->sck,
+            GpioModeAltFunctionPushPull,
+            GpioPullNo,
+            GpioSpeedVeryHigh,
+            GpioAltFn5SPI2);
+
+    } else if(event == FuriHalSpiBusHandleEventDeinit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullUp, GpioSpeedLow);
+    } else if(event == FuriHalSpiBusHandleEventActivate) {
+        LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
+        LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
+        LL_SPI_Enable(handle->bus->spi);
+        hal_gpio_write(handle->cs, false);
+    } else if(event == FuriHalSpiBusHandleEventDeactivate) {
+        hal_gpio_write(handle->cs, true);
+        LL_SPI_Disable(handle->bus->spi);
+    }
+}
+
+static void furi_hal_spi_bus_handle_display_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_4m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_display = {
+    .bus = &furi_hal_spi_bus_d,
+    .callback = furi_hal_spi_bus_handle_display_event_callback,
     .miso = &gpio_spi_d_miso,
     .miso = &gpio_spi_d_miso,
     .mosi = &gpio_spi_d_mosi,
     .mosi = &gpio_spi_d_mosi,
-    .clk = &gpio_spi_d_sck,
+    .sck = &gpio_spi_d_sck,
+    .cs = &gpio_display_cs,
 };
 };
 
 
-const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax] = {
-    {
-        .bus = &spi_r,
-        .config = &furi_hal_spi_config_subghz,
-        .chip_select = &gpio_subghz_cs,
-    },
-    {
-        .bus = &spi_d,
-        .config = &furi_hal_spi_config_display,
-        .chip_select = &gpio_display_cs,
-    },
-    {
-        .bus = &spi_d,
-        .config = &furi_hal_spi_config_sd_fast,
-        .chip_select = &gpio_sdcard_cs,
-    },
-    {
-        .bus = &spi_d,
-        .config = &furi_hal_spi_config_sd_slow,
-        .chip_select = &gpio_sdcard_cs,
-    },
-    {.bus = &spi_r, .config = &furi_hal_spi_config_nfc, .chip_select = &gpio_nfc_cs},
+static void furi_hal_spi_bus_handle_sd_fast_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_16m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast = {
+    .bus = &furi_hal_spi_bus_d,
+    .callback = furi_hal_spi_bus_handle_sd_fast_event_callback,
+    .miso = &gpio_spi_d_miso,
+    .mosi = &gpio_spi_d_mosi,
+    .sck = &gpio_spi_d_sck,
+    .cs = &gpio_sdcard_cs,
+};
+
+static void furi_hal_spi_bus_handle_sd_slow_event_callback(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow = {
+    .bus = &furi_hal_spi_bus_d,
+    .callback = furi_hal_spi_bus_handle_sd_slow_event_callback,
+    .miso = &gpio_spi_d_miso,
+    .mosi = &gpio_spi_d_mosi,
+    .sck = &gpio_spi_d_sck,
+    .cs = &gpio_sdcard_cs,
 };
 };

+ 46 - 46
bootloader/targets/f7/furi-hal/furi-hal-spi-config.h

@@ -1,60 +1,60 @@
 #pragma once
 #pragma once
 
 
-#include <furi-hal-gpio.h>
-#include <stm32wbxx_ll_spi.h>
+#include <furi-hal-spi-types.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_nfc;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_subghz;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_display;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow;
+/** Preset for ST25R916 */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m;
 
 
-/** FURI HAL SPI BUS handler
- * Structure content may change at some point
- */
-typedef struct {
-    const SPI_TypeDef* spi;
-    const GpioPin* miso;
-    const GpioPin* mosi;
-    const GpioPin* clk;
-} FuriHalSpiBus;
-
-/** FURI HAL SPI Device handler
- * Structure content may change at some point
- */
-typedef struct {
-    const FuriHalSpiBus* bus;
-    const LL_SPI_InitTypeDef* config;
-    const GpioPin* chip_select;
-} FuriHalSpiDevice;
-
-/** FURI HAL SPI Standard Device IDs */
-typedef enum {
-    FuriHalSpiDeviceIdSubGhz, /** SubGhz: CC1101, non-standard SPI usage */
-    FuriHalSpiDeviceIdDisplay, /** Display: ERC12864, only have MOSI */
-    FuriHalSpiDeviceIdSdCardFast, /** SDCARD: fast mode, after initialization */
-    FuriHalSpiDeviceIdSdCardSlow, /** SDCARD: slow mode, before initialization */
-    FuriHalSpiDeviceIdNfc, /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */
-
-    FuriHalSpiDeviceIdMax, /** Service Value, do not use */
-} FuriHalSpiDeviceId;
-
-/** Furi Hal Spi Bus R
- * CC1101, Nfc
- */
-extern const FuriHalSpiBus spi_r;
+/** Preset for CC1101 */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m;
+
+/** Preset for ST7567 (Display) */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m;
+
+/** Preset for SdCard in fast mode */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m;
+
+/** Preset for SdCard in slow mode */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m;
 
 
-/** Furi Hal Spi Bus D
- * Display, SdCard
+/** Furi Hal Spi Bus R (Radio: CC1101, Nfc, External)*/
+extern FuriHalSpiBus furi_hal_spi_bus_r;
+
+/** Furi Hal Spi Bus D (Display, SdCard) */
+extern FuriHalSpiBus furi_hal_spi_bus_d;
+
+/** CC1101 on `furi_hal_spi_bus_r` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz;
+
+/** ST25R3916 on `furi_hal_spi_bus_r` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc;
+
+/** External on `furi_hal_spi_bus_r`
+ * Preset: `furi_hal_spi_preset_1edge_low_2m`
+ * 
+ * miso: pa6
+ * mosi: pa7
+ * sck: pb3
+ * cs:  pa4 (software controlled)
+ * 
+ * @warning not initialized by default, call `furi_hal_spi_bus_handle_init` to initialize
+ * Bus pins are floating on inactive state, CS high after initialization
+ * 
  */
  */
-extern const FuriHalSpiBus spi_d;
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_external;
+
+/** ST7567(Display) on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_display;
+
+/** SdCard in fast mode on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast;
 
 
-/** Furi Hal Spi devices */
-extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax];
+/** SdCard in slow mode on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 64 - 0
bootloader/targets/f7/furi-hal/furi-hal-spi-types.h

@@ -0,0 +1,64 @@
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <furi-hal-gpio.h>
+
+#include <stm32wbxx_ll_spi.h>
+#include <stm32wbxx_ll_rcc.h>
+#include <stm32wbxx_ll_bus.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct FuriHalSpiBus FuriHalSpiBus;
+typedef struct FuriHalSpiBusHandle FuriHalSpiBusHandle;
+
+/** FuriHal spi bus states */
+typedef enum {
+    FuriHalSpiBusEventInit, /**< Bus initialization event, called on system start */
+    FuriHalSpiBusEventDeinit, /**< Bus deinitialization event, called on system stop */
+    FuriHalSpiBusEventLock, /**< Bus lock event, called before activation */
+    FuriHalSpiBusEventUnlock, /**< Bus unlock event, called after deactivation */
+    FuriHalSpiBusEventActivate, /**< Bus activation event, called before handle activation */
+    FuriHalSpiBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation  */
+} FuriHalSpiBusEvent;
+
+/** FuriHal spi bus event callback */
+typedef void (*FuriHalSpiBusEventCallback)(FuriHalSpiBus* bus, FuriHalSpiBusEvent event);
+
+/** FuriHal spi bus */
+struct FuriHalSpiBus {
+    SPI_TypeDef* spi;
+    FuriHalSpiBusEventCallback callback;
+    FuriHalSpiBusHandle* current_handle;
+};
+
+/** FuriHal spi handle states */
+typedef enum {
+    FuriHalSpiBusHandleEventInit, /**< Handle init, called on system start, initialize gpio for idle state */
+    FuriHalSpiBusHandleEventDeinit, /**< Handle deinit, called on system stop, deinitialize gpio for default state */
+    FuriHalSpiBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
+    FuriHalSpiBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
+} FuriHalSpiBusHandleEvent;
+
+/** FuriHal spi handle event callback */
+typedef void (*FuriHalSpiBusHandleEventCallback)(
+    FuriHalSpiBusHandle* handle,
+    FuriHalSpiBusHandleEvent event);
+
+/** FuriHal spi handle */
+struct FuriHalSpiBusHandle {
+    FuriHalSpiBus* bus;
+    FuriHalSpiBusHandleEventCallback callback;
+    const GpioPin* miso;
+    const GpioPin* mosi;
+    const GpioPin* sck;
+    const GpioPin* cs;
+};
+
+#ifdef __cplusplus
+}
+#endif

+ 79 - 168
bootloader/targets/f7/furi-hal/furi-hal-spi.c

@@ -2,239 +2,150 @@
 #include "furi-hal-resources.h"
 #include "furi-hal-resources.h"
 
 
 #include <stdbool.h>
 #include <stdbool.h>
+#include <string.h>
 #include <assert.h>
 #include <assert.h>
 
 
 #include <stm32wbxx_ll_spi.h>
 #include <stm32wbxx_ll_spi.h>
 #include <stm32wbxx_ll_utils.h>
 #include <stm32wbxx_ll_utils.h>
 #include <stm32wbxx_ll_cortex.h>
 #include <stm32wbxx_ll_cortex.h>
 
 
-extern void Enable_SPI(SPI_TypeDef* spi);
-
 void furi_hal_spi_init() {
 void furi_hal_spi_init() {
-    for(size_t i = 0; i < FuriHalSpiDeviceIdMax; ++i) {
-        hal_gpio_write(furi_hal_spi_devices[i].chip_select, true);
-        hal_gpio_init(
-            furi_hal_spi_devices[i].chip_select,
-            GpioModeOutputPushPull,
-            GpioPullNo,
-            GpioSpeedVeryHigh);
-    }
-
-    hal_gpio_init_ex(
-        &gpio_spi_r_miso,
-        GpioModeAltFunctionPushPull,
-        GpioPullNo,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI1);
-    hal_gpio_init_ex(
-        &gpio_spi_r_mosi,
-        GpioModeAltFunctionPushPull,
-        GpioPullNo,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI1);
-    hal_gpio_init_ex(
-        &gpio_spi_r_sck,
-        GpioModeAltFunctionPushPull,
-        GpioPullNo,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI1);
-
-    hal_gpio_init_ex(
-        &gpio_spi_d_miso,
-        GpioModeAltFunctionPushPull,
-        GpioPullUp,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI2);
-    hal_gpio_init_ex(
-        &gpio_spi_d_mosi,
-        GpioModeAltFunctionPushPull,
-        GpioPullUp,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI2);
-    hal_gpio_init_ex(
-        &gpio_spi_d_sck,
-        GpioModeAltFunctionPushPull,
-        GpioPullUp,
-        GpioSpeedVeryHigh,
-        GpioAltFn5SPI2);
+    furi_hal_spi_bus_init(&furi_hal_spi_bus_r);
+    furi_hal_spi_bus_init(&furi_hal_spi_bus_d);
+
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow);
 }
 }
 
 
-void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus) {
+void furi_hal_spi_bus_init(FuriHalSpiBus* bus) {
     assert(bus);
     assert(bus);
+    bus->callback(bus, FuriHalSpiBusEventInit);
 }
 }
 
 
-void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) {
+void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus) {
     assert(bus);
     assert(bus);
+    bus->callback(bus, FuriHalSpiBusEventDeinit);
 }
 }
 
 
-void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config) {
-    assert(bus);
-    LL_SPI_DeInit((SPI_TypeDef*)bus->spi);
-    LL_SPI_Init((SPI_TypeDef*)bus->spi, (LL_SPI_InitTypeDef*)config);
-    LL_SPI_SetRxFIFOThreshold((SPI_TypeDef*)bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
-    LL_SPI_Enable((SPI_TypeDef*)bus->spi);
+void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle) {
+    assert(handle);
+    handle->callback(handle, FuriHalSpiBusHandleEventInit);
+}
+
+void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle) {
+    assert(handle);
+    handle->callback(handle, FuriHalSpiBusHandleEventDeinit);
+}
+
+void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle) {
+    assert(handle);
+
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventLock);
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventActivate);
+
+    assert(handle->bus->current_handle == NULL);
+
+    handle->bus->current_handle = handle;
+    handle->callback(handle, FuriHalSpiBusHandleEventActivate);
+}
+
+void furi_hal_spi_release(FuriHalSpiBusHandle* handle) {
+    assert(handle);
+    assert(handle->bus->current_handle == handle);
+
+    // Handle event and unset handle
+    handle->callback(handle, FuriHalSpiBusHandleEventDeactivate);
+    handle->bus->current_handle = NULL;
+
+    // Bus events
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventDeactivate);
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventUnlock);
 }
 }
 
 
-void furi_hal_spi_bus_end_txrx(const FuriHalSpiBus* bus, uint32_t timeout) {
-    while(LL_SPI_GetTxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_TX_FIFO_EMPTY)
+static void furi_hal_spi_bus_end_txrx(FuriHalSpiBusHandle* handle, uint32_t timeout) {
+    while(LL_SPI_GetTxFIFOLevel(handle->bus->spi) != LL_SPI_TX_FIFO_EMPTY)
         ;
         ;
-    while(LL_SPI_IsActiveFlag_BSY((SPI_TypeDef*)bus->spi))
+    while(LL_SPI_IsActiveFlag_BSY(handle->bus->spi))
         ;
         ;
-    while(LL_SPI_GetRxFIFOLevel((SPI_TypeDef*)bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
-        LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
+    while(LL_SPI_GetRxFIFOLevel(handle->bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
+        LL_SPI_ReceiveData8(handle->bus->spi);
     }
     }
 }
 }
 
 
-bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
-    assert(bus);
+bool furi_hal_spi_bus_rx(
+    FuriHalSpiBusHandle* handle,
+    uint8_t* buffer,
+    size_t size,
+    uint32_t timeout) {
+    assert(handle);
+    assert(handle->bus->current_handle == handle);
     assert(buffer);
     assert(buffer);
     assert(size > 0);
     assert(size > 0);
 
 
-    return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout);
+    return furi_hal_spi_bus_trx(handle, buffer, buffer, size, timeout);
 }
 }
 
 
-bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
-    assert(bus);
+bool furi_hal_spi_bus_tx(
+    FuriHalSpiBusHandle* handle,
+    uint8_t* buffer,
+    size_t size,
+    uint32_t timeout) {
+    assert(handle);
+    assert(handle->bus->current_handle == handle);
     assert(buffer);
     assert(buffer);
     assert(size > 0);
     assert(size > 0);
     bool ret = true;
     bool ret = true;
 
 
     while(size > 0) {
     while(size > 0) {
-        if(LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi)) {
-            LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *buffer);
+        if(LL_SPI_IsActiveFlag_TXE(handle->bus->spi)) {
+            LL_SPI_TransmitData8(handle->bus->spi, *buffer);
             buffer++;
             buffer++;
             size--;
             size--;
         }
         }
     }
     }
 
 
-    furi_hal_spi_bus_end_txrx(bus, timeout);
-    LL_SPI_ClearFlag_OVR((SPI_TypeDef*)bus->spi);
+    furi_hal_spi_bus_end_txrx(handle, timeout);
+    LL_SPI_ClearFlag_OVR(handle->bus->spi);
 
 
     return ret;
     return ret;
 }
 }
 
 
 bool furi_hal_spi_bus_trx(
 bool furi_hal_spi_bus_trx(
-    const FuriHalSpiBus* bus,
+    FuriHalSpiBusHandle* handle,
     uint8_t* tx_buffer,
     uint8_t* tx_buffer,
     uint8_t* rx_buffer,
     uint8_t* rx_buffer,
     size_t size,
     size_t size,
     uint32_t timeout) {
     uint32_t timeout) {
-    assert(bus);
+    assert(handle);
+    assert(handle->bus->current_handle == handle);
     assert(tx_buffer);
     assert(tx_buffer);
     assert(rx_buffer);
     assert(rx_buffer);
     assert(size > 0);
     assert(size > 0);
+
     bool ret = true;
     bool ret = true;
     size_t tx_size = size;
     size_t tx_size = size;
     bool tx_allowed = true;
     bool tx_allowed = true;
 
 
     while(size > 0) {
     while(size > 0) {
-        if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi) && tx_allowed) {
-            LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *tx_buffer);
+        if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) {
+            LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
             tx_buffer++;
             tx_buffer++;
             tx_size--;
             tx_size--;
             tx_allowed = false;
             tx_allowed = false;
         }
         }
 
 
-        if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef*)bus->spi)) {
-            *rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
+        if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) {
+            *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
             rx_buffer++;
             rx_buffer++;
             size--;
             size--;
             tx_allowed = true;
             tx_allowed = true;
         }
         }
     }
     }
 
 
-    furi_hal_spi_bus_end_txrx(bus, timeout);
-
-    return ret;
-}
-
-void furi_hal_spi_device_configure(const FuriHalSpiDevice* device) {
-    assert(device);
-    assert(device->config);
-
-    furi_hal_spi_bus_configure(device->bus, device->config);
-}
-
-const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) {
-    assert(device_id < FuriHalSpiDeviceIdMax);
-
-    const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id];
-    assert(device);
-
-    furi_hal_spi_bus_lock(device->bus);
-    furi_hal_spi_device_configure(device);
-
-    return device;
-}
-
-void furi_hal_spi_device_return(const FuriHalSpiDevice* device) {
-    furi_hal_spi_bus_unlock(device->bus);
-}
-
-bool furi_hal_spi_device_rx(
-    const FuriHalSpiDevice* device,
-    uint8_t* buffer,
-    size_t size,
-    uint32_t timeout) {
-    assert(device);
-    assert(buffer);
-    assert(size > 0);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_rx(device->bus, buffer, size, timeout);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
-
-    return ret;
-}
-
-bool furi_hal_spi_device_tx(
-    const FuriHalSpiDevice* device,
-    uint8_t* buffer,
-    size_t size,
-    uint32_t timeout) {
-    assert(device);
-    assert(buffer);
-    assert(size > 0);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_tx(device->bus, buffer, size, timeout);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
-
-    return ret;
-}
-
-bool furi_hal_spi_device_trx(
-    const FuriHalSpiDevice* device,
-    uint8_t* tx_buffer,
-    uint8_t* rx_buffer,
-    size_t size,
-    uint32_t timeout) {
-    assert(device);
-    assert(tx_buffer);
-    assert(rx_buffer);
-    assert(size > 0);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, timeout);
-
-    if(device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
+    furi_hal_spi_bus_end_txrx(handle, timeout);
 
 
     return ret;
     return ret;
 }
 }

+ 0 - 129
bootloader/targets/f7/furi-hal/furi-hal-spi.h

@@ -1,129 +0,0 @@
-#pragma once
-
-#include "main.h"
-
-#include "furi-hal-spi-config.h"
-#include <furi-hal-gpio.h>
-
-#include <stdbool.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Init SPI API
- */
-void furi_hal_spi_init();
-
-/* Bus Level API */
-
-/** Lock SPI bus
- * Takes bus mutex, if used
- */
-void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
-
-/** Unlock SPI bus
- * Releases BUS mutex, if used
- */
-void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
-
-/**
- * Configure SPI bus
- * @param bus - spi bus handler
- * @param config - spi configuration structure
- */
-void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config);
-
-/** SPI Receive
- * @param bus - spi bus handler
- * @param buffer - receive buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
-
-/** SPI Transmit
- * @param bus - spi bus handler
- * @param buffer - transmit buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
-
-/** SPI Transmit and Receive
- * @param bus - spi bus handlere
- * @param tx_buffer - device handle
- * @param rx_buffer - device handle
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_bus_trx(
-    const FuriHalSpiBus* bus,
-    uint8_t* tx_buffer,
-    uint8_t* rx_buffer,
-    size_t size,
-    uint32_t timeout);
-
-/* Device Level API */
-
-/** Reconfigure SPI bus for device
- * @param device - device description
- */
-void furi_hal_spi_device_configure(const FuriHalSpiDevice* device);
-
-/** Get Device handle
- * And lock access to the corresponding SPI BUS
- * @param device_id - device identifier
- * @return device handle
- */
-const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id);
-
-/** Return Device handle
- * And unlock access to the corresponding SPI BUS
- * @param device - device handle
- */
-void furi_hal_spi_device_return(const FuriHalSpiDevice* device);
-
-/** SPI Recieve
- * @param device - device handle
- * @param buffer - receive buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_device_rx(
-    const FuriHalSpiDevice* device,
-    uint8_t* buffer,
-    size_t size,
-    uint32_t timeout);
-
-/** SPI Transmit
- * @param device - device handle
- * @param buffer - transmit buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_device_tx(
-    const FuriHalSpiDevice* device,
-    uint8_t* buffer,
-    size_t size,
-    uint32_t timeout);
-
-/** SPI Transmit and Receive
- * @param device - device handle
- * @param tx_buffer - device handle
- * @param rx_buffer - device handle
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
- */
-bool furi_hal_spi_device_trx(
-    const FuriHalSpiDevice* device,
-    uint8_t* tx_buffer,
-    uint8_t* rx_buffer,
-    size_t size,
-    uint32_t timeout);
-
-#ifdef __cplusplus
-}
-#endif

+ 102 - 0
bootloader/targets/furi-hal-include/furi-hal-spi.h

@@ -0,0 +1,102 @@
+#pragma once
+
+#include <furi-hal-spi-config.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Initialize SPI HAL */
+void furi_hal_spi_init();
+
+/** Initialize SPI Bus
+ *
+ * @param      handle  pointer to FuriHalSpiBus instance
+ */
+void furi_hal_spi_bus_init(FuriHalSpiBus* bus);
+
+/** Deinitialize SPI Bus
+ *
+ * @param      handle  pointer to FuriHalSpiBus instance
+ */
+void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus);
+
+/** Initialize SPI Bus Handle
+ *
+ * @param      handle  pointer to FuriHalSpiBusHandle instance
+ */
+void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle);
+
+/** Deinitialize SPI Bus Handle
+ *
+ * @param      handle  pointer to FuriHalSpiBusHandle instance
+ */
+void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle);
+
+/** Acquire SPI bus
+ *
+ * @warning blocking, calls `furi_crash` on programming error, CS transition is up to handler event routine
+ *
+ * @param      handle  pointer to FuriHalSpiBusHandle instance
+ */
+void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle);
+
+/** Release SPI bus
+ *
+ * @warning calls `furi_crash` on programming error, CS transition is up to handler event routine
+ * 
+ * @param      handle  pointer to FuriHalSpiBusHandle instance
+ */
+void furi_hal_spi_release(FuriHalSpiBusHandle* handle);
+
+/** SPI Receive
+ *
+ * @param      handle   pointer to FuriHalSpiBusHandle instance
+ * @param      buffer   receive buffer
+ * @param      size     transaction size (buffer size)
+ * @param      timeout  operation timeout in ms
+ *
+ * @return     true on sucess
+ */
+bool furi_hal_spi_bus_rx(
+    FuriHalSpiBusHandle* handle,
+    uint8_t* buffer,
+    size_t size,
+    uint32_t timeout);
+
+/** SPI Transmit
+ *
+ * @param      handle   pointer to FuriHalSpiBusHandle instance
+ * @param      buffer   transmit buffer
+ * @param      size     transaction size (buffer size)
+ * @param      timeout  operation timeout in ms
+ *
+ * @return     true on success
+ */
+bool furi_hal_spi_bus_tx(
+    FuriHalSpiBusHandle* handle,
+    uint8_t* buffer,
+    size_t size,
+    uint32_t timeout);
+
+/** SPI Transmit and Receive
+ *
+ * @param      handle     pointer to FuriHalSpiBusHandle instance
+ * @param      tx_buffer  pointer to tx buffer
+ * @param      rx_buffer  pointer to rx buffer
+ * @param      size       transaction size (buffer size)
+ * @param      timeout    operation timeout in ms
+ *
+ * @return     true on success
+ */
+bool furi_hal_spi_bus_trx(
+    FuriHalSpiBusHandle* handle,
+    uint8_t* tx_buffer,
+    uint8_t* rx_buffer,
+    size_t size,
+    uint32_t timeout);
+
+#ifdef __cplusplus
+}
+#endif

+ 5 - 7
firmware/targets/f6/fatfs/spi_sd_hal.c

@@ -7,8 +7,6 @@
 const uint32_t SpiTimeout = 1000;
 const uint32_t SpiTimeout = 1000;
 uint8_t SD_IO_WriteByte(uint8_t Data);
 uint8_t SD_IO_WriteByte(uint8_t Data);
 
 
-static const FuriHalSpiDevice* sd_spi_dev = &furi_hal_spi_devices[FuriHalSpiDeviceIdSdCardFast];
-
 /******************************************************************************
 /******************************************************************************
                             BUS OPERATIONS
                             BUS OPERATIONS
  *******************************************************************************/
  *******************************************************************************/
@@ -21,7 +19,7 @@ static const FuriHalSpiDevice* sd_spi_dev = &furi_hal_spi_devices[FuriHalSpiDevi
  * @retval None
  * @retval None
  */
  */
 static void SPIx_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) {
 static void SPIx_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) {
-    furi_check(furi_hal_spi_bus_trx(sd_spi_dev->bus, (uint8_t*)DataIn, DataOut, DataLength, SpiTimeout));
+    furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, (uint8_t*)DataIn, DataOut, DataLength, SpiTimeout));
 }
 }
 
 
 /**
 /**
@@ -30,7 +28,7 @@ static void SPIx_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t
  * @retval None
  * @retval None
  */
  */
 __attribute__((unused)) static void SPIx_Write(uint8_t Value) {
 __attribute__((unused)) static void SPIx_Write(uint8_t Value) {
-    furi_check(furi_hal_spi_bus_tx(sd_spi_dev->bus, (uint8_t*)&Value, 1, SpiTimeout));
+    furi_check(furi_hal_spi_bus_tx(furi_hal_sd_spi_handle, (uint8_t*)&Value, 1, SpiTimeout));
 }
 }
 
 
 /******************************************************************************
 /******************************************************************************
@@ -47,7 +45,7 @@ void SD_IO_Init(void) {
     uint8_t counter = 0;
     uint8_t counter = 0;
 
 
     /* SD chip select high */
     /* SD chip select high */
-    hal_gpio_write(sd_spi_dev->chip_select, true);
+    hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
     delay_us(10);
     delay_us(10);
 
 
     /* Send dummy byte 0xFF, 10 times with CS high */
     /* Send dummy byte 0xFF, 10 times with CS high */
@@ -67,9 +65,9 @@ void SD_IO_CSState(uint8_t val) {
     /* Some SD Cards are prone to fail if CLK-ed too soon after CS transition. Worst case found: 8us */
     /* Some SD Cards are prone to fail if CLK-ed too soon after CS transition. Worst case found: 8us */
     if(val == 1) {
     if(val == 1) {
         delay_us(10); // Exit guard time for some SD cards
         delay_us(10); // Exit guard time for some SD cards
-        hal_gpio_write(sd_spi_dev->chip_select, true);
+        hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
     } else {
     } else {
-        hal_gpio_write(sd_spi_dev->chip_select, false);
+        hal_gpio_write(furi_hal_sd_spi_handle->cs, false);
         delay_us(10); // Entry guard time for some SD cards
         delay_us(10); // Entry guard time for some SD cards
     }
     }
 }
 }

+ 17 - 20
firmware/targets/f6/fatfs/stm32_adafruit_sd.c

@@ -91,12 +91,7 @@
 #include "stdlib.h"
 #include "stdlib.h"
 #include "string.h"
 #include "string.h"
 #include "stdio.h"
 #include "stdio.h"
-#include <furi-hal-spi.h>
-#include <furi-hal-gpio.h>
-#include <furi-hal-resources.h>
-#include <furi-hal-power.h>
-#include <furi-hal-delay.h>
-#include <furi-hal-sd.h>
+#include <furi-hal.h>
 
 
 /** @addtogroup BSP
 /** @addtogroup BSP
   * @{
   * @{
@@ -284,22 +279,22 @@ static uint8_t SD_ReadData(void);
 /* Private functions ---------------------------------------------------------*/
 /* Private functions ---------------------------------------------------------*/
 
 
 void SD_SPI_Bus_To_Down_State(){
 void SD_SPI_Bus_To_Down_State(){
-    hal_gpio_init_ex(&gpio_spi_d_miso, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
-    hal_gpio_init_ex(&gpio_spi_d_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
-    hal_gpio_init_ex(&gpio_spi_d_sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
-
-    hal_gpio_write(&gpio_sdcard_cs, false);
-    hal_gpio_write(&gpio_spi_d_miso, false);
-    hal_gpio_write(&gpio_spi_d_mosi, false);
-    hal_gpio_write(&gpio_spi_d_sck, false);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->miso, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
+
+    hal_gpio_write(furi_hal_sd_spi_handle->cs, false);
+    hal_gpio_write(furi_hal_sd_spi_handle->miso, false);
+    hal_gpio_write(furi_hal_sd_spi_handle->mosi, false);
+    hal_gpio_write(furi_hal_sd_spi_handle->sck, false);
 }
 }
 
 
 void SD_SPI_Bus_To_Normal_State(){
 void SD_SPI_Bus_To_Normal_State(){
-    hal_gpio_write(&gpio_sdcard_cs, true);
+    hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
 
 
-    hal_gpio_init_ex(&gpio_spi_d_miso, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
-    hal_gpio_init_ex(&gpio_spi_d_mosi, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
-    hal_gpio_init_ex(&gpio_spi_d_sck, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->miso, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->mosi, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->sck, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
 }
 }
 
 
 /** @defgroup STM32_ADAFRUIT_SD_Private_Functions
 /** @defgroup STM32_ADAFRUIT_SD_Private_Functions
@@ -315,7 +310,8 @@ void SD_SPI_Bus_To_Normal_State(){
   */
   */
 uint8_t BSP_SD_Init(bool reset_card) {
 uint8_t BSP_SD_Init(bool reset_card) {
     /* Slow speed init */
     /* Slow speed init */
-    const FuriHalSpiDevice* sd_spi_slow_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardSlow);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_slow);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_slow;
 
 
     /* We must reset card in spi_lock context */
     /* We must reset card in spi_lock context */
     if(reset_card) {
     if(reset_card) {
@@ -344,7 +340,8 @@ uint8_t BSP_SD_Init(bool reset_card) {
         if(res == BSP_SD_OK) break;
         if(res == BSP_SD_OK) break;
     }
     }
 
 
-    furi_hal_spi_device_return(sd_spi_slow_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow);
 
 
     /* SD initialized and set to SPI mode properly */
     /* SD initialized and set to SPI mode properly */
     return res;
     return res;

+ 17 - 9
firmware/targets/f6/fatfs/user_diskio.c

@@ -35,7 +35,7 @@
 
 
 /* Includes ------------------------------------------------------------------*/
 /* Includes ------------------------------------------------------------------*/
 #include "user_diskio.h"
 #include "user_diskio.h"
-#include "furi-hal-spi.h"
+#include <furi-hal.h>
 /* Private typedef -----------------------------------------------------------*/
 /* Private typedef -----------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
 
 
@@ -87,11 +87,13 @@ Diskio_drvTypeDef USER_Driver = {
 DSTATUS USER_initialize(BYTE pdrv) {
 DSTATUS USER_initialize(BYTE pdrv) {
     /* USER CODE BEGIN INIT */
     /* USER CODE BEGIN INIT */
 
 
-    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
 
 
     DSTATUS status = User_CheckStatus(pdrv);
     DSTATUS status = User_CheckStatus(pdrv);
 
 
-    furi_hal_spi_device_return(sd_spi_fast_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
 
 
     return status;
     return status;
     /* USER CODE END INIT */
     /* USER CODE END INIT */
@@ -120,7 +122,8 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
     /* USER CODE BEGIN READ */
     /* USER CODE BEGIN READ */
     DRESULT res = RES_ERROR;
     DRESULT res = RES_ERROR;
 
 
-    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
 
 
     if(BSP_SD_ReadBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
     if(BSP_SD_ReadBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
         /* wait until the read operation is finished */
         /* wait until the read operation is finished */
@@ -129,7 +132,8 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
         res = RES_OK;
         res = RES_OK;
     }
     }
 
 
-    furi_hal_spi_device_return(sd_spi_fast_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
 
 
     return res;
     return res;
     /* USER CODE END READ */
     /* USER CODE END READ */
@@ -149,7 +153,8 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
     /* USER CODE HERE */
     /* USER CODE HERE */
     DRESULT res = RES_ERROR;
     DRESULT res = RES_ERROR;
 
 
-    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
 
 
     if(BSP_SD_WriteBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
     if(BSP_SD_WriteBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
         /* wait until the Write operation is finished */
         /* wait until the Write operation is finished */
@@ -158,7 +163,8 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
         res = RES_OK;
         res = RES_OK;
     }
     }
 
 
-    furi_hal_spi_device_return(sd_spi_fast_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
 
 
     return res;
     return res;
     /* USER CODE END WRITE */
     /* USER CODE END WRITE */
@@ -180,7 +186,8 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
 
 
     if(Stat & STA_NOINIT) return RES_NOTRDY;
     if(Stat & STA_NOINIT) return RES_NOTRDY;
 
 
-    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
 
 
     switch(cmd) {
     switch(cmd) {
     /* Make sure that no pending write process */
     /* Make sure that no pending write process */
@@ -213,7 +220,8 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
         res = RES_PARERR;
         res = RES_PARERR;
     }
     }
 
 
-    furi_hal_spi_device_return(sd_spi_fast_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
 
 
     return res;
     return res;
     /* USER CODE END IOCTL */
     /* USER CODE END IOCTL */

+ 3 - 1
firmware/targets/f6/furi-hal/furi-hal-sd.c

@@ -19,4 +19,6 @@ void hal_sd_detect_set_low(void) {
 bool hal_sd_detect(void) {
 bool hal_sd_detect(void) {
     bool result = !(LL_GPIO_IsInputPinSet(SD_CD_GPIO_Port, SD_CD_Pin));
     bool result = !(LL_GPIO_IsInputPinSet(SD_CD_GPIO_Port, SD_CD_Pin));
     return result;
     return result;
-}
+}
+
+FuriHalSpiBusHandle* furi_hal_sd_spi_handle = NULL;

+ 180 - 29
firmware/targets/f6/furi-hal/furi-hal-spi-config.c

@@ -1,10 +1,9 @@
 #include <furi-hal-spi-config.h>
 #include <furi-hal-spi-config.h>
 #include <furi-hal-resources.h>
 #include <furi-hal-resources.h>
 
 
-#define SPI_R SPI1
-#define SPI_D SPI2
+/* SPI Presets */
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -17,7 +16,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -30,7 +29,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -43,10 +42,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-/**
- * SD Card in fast mode (after init)
- */
-const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -59,10 +55,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-/**
- * SD Card in slow mode (before init)
- */
-const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -75,29 +68,187 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-osMutexId_t spi_mutex_d = NULL;
-osMutexId_t spi_mutex_r = NULL;
+/* SPI Buses */
 
 
-const FuriHalSpiBus spi_r = {
-    .spi=SPI_R,
-    .mutex=&spi_mutex_r,
+osMutexId_t furi_hal_spi_bus_r_mutex = NULL;
+
+static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
+    if (event == FuriHalSpiBusEventInit) {
+        furi_hal_spi_bus_r_mutex = osMutexNew(NULL);
+        LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
+        LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
+        bus->current_handle = NULL;
+    } else if (event == FuriHalSpiBusEventDeinit) {
+        furi_check(osMutexDelete(furi_hal_spi_bus_r_mutex));
+    } else if (event == FuriHalSpiBusEventLock) {
+        furi_check(osMutexAcquire(furi_hal_spi_bus_r_mutex, osWaitForever) == osOK);
+    } else if (event == FuriHalSpiBusEventUnlock) {
+        furi_check(osMutexRelease(furi_hal_spi_bus_r_mutex) == osOK);
+    } else if (event == FuriHalSpiBusEventActivate) {
+        LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
+    } else if (event == FuriHalSpiBusEventDeactivate) {
+        LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
+    }
+}
+
+FuriHalSpiBus furi_hal_spi_bus_r = {
+    .spi=SPI1,
+    .callback = furi_hal_spi_bus_r_event_callback,
+};
+
+osMutexId_t furi_hal_spi_bus_d_mutex = NULL;
+
+static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
+    if (event == FuriHalSpiBusEventInit) {
+        furi_hal_spi_bus_d_mutex = osMutexNew(NULL);
+        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
+        LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
+        bus->current_handle = NULL;
+    } else if (event == FuriHalSpiBusEventDeinit) {
+        furi_check(osMutexDelete(furi_hal_spi_bus_d_mutex));
+    } else if (event == FuriHalSpiBusEventLock) {
+        furi_check(osMutexAcquire(furi_hal_spi_bus_d_mutex, osWaitForever) == osOK);
+    } else if (event == FuriHalSpiBusEventUnlock) {
+        furi_check(osMutexRelease(furi_hal_spi_bus_d_mutex) == osOK);
+    } else if (event == FuriHalSpiBusEventActivate) {
+        LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
+    } else if (event == FuriHalSpiBusEventDeactivate) {
+        LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
+    }
+}
+
+FuriHalSpiBus furi_hal_spi_bus_d = {
+    .spi=SPI2,
+    .callback = furi_hal_spi_bus_d_event_callback,
+};
+
+/* SPI Bus Handles */
+
+inline static void furi_hal_spi_bus_r_handle_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event, const LL_SPI_InitTypeDef* preset) {
+    if (event == FuriHalSpiBusHandleEventInit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    } else if (event == FuriHalSpiBusHandleEventDeinit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+    } else if (event == FuriHalSpiBusHandleEventActivate) {
+        LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
+        LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
+        LL_SPI_Enable(handle->bus->spi);
+
+        hal_gpio_init_ex(handle->miso, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
+        hal_gpio_init_ex(handle->mosi, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
+        hal_gpio_init_ex(handle->sck, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
+
+        hal_gpio_write(handle->cs, false);
+    } else if (event == FuriHalSpiBusHandleEventDeactivate) {
+        hal_gpio_write(handle->cs, true);
+
+        hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+
+        LL_SPI_Disable(handle->bus->spi);
+    }
+}
+
+static void furi_hal_spi_bus_handle_subghz_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_8m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = {
+    .bus=&furi_hal_spi_bus_r,
+    .callback=furi_hal_spi_bus_handle_subghz_event_callback,
     .miso=&gpio_spi_r_miso,
     .miso=&gpio_spi_r_miso,
     .mosi=&gpio_spi_r_mosi,
     .mosi=&gpio_spi_r_mosi,
-    .clk=&gpio_spi_r_sck,
+    .sck=&gpio_spi_r_sck,
+    .cs=&gpio_subghz_cs,
 };
 };
 
 
-const FuriHalSpiBus spi_d = {
-    .spi=SPI_D,
-    .mutex=&spi_mutex_d,
+static void furi_hal_spi_bus_handle_nfc_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = {
+    .bus=&furi_hal_spi_bus_r,
+    .callback=furi_hal_spi_bus_handle_nfc_event_callback,
+    .miso=&gpio_spi_r_miso,
+    .mosi=&gpio_spi_r_mosi,
+    .sck=&gpio_spi_r_sck,
+    .cs=&gpio_nfc_cs,
+};
+
+static void furi_hal_spi_bus_handle_external_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = {
+    .bus=&furi_hal_spi_bus_r,
+    .callback=furi_hal_spi_bus_handle_external_event_callback,
+    .miso=&gpio_ext_pa6,
+    .mosi=&gpio_ext_pa7,
+    .sck=&gpio_ext_pb3,
+    .cs=&gpio_ext_pa4,
+};
+
+inline static void furi_hal_spi_bus_d_handle_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event, const LL_SPI_InitTypeDef* preset) {
+    if (event == FuriHalSpiBusHandleEventInit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
+
+        hal_gpio_init_ex(handle->miso, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+        hal_gpio_init_ex(handle->mosi, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+        hal_gpio_init_ex(handle->sck, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+
+    } else if (event == FuriHalSpiBusHandleEventDeinit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullUp, GpioSpeedLow);
+    } else if (event == FuriHalSpiBusHandleEventActivate) {
+        LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
+        LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
+        LL_SPI_Enable(handle->bus->spi);
+        hal_gpio_write(handle->cs, false);
+    } else if (event == FuriHalSpiBusHandleEventDeactivate) {
+        hal_gpio_write(handle->cs, true);
+        LL_SPI_Disable(handle->bus->spi);
+    }
+}
+
+static void furi_hal_spi_bus_handle_display_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_4m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_display = {
+    .bus=&furi_hal_spi_bus_d,
+    .callback=furi_hal_spi_bus_handle_display_event_callback,
     .miso=&gpio_spi_d_miso,
     .miso=&gpio_spi_d_miso,
     .mosi=&gpio_spi_d_mosi,
     .mosi=&gpio_spi_d_mosi,
-    .clk=&gpio_spi_d_sck,
+    .sck=&gpio_spi_d_sck,
+    .cs=&gpio_display_cs,
 };
 };
 
 
-const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax] = {
-    { .bus=&spi_r, .config=&furi_hal_spi_config_subghz, .chip_select=&gpio_subghz_cs, },
-    { .bus=&spi_d, .config=&furi_hal_spi_config_display, .chip_select=&gpio_display_cs, },
-    { .bus=&spi_d, .config=&furi_hal_spi_config_sd_fast, .chip_select=&gpio_sdcard_cs, },
-    { .bus=&spi_d, .config=&furi_hal_spi_config_sd_slow, .chip_select=&gpio_sdcard_cs, },
-    { .bus=&spi_r, .config=&furi_hal_spi_config_nfc, .chip_select=&gpio_nfc_cs },
+static void furi_hal_spi_bus_handle_sd_fast_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_16m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast = {
+    .bus=&furi_hal_spi_bus_d,
+    .callback=furi_hal_spi_bus_handle_sd_fast_event_callback,
+    .miso=&gpio_spi_d_miso,
+    .mosi=&gpio_spi_d_mosi,
+    .sck=&gpio_spi_d_sck,
+    .cs=&gpio_sdcard_cs,
+};
+
+static void furi_hal_spi_bus_handle_sd_slow_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow = {
+    .bus=&furi_hal_spi_bus_d,
+    .callback=furi_hal_spi_bus_handle_sd_slow_event_callback,
+    .miso=&gpio_spi_d_miso,
+    .mosi=&gpio_spi_d_mosi,
+    .sck=&gpio_spi_d_sck,
+    .cs=&gpio_sdcard_cs,
 };
 };

+ 46 - 48
firmware/targets/f6/furi-hal/furi-hal-spi-config.h

@@ -1,62 +1,60 @@
 #pragma once
 #pragma once
 
 
-#include <furi-hal-gpio.h>
-#include <stm32wbxx_ll_spi.h>
-#include <cmsis_os2.h>
+#include <furi-hal-spi-types.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_nfc;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_subghz;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_display;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow;
+/** Preset for ST25R916 */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m;
 
 
-/** FURI HAL SPI BUS handler
- * Structure content may change at some point
- */
-typedef struct {
-    const SPI_TypeDef* spi;
-    const osMutexId_t* mutex;
-    const GpioPin* miso;
-    const GpioPin* mosi;
-    const GpioPin* clk;
-} FuriHalSpiBus;
-
-/** FURI HAL SPI Device handler
- * Structure content may change at some point
- */
-typedef struct {
-    const FuriHalSpiBus* bus;
-    const LL_SPI_InitTypeDef* config;
-    const GpioPin* chip_select;
-} FuriHalSpiDevice;
-
-/** FURI HAL SPI Standard Device IDs */
-typedef enum {
-    FuriHalSpiDeviceIdSubGhz,        /** SubGhz: CC1101, non-standard SPI usage */
-    FuriHalSpiDeviceIdDisplay,       /** Display: ERC12864, only have MOSI */
-    FuriHalSpiDeviceIdSdCardFast,    /** SDCARD: fast mode, after initialization */
-    FuriHalSpiDeviceIdSdCardSlow,    /** SDCARD: slow mode, before initialization */
-    FuriHalSpiDeviceIdNfc,           /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */
-
-    FuriHalSpiDeviceIdMax,           /** Service Value, do not use */
-} FuriHalSpiDeviceId;
-
-/** Furi Hal Spi Bus R
- * CC1101, Nfc
- */
-extern const FuriHalSpiBus spi_r;
+/** Preset for CC1101 */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m;
+
+/** Preset for ST7567 (Display) */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m;
+
+/** Preset for SdCard in fast mode */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m;
+
+/** Preset for SdCard in slow mode */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m;
 
 
-/** Furi Hal Spi Bus D
- * Display, SdCard
+/** Furi Hal Spi Bus R (Radio: CC1101, Nfc, External)*/
+extern FuriHalSpiBus furi_hal_spi_bus_r;
+
+/** Furi Hal Spi Bus D (Display, SdCard) */
+extern FuriHalSpiBus furi_hal_spi_bus_d;
+
+/** CC1101 on `furi_hal_spi_bus_r` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz;
+
+/** ST25R3916 on `furi_hal_spi_bus_r` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc;
+
+/** External on `furi_hal_spi_bus_r`
+ * Preset: `furi_hal_spi_preset_1edge_low_2m`
+ * 
+ * miso: pa6
+ * mosi: pa7
+ * sck: pb3
+ * cs:  pa4 (software controlled)
+ * 
+ * @warning not initialized by default, call `furi_hal_spi_bus_handle_init` to initialize
+ * Bus pins are floating on inactive state, CS high after initialization
+ * 
  */
  */
-extern const FuriHalSpiBus spi_d;
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_external;
+
+/** ST7567(Display) on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_display;
+
+/** SdCard in fast mode on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast;
 
 
-/** Furi Hal Spi devices */
-extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax];
+/** SdCard in slow mode on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 62 - 0
firmware/targets/f6/furi-hal/furi-hal-spi-types.h

@@ -0,0 +1,62 @@
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <furi-hal-gpio.h>
+
+#include <stm32wbxx_ll_spi.h>
+#include <stm32wbxx_ll_rcc.h>
+#include <stm32wbxx_ll_bus.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct FuriHalSpiBus FuriHalSpiBus;
+typedef struct FuriHalSpiBusHandle FuriHalSpiBusHandle;
+
+/** FuriHal spi bus states */
+typedef enum {
+    FuriHalSpiBusEventInit, /**< Bus initialization event, called on system start */
+    FuriHalSpiBusEventDeinit, /**< Bus deinitialization event, called on system stop */
+    FuriHalSpiBusEventLock, /**< Bus lock event, called before activation */
+    FuriHalSpiBusEventUnlock, /**< Bus unlock event, called after deactivation */
+    FuriHalSpiBusEventActivate, /**< Bus activation event, called before handle activation */
+    FuriHalSpiBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation  */
+} FuriHalSpiBusEvent;
+
+/** FuriHal spi bus event callback */
+typedef void (*FuriHalSpiBusEventCallback)(FuriHalSpiBus* bus, FuriHalSpiBusEvent event);
+
+/** FuriHal spi bus */
+struct FuriHalSpiBus {
+    SPI_TypeDef* spi;
+    FuriHalSpiBusEventCallback callback;
+    FuriHalSpiBusHandle* current_handle;
+};
+
+/** FuriHal spi handle states */
+typedef enum {
+    FuriHalSpiBusHandleEventInit, /**< Handle init, called on system start, initialize gpio for idle state */
+    FuriHalSpiBusHandleEventDeinit, /**< Handle deinit, called on system stop, deinitialize gpio for default state */
+    FuriHalSpiBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
+    FuriHalSpiBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
+} FuriHalSpiBusHandleEvent;
+
+/** FuriHal spi handle event callback */
+typedef void (*FuriHalSpiBusHandleEventCallback)(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event);
+
+/** FuriHal spi handle */
+struct FuriHalSpiBusHandle {
+    FuriHalSpiBus* bus;
+    FuriHalSpiBusHandleEventCallback callback;
+    const GpioPin* miso;
+    const GpioPin* mosi;
+    const GpioPin* sck;
+    const GpioPin* cs;
+};
+
+#ifdef __cplusplus
+}
+#endif

+ 67 - 129
firmware/targets/f6/furi-hal/furi-hal-spi.c

@@ -12,89 +12,104 @@
 #define TAG "FuriHalSpi"
 #define TAG "FuriHalSpi"
 
 
 void furi_hal_spi_init() {
 void furi_hal_spi_init() {
-    // Spi structure is const, but mutex is not
-    // Need some hell-ish casting to make it work
-    *(osMutexId_t*)spi_r.mutex = osMutexNew(NULL);
-    *(osMutexId_t*)spi_d.mutex = osMutexNew(NULL);
-    // 
-    for (size_t i=0; i<FuriHalSpiDeviceIdMax; ++i) {
-        hal_gpio_write(furi_hal_spi_devices[i].chip_select, true);
-        hal_gpio_init(
-            furi_hal_spi_devices[i].chip_select,
-            GpioModeOutputPushPull,
-            GpioPullNo,
-            GpioSpeedVeryHigh
-        );
-    }
-
-    hal_gpio_init_ex(&gpio_spi_r_miso, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
-    hal_gpio_init_ex(&gpio_spi_r_mosi, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
-    hal_gpio_init_ex(&gpio_spi_r_sck, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
+    furi_hal_spi_bus_init(&furi_hal_spi_bus_r);
+    furi_hal_spi_bus_init(&furi_hal_spi_bus_d);
 
 
-    hal_gpio_init_ex(&gpio_spi_d_miso, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
-    hal_gpio_init_ex(&gpio_spi_d_mosi, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
-    hal_gpio_init_ex(&gpio_spi_d_sck, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow);
 
 
     FURI_LOG_I(TAG, "Init OK");
     FURI_LOG_I(TAG, "Init OK");
 }
 }
 
 
-void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus) {
+void furi_hal_spi_bus_init(FuriHalSpiBus* bus) {
     furi_assert(bus);
     furi_assert(bus);
-    furi_check(osMutexAcquire(*bus->mutex, osWaitForever) == osOK);
+    bus->callback(bus, FuriHalSpiBusEventInit);
 }
 }
 
 
-void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) {
+void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus) {
     furi_assert(bus);
     furi_assert(bus);
-    furi_check(osMutexRelease(*bus->mutex) == osOK);
+    bus->callback(bus, FuriHalSpiBusEventDeinit);
 }
 }
 
 
-void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config) {
-    furi_assert(bus);
+void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle) {
+    furi_assert(handle);
+    handle->callback(handle, FuriHalSpiBusHandleEventInit);
+}
 
 
-    LL_SPI_DeInit((SPI_TypeDef*)bus->spi);
-    LL_SPI_Init((SPI_TypeDef*)bus->spi, (LL_SPI_InitTypeDef*)config);
-    LL_SPI_SetRxFIFOThreshold((SPI_TypeDef*)bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
-    LL_SPI_Enable((SPI_TypeDef*)bus->spi);
+void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle) {
+    furi_assert(handle);
+    handle->callback(handle, FuriHalSpiBusHandleEventDeinit);
 }
 }
 
 
-void furi_hal_spi_bus_end_txrx(const FuriHalSpiBus* bus, uint32_t timeout) {
-    while(LL_SPI_GetTxFIFOLevel((SPI_TypeDef *)bus->spi) != LL_SPI_TX_FIFO_EMPTY);
-    while(LL_SPI_IsActiveFlag_BSY((SPI_TypeDef *)bus->spi));
-    while(LL_SPI_GetRxFIFOLevel((SPI_TypeDef *)bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
-        LL_SPI_ReceiveData8((SPI_TypeDef *)bus->spi);
+void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle) {
+    furi_assert(handle);
+
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventLock);
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventActivate);
+
+    furi_assert(handle->bus->current_handle == NULL);
+
+    handle->bus->current_handle = handle;
+    handle->callback(handle, FuriHalSpiBusHandleEventActivate);
+}
+
+void furi_hal_spi_release(FuriHalSpiBusHandle* handle) {
+    furi_assert(handle);
+    furi_assert(handle->bus->current_handle == handle);
+
+    // Handle event and unset handle
+    handle->callback(handle, FuriHalSpiBusHandleEventDeactivate);
+    handle->bus->current_handle = NULL;
+
+    // Bus events
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventDeactivate);
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventUnlock);
+}
+
+static void furi_hal_spi_bus_end_txrx(FuriHalSpiBusHandle* handle, uint32_t timeout) {
+    while(LL_SPI_GetTxFIFOLevel(handle->bus->spi) != LL_SPI_TX_FIFO_EMPTY);
+    while(LL_SPI_IsActiveFlag_BSY(handle->bus->spi));
+    while(LL_SPI_GetRxFIFOLevel(handle->bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
+        LL_SPI_ReceiveData8(handle->bus->spi);
     }
     }
 }
 }
 
 
-bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
-    furi_assert(bus);
+bool furi_hal_spi_bus_rx(FuriHalSpiBusHandle* handle, uint8_t* buffer, size_t size, uint32_t timeout) {
+    furi_assert(handle);
+    furi_assert(handle->bus->current_handle == handle);
     furi_assert(buffer);
     furi_assert(buffer);
     furi_assert(size > 0);
     furi_assert(size > 0);
 
 
-    return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout);
+    return furi_hal_spi_bus_trx(handle, buffer, buffer, size, timeout);
 }
 }
 
 
-bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
-    furi_assert(bus);
+bool furi_hal_spi_bus_tx(FuriHalSpiBusHandle* handle, uint8_t* buffer, size_t size, uint32_t timeout) {
+    furi_assert(handle);
+    furi_assert(handle->bus->current_handle == handle);
     furi_assert(buffer);
     furi_assert(buffer);
     furi_assert(size > 0);
     furi_assert(size > 0);
     bool ret = true;
     bool ret = true;
 
 
     while(size > 0) {
     while(size > 0) {
-        if (LL_SPI_IsActiveFlag_TXE((SPI_TypeDef *)bus->spi)) {
-            LL_SPI_TransmitData8((SPI_TypeDef *)bus->spi, *buffer);
+        if (LL_SPI_IsActiveFlag_TXE(handle->bus->spi)) {
+            LL_SPI_TransmitData8(handle->bus->spi, *buffer);
             buffer++;
             buffer++;
             size--;
             size--;
         }
         }
     }
     }
 
 
-    furi_hal_spi_bus_end_txrx(bus, timeout);
-    LL_SPI_ClearFlag_OVR((SPI_TypeDef *)bus->spi);
+    furi_hal_spi_bus_end_txrx(handle, timeout);
+    LL_SPI_ClearFlag_OVR(handle->bus->spi);
 
 
     return ret;
     return ret;
 }
 }
 
 
-bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) {
-    furi_assert(bus);
+bool furi_hal_spi_bus_trx(FuriHalSpiBusHandle* handle, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) {
+    furi_assert(handle);
+    furi_assert(handle->bus->current_handle == handle);
     furi_assert(tx_buffer);
     furi_assert(tx_buffer);
     furi_assert(rx_buffer);
     furi_assert(rx_buffer);
     furi_assert(size > 0);
     furi_assert(size > 0);
@@ -104,99 +119,22 @@ bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t*
     bool tx_allowed = true;
     bool tx_allowed = true;
 
 
     while(size > 0) {
     while(size > 0) {
-        if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE((SPI_TypeDef *)bus->spi) && tx_allowed) {
-            LL_SPI_TransmitData8((SPI_TypeDef *)bus->spi, *tx_buffer);
+        if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) {
+            LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
             tx_buffer++;
             tx_buffer++;
             tx_size--;
             tx_size--;
             tx_allowed = false;
             tx_allowed = false;
         }
         }
         
         
-        if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef *)bus->spi)) {
-            *rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef *)bus->spi);
+        if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) {
+            *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
             rx_buffer++;
             rx_buffer++;
             size--;
             size--;
             tx_allowed = true;
             tx_allowed = true;
         }
         }
     }
     }
 
 
-    furi_hal_spi_bus_end_txrx(bus, timeout);
-
-    return ret;
-}
-
-void furi_hal_spi_device_configure(const FuriHalSpiDevice* device) {
-    furi_assert(device);
-    furi_assert(device->config);
-
-    furi_hal_spi_bus_configure(device->bus, device->config);
-}
-
-const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) {
-    furi_assert(device_id < FuriHalSpiDeviceIdMax);
-
-    const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id];
-    furi_assert(device);
-    furi_hal_spi_bus_lock(device->bus);
-    furi_hal_spi_device_configure(device);
-
-    return device;
-}
-
-void furi_hal_spi_device_return(const FuriHalSpiDevice* device) {
-    furi_hal_spi_bus_unlock(device->bus);
-}
-
-bool furi_hal_spi_device_rx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) {
-    furi_assert(device);
-    furi_assert(buffer);
-    furi_assert(size > 0);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_rx(device->bus, buffer, size, timeout);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
-
-    return ret;
-}
-
-bool furi_hal_spi_device_tx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) {
-    furi_assert(device);
-    furi_assert(buffer);
-    furi_assert(size > 0);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_tx(device->bus, buffer, size, timeout);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
-
-    return ret;
-}
-
-bool furi_hal_spi_device_trx(const FuriHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) {
-    furi_assert(device);
-    furi_assert(tx_buffer);
-    furi_assert(rx_buffer);
-    furi_assert(size > 0);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, timeout);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
+    furi_hal_spi_bus_end_txrx(handle, timeout);
 
 
     return ret;
     return ret;
 }
 }

+ 66 - 66
firmware/targets/f6/furi-hal/furi-hal-subghz.c

@@ -269,7 +269,7 @@ void furi_hal_subghz_init() {
     furi_assert(furi_hal_subghz_state == SubGhzStateInit);
     furi_assert(furi_hal_subghz_state == SubGhzStateInit);
     furi_hal_subghz_state = SubGhzStateIdle;
     furi_hal_subghz_state = SubGhzStateIdle;
 
 
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 
 
 #ifdef FURI_HAL_SUBGHZ_TX_GPIO
 #ifdef FURI_HAL_SUBGHZ_TX_GPIO
     hal_gpio_init(&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
@@ -277,58 +277,58 @@ void furi_hal_subghz_init() {
 
 
     // Reset
     // Reset
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
-    cc1101_reset(device);
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
+    cc1101_reset(&furi_hal_spi_bus_handle_subghz);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
 
 
     // Prepare GD0 for power on self test
     // Prepare GD0 for power on self test
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 
 
     // GD0 low
     // GD0 low
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW);
     while(hal_gpio_read(&gpio_cc1101_g0) != false)
     while(hal_gpio_read(&gpio_cc1101_g0) != false)
         ;
         ;
 
 
     // GD0 high
     // GD0 high
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
     while(hal_gpio_read(&gpio_cc1101_g0) != true)
     while(hal_gpio_read(&gpio_cc1101_g0) != true)
         ;
         ;
 
 
     // Reset GD0 to floating state
     // Reset GD0 to floating state
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 
 
     // RF switches
     // RF switches
     hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-    cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW);
 
 
     // Go to sleep
     // Go to sleep
-    cc1101_shutdown(device);
+    cc1101_shutdown(&furi_hal_spi_bus_handle_subghz);
 
 
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
     FURI_LOG_I(TAG, "Init OK");
     FURI_LOG_I(TAG, "Init OK");
 }
 }
 
 
 void furi_hal_subghz_sleep() {
 void furi_hal_subghz_sleep() {
     furi_assert(furi_hal_subghz_state == SubGhzStateIdle);
     furi_assert(furi_hal_subghz_state == SubGhzStateIdle);
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 
 
-    cc1101_switch_to_idle(device);
+    cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
 
 
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 
 
-    cc1101_shutdown(device);
+    cc1101_shutdown(&furi_hal_spi_bus_handle_subghz);
 
 
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_dump_state() {
 void furi_hal_subghz_dump_state() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
     printf(
     printf(
         "[furi_hal_subghz] cc1101 chip %d, version %d\r\n",
         "[furi_hal_subghz] cc1101 chip %d, version %d\r\n",
-        cc1101_get_partnumber(device),
-        cc1101_get_version(device));
-    furi_hal_spi_device_return(device);
+        cc1101_get_partnumber(&furi_hal_spi_bus_handle_subghz),
+        cc1101_get_version(&furi_hal_spi_bus_handle_subghz));
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
 void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
@@ -350,81 +350,81 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
 }
 }
 
 
 void furi_hal_subghz_load_registers(const uint8_t data[][2]) {
 void furi_hal_subghz_load_registers(const uint8_t data[][2]) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_reset(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_reset(&furi_hal_spi_bus_handle_subghz);
     uint32_t i = 0;
     uint32_t i = 0;
     while(data[i][0]) {
     while(data[i][0]) {
-        cc1101_write_reg(device, data[i][0], data[i][1]);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i][0], data[i][1]);
         i++;
         i++;
     }
     }
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_load_patable(const uint8_t data[8]) {
 void furi_hal_subghz_load_patable(const uint8_t data[8]) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_set_pa_table(device, data);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_set_pa_table(&furi_hal_spi_bus_handle_subghz, data);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
 void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_flush_tx(device);
-    cc1101_write_fifo(device, data, size);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
+    cc1101_write_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_flush_rx() {
 void furi_hal_subghz_flush_rx() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_flush_rx(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_flush_rx(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) {
 void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_read_fifo(device, data, size);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_read_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_shutdown() {
 void furi_hal_subghz_shutdown() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
     // Reset and shutdown
     // Reset and shutdown
-    cc1101_shutdown(device);
-    furi_hal_spi_device_return(device);
+    cc1101_shutdown(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_reset() {
 void furi_hal_subghz_reset() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
-    cc1101_switch_to_idle(device);
-    cc1101_reset(device);
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
-    furi_hal_spi_device_return(device);
+    cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
+    cc1101_reset(&furi_hal_spi_bus_handle_subghz);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_idle() {
 void furi_hal_subghz_idle() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_switch_to_idle(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_rx() {
 void furi_hal_subghz_rx() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_switch_to_rx(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 bool furi_hal_subghz_tx() {
 bool furi_hal_subghz_tx() {
     if(furi_hal_subghz_regulation != SubGhzRegulationTxRx) return false;
     if(furi_hal_subghz_regulation != SubGhzRegulationTxRx) return false;
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_switch_to_tx(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_switch_to_tx(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
     return true;
     return true;
 }
 }
 
 
 float furi_hal_subghz_get_rssi() {
 float furi_hal_subghz_get_rssi() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    int32_t rssi_dec = cc1101_get_rssi(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    int32_t rssi_dec = cc1101_get_rssi(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 
 
     float rssi = rssi_dec;
     float rssi = rssi_dec;
     if(rssi_dec >= 128) {
     if(rssi_dec >= 128) {
@@ -461,7 +461,7 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) {
 }
 }
 
 
 uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
 uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 
 
     //checking regional settings
     //checking regional settings
     bool txrx = false;
     bool txrx = false;
@@ -503,37 +503,37 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
         furi_hal_subghz_regulation = SubGhzRegulationOnlyRx;
         furi_hal_subghz_regulation = SubGhzRegulationOnlyRx;
     }
     }
 
 
-    uint32_t real_frequency = cc1101_set_frequency(device, value);
-    cc1101_calibrate(device);
+    uint32_t real_frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, value);
+    cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
 
 
     while(true) {
     while(true) {
-        CC1101Status status = cc1101_get_status(device);
+        CC1101Status status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz);
         if(status.STATE == CC1101StateIDLE) break;
         if(status.STATE == CC1101StateIDLE) break;
     }
     }
 
 
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 
 
     return real_frequency;
     return real_frequency;
 }
 }
 
 
 void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
 void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
     if(path == FuriHalSubGhzPath433) {
     if(path == FuriHalSubGhzPath433) {
         hal_gpio_write(&gpio_rf_sw_0, 0);
         hal_gpio_write(&gpio_rf_sw_0, 0);
-        cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
     } else if(path == FuriHalSubGhzPath315) {
     } else if(path == FuriHalSubGhzPath315) {
         hal_gpio_write(&gpio_rf_sw_0, 1);
         hal_gpio_write(&gpio_rf_sw_0, 1);
-        cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW);
     } else if(path == FuriHalSubGhzPath868) {
     } else if(path == FuriHalSubGhzPath868) {
         hal_gpio_write(&gpio_rf_sw_0, 1);
         hal_gpio_write(&gpio_rf_sw_0, 1);
-        cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
     } else if(path == FuriHalSubGhzPathIsolate) {
     } else if(path == FuriHalSubGhzPathIsolate) {
         hal_gpio_write(&gpio_rf_sw_0, 0);
         hal_gpio_write(&gpio_rf_sw_0, 0);
-        cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW);
     } else {
     } else {
         furi_crash(NULL);
         furi_crash(NULL);
     }
     }
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 volatile uint32_t furi_hal_subghz_capture_delta_duration = 0;
 volatile uint32_t furi_hal_subghz_capture_delta_duration = 0;

+ 5 - 7
firmware/targets/f7/fatfs/spi_sd_hal.c

@@ -7,8 +7,6 @@
 const uint32_t SpiTimeout = 1000;
 const uint32_t SpiTimeout = 1000;
 uint8_t SD_IO_WriteByte(uint8_t Data);
 uint8_t SD_IO_WriteByte(uint8_t Data);
 
 
-static const FuriHalSpiDevice* sd_spi_dev = &furi_hal_spi_devices[FuriHalSpiDeviceIdSdCardFast];
-
 /******************************************************************************
 /******************************************************************************
                             BUS OPERATIONS
                             BUS OPERATIONS
  *******************************************************************************/
  *******************************************************************************/
@@ -21,7 +19,7 @@ static const FuriHalSpiDevice* sd_spi_dev = &furi_hal_spi_devices[FuriHalSpiDevi
  * @retval None
  * @retval None
  */
  */
 static void SPIx_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) {
 static void SPIx_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) {
-    furi_check(furi_hal_spi_bus_trx(sd_spi_dev->bus, (uint8_t*)DataIn, DataOut, DataLength, SpiTimeout));
+    furi_check(furi_hal_spi_bus_trx(furi_hal_sd_spi_handle, (uint8_t*)DataIn, DataOut, DataLength, SpiTimeout));
 }
 }
 
 
 /**
 /**
@@ -30,7 +28,7 @@ static void SPIx_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t
  * @retval None
  * @retval None
  */
  */
 __attribute__((unused)) static void SPIx_Write(uint8_t Value) {
 __attribute__((unused)) static void SPIx_Write(uint8_t Value) {
-    furi_check(furi_hal_spi_bus_tx(sd_spi_dev->bus, (uint8_t*)&Value, 1, SpiTimeout));
+    furi_check(furi_hal_spi_bus_tx(furi_hal_sd_spi_handle, (uint8_t*)&Value, 1, SpiTimeout));
 }
 }
 
 
 /******************************************************************************
 /******************************************************************************
@@ -47,7 +45,7 @@ void SD_IO_Init(void) {
     uint8_t counter = 0;
     uint8_t counter = 0;
 
 
     /* SD chip select high */
     /* SD chip select high */
-    hal_gpio_write(sd_spi_dev->chip_select, true);
+    hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
     delay_us(10);
     delay_us(10);
 
 
     /* Send dummy byte 0xFF, 10 times with CS high */
     /* Send dummy byte 0xFF, 10 times with CS high */
@@ -67,9 +65,9 @@ void SD_IO_CSState(uint8_t val) {
     /* Some SD Cards are prone to fail if CLK-ed too soon after CS transition. Worst case found: 8us */
     /* Some SD Cards are prone to fail if CLK-ed too soon after CS transition. Worst case found: 8us */
     if(val == 1) {
     if(val == 1) {
         delay_us(10); // Exit guard time for some SD cards
         delay_us(10); // Exit guard time for some SD cards
-        hal_gpio_write(sd_spi_dev->chip_select, true);
+        hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
     } else {
     } else {
-        hal_gpio_write(sd_spi_dev->chip_select, false);
+        hal_gpio_write(furi_hal_sd_spi_handle->cs, false);
         delay_us(10); // Entry guard time for some SD cards
         delay_us(10); // Entry guard time for some SD cards
     }
     }
 }
 }

+ 17 - 20
firmware/targets/f7/fatfs/stm32_adafruit_sd.c

@@ -91,12 +91,7 @@
 #include "stdlib.h"
 #include "stdlib.h"
 #include "string.h"
 #include "string.h"
 #include "stdio.h"
 #include "stdio.h"
-#include <furi-hal-spi.h>
-#include <furi-hal-gpio.h>
-#include <furi-hal-resources.h>
-#include <furi-hal-power.h>
-#include <furi-hal-delay.h>
-#include <furi-hal-sd.h>
+#include <furi-hal.h>
 
 
 /** @addtogroup BSP
 /** @addtogroup BSP
   * @{
   * @{
@@ -284,22 +279,22 @@ static uint8_t SD_ReadData(void);
 /* Private functions ---------------------------------------------------------*/
 /* Private functions ---------------------------------------------------------*/
 
 
 void SD_SPI_Bus_To_Down_State(){
 void SD_SPI_Bus_To_Down_State(){
-    hal_gpio_init_ex(&gpio_spi_d_miso, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
-    hal_gpio_init_ex(&gpio_spi_d_mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
-    hal_gpio_init_ex(&gpio_spi_d_sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
-
-    hal_gpio_write(&gpio_sdcard_cs, false);
-    hal_gpio_write(&gpio_spi_d_miso, false);
-    hal_gpio_write(&gpio_spi_d_mosi, false);
-    hal_gpio_write(&gpio_spi_d_sck, false);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->miso, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFnUnused);
+
+    hal_gpio_write(furi_hal_sd_spi_handle->cs, false);
+    hal_gpio_write(furi_hal_sd_spi_handle->miso, false);
+    hal_gpio_write(furi_hal_sd_spi_handle->mosi, false);
+    hal_gpio_write(furi_hal_sd_spi_handle->sck, false);
 }
 }
 
 
 void SD_SPI_Bus_To_Normal_State(){
 void SD_SPI_Bus_To_Normal_State(){
-    hal_gpio_write(&gpio_sdcard_cs, true);
+    hal_gpio_write(furi_hal_sd_spi_handle->cs, true);
 
 
-    hal_gpio_init_ex(&gpio_spi_d_miso, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
-    hal_gpio_init_ex(&gpio_spi_d_mosi, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
-    hal_gpio_init_ex(&gpio_spi_d_sck, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->miso, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->mosi, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+    hal_gpio_init_ex(furi_hal_sd_spi_handle->sck, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
 }
 }
 
 
 /** @defgroup STM32_ADAFRUIT_SD_Private_Functions
 /** @defgroup STM32_ADAFRUIT_SD_Private_Functions
@@ -315,7 +310,8 @@ void SD_SPI_Bus_To_Normal_State(){
   */
   */
 uint8_t BSP_SD_Init(bool reset_card) {
 uint8_t BSP_SD_Init(bool reset_card) {
     /* Slow speed init */
     /* Slow speed init */
-    const FuriHalSpiDevice* sd_spi_slow_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardSlow);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_slow);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_slow;
 
 
     /* We must reset card in spi_lock context */
     /* We must reset card in spi_lock context */
     if(reset_card) {
     if(reset_card) {
@@ -344,7 +340,8 @@ uint8_t BSP_SD_Init(bool reset_card) {
         if(res == BSP_SD_OK) break;
         if(res == BSP_SD_OK) break;
     }
     }
 
 
-    furi_hal_spi_device_return(sd_spi_slow_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow);
 
 
     /* SD initialized and set to SPI mode properly */
     /* SD initialized and set to SPI mode properly */
     return res;
     return res;

+ 17 - 9
firmware/targets/f7/fatfs/user_diskio.c

@@ -35,7 +35,7 @@
 
 
 /* Includes ------------------------------------------------------------------*/
 /* Includes ------------------------------------------------------------------*/
 #include "user_diskio.h"
 #include "user_diskio.h"
-#include "furi-hal-spi.h"
+#include <furi-hal.h>
 /* Private typedef -----------------------------------------------------------*/
 /* Private typedef -----------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
 
 
@@ -87,11 +87,13 @@ Diskio_drvTypeDef USER_Driver = {
 DSTATUS USER_initialize(BYTE pdrv) {
 DSTATUS USER_initialize(BYTE pdrv) {
     /* USER CODE BEGIN INIT */
     /* USER CODE BEGIN INIT */
 
 
-    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
 
 
     DSTATUS status = User_CheckStatus(pdrv);
     DSTATUS status = User_CheckStatus(pdrv);
 
 
-    furi_hal_spi_device_return(sd_spi_fast_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
 
 
     return status;
     return status;
     /* USER CODE END INIT */
     /* USER CODE END INIT */
@@ -120,7 +122,8 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
     /* USER CODE BEGIN READ */
     /* USER CODE BEGIN READ */
     DRESULT res = RES_ERROR;
     DRESULT res = RES_ERROR;
 
 
-    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
 
 
     if(BSP_SD_ReadBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
     if(BSP_SD_ReadBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
         /* wait until the read operation is finished */
         /* wait until the read operation is finished */
@@ -129,7 +132,8 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
         res = RES_OK;
         res = RES_OK;
     }
     }
 
 
-    furi_hal_spi_device_return(sd_spi_fast_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
 
 
     return res;
     return res;
     /* USER CODE END READ */
     /* USER CODE END READ */
@@ -149,7 +153,8 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
     /* USER CODE HERE */
     /* USER CODE HERE */
     DRESULT res = RES_ERROR;
     DRESULT res = RES_ERROR;
 
 
-    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
 
 
     if(BSP_SD_WriteBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
     if(BSP_SD_WriteBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
         /* wait until the Write operation is finished */
         /* wait until the Write operation is finished */
@@ -158,7 +163,8 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
         res = RES_OK;
         res = RES_OK;
     }
     }
 
 
-    furi_hal_spi_device_return(sd_spi_fast_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
 
 
     return res;
     return res;
     /* USER CODE END WRITE */
     /* USER CODE END WRITE */
@@ -180,7 +186,8 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
 
 
     if(Stat & STA_NOINIT) return RES_NOTRDY;
     if(Stat & STA_NOINIT) return RES_NOTRDY;
 
 
-    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
 
 
     switch(cmd) {
     switch(cmd) {
     /* Make sure that no pending write process */
     /* Make sure that no pending write process */
@@ -213,7 +220,8 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
         res = RES_PARERR;
         res = RES_PARERR;
     }
     }
 
 
-    furi_hal_spi_device_return(sd_spi_fast_dev);
+    furi_hal_sd_spi_handle = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
 
 
     return res;
     return res;
     /* USER CODE END IOCTL */
     /* USER CODE END IOCTL */

+ 3 - 1
firmware/targets/f7/furi-hal/furi-hal-sd.c

@@ -19,4 +19,6 @@ void hal_sd_detect_set_low(void) {
 bool hal_sd_detect(void) {
 bool hal_sd_detect(void) {
     bool result = !(LL_GPIO_IsInputPinSet(SD_CD_GPIO_Port, SD_CD_Pin));
     bool result = !(LL_GPIO_IsInputPinSet(SD_CD_GPIO_Port, SD_CD_Pin));
     return result;
     return result;
-}
+}
+
+FuriHalSpiBusHandle* furi_hal_sd_spi_handle = NULL;

+ 180 - 29
firmware/targets/f7/furi-hal/furi-hal-spi-config.c

@@ -1,10 +1,9 @@
 #include <furi-hal-spi-config.h>
 #include <furi-hal-spi-config.h>
 #include <furi-hal-resources.h>
 #include <furi-hal-resources.h>
 
 
-#define SPI_R SPI1
-#define SPI_D SPI2
+/* SPI Presets */
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -17,7 +16,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -30,7 +29,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -43,10 +42,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-/**
- * SD Card in fast mode (after init)
- */
-const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -59,10 +55,7 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-/**
- * SD Card in slow mode (before init)
- */
-const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
+const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = {
     .Mode = LL_SPI_MODE_MASTER,
     .Mode = LL_SPI_MODE_MASTER,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .TransferDirection = LL_SPI_FULL_DUPLEX,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
     .DataWidth = LL_SPI_DATAWIDTH_8BIT,
@@ -75,29 +68,187 @@ const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
     .CRCPoly = 7,
     .CRCPoly = 7,
 };
 };
 
 
-osMutexId_t spi_mutex_d = NULL;
-osMutexId_t spi_mutex_r = NULL;
+/* SPI Buses */
 
 
-const FuriHalSpiBus spi_r = {
-    .spi=SPI_R,
-    .mutex=&spi_mutex_r,
+osMutexId_t furi_hal_spi_bus_r_mutex = NULL;
+
+static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
+    if (event == FuriHalSpiBusEventInit) {
+        furi_hal_spi_bus_r_mutex = osMutexNew(NULL);
+        LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
+        LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
+        bus->current_handle = NULL;
+    } else if (event == FuriHalSpiBusEventDeinit) {
+        furi_check(osMutexDelete(furi_hal_spi_bus_r_mutex));
+    } else if (event == FuriHalSpiBusEventLock) {
+        furi_check(osMutexAcquire(furi_hal_spi_bus_r_mutex, osWaitForever) == osOK);
+    } else if (event == FuriHalSpiBusEventUnlock) {
+        furi_check(osMutexRelease(furi_hal_spi_bus_r_mutex) == osOK);
+    } else if (event == FuriHalSpiBusEventActivate) {
+        LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1);
+    } else if (event == FuriHalSpiBusEventDeactivate) {
+        LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1);
+    }
+}
+
+FuriHalSpiBus furi_hal_spi_bus_r = {
+    .spi=SPI1,
+    .callback = furi_hal_spi_bus_r_event_callback,
+};
+
+osMutexId_t furi_hal_spi_bus_d_mutex = NULL;
+
+static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) {
+    if (event == FuriHalSpiBusEventInit) {
+        furi_hal_spi_bus_d_mutex = osMutexNew(NULL);
+        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
+        LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
+        bus->current_handle = NULL;
+    } else if (event == FuriHalSpiBusEventDeinit) {
+        furi_check(osMutexDelete(furi_hal_spi_bus_d_mutex));
+    } else if (event == FuriHalSpiBusEventLock) {
+        furi_check(osMutexAcquire(furi_hal_spi_bus_d_mutex, osWaitForever) == osOK);
+    } else if (event == FuriHalSpiBusEventUnlock) {
+        furi_check(osMutexRelease(furi_hal_spi_bus_d_mutex) == osOK);
+    } else if (event == FuriHalSpiBusEventActivate) {
+        LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2);
+    } else if (event == FuriHalSpiBusEventDeactivate) {
+        LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2);
+    }
+}
+
+FuriHalSpiBus furi_hal_spi_bus_d = {
+    .spi=SPI2,
+    .callback = furi_hal_spi_bus_d_event_callback,
+};
+
+/* SPI Bus Handles */
+
+inline static void furi_hal_spi_bus_r_handle_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event, const LL_SPI_InitTypeDef* preset) {
+    if (event == FuriHalSpiBusHandleEventInit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
+    } else if (event == FuriHalSpiBusHandleEventDeinit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+    } else if (event == FuriHalSpiBusHandleEventActivate) {
+        LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
+        LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
+        LL_SPI_Enable(handle->bus->spi);
+
+        hal_gpio_init_ex(handle->miso, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
+        hal_gpio_init_ex(handle->mosi, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
+        hal_gpio_init_ex(handle->sck, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
+
+        hal_gpio_write(handle->cs, false);
+    } else if (event == FuriHalSpiBusHandleEventDeactivate) {
+        hal_gpio_write(handle->cs, true);
+
+        hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+        hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
+
+        LL_SPI_Disable(handle->bus->spi);
+    }
+}
+
+static void furi_hal_spi_bus_handle_subghz_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_8m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = {
+    .bus=&furi_hal_spi_bus_r,
+    .callback=furi_hal_spi_bus_handle_subghz_event_callback,
     .miso=&gpio_spi_r_miso,
     .miso=&gpio_spi_r_miso,
     .mosi=&gpio_spi_r_mosi,
     .mosi=&gpio_spi_r_mosi,
-    .clk=&gpio_spi_r_sck,
+    .sck=&gpio_spi_r_sck,
+    .cs=&gpio_subghz_cs,
 };
 };
 
 
-const FuriHalSpiBus spi_d = {
-    .spi=SPI_D,
-    .mutex=&spi_mutex_d,
+static void furi_hal_spi_bus_handle_nfc_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = {
+    .bus=&furi_hal_spi_bus_r,
+    .callback=furi_hal_spi_bus_handle_nfc_event_callback,
+    .miso=&gpio_spi_r_miso,
+    .mosi=&gpio_spi_r_mosi,
+    .sck=&gpio_spi_r_sck,
+    .cs=&gpio_nfc_cs,
+};
+
+static void furi_hal_spi_bus_handle_external_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = {
+    .bus=&furi_hal_spi_bus_r,
+    .callback=furi_hal_spi_bus_handle_external_event_callback,
+    .miso=&gpio_ext_pa6,
+    .mosi=&gpio_ext_pa7,
+    .sck=&gpio_ext_pb3,
+    .cs=&gpio_ext_pa4,
+};
+
+inline static void furi_hal_spi_bus_d_handle_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event, const LL_SPI_InitTypeDef* preset) {
+    if (event == FuriHalSpiBusHandleEventInit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh);
+
+        hal_gpio_init_ex(handle->miso, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+        hal_gpio_init_ex(handle->mosi, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+        hal_gpio_init_ex(handle->sck, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+
+    } else if (event == FuriHalSpiBusHandleEventDeinit) {
+        hal_gpio_write(handle->cs, true);
+        hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullUp, GpioSpeedLow);
+    } else if (event == FuriHalSpiBusHandleEventActivate) {
+        LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset);
+        LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
+        LL_SPI_Enable(handle->bus->spi);
+        hal_gpio_write(handle->cs, false);
+    } else if (event == FuriHalSpiBusHandleEventDeactivate) {
+        hal_gpio_write(handle->cs, true);
+        LL_SPI_Disable(handle->bus->spi);
+    }
+}
+
+static void furi_hal_spi_bus_handle_display_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_4m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_display = {
+    .bus=&furi_hal_spi_bus_d,
+    .callback=furi_hal_spi_bus_handle_display_event_callback,
     .miso=&gpio_spi_d_miso,
     .miso=&gpio_spi_d_miso,
     .mosi=&gpio_spi_d_mosi,
     .mosi=&gpio_spi_d_mosi,
-    .clk=&gpio_spi_d_sck,
+    .sck=&gpio_spi_d_sck,
+    .cs=&gpio_display_cs,
 };
 };
 
 
-const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax] = {
-    { .bus=&spi_r, .config=&furi_hal_spi_config_subghz, .chip_select=&gpio_subghz_cs, },
-    { .bus=&spi_d, .config=&furi_hal_spi_config_display, .chip_select=&gpio_display_cs, },
-    { .bus=&spi_d, .config=&furi_hal_spi_config_sd_fast, .chip_select=&gpio_sdcard_cs, },
-    { .bus=&spi_d, .config=&furi_hal_spi_config_sd_slow, .chip_select=&gpio_sdcard_cs, },
-    { .bus=&spi_r, .config=&furi_hal_spi_config_nfc, .chip_select=&gpio_nfc_cs },
+static void furi_hal_spi_bus_handle_sd_fast_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_16m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast = {
+    .bus=&furi_hal_spi_bus_d,
+    .callback=furi_hal_spi_bus_handle_sd_fast_event_callback,
+    .miso=&gpio_spi_d_miso,
+    .mosi=&gpio_spi_d_mosi,
+    .sck=&gpio_spi_d_sck,
+    .cs=&gpio_sdcard_cs,
+};
+
+static void furi_hal_spi_bus_handle_sd_slow_event_callback(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event) {
+    furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m);
+}
+
+FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow = {
+    .bus=&furi_hal_spi_bus_d,
+    .callback=furi_hal_spi_bus_handle_sd_slow_event_callback,
+    .miso=&gpio_spi_d_miso,
+    .mosi=&gpio_spi_d_mosi,
+    .sck=&gpio_spi_d_sck,
+    .cs=&gpio_sdcard_cs,
 };
 };

+ 46 - 48
firmware/targets/f7/furi-hal/furi-hal-spi-config.h

@@ -1,62 +1,60 @@
 #pragma once
 #pragma once
 
 
-#include <furi-hal-gpio.h>
-#include <stm32wbxx_ll_spi.h>
-#include <cmsis_os2.h>
+#include <furi-hal-spi-types.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_nfc;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_subghz;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_display;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast;
-extern const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow;
+/** Preset for ST25R916 */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m;
 
 
-/** FURI HAL SPI BUS handler
- * Structure content may change at some point
- */
-typedef struct {
-    const SPI_TypeDef* spi;
-    const osMutexId_t* mutex;
-    const GpioPin* miso;
-    const GpioPin* mosi;
-    const GpioPin* clk;
-} FuriHalSpiBus;
-
-/** FURI HAL SPI Device handler
- * Structure content may change at some point
- */
-typedef struct {
-    const FuriHalSpiBus* bus;
-    const LL_SPI_InitTypeDef* config;
-    const GpioPin* chip_select;
-} FuriHalSpiDevice;
-
-/** FURI HAL SPI Standard Device IDs */
-typedef enum {
-    FuriHalSpiDeviceIdSubGhz,        /** SubGhz: CC1101, non-standard SPI usage */
-    FuriHalSpiDeviceIdDisplay,       /** Display: ERC12864, only have MOSI */
-    FuriHalSpiDeviceIdSdCardFast,    /** SDCARD: fast mode, after initialization */
-    FuriHalSpiDeviceIdSdCardSlow,    /** SDCARD: slow mode, before initialization */
-    FuriHalSpiDeviceIdNfc,           /** NFC: ST25R3916, pretty standard, but RFAL makes it complex */
-
-    FuriHalSpiDeviceIdMax,           /** Service Value, do not use */
-} FuriHalSpiDeviceId;
-
-/** Furi Hal Spi Bus R
- * CC1101, Nfc
- */
-extern const FuriHalSpiBus spi_r;
+/** Preset for CC1101 */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m;
+
+/** Preset for ST7567 (Display) */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m;
+
+/** Preset for SdCard in fast mode */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m;
+
+/** Preset for SdCard in slow mode */
+extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m;
 
 
-/** Furi Hal Spi Bus D
- * Display, SdCard
+/** Furi Hal Spi Bus R (Radio: CC1101, Nfc, External)*/
+extern FuriHalSpiBus furi_hal_spi_bus_r;
+
+/** Furi Hal Spi Bus D (Display, SdCard) */
+extern FuriHalSpiBus furi_hal_spi_bus_d;
+
+/** CC1101 on `furi_hal_spi_bus_r` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz;
+
+/** ST25R3916 on `furi_hal_spi_bus_r` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc;
+
+/** External on `furi_hal_spi_bus_r`
+ * Preset: `furi_hal_spi_preset_1edge_low_2m`
+ * 
+ * miso: pa6
+ * mosi: pa7
+ * sck: pb3
+ * cs:  pa4 (software controlled)
+ * 
+ * @warning not initialized by default, call `furi_hal_spi_bus_handle_init` to initialize
+ * Bus pins are floating on inactive state, CS high after initialization
+ * 
  */
  */
-extern const FuriHalSpiBus spi_d;
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_external;
+
+/** ST7567(Display) on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_display;
+
+/** SdCard in fast mode on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast;
 
 
-/** Furi Hal Spi devices */
-extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax];
+/** SdCard in slow mode on `furi_hal_spi_bus_d` */
+extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 62 - 0
firmware/targets/f7/furi-hal/furi-hal-spi-types.h

@@ -0,0 +1,62 @@
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <furi-hal-gpio.h>
+
+#include <stm32wbxx_ll_spi.h>
+#include <stm32wbxx_ll_rcc.h>
+#include <stm32wbxx_ll_bus.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct FuriHalSpiBus FuriHalSpiBus;
+typedef struct FuriHalSpiBusHandle FuriHalSpiBusHandle;
+
+/** FuriHal spi bus states */
+typedef enum {
+    FuriHalSpiBusEventInit, /**< Bus initialization event, called on system start */
+    FuriHalSpiBusEventDeinit, /**< Bus deinitialization event, called on system stop */
+    FuriHalSpiBusEventLock, /**< Bus lock event, called before activation */
+    FuriHalSpiBusEventUnlock, /**< Bus unlock event, called after deactivation */
+    FuriHalSpiBusEventActivate, /**< Bus activation event, called before handle activation */
+    FuriHalSpiBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation  */
+} FuriHalSpiBusEvent;
+
+/** FuriHal spi bus event callback */
+typedef void (*FuriHalSpiBusEventCallback)(FuriHalSpiBus* bus, FuriHalSpiBusEvent event);
+
+/** FuriHal spi bus */
+struct FuriHalSpiBus {
+    SPI_TypeDef* spi;
+    FuriHalSpiBusEventCallback callback;
+    FuriHalSpiBusHandle* current_handle;
+};
+
+/** FuriHal spi handle states */
+typedef enum {
+    FuriHalSpiBusHandleEventInit, /**< Handle init, called on system start, initialize gpio for idle state */
+    FuriHalSpiBusHandleEventDeinit, /**< Handle deinit, called on system stop, deinitialize gpio for default state */
+    FuriHalSpiBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
+    FuriHalSpiBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
+} FuriHalSpiBusHandleEvent;
+
+/** FuriHal spi handle event callback */
+typedef void (*FuriHalSpiBusHandleEventCallback)(FuriHalSpiBusHandle* handle, FuriHalSpiBusHandleEvent event);
+
+/** FuriHal spi handle */
+struct FuriHalSpiBusHandle {
+    FuriHalSpiBus* bus;
+    FuriHalSpiBusHandleEventCallback callback;
+    const GpioPin* miso;
+    const GpioPin* mosi;
+    const GpioPin* sck;
+    const GpioPin* cs;
+};
+
+#ifdef __cplusplus
+}
+#endif

+ 67 - 129
firmware/targets/f7/furi-hal/furi-hal-spi.c

@@ -12,89 +12,104 @@
 #define TAG "FuriHalSpi"
 #define TAG "FuriHalSpi"
 
 
 void furi_hal_spi_init() {
 void furi_hal_spi_init() {
-    // Spi structure is const, but mutex is not
-    // Need some hell-ish casting to make it work
-    *(osMutexId_t*)spi_r.mutex = osMutexNew(NULL);
-    *(osMutexId_t*)spi_d.mutex = osMutexNew(NULL);
-    // 
-    for (size_t i=0; i<FuriHalSpiDeviceIdMax; ++i) {
-        hal_gpio_write(furi_hal_spi_devices[i].chip_select, true);
-        hal_gpio_init(
-            furi_hal_spi_devices[i].chip_select,
-            GpioModeOutputPushPull,
-            GpioPullNo,
-            GpioSpeedVeryHigh
-        );
-    }
-
-    hal_gpio_init_ex(&gpio_spi_r_miso, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
-    hal_gpio_init_ex(&gpio_spi_r_mosi, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
-    hal_gpio_init_ex(&gpio_spi_r_sck, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedVeryHigh, GpioAltFn5SPI1);
+    furi_hal_spi_bus_init(&furi_hal_spi_bus_r);
+    furi_hal_spi_bus_init(&furi_hal_spi_bus_d);
 
 
-    hal_gpio_init_ex(&gpio_spi_d_miso, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
-    hal_gpio_init_ex(&gpio_spi_d_mosi, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
-    hal_gpio_init_ex(&gpio_spi_d_sck, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedVeryHigh, GpioAltFn5SPI2);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast);
+    furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow);
 
 
     FURI_LOG_I(TAG, "Init OK");
     FURI_LOG_I(TAG, "Init OK");
 }
 }
 
 
-void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus) {
+void furi_hal_spi_bus_init(FuriHalSpiBus* bus) {
     furi_assert(bus);
     furi_assert(bus);
-    furi_check(osMutexAcquire(*bus->mutex, osWaitForever) == osOK);
+    bus->callback(bus, FuriHalSpiBusEventInit);
 }
 }
 
 
-void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) {
+void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus) {
     furi_assert(bus);
     furi_assert(bus);
-    furi_check(osMutexRelease(*bus->mutex) == osOK);
+    bus->callback(bus, FuriHalSpiBusEventDeinit);
 }
 }
 
 
-void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config) {
-    furi_assert(bus);
+void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle) {
+    furi_assert(handle);
+    handle->callback(handle, FuriHalSpiBusHandleEventInit);
+}
 
 
-    LL_SPI_DeInit((SPI_TypeDef*)bus->spi);
-    LL_SPI_Init((SPI_TypeDef*)bus->spi, (LL_SPI_InitTypeDef*)config);
-    LL_SPI_SetRxFIFOThreshold((SPI_TypeDef*)bus->spi, LL_SPI_RX_FIFO_TH_QUARTER);
-    LL_SPI_Enable((SPI_TypeDef*)bus->spi);
+void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle) {
+    furi_assert(handle);
+    handle->callback(handle, FuriHalSpiBusHandleEventDeinit);
 }
 }
 
 
-void furi_hal_spi_bus_end_txrx(const FuriHalSpiBus* bus, uint32_t timeout) {
-    while(LL_SPI_GetTxFIFOLevel((SPI_TypeDef *)bus->spi) != LL_SPI_TX_FIFO_EMPTY);
-    while(LL_SPI_IsActiveFlag_BSY((SPI_TypeDef *)bus->spi));
-    while(LL_SPI_GetRxFIFOLevel((SPI_TypeDef *)bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
-        LL_SPI_ReceiveData8((SPI_TypeDef *)bus->spi);
+void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle) {
+    furi_assert(handle);
+
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventLock);
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventActivate);
+
+    furi_assert(handle->bus->current_handle == NULL);
+
+    handle->bus->current_handle = handle;
+    handle->callback(handle, FuriHalSpiBusHandleEventActivate);
+}
+
+void furi_hal_spi_release(FuriHalSpiBusHandle* handle) {
+    furi_assert(handle);
+    furi_assert(handle->bus->current_handle == handle);
+
+    // Handle event and unset handle
+    handle->callback(handle, FuriHalSpiBusHandleEventDeactivate);
+    handle->bus->current_handle = NULL;
+
+    // Bus events
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventDeactivate);
+    handle->bus->callback(handle->bus, FuriHalSpiBusEventUnlock);
+}
+
+static void furi_hal_spi_bus_end_txrx(FuriHalSpiBusHandle* handle, uint32_t timeout) {
+    while(LL_SPI_GetTxFIFOLevel(handle->bus->spi) != LL_SPI_TX_FIFO_EMPTY);
+    while(LL_SPI_IsActiveFlag_BSY(handle->bus->spi));
+    while(LL_SPI_GetRxFIFOLevel(handle->bus->spi) != LL_SPI_RX_FIFO_EMPTY) {
+        LL_SPI_ReceiveData8(handle->bus->spi);
     }
     }
 }
 }
 
 
-bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
-    furi_assert(bus);
+bool furi_hal_spi_bus_rx(FuriHalSpiBusHandle* handle, uint8_t* buffer, size_t size, uint32_t timeout) {
+    furi_assert(handle);
+    furi_assert(handle->bus->current_handle == handle);
     furi_assert(buffer);
     furi_assert(buffer);
     furi_assert(size > 0);
     furi_assert(size > 0);
 
 
-    return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout);
+    return furi_hal_spi_bus_trx(handle, buffer, buffer, size, timeout);
 }
 }
 
 
-bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
-    furi_assert(bus);
+bool furi_hal_spi_bus_tx(FuriHalSpiBusHandle* handle, uint8_t* buffer, size_t size, uint32_t timeout) {
+    furi_assert(handle);
+    furi_assert(handle->bus->current_handle == handle);
     furi_assert(buffer);
     furi_assert(buffer);
     furi_assert(size > 0);
     furi_assert(size > 0);
     bool ret = true;
     bool ret = true;
 
 
     while(size > 0) {
     while(size > 0) {
-        if (LL_SPI_IsActiveFlag_TXE((SPI_TypeDef *)bus->spi)) {
-            LL_SPI_TransmitData8((SPI_TypeDef *)bus->spi, *buffer);
+        if (LL_SPI_IsActiveFlag_TXE(handle->bus->spi)) {
+            LL_SPI_TransmitData8(handle->bus->spi, *buffer);
             buffer++;
             buffer++;
             size--;
             size--;
         }
         }
     }
     }
 
 
-    furi_hal_spi_bus_end_txrx(bus, timeout);
-    LL_SPI_ClearFlag_OVR((SPI_TypeDef *)bus->spi);
+    furi_hal_spi_bus_end_txrx(handle, timeout);
+    LL_SPI_ClearFlag_OVR(handle->bus->spi);
 
 
     return ret;
     return ret;
 }
 }
 
 
-bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) {
-    furi_assert(bus);
+bool furi_hal_spi_bus_trx(FuriHalSpiBusHandle* handle, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) {
+    furi_assert(handle);
+    furi_assert(handle->bus->current_handle == handle);
     furi_assert(tx_buffer);
     furi_assert(tx_buffer);
     furi_assert(rx_buffer);
     furi_assert(rx_buffer);
     furi_assert(size > 0);
     furi_assert(size > 0);
@@ -104,99 +119,22 @@ bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t*
     bool tx_allowed = true;
     bool tx_allowed = true;
 
 
     while(size > 0) {
     while(size > 0) {
-        if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE((SPI_TypeDef *)bus->spi) && tx_allowed) {
-            LL_SPI_TransmitData8((SPI_TypeDef *)bus->spi, *tx_buffer);
+        if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) {
+            LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
             tx_buffer++;
             tx_buffer++;
             tx_size--;
             tx_size--;
             tx_allowed = false;
             tx_allowed = false;
         }
         }
         
         
-        if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef *)bus->spi)) {
-            *rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef *)bus->spi);
+        if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) {
+            *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
             rx_buffer++;
             rx_buffer++;
             size--;
             size--;
             tx_allowed = true;
             tx_allowed = true;
         }
         }
     }
     }
 
 
-    furi_hal_spi_bus_end_txrx(bus, timeout);
-
-    return ret;
-}
-
-void furi_hal_spi_device_configure(const FuriHalSpiDevice* device) {
-    furi_assert(device);
-    furi_assert(device->config);
-
-    furi_hal_spi_bus_configure(device->bus, device->config);
-}
-
-const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id) {
-    furi_assert(device_id < FuriHalSpiDeviceIdMax);
-
-    const FuriHalSpiDevice* device = &furi_hal_spi_devices[device_id];
-    furi_assert(device);
-    furi_hal_spi_bus_lock(device->bus);
-    furi_hal_spi_device_configure(device);
-
-    return device;
-}
-
-void furi_hal_spi_device_return(const FuriHalSpiDevice* device) {
-    furi_hal_spi_bus_unlock(device->bus);
-}
-
-bool furi_hal_spi_device_rx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) {
-    furi_assert(device);
-    furi_assert(buffer);
-    furi_assert(size > 0);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_rx(device->bus, buffer, size, timeout);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
-
-    return ret;
-}
-
-bool furi_hal_spi_device_tx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout) {
-    furi_assert(device);
-    furi_assert(buffer);
-    furi_assert(size > 0);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_tx(device->bus, buffer, size, timeout);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
-
-    return ret;
-}
-
-bool furi_hal_spi_device_trx(const FuriHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout) {
-    furi_assert(device);
-    furi_assert(tx_buffer);
-    furi_assert(rx_buffer);
-    furi_assert(size > 0);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, false);
-    }
-
-    bool ret = furi_hal_spi_bus_trx(device->bus, tx_buffer, rx_buffer, size, timeout);
-
-    if (device->chip_select) {
-        hal_gpio_write(device->chip_select, true);
-    }
+    furi_hal_spi_bus_end_txrx(handle, timeout);
 
 
     return ret;
     return ret;
 }
 }

+ 66 - 66
firmware/targets/f7/furi-hal/furi-hal-subghz.c

@@ -269,7 +269,7 @@ void furi_hal_subghz_init() {
     furi_assert(furi_hal_subghz_state == SubGhzStateInit);
     furi_assert(furi_hal_subghz_state == SubGhzStateInit);
     furi_hal_subghz_state = SubGhzStateIdle;
     furi_hal_subghz_state = SubGhzStateIdle;
 
 
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 
 
 #ifdef FURI_HAL_SUBGHZ_TX_GPIO
 #ifdef FURI_HAL_SUBGHZ_TX_GPIO
     hal_gpio_init(&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
@@ -277,58 +277,58 @@ void furi_hal_subghz_init() {
 
 
     // Reset
     // Reset
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
-    cc1101_reset(device);
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
+    cc1101_reset(&furi_hal_spi_bus_handle_subghz);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
 
 
     // Prepare GD0 for power on self test
     // Prepare GD0 for power on self test
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 
 
     // GD0 low
     // GD0 low
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW);
     while(hal_gpio_read(&gpio_cc1101_g0) != false)
     while(hal_gpio_read(&gpio_cc1101_g0) != false)
         ;
         ;
 
 
     // GD0 high
     // GD0 high
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV);
     while(hal_gpio_read(&gpio_cc1101_g0) != true)
     while(hal_gpio_read(&gpio_cc1101_g0) != true)
         ;
         ;
 
 
     // Reset GD0 to floating state
     // Reset GD0 to floating state
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 
 
     // RF switches
     // RF switches
     hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-    cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW);
 
 
     // Go to sleep
     // Go to sleep
-    cc1101_shutdown(device);
+    cc1101_shutdown(&furi_hal_spi_bus_handle_subghz);
 
 
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
     FURI_LOG_I(TAG, "Init OK");
     FURI_LOG_I(TAG, "Init OK");
 }
 }
 
 
 void furi_hal_subghz_sleep() {
 void furi_hal_subghz_sleep() {
     furi_assert(furi_hal_subghz_state == SubGhzStateIdle);
     furi_assert(furi_hal_subghz_state == SubGhzStateIdle);
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 
 
-    cc1101_switch_to_idle(device);
+    cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
 
 
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 
 
-    cc1101_shutdown(device);
+    cc1101_shutdown(&furi_hal_spi_bus_handle_subghz);
 
 
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_dump_state() {
 void furi_hal_subghz_dump_state() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
     printf(
     printf(
         "[furi_hal_subghz] cc1101 chip %d, version %d\r\n",
         "[furi_hal_subghz] cc1101 chip %d, version %d\r\n",
-        cc1101_get_partnumber(device),
-        cc1101_get_version(device));
-    furi_hal_spi_device_return(device);
+        cc1101_get_partnumber(&furi_hal_spi_bus_handle_subghz),
+        cc1101_get_version(&furi_hal_spi_bus_handle_subghz));
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
 void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
@@ -350,81 +350,81 @@ void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
 }
 }
 
 
 void furi_hal_subghz_load_registers(const uint8_t data[][2]) {
 void furi_hal_subghz_load_registers(const uint8_t data[][2]) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_reset(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_reset(&furi_hal_spi_bus_handle_subghz);
     uint32_t i = 0;
     uint32_t i = 0;
     while(data[i][0]) {
     while(data[i][0]) {
-        cc1101_write_reg(device, data[i][0], data[i][1]);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, data[i][0], data[i][1]);
         i++;
         i++;
     }
     }
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_load_patable(const uint8_t data[8]) {
 void furi_hal_subghz_load_patable(const uint8_t data[8]) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_set_pa_table(device, data);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_set_pa_table(&furi_hal_spi_bus_handle_subghz, data);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
 void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_flush_tx(device);
-    cc1101_write_fifo(device, data, size);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_flush_tx(&furi_hal_spi_bus_handle_subghz);
+    cc1101_write_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_flush_rx() {
 void furi_hal_subghz_flush_rx() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_flush_rx(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_flush_rx(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) {
 void furi_hal_subghz_read_packet(uint8_t* data, uint8_t* size) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_read_fifo(device, data, size);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_read_fifo(&furi_hal_spi_bus_handle_subghz, data, size);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_shutdown() {
 void furi_hal_subghz_shutdown() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
     // Reset and shutdown
     // Reset and shutdown
-    cc1101_shutdown(device);
-    furi_hal_spi_device_return(device);
+    cc1101_shutdown(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_reset() {
 void furi_hal_subghz_reset() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
-    cc1101_switch_to_idle(device);
-    cc1101_reset(device);
-    cc1101_write_reg(device, CC1101_IOCFG0, CC1101IocfgHighImpedance);
-    furi_hal_spi_device_return(device);
+    cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
+    cc1101_reset(&furi_hal_spi_bus_handle_subghz);
+    cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_idle() {
 void furi_hal_subghz_idle() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_switch_to_idle(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 void furi_hal_subghz_rx() {
 void furi_hal_subghz_rx() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_switch_to_rx(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_switch_to_rx(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 bool furi_hal_subghz_tx() {
 bool furi_hal_subghz_tx() {
     if(furi_hal_subghz_regulation != SubGhzRegulationTxRx) return false;
     if(furi_hal_subghz_regulation != SubGhzRegulationTxRx) return false;
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    cc1101_switch_to_tx(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    cc1101_switch_to_tx(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
     return true;
     return true;
 }
 }
 
 
 float furi_hal_subghz_get_rssi() {
 float furi_hal_subghz_get_rssi() {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
-    int32_t rssi_dec = cc1101_get_rssi(device);
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
+    int32_t rssi_dec = cc1101_get_rssi(&furi_hal_spi_bus_handle_subghz);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 
 
     float rssi = rssi_dec;
     float rssi = rssi_dec;
     if(rssi_dec >= 128) {
     if(rssi_dec >= 128) {
@@ -461,7 +461,7 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value) {
 }
 }
 
 
 uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
 uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
 
 
     //checking regional settings
     //checking regional settings
     bool txrx = false;
     bool txrx = false;
@@ -503,37 +503,37 @@ uint32_t furi_hal_subghz_set_frequency(uint32_t value) {
         furi_hal_subghz_regulation = SubGhzRegulationOnlyRx;
         furi_hal_subghz_regulation = SubGhzRegulationOnlyRx;
     }
     }
 
 
-    uint32_t real_frequency = cc1101_set_frequency(device, value);
-    cc1101_calibrate(device);
+    uint32_t real_frequency = cc1101_set_frequency(&furi_hal_spi_bus_handle_subghz, value);
+    cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
 
 
     while(true) {
     while(true) {
-        CC1101Status status = cc1101_get_status(device);
+        CC1101Status status = cc1101_get_status(&furi_hal_spi_bus_handle_subghz);
         if(status.STATE == CC1101StateIDLE) break;
         if(status.STATE == CC1101StateIDLE) break;
     }
     }
 
 
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 
 
     return real_frequency;
     return real_frequency;
 }
 }
 
 
 void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
 void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
-    const FuriHalSpiDevice* device = furi_hal_spi_device_get(FuriHalSpiDeviceIdSubGhz);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
     if(path == FuriHalSubGhzPath433) {
     if(path == FuriHalSubGhzPath433) {
         hal_gpio_write(&gpio_rf_sw_0, 0);
         hal_gpio_write(&gpio_rf_sw_0, 0);
-        cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
     } else if(path == FuriHalSubGhzPath315) {
     } else if(path == FuriHalSubGhzPath315) {
         hal_gpio_write(&gpio_rf_sw_0, 1);
         hal_gpio_write(&gpio_rf_sw_0, 1);
-        cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW);
     } else if(path == FuriHalSubGhzPath868) {
     } else if(path == FuriHalSubGhzPath868) {
         hal_gpio_write(&gpio_rf_sw_0, 1);
         hal_gpio_write(&gpio_rf_sw_0, 1);
-        cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW | CC1101_IOCFG_INV);
     } else if(path == FuriHalSubGhzPathIsolate) {
     } else if(path == FuriHalSubGhzPathIsolate) {
         hal_gpio_write(&gpio_rf_sw_0, 0);
         hal_gpio_write(&gpio_rf_sw_0, 0);
-        cc1101_write_reg(device, CC1101_IOCFG2, CC1101IocfgHW);
+        cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW);
     } else {
     } else {
         furi_crash(NULL);
         furi_crash(NULL);
     }
     }
-    furi_hal_spi_device_return(device);
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
 }
 }
 
 
 volatile uint32_t furi_hal_subghz_capture_delta_duration = 0;
 volatile uint32_t furi_hal_subghz_capture_delta_duration = 0;

+ 4 - 0
firmware/targets/furi-hal-include/furi-hal-sd.h

@@ -5,6 +5,7 @@
 
 
 #include <stdint.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdbool.h>
+#include <furi-hal-spi-types.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -24,6 +25,9 @@ void hal_sd_detect_set_low(void);
  */
  */
 bool hal_sd_detect(void);
 bool hal_sd_detect(void);
 
 
+/** Pointer to currently used SPI Handle */
+extern FuriHalSpiBusHandle* furi_hal_sd_spi_handle;
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 57 - 75
firmware/targets/furi-hal-include/furi-hal-spi.h

@@ -1,106 +1,88 @@
 #pragma once
 #pragma once
-#include "main.h"
-#include "furi-hal-spi-config.h"
-#include <furi-hal-gpio.h>
+
+#include <furi-hal-spi-config.h>
 #include <stdbool.h>
 #include <stdbool.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-/**
- * Init SPI API
- */
+/** Initialize SPI HAL */
 void furi_hal_spi_init();
 void furi_hal_spi_init();
 
 
-/* Bus Level API */
-
-/** Lock SPI bus
- * Takes bus mutex, if used
+/** Initialize SPI Bus
+ *
+ * @param      handle  pointer to FuriHalSpiBus instance
  */
  */
-void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
+void furi_hal_spi_bus_init(FuriHalSpiBus* bus);
 
 
-/** Unlock SPI bus
- * Releases BUS mutex, if used
+/** Deinitialize SPI Bus
+ *
+ * @param      handle  pointer to FuriHalSpiBus instance
  */
  */
-void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
+void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus);
 
 
-/** Configure SPI bus
- * @param bus - spi bus handler
- * @param config - spi configuration structure
+/** Initialize SPI Bus Handle
+ *
+ * @param      handle  pointer to FuriHalSpiBusHandle instance
  */
  */
-void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config);
+void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle);
 
 
-/** SPI Receive
- * @param bus - spi bus handler
- * @param buffer - receive buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
+/** Deinitialize SPI Bus Handle
+ *
+ * @param      handle  pointer to FuriHalSpiBusHandle instance
  */
  */
-bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
+void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle);
 
 
-/** SPI Transmit
- * @param bus - spi bus handler
- * @param buffer - transmit buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
+/** Acquire SPI bus
+ *
+ * @warning blocking, calls `furi_crash` on programming error, CS transition is up to handler event routine
+ *
+ * @param      handle  pointer to FuriHalSpiBusHandle instance
  */
  */
-bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
+void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle);
 
 
-/** SPI Transmit and Receive
- * @param bus - spi bus handlere
- * @param tx_buffer - device handle
- * @param rx_buffer - device handle
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
+/** Release SPI bus
+ *
+ * @warning calls `furi_crash` on programming error, CS transition is up to handler event routine
+ * 
+ * @param      handle  pointer to FuriHalSpiBusHandle instance
  */
  */
-bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
+void furi_hal_spi_release(FuriHalSpiBusHandle* handle);
 
 
-/* Device Level API */
-
-/** Reconfigure SPI bus for device
- * @param device - device description
- */
-void furi_hal_spi_device_configure(const FuriHalSpiDevice* device);
-
-/** Get Device handle
- * And lock access to the corresponding SPI BUS
- * @param device_id - device identifier
- * @return device handle
- */
-const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id);
-
-/** Return Device handle
- * And unlock access to the corresponding SPI BUS
- * @param device - device handle
- */
-void furi_hal_spi_device_return(const FuriHalSpiDevice* device);
-
-/** SPI Recieve
- * @param device - device handle
- * @param buffer - receive buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
+/** SPI Receive
+ *
+ * @param      handle   pointer to FuriHalSpiBusHandle instance
+ * @param      buffer   receive buffer
+ * @param      size     transaction size (buffer size)
+ * @param      timeout  operation timeout in ms
+ *
+ * @return     true on sucess
  */
  */
-bool furi_hal_spi_device_rx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout);
+bool furi_hal_spi_bus_rx(FuriHalSpiBusHandle* handle, uint8_t* buffer, size_t size, uint32_t timeout);
 
 
 /** SPI Transmit
 /** SPI Transmit
- * @param device - device handle
- * @param buffer - transmit buffer
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
+ *
+ * @param      handle   pointer to FuriHalSpiBusHandle instance
+ * @param      buffer   transmit buffer
+ * @param      size     transaction size (buffer size)
+ * @param      timeout  operation timeout in ms
+ *
+ * @return     true on success
  */
  */
-bool furi_hal_spi_device_tx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout);
+bool furi_hal_spi_bus_tx(FuriHalSpiBusHandle* handle, uint8_t* buffer, size_t size, uint32_t timeout);
 
 
 /** SPI Transmit and Receive
 /** SPI Transmit and Receive
- * @param device - device handle
- * @param tx_buffer - device handle
- * @param rx_buffer - device handle
- * @param size - transaction size
- * @param timeout - bus operation timeout in ms
+ *
+ * @param      handle     pointer to FuriHalSpiBusHandle instance
+ * @param      tx_buffer  pointer to tx buffer
+ * @param      rx_buffer  pointer to rx buffer
+ * @param      size       transaction size (buffer size)
+ * @param      timeout    operation timeout in ms
+ *
+ * @return     true on success
  */
  */
-bool furi_hal_spi_device_trx(const FuriHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
-
+bool furi_hal_spi_bus_trx(FuriHalSpiBusHandle* handle, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 1 - 0
firmware/targets/furi-hal-include/furi-hal.h

@@ -14,6 +14,7 @@ template <unsigned int N> struct STOP_EXTERNING_ME {};
 #include "furi-hal-crypto.h"
 #include "furi-hal-crypto.h"
 #include "furi-hal-console.h"
 #include "furi-hal-console.h"
 #include "furi-hal-os.h"
 #include "furi-hal-os.h"
+#include "furi-hal-sd.h"
 #include "furi-hal-i2c.h"
 #include "furi-hal-i2c.h"
 #include "furi-hal-resources.h"
 #include "furi-hal-resources.h"
 #include "furi-hal-gpio.h"
 #include "furi-hal-gpio.h"

+ 5 - 13
lib/ST25RFAL002/platform.c

@@ -7,7 +7,6 @@
 static osThreadAttr_t platform_irq_thread_attr;
 static osThreadAttr_t platform_irq_thread_attr;
 static volatile osThreadId_t platform_irq_thread_id = NULL;
 static volatile osThreadId_t platform_irq_thread_id = NULL;
 static volatile PlatformIrqCallback platform_irq_callback = NULL;
 static volatile PlatformIrqCallback platform_irq_callback = NULL;
-static FuriHalSpiDevice* platform_st25r3916 = NULL;
 static const GpioPin pin = {ST25R_INT_PORT, ST25R_INT_PIN};
 static const GpioPin pin = {ST25R_INT_PORT, ST25R_INT_PIN};
 
 
 void nfc_isr(void* _ctx) {
 void nfc_isr(void* _ctx) {
@@ -49,14 +48,13 @@ void platformSetIrqCallback(PlatformIrqCallback callback) {
 }
 }
 
 
 HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len) {
 HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len) {
-    furi_assert(platform_st25r3916);
     bool ret = false;
     bool ret = false;
     if (txBuf && rxBuf) {
     if (txBuf && rxBuf) {
-        ret = furi_hal_spi_bus_trx(platform_st25r3916->bus, (uint8_t*)txBuf, rxBuf, len, 1000);
+        ret = furi_hal_spi_bus_trx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)txBuf, rxBuf, len, 1000);
     } else if (txBuf) {
     } else if (txBuf) {
-        ret = furi_hal_spi_bus_tx(platform_st25r3916->bus, (uint8_t*)txBuf, len, 1000);
+        ret = furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)txBuf, len, 1000);
     } else if (rxBuf) {
     } else if (rxBuf) {
-        ret = furi_hal_spi_bus_rx(platform_st25r3916->bus, (uint8_t*)rxBuf, len, 1000);
+        ret = furi_hal_spi_bus_rx(&furi_hal_spi_bus_handle_nfc, (uint8_t*)rxBuf, len, 1000);
     }
     }
 
 
     if(!ret) {
     if(!ret) {
@@ -68,15 +66,9 @@ HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t
 }
 }
 
 
 void platformProtectST25RComm() {
 void platformProtectST25RComm() {
-    // Don't check platform_st25r3916 since spi device is used simultaneously from nfc worker
-    // thread and platformIrqWorker thread with the highest priority
-
-    // furi_assert(platform_st25r3916 == NULL);
-    platform_st25r3916 = (FuriHalSpiDevice*)furi_hal_spi_device_get(FuriHalSpiDeviceIdNfc);
+    furi_hal_spi_acquire(&furi_hal_spi_bus_handle_nfc);
 }
 }
 
 
 void platformUnprotectST25RComm() {
 void platformUnprotectST25RComm() {
-    // furi_assert(platform_st25r3916);
-    furi_hal_spi_device_return(platform_st25r3916);
-    // platform_st25r3916 = NULL;
+    furi_hal_spi_release(&furi_hal_spi_bus_handle_nfc);
 }
 }

+ 50 - 66
lib/drivers/cc1101.c

@@ -4,180 +4,164 @@
 #include <assert.h>
 #include <assert.h>
 #include <string.h>
 #include <string.h>
 
 
-CC1101Status cc1101_strobe(const FuriHalSpiDevice* device, uint8_t strobe) {
+CC1101Status cc1101_strobe(FuriHalSpiBusHandle* handle, uint8_t strobe) {
     uint8_t tx[1] = { strobe };
     uint8_t tx[1] = { strobe };
     CC1101Status rx[1] = { 0 };
     CC1101Status rx[1] = { 0 };
 
 
-    hal_gpio_write(device->chip_select, false);
-    while(hal_gpio_read(device->bus->miso));
-    furi_hal_spi_bus_trx(device->bus, tx, (uint8_t*)rx, 1, CC1101_TIMEOUT);
-    hal_gpio_write(device->chip_select, true);
+    while(hal_gpio_read(handle->miso));
+    furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 1, CC1101_TIMEOUT);
 
 
     assert(rx[0].CHIP_RDYn == 0);
     assert(rx[0].CHIP_RDYn == 0);
     return rx[0];
     return rx[0];
 }
 }
 
 
-CC1101Status cc1101_write_reg(const FuriHalSpiDevice* device, uint8_t reg, uint8_t data) {
+CC1101Status cc1101_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t data) {
     uint8_t tx[2] = { reg, data };
     uint8_t tx[2] = { reg, data };
     CC1101Status rx[2] = { 0 };
     CC1101Status rx[2] = { 0 };
 
 
-    hal_gpio_write(device->chip_select, false);
-    while(hal_gpio_read(device->bus->miso));
-    furi_hal_spi_bus_trx(device->bus, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT);
-    hal_gpio_write(device->chip_select, true);
+    while(hal_gpio_read(handle->miso));
+    furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT);
 
 
     assert((rx[0].CHIP_RDYn|rx[1].CHIP_RDYn) == 0);
     assert((rx[0].CHIP_RDYn|rx[1].CHIP_RDYn) == 0);
     return rx[1];
     return rx[1];
 }
 }
 
 
-CC1101Status cc1101_read_reg(const FuriHalSpiDevice* device, uint8_t reg, uint8_t* data) {
+CC1101Status cc1101_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data) {
     assert(sizeof(CC1101Status) == 1);
     assert(sizeof(CC1101Status) == 1);
     uint8_t tx[2] = { reg|CC1101_READ, 0};
     uint8_t tx[2] = { reg|CC1101_READ, 0};
     CC1101Status rx[2] = { 0 };
     CC1101Status rx[2] = { 0 };
 
 
-    hal_gpio_write(device->chip_select, false);
-    while(hal_gpio_read(device->bus->miso));
-    furi_hal_spi_bus_trx(device->bus, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT);
-    hal_gpio_write(device->chip_select, true);
+    while(hal_gpio_read(handle->miso));
+    furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, 2, CC1101_TIMEOUT);
 
 
     assert((rx[0].CHIP_RDYn) == 0);
     assert((rx[0].CHIP_RDYn) == 0);
     *data = *(uint8_t*)&rx[1];
     *data = *(uint8_t*)&rx[1];
     return rx[0];
     return rx[0];
 }
 }
 
 
-uint8_t cc1101_get_partnumber(const FuriHalSpiDevice* device) {
+uint8_t cc1101_get_partnumber(FuriHalSpiBusHandle* handle) {
     uint8_t partnumber=0;
     uint8_t partnumber=0;
-    cc1101_read_reg(device, CC1101_STATUS_PARTNUM|CC1101_BURST, &partnumber);
+    cc1101_read_reg(handle, CC1101_STATUS_PARTNUM|CC1101_BURST, &partnumber);
     return partnumber;
     return partnumber;
 }
 }
 
 
-uint8_t cc1101_get_version(const FuriHalSpiDevice* device) {
+uint8_t cc1101_get_version(FuriHalSpiBusHandle* handle) {
     uint8_t version=0;
     uint8_t version=0;
-    cc1101_read_reg(device, CC1101_STATUS_VERSION|CC1101_BURST, &version);
+    cc1101_read_reg(handle, CC1101_STATUS_VERSION|CC1101_BURST, &version);
     return version;
     return version;
 }
 }
 
 
-uint8_t cc1101_get_rssi(const FuriHalSpiDevice* device) {
+uint8_t cc1101_get_rssi(FuriHalSpiBusHandle* handle) {
     uint8_t rssi=0;
     uint8_t rssi=0;
-    cc1101_read_reg(device, CC1101_STATUS_RSSI|CC1101_BURST, &rssi);
+    cc1101_read_reg(handle, CC1101_STATUS_RSSI|CC1101_BURST, &rssi);
     return rssi;
     return rssi;
 }
 }
 
 
-void cc1101_reset(const FuriHalSpiDevice* device) {
-    hal_gpio_write(device->chip_select, false);
+void cc1101_reset(FuriHalSpiBusHandle* handle) {
     delay_us(1000);
     delay_us(1000);
-    hal_gpio_write(device->chip_select, true);
     delay_us(1000);
     delay_us(1000);
-    cc1101_strobe(device, CC1101_STROBE_SRES);
+    cc1101_strobe(handle, CC1101_STROBE_SRES);
 }
 }
 
 
-CC1101Status cc1101_get_status(const FuriHalSpiDevice* device) {
-    return cc1101_strobe(device, CC1101_STROBE_SNOP);
+CC1101Status cc1101_get_status(FuriHalSpiBusHandle* handle) {
+    return cc1101_strobe(handle, CC1101_STROBE_SNOP);
 }
 }
 
 
-void cc1101_shutdown(const FuriHalSpiDevice* device) {
-    cc1101_strobe(device, CC1101_STROBE_SPWD);
+void cc1101_shutdown(FuriHalSpiBusHandle* handle) {
+    cc1101_strobe(handle, CC1101_STROBE_SPWD);
 }
 }
 
 
-void cc1101_calibrate(const FuriHalSpiDevice* device) {
-    cc1101_strobe(device, CC1101_STROBE_SCAL);
+void cc1101_calibrate(FuriHalSpiBusHandle* handle) {
+    cc1101_strobe(handle, CC1101_STROBE_SCAL);
 }
 }
 
 
-void cc1101_switch_to_idle(const FuriHalSpiDevice* device) {
-    cc1101_strobe(device, CC1101_STROBE_SIDLE);
+void cc1101_switch_to_idle(FuriHalSpiBusHandle* handle) {
+    cc1101_strobe(handle, CC1101_STROBE_SIDLE);
 }
 }
 
 
-void cc1101_switch_to_rx(const FuriHalSpiDevice* device) {
-    cc1101_strobe(device, CC1101_STROBE_SRX);
+void cc1101_switch_to_rx(FuriHalSpiBusHandle* handle) {
+    cc1101_strobe(handle, CC1101_STROBE_SRX);
 }
 }
 
 
-void cc1101_switch_to_tx(const FuriHalSpiDevice* device) {
-    cc1101_strobe(device, CC1101_STROBE_STX);
+void cc1101_switch_to_tx(FuriHalSpiBusHandle* handle) {
+    cc1101_strobe(handle, CC1101_STROBE_STX);
 }
 }
 
 
-void cc1101_flush_rx(const FuriHalSpiDevice* device) {
-    cc1101_strobe(device, CC1101_STROBE_SFRX);
+void cc1101_flush_rx(FuriHalSpiBusHandle* handle) {
+    cc1101_strobe(handle, CC1101_STROBE_SFRX);
 }
 }
 
 
-void cc1101_flush_tx(const FuriHalSpiDevice* device) {
-    cc1101_strobe(device, CC1101_STROBE_SFTX);
+void cc1101_flush_tx(FuriHalSpiBusHandle* handle) {
+    cc1101_strobe(handle, CC1101_STROBE_SFTX);
 }
 }
 
 
-uint32_t cc1101_set_frequency(const FuriHalSpiDevice* device, uint32_t value) {
+uint32_t cc1101_set_frequency(FuriHalSpiBusHandle* handle, uint32_t value) {
     uint64_t real_value = (uint64_t)value * CC1101_FDIV / CC1101_QUARTZ;
     uint64_t real_value = (uint64_t)value * CC1101_FDIV / CC1101_QUARTZ;
 
 
     // Sanity check
     // Sanity check
     assert((real_value & CC1101_FMASK) == real_value);
     assert((real_value & CC1101_FMASK) == real_value);
 
 
-    cc1101_write_reg(device, CC1101_FREQ2, (real_value >> 16) & 0xFF);
-    cc1101_write_reg(device, CC1101_FREQ1, (real_value >> 8 ) & 0xFF);
-    cc1101_write_reg(device, CC1101_FREQ0, (real_value >> 0 ) & 0xFF);
+    cc1101_write_reg(handle, CC1101_FREQ2, (real_value >> 16) & 0xFF);
+    cc1101_write_reg(handle, CC1101_FREQ1, (real_value >> 8 ) & 0xFF);
+    cc1101_write_reg(handle, CC1101_FREQ0, (real_value >> 0 ) & 0xFF);
 
 
     uint64_t real_frequency = real_value * CC1101_QUARTZ / CC1101_FDIV;
     uint64_t real_frequency = real_value * CC1101_QUARTZ / CC1101_FDIV;
 
 
     return (uint32_t)real_frequency;
     return (uint32_t)real_frequency;
 }
 }
 
 
-uint32_t cc1101_set_intermediate_frequency(const FuriHalSpiDevice* device, uint32_t value) {
+uint32_t cc1101_set_intermediate_frequency(FuriHalSpiBusHandle* handle, uint32_t value) {
     uint64_t real_value = value * CC1101_IFDIV / CC1101_QUARTZ;
     uint64_t real_value = value * CC1101_IFDIV / CC1101_QUARTZ;
     assert((real_value & 0xFF) == real_value);
     assert((real_value & 0xFF) == real_value);
 
 
-    cc1101_write_reg(device, CC1101_FSCTRL0, (real_value >> 0 ) & 0xFF);
+    cc1101_write_reg(handle, CC1101_FSCTRL0, (real_value >> 0 ) & 0xFF);
 
 
     uint64_t real_frequency = real_value * CC1101_QUARTZ / CC1101_IFDIV;
     uint64_t real_frequency = real_value * CC1101_QUARTZ / CC1101_IFDIV;
 
 
     return (uint32_t)real_frequency;
     return (uint32_t)real_frequency;
 }
 }
 
 
-void cc1101_set_pa_table(const FuriHalSpiDevice* device, const uint8_t value[8]) {
+void cc1101_set_pa_table(FuriHalSpiBusHandle* handle, const uint8_t value[8]) {
     uint8_t tx[9] = { CC1101_PATABLE | CC1101_BURST };
     uint8_t tx[9] = { CC1101_PATABLE | CC1101_BURST };
     CC1101Status rx[9] = { 0 };
     CC1101Status rx[9] = { 0 };
 
 
     memcpy(&tx[1], &value[0], 8);
     memcpy(&tx[1], &value[0], 8);
 
 
-    hal_gpio_write(device->chip_select, false);
-    while(hal_gpio_read(device->bus->miso));
-    furi_hal_spi_bus_trx(device->bus, tx, (uint8_t*)rx, sizeof(rx), CC1101_TIMEOUT);
-    hal_gpio_write(device->chip_select, true);
+    while(hal_gpio_read(handle->miso));
+    furi_hal_spi_bus_trx(handle, tx, (uint8_t*)rx, sizeof(rx), CC1101_TIMEOUT);
 
 
     assert((rx[0].CHIP_RDYn|rx[8].CHIP_RDYn) == 0);
     assert((rx[0].CHIP_RDYn|rx[8].CHIP_RDYn) == 0);
 }
 }
 
 
-uint8_t cc1101_write_fifo(const FuriHalSpiDevice* device, const uint8_t* data, uint8_t size) {
+uint8_t cc1101_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* data, uint8_t size) {
     uint8_t buff_tx[64];
     uint8_t buff_tx[64];
     uint8_t buff_rx[64];
     uint8_t buff_rx[64];
     buff_tx[0] = CC1101_FIFO | CC1101_BURST;
     buff_tx[0] = CC1101_FIFO | CC1101_BURST;
     memcpy(&buff_tx[1], data, size);
     memcpy(&buff_tx[1], data, size);
 
 
     // Start transaction
     // Start transaction
-    hal_gpio_write(device->chip_select, false);
     // Wait IC to become ready
     // Wait IC to become ready
-    while(hal_gpio_read(device->bus->miso));
+    while(hal_gpio_read(handle->miso));
     // Tell IC what we want
     // Tell IC what we want
-    furi_hal_spi_bus_trx(device->bus, buff_tx, (uint8_t*) buff_rx, size + 1, CC1101_TIMEOUT);
-
-    // Finish transaction
-    hal_gpio_write(device->chip_select, true);
+    furi_hal_spi_bus_trx(handle, buff_tx, (uint8_t*) buff_rx, size + 1, CC1101_TIMEOUT);
 
 
     return size;
     return size;
 }
 }
 
 
-uint8_t cc1101_read_fifo(const FuriHalSpiDevice* device, uint8_t* data, uint8_t* size) {
+uint8_t cc1101_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* data, uint8_t* size) {
     uint8_t buff_tx[64];
     uint8_t buff_tx[64];
     buff_tx[0] = CC1101_FIFO | CC1101_READ | CC1101_BURST;
     buff_tx[0] = CC1101_FIFO | CC1101_READ | CC1101_BURST;
     uint8_t buff_rx[2];
     uint8_t buff_rx[2];
 
 
     // Start transaction
     // Start transaction
-    hal_gpio_write(device->chip_select, false);
     // Wait IC to become ready
     // Wait IC to become ready
-    while(hal_gpio_read(device->bus->miso));
+    while(hal_gpio_read(handle->miso));
 
 
     // First byte - packet length
     // First byte - packet length
-    furi_hal_spi_bus_trx(device->bus, buff_tx, buff_rx, 2, CC1101_TIMEOUT);
+    furi_hal_spi_bus_trx(handle, buff_tx, buff_rx, 2, CC1101_TIMEOUT);
     *size = buff_rx[1];
     *size = buff_rx[1];
-    furi_hal_spi_bus_trx(device->bus, &buff_tx[1], data, *size, CC1101_TIMEOUT);
-    cc1101_flush_rx(device);
+    furi_hal_spi_bus_trx(handle, &buff_tx[1], data, *size, CC1101_TIMEOUT);
+    cc1101_flush_rx(handle);
 
 
-    hal_gpio_write(device->chip_select, true);
     return *size;
     return *size;
 }
 }

+ 99 - 63
lib/drivers/cc1101.h

@@ -13,131 +13,167 @@ extern "C" {
 /* Low level API */
 /* Low level API */
 
 
 /** Strobe command to the device
 /** Strobe command to the device
- * @param device - pointer to FuriHalSpiDevice
- * @param strobe - command to execute
- * @return device status
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      strobe  - command to execute
+ *
+ * @return     device status
  */
  */
-CC1101Status cc1101_strobe(const FuriHalSpiDevice* device, uint8_t strobe);
+CC1101Status cc1101_strobe(FuriHalSpiBusHandle* handle, uint8_t strobe);
 
 
 /** Write device register
 /** Write device register
- * @param device - pointer to FuriHalSpiDevice
- * @param reg - register
- * @param data - data to write
- * @return device status
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      reg     - register
+ * @param      data    - data to write
+ *
+ * @return     device status
  */
  */
-CC1101Status cc1101_write_reg(const FuriHalSpiDevice* device, uint8_t reg, uint8_t data);
+CC1101Status cc1101_write_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t data);
 
 
 /** Read device register
 /** Read device register
- * @param device - pointer to FuriHalSpiDevice
- * @param reg - register
- * @param[out] data - pointer to data
- * @return device status
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      reg     - register
+ * @param[out] data    - pointer to data
+ *
+ * @return     device status
  */
  */
-CC1101Status cc1101_read_reg(const FuriHalSpiDevice* device, uint8_t reg, uint8_t* data);
+CC1101Status cc1101_read_reg(FuriHalSpiBusHandle* handle, uint8_t reg, uint8_t* data);
 
 
 /* High level API */
 /* High level API */
 
 
 /** Reset
 /** Reset
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
  */
  */
-void cc1101_reset(const FuriHalSpiDevice* device);
+void cc1101_reset(FuriHalSpiBusHandle* handle);
 
 
 /** Get status
 /** Get status
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ *
+ * @return     CC1101Status structure
  */
  */
-CC1101Status cc1101_get_status(const FuriHalSpiDevice* device);
+CC1101Status cc1101_get_status(FuriHalSpiBusHandle* handle);
 
 
 /** Enable shutdown mode
 /** Enable shutdown mode
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
  */
  */
-void cc1101_shutdown(const FuriHalSpiDevice* device);
+void cc1101_shutdown(FuriHalSpiBusHandle* handle);
 
 
 /** Get Partnumber
 /** Get Partnumber
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ *
+ * @return     part number id
  */
  */
-uint8_t cc1101_get_partnumber(const FuriHalSpiDevice* device);
+uint8_t cc1101_get_partnumber(FuriHalSpiBusHandle* handle);
 
 
 /** Get Version
 /** Get Version
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ *
+ * @return     version
  */
  */
-uint8_t cc1101_get_version(const FuriHalSpiDevice* device);
+uint8_t cc1101_get_version(FuriHalSpiBusHandle* handle);
 
 
 /** Get raw RSSI value
 /** Get raw RSSI value
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ *
+ * @return     rssi value
  */
  */
-uint8_t cc1101_get_rssi(const FuriHalSpiDevice* device);
+uint8_t cc1101_get_rssi(FuriHalSpiBusHandle* handle);
 
 
 /** Calibrate oscillator
 /** Calibrate oscillator
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
  */
  */
-void cc1101_calibrate(const FuriHalSpiDevice* device);
+void cc1101_calibrate(FuriHalSpiBusHandle* handle);
 
 
 /** Switch to idle
 /** Switch to idle
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
  */
  */
-void cc1101_switch_to_idle(const FuriHalSpiDevice* device);
+void cc1101_switch_to_idle(FuriHalSpiBusHandle* handle);
 
 
 /** Switch to RX
 /** Switch to RX
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
  */
  */
-void cc1101_switch_to_rx(const FuriHalSpiDevice* device);
+void cc1101_switch_to_rx(FuriHalSpiBusHandle* handle);
 
 
 /** Switch to TX
 /** Switch to TX
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
  */
  */
-void cc1101_switch_to_tx(const FuriHalSpiDevice* device);
+void cc1101_switch_to_tx(FuriHalSpiBusHandle* handle);
 
 
 /** Flush RX FIFO
 /** Flush RX FIFO
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
  */
  */
-void cc1101_flush_rx(const FuriHalSpiDevice* device);
+void cc1101_flush_rx(FuriHalSpiBusHandle* handle);
 
 
 /** Flush TX FIFO
 /** Flush TX FIFO
- * @param device - pointer to FuriHalSpiDevice
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
  */
  */
-void cc1101_flush_tx(const FuriHalSpiDevice* device);
+void cc1101_flush_tx(FuriHalSpiBusHandle* handle);
 
 
 /** Set Frequency
 /** Set Frequency
- * @param device - pointer to FuriHalSpiDevice
- * @param value - frequency in herz
- * @return real frequency that were synthesized
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      value   - frequency in herz
+ *
+ * @return     real frequency that were synthesized
  */
  */
-uint32_t cc1101_set_frequency(const FuriHalSpiDevice* device, uint32_t value);
+uint32_t cc1101_set_frequency(FuriHalSpiBusHandle* handle, uint32_t value);
 
 
 /** Set Intermediate Frequency
 /** Set Intermediate Frequency
- * @param device - pointer to FuriHalSpiDevice
- * @param value - frequency in herz
- * @return real inermediate frequency that were synthesized
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      value   - frequency in herz
+ *
+ * @return     real inermediate frequency that were synthesized
  */
  */
-uint32_t cc1101_set_intermediate_frequency(const FuriHalSpiDevice* device, uint32_t value);
+uint32_t cc1101_set_intermediate_frequency(FuriHalSpiBusHandle* handle, uint32_t value);
 
 
 /** Set Power Amplifier level table, ramp
 /** Set Power Amplifier level table, ramp
- * @param device - pointer to FuriHalSpiDevice
- * @param value - array of power level values
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      value   - array of power level values
  */
  */
-void cc1101_set_pa_table(const FuriHalSpiDevice* device, const uint8_t value[8]);
+void cc1101_set_pa_table(FuriHalSpiBusHandle* handle, const uint8_t value[8]);
 
 
 /** Set Power Amplifier level table, ramp
 /** Set Power Amplifier level table, ramp
- * @param device - pointer to FuriHalSpiDevice
- * @param value - array of power level values
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      value   - array of power level values
  */
  */
-void cc1101_set_pa_table(const FuriHalSpiDevice* device, const uint8_t value[8]);
+void cc1101_set_pa_table(FuriHalSpiBusHandle* handle, const uint8_t value[8]);
 
 
 /** Write FIFO
 /** Write FIFO
- * @param device - pointer to FuriHalSpiDevice
- * @param data, pointer to byte array
- * @param size, write bytes count
- * @return size, written bytes count
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      data    pointer to byte array
+ * @param      size    write bytes count
+ *
+ * @return     size, written bytes count
  */
  */
-uint8_t cc1101_write_fifo(const FuriHalSpiDevice* device, const uint8_t* data, uint8_t size);
+uint8_t cc1101_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* data, uint8_t size);
 
 
 /** Read FIFO
 /** Read FIFO
- * @param device - pointer to FuriHalSpiDevice
- * @param data, pointer to byte array
- * @param size, bytes to read from fifo
- * @return size, read bytes count
- */
-uint8_t cc1101_read_fifo(const FuriHalSpiDevice* device, uint8_t* data, uint8_t* size);
+ *
+ * @param      handle  - pointer to FuriHalSpiHandle
+ * @param      data    pointer to byte array
+ * @param      size    bytes to read from fifo
+ *
+ * @return     size, read bytes count
+ */
+uint8_t cc1101_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* data, uint8_t* size);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 3 - 11
lib/u8g2/u8g2_glue.c

@@ -2,8 +2,6 @@
 
 
 #include <furi-hal.h>
 #include <furi-hal.h>
 
 
-static FuriHalSpiDevice* u8g2_periphery_display = NULL;
-
 uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
 uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
     switch(msg) {
     switch(msg) {
     case U8X8_MSG_GPIO_AND_DELAY_INIT:
     case U8X8_MSG_GPIO_AND_DELAY_INIT:
@@ -31,7 +29,7 @@ uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, vo
 uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
 uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
     switch(msg) {
     switch(msg) {
     case U8X8_MSG_BYTE_SEND:
     case U8X8_MSG_BYTE_SEND:
-        furi_hal_spi_bus_tx(u8g2_periphery_display->bus, (uint8_t*)arg_ptr, arg_int, 10000);
+        furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_display, (uint8_t*)arg_ptr, arg_int, 10000);
         break;
         break;
     case U8X8_MSG_BYTE_SET_DC:
     case U8X8_MSG_BYTE_SET_DC:
         hal_gpio_write(&gpio_display_di, arg_int);
         hal_gpio_write(&gpio_display_di, arg_int);
@@ -39,16 +37,10 @@ uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_
     case U8X8_MSG_BYTE_INIT:
     case U8X8_MSG_BYTE_INIT:
         break;
         break;
     case U8X8_MSG_BYTE_START_TRANSFER:
     case U8X8_MSG_BYTE_START_TRANSFER:
-        furi_assert(u8g2_periphery_display == NULL);
-        u8g2_periphery_display =
-            (FuriHalSpiDevice*)furi_hal_spi_device_get(FuriHalSpiDeviceIdDisplay);
-        hal_gpio_write(u8g2_periphery_display->chip_select, false);
+        furi_hal_spi_acquire(&furi_hal_spi_bus_handle_display);
         break;
         break;
     case U8X8_MSG_BYTE_END_TRANSFER:
     case U8X8_MSG_BYTE_END_TRANSFER:
-        furi_assert(u8g2_periphery_display);
-        hal_gpio_write(u8g2_periphery_display->chip_select, true);
-        furi_hal_spi_device_return(u8g2_periphery_display);
-        u8g2_periphery_display = NULL;
+        furi_hal_spi_release(&furi_hal_spi_bus_handle_display);
         break;
         break;
     default:
     default:
         return 0;
         return 0;