Просмотр исходного кода

[FL-1587] RFID: Clock for emulation timer from antenna (#622)

* RFID: pull antenna down when emulating
* Rfid: fixed HID emulation by adding zero pulse every 4 bits
* Rfid: HID emulation fixed with DSP based FSK oscillator.
* Rfid: receive 125KHz clock for emulation timer from antenna and comparator
* Rfid: commented unused variable
* Firmware: rollback changes in f6.
* Add F7 target based on F6.
* F7/F6: update cube projects, apply changes to the targets, update linker scripts with correct RAM start values.
* FuriHal: RFID init routine.
* Scripts: update OTP tool for v11 board

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
SG 4 лет назад
Родитель
Сommit
8073992925
100 измененных файлов с 11297 добавлено и 928 удалено
  1. 1 1
      .github/workflows/build.yml
  2. 1 1
      .github/workflows/lint_c.yml
  3. 189 0
      bootloader/targets/f7/furi-hal/furi-hal-gpio.c
  4. 264 0
      bootloader/targets/f7/furi-hal/furi-hal-gpio.h
  5. 137 0
      bootloader/targets/f7/furi-hal/furi-hal-i2c.c
  6. 43 0
      bootloader/targets/f7/furi-hal/furi-hal-i2c.h
  7. 43 0
      bootloader/targets/f7/furi-hal/furi-hal-light.c
  8. 17 0
      bootloader/targets/f7/furi-hal/furi-hal-light.h
  9. 41 0
      bootloader/targets/f7/furi-hal/furi-hal-resources.c
  10. 82 0
      bootloader/targets/f7/furi-hal/furi-hal-resources.h
  11. 114 0
      bootloader/targets/f7/furi-hal/furi-hal-spi-config.c
  12. 61 0
      bootloader/targets/f7/furi-hal/furi-hal-spi-config.h
  13. 240 0
      bootloader/targets/f7/furi-hal/furi-hal-spi.c
  14. 129 0
      bootloader/targets/f7/furi-hal/furi-hal-spi.h
  15. 7 0
      bootloader/targets/f7/furi-hal/furi-hal.c
  16. 8 0
      bootloader/targets/f7/furi-hal/furi-hal.h
  17. 108 0
      bootloader/targets/f7/furi-hal/main.h
  18. 69 0
      bootloader/targets/f7/furi-hal/u8g2_periphery.c
  19. 187 0
      bootloader/targets/f7/stm32wb55xx_flash_cm4.ld
  20. 264 0
      bootloader/targets/f7/target.c
  21. 48 0
      bootloader/targets/f7/target.mk
  22. 8 0
      firmware/targets/f6/Inc/FreeRTOSConfig.h
  23. 16 4
      firmware/targets/f6/cube/Inc/FreeRTOSConfig.h
  24. 1 37
      firmware/targets/f6/cube/Inc/main.h
  25. 1 2
      firmware/targets/f6/cube/Inc/usbd_cdc_if.h
  26. 63 63
      firmware/targets/f6/cube/Makefile
  27. 11 0
      firmware/targets/f6/cube/Src/adc.c
  28. 20 0
      firmware/targets/f6/cube/Src/aes.c
  29. 10 0
      firmware/targets/f6/cube/Src/comp.c
  30. 10 0
      firmware/targets/f6/cube/Src/crc.c
  31. 11 0
      firmware/targets/f6/cube/Src/i2c.c
  32. 6 2
      firmware/targets/f6/cube/Src/main.c
  33. 10 0
      firmware/targets/f6/cube/Src/pka.c
  34. 11 0
      firmware/targets/f6/cube/Src/rf.c
  35. 11 0
      firmware/targets/f6/cube/Src/rng.c
  36. 11 0
      firmware/targets/f6/cube/Src/rtc.c
  37. 20 0
      firmware/targets/f6/cube/Src/spi.c
  38. 368 357
      firmware/targets/f6/cube/Src/system_stm32wbxx.c
  39. 33 0
      firmware/targets/f6/cube/Src/tim.c
  40. 12 1
      firmware/targets/f6/cube/Src/usart.c
  41. 1 1
      firmware/targets/f6/cube/Src/usbd_cdc_if.c
  42. 3 3
      firmware/targets/f6/cube/Src/usbd_conf.c
  43. 1 1
      firmware/targets/f6/cube/Src/usbd_desc.c
  44. 16 7
      firmware/targets/f6/cube/f6.ioc
  45. 444 445
      firmware/targets/f6/cube/startup_stm32wb55xx_cm4.s
  46. 1 1
      firmware/targets/f6/cube/stm32wb55xx_flash_cm4.ld
  47. 1 0
      firmware/targets/f6/furi-hal/furi-hal-clock.c
  48. 4 0
      firmware/targets/f6/furi-hal/furi-hal-rfid.c
  49. 1 0
      firmware/targets/f6/furi-hal/furi-hal.c
  50. 1 1
      firmware/targets/f6/stm32wb55xx_flash_cm4_boot.ld
  51. 1 1
      firmware/targets/f6/stm32wb55xx_flash_cm4_no_boot.ld
  52. 180 0
      firmware/targets/f7/Inc/FreeRTOSConfig.h
  53. 54 0
      firmware/targets/f7/Inc/aes.h
  54. 52 0
      firmware/targets/f7/Inc/comp.h
  55. 49 0
      firmware/targets/f7/Inc/gpio.h
  56. 149 0
      firmware/targets/f7/Inc/main.h
  57. 52 0
      firmware/targets/f7/Inc/pka.h
  58. 50 0
      firmware/targets/f7/Inc/rf.h
  59. 52 0
      firmware/targets/f7/Inc/rng.h
  60. 52 0
      firmware/targets/f7/Inc/rtc.h
  61. 353 0
      firmware/targets/f7/Inc/stm32wbxx_hal_conf.h
  62. 69 0
      firmware/targets/f7/Inc/stm32wbxx_it.h
  63. 58 0
      firmware/targets/f7/Inc/tim.h
  64. 127 0
      firmware/targets/f7/Src/aes.c
  65. 103 0
      firmware/targets/f7/Src/comp.c
  66. 56 0
      firmware/targets/f7/Src/fatfs/fatfs.c
  67. 49 0
      firmware/targets/f7/Src/fatfs/fatfs.h
  68. 270 0
      firmware/targets/f7/Src/fatfs/ffconf.h
  69. 100 0
      firmware/targets/f7/Src/fatfs/spi_sd_hal.c
  70. 1073 0
      firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.c
  71. 252 0
      firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.h
  72. 138 0
      firmware/targets/f7/Src/fatfs/syscall.c
  73. 223 0
      firmware/targets/f7/Src/fatfs/user_diskio.c
  74. 48 0
      firmware/targets/f7/Src/fatfs/user_diskio.h
  75. 21 0
      firmware/targets/f7/Src/freertos-openocd.c
  76. 139 0
      firmware/targets/f7/Src/gpio.c
  77. 55 0
      firmware/targets/f7/Src/main.c
  78. 77 0
      firmware/targets/f7/Src/pka.c
  79. 37 0
      firmware/targets/f7/Src/rf.c
  80. 77 0
      firmware/targets/f7/Src/rng.c
  81. 123 0
      firmware/targets/f7/Src/rtc.c
  82. 93 0
      firmware/targets/f7/Src/stm32wbxx_hal_msp.c
  83. 52 0
      firmware/targets/f7/Src/stm32wbxx_it.c
  84. 357 0
      firmware/targets/f7/Src/system_stm32wbxx.c
  85. 361 0
      firmware/targets/f7/Src/tim.c
  86. 776 0
      firmware/targets/f7/ble-glue/app_ble.c
  87. 27 0
      firmware/targets/f7/ble-glue/app_ble.h
  88. 43 0
      firmware/targets/f7/ble-glue/app_common.h
  89. 474 0
      firmware/targets/f7/ble-glue/app_conf.h
  90. 192 0
      firmware/targets/f7/ble-glue/app_entry.c
  91. 20 0
      firmware/targets/f7/ble-glue/app_entry.h
  92. 55 0
      firmware/targets/f7/ble-glue/battery_service.c
  93. 16 0
      firmware/targets/f7/ble-glue/battery_service.h
  94. 69 0
      firmware/targets/f7/ble-glue/ble_conf.h
  95. 199 0
      firmware/targets/f7/ble-glue/ble_dbg_conf.h
  96. 121 0
      firmware/targets/f7/ble-glue/dev_info_service.c
  97. 20 0
      firmware/targets/f7/ble-glue/dev_info_service.h
  98. 199 0
      firmware/targets/f7/ble-glue/hw_conf.h
  99. 250 0
      firmware/targets/f7/ble-glue/hw_if.h
  100. 675 0
      firmware/targets/f7/ble-glue/hw_ipcc.c

+ 1 - 1
.github/workflows/build.yml

@@ -10,7 +10,7 @@ on:
   pull_request:
 
 env:
-  TARGETS: f6
+  TARGETS: f6 f7
 
 jobs:
   build:

+ 1 - 1
.github/workflows/lint_c.yml

@@ -10,7 +10,7 @@ on:
   pull_request:
 
 env:
-  TARGETS: f6
+  TARGETS: f6 f7
 
 jobs:
   lint_c_cpp:

+ 189 - 0
bootloader/targets/f7/furi-hal/furi-hal-gpio.c

@@ -0,0 +1,189 @@
+#include <furi-hal-gpio.h>
+#include <stddef.h>
+#include <assert.h>
+
+#define GET_SYSCFG_EXTI_PORT(gpio)                \
+    (((gpio) == (GPIOA)) ? LL_SYSCFG_EXTI_PORTA : \
+     ((gpio) == (GPIOB)) ? LL_SYSCFG_EXTI_PORTB : \
+     ((gpio) == (GPIOC)) ? LL_SYSCFG_EXTI_PORTC : \
+     ((gpio) == (GPIOD)) ? LL_SYSCFG_EXTI_PORTD : \
+     ((gpio) == (GPIOE)) ? LL_SYSCFG_EXTI_PORTE : \
+                           LL_SYSCFG_EXTI_PORTH)
+
+#define GPIO_PIN_MAP(pin, prefix)               \
+    (((pin) == (LL_GPIO_PIN_0))  ? prefix##0 :  \
+     ((pin) == (LL_GPIO_PIN_1))  ? prefix##1 :  \
+     ((pin) == (LL_GPIO_PIN_2))  ? prefix##2 :  \
+     ((pin) == (LL_GPIO_PIN_3))  ? prefix##3 :  \
+     ((pin) == (LL_GPIO_PIN_4))  ? prefix##4 :  \
+     ((pin) == (LL_GPIO_PIN_5))  ? prefix##5 :  \
+     ((pin) == (LL_GPIO_PIN_6))  ? prefix##6 :  \
+     ((pin) == (LL_GPIO_PIN_7))  ? prefix##7 :  \
+     ((pin) == (LL_GPIO_PIN_8))  ? prefix##8 :  \
+     ((pin) == (LL_GPIO_PIN_9))  ? prefix##9 :  \
+     ((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \
+     ((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \
+     ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \
+     ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \
+     ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \
+                                   prefix##15)
+
+#define GET_SYSCFG_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_SYSCFG_EXTI_LINE)
+#define GET_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_EXTI_LINE_)
+
+static volatile GpioInterrupt gpio_interrupt[GPIO_NUMBER];
+
+static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) {
+    uint8_t pin_num = 0;
+    for(pin_num = 0; pin_num < GPIO_NUMBER; pin_num++) {
+        if(gpio->pin & (1 << pin_num)) break;
+    }
+    return pin_num;
+}
+
+void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode) {
+    hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow);
+}
+
+void hal_gpio_init(
+    const GpioPin* gpio,
+    const GpioMode mode,
+    const GpioPull pull,
+    const GpioSpeed speed) {
+    // we cannot set alternate mode in this function
+    assert(mode != GpioModeAltFunctionPushPull);
+    assert(mode != GpioModeAltFunctionOpenDrain);
+
+    hal_gpio_init_ex(gpio, mode, pull, speed, GpioAltFnUnused);
+}
+
+void hal_gpio_init_ex(
+    const GpioPin* gpio,
+    const GpioMode mode,
+    const GpioPull pull,
+    const GpioSpeed speed,
+    const GpioAltFn alt_fn) {
+    uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port);
+    uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin);
+    uint32_t exti_line = GET_EXTI_LINE(gpio->pin);
+
+    // Configure gpio with interrupts disabled
+    __disable_irq();
+    // Set gpio speed
+    if(speed == GpioSpeedLow) {
+        LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_LOW);
+    } else if(speed == GpioSpeedMedium) {
+        LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_MEDIUM);
+    } else if(speed == GpioSpeedHigh) {
+        LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_HIGH);
+    } else {
+        LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_VERY_HIGH);
+    }
+    // Set gpio pull mode
+    if(pull == GpioPullNo) {
+        LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_NO);
+    } else if(pull == GpioPullUp) {
+        LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_UP);
+    } else {
+        LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_DOWN);
+    }
+    // Set gpio mode
+    if(mode >= GpioModeInterruptRise) {
+        // Set pin in interrupt mode
+        LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT);
+        LL_SYSCFG_SetEXTISource(sys_exti_port, sys_exti_line);
+        if(mode == GpioModeInterruptRise || mode == GpioModeInterruptRiseFall) {
+            LL_EXTI_EnableIT_0_31(exti_line);
+            LL_EXTI_EnableRisingTrig_0_31(exti_line);
+        }
+        if(mode == GpioModeInterruptFall || mode == GpioModeInterruptRiseFall) {
+            LL_EXTI_EnableIT_0_31(exti_line);
+            LL_EXTI_EnableFallingTrig_0_31(exti_line);
+        }
+        if(mode == GpioModeEventRise || mode == GpioModeInterruptRiseFall) {
+            LL_EXTI_EnableEvent_0_31(exti_line);
+            LL_EXTI_EnableRisingTrig_0_31(exti_line);
+        }
+        if(mode == GpioModeEventFall || mode == GpioModeInterruptRiseFall) {
+            LL_EXTI_EnableEvent_0_31(exti_line);
+            LL_EXTI_EnableFallingTrig_0_31(exti_line);
+        }
+    } else {
+        // Disable interrupt if it was set
+        if(LL_SYSCFG_GetEXTISource(sys_exti_line) == sys_exti_port &&
+           LL_EXTI_IsEnabledIT_0_31(exti_line)) {
+            LL_EXTI_DisableIT_0_31(exti_line);
+            LL_EXTI_DisableRisingTrig_0_31(exti_line);
+            LL_EXTI_DisableFallingTrig_0_31(exti_line);
+        }
+        // Set not interrupt pin modes
+        if(mode == GpioModeInput) {
+            LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT);
+        } else if(mode == GpioModeOutputPushPull || mode == GpioModeAltFunctionPushPull) {
+            LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT);
+            LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_PUSHPULL);
+        } else if(mode == GpioModeOutputOpenDrain || mode == GpioModeAltFunctionOpenDrain) {
+            LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT);
+            LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_OPENDRAIN);
+        } else if(mode == GpioModeAnalog) {
+            LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG);
+        }
+    }
+
+    if(mode == GpioModeAltFunctionPushPull || mode == GpioModeAltFunctionOpenDrain) {
+        // enable alternate mode
+        LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE);
+
+        // set alternate function
+        if(hal_gpio_get_pin_num(gpio) < 8) {
+            LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn);
+        } else {
+            LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn);
+        }
+    }
+
+    __enable_irq();
+}
+
+void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx) {
+    assert(gpio);
+    assert(cb);
+
+    __disable_irq();
+    uint8_t pin_num = hal_gpio_get_pin_num(gpio);
+    gpio_interrupt[pin_num].callback = cb;
+    gpio_interrupt[pin_num].context = ctx;
+    gpio_interrupt[pin_num].ready = true;
+    __enable_irq();
+}
+
+void hal_gpio_enable_int_callback(const GpioPin* gpio) {
+    assert(gpio);
+
+    __disable_irq();
+    uint8_t pin_num = hal_gpio_get_pin_num(gpio);
+    if(gpio_interrupt[pin_num].callback) {
+        gpio_interrupt[pin_num].ready = true;
+    }
+    __enable_irq();
+}
+
+void hal_gpio_disable_int_callback(const GpioPin* gpio) {
+    assert(gpio);
+
+    __disable_irq();
+    uint8_t pin_num = hal_gpio_get_pin_num(gpio);
+    gpio_interrupt[pin_num].ready = false;
+    __enable_irq();
+}
+
+void hal_gpio_remove_int_callback(const GpioPin* gpio) {
+    assert(gpio);
+
+    __disable_irq();
+    uint8_t pin_num = hal_gpio_get_pin_num(gpio);
+    gpio_interrupt[pin_num].callback = NULL;
+    gpio_interrupt[pin_num].context = NULL;
+    gpio_interrupt[pin_num].ready = false;
+    __enable_irq();
+}

+ 264 - 0
bootloader/targets/f7/furi-hal/furi-hal-gpio.h

@@ -0,0 +1,264 @@
+#pragma once
+#include "main.h"
+#include "stdbool.h"
+#include <stm32wbxx_ll_gpio.h>
+#include <stm32wbxx_ll_system.h>
+#include <stm32wbxx_ll_exti.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Number of gpio on one port
+ */
+#define GPIO_NUMBER (16U)
+
+/**
+ * Interrupt callback prototype
+ */
+typedef void (*GpioExtiCallback)(void* ctx);
+
+/**
+ * Gpio interrupt type
+ */
+typedef struct {
+    GpioExtiCallback callback;
+    void* context;
+    volatile bool ready;
+} GpioInterrupt;
+
+/**
+ * Gpio modes
+ */
+typedef enum {
+    GpioModeInput,
+    GpioModeOutputPushPull,
+    GpioModeOutputOpenDrain,
+    GpioModeAltFunctionPushPull,
+    GpioModeAltFunctionOpenDrain,
+    GpioModeAnalog,
+    GpioModeInterruptRise,
+    GpioModeInterruptFall,
+    GpioModeInterruptRiseFall,
+    GpioModeEventRise,
+    GpioModeEventFall,
+    GpioModeEventRiseFall,
+} GpioMode;
+
+/**
+ * Gpio pull modes
+ */
+typedef enum {
+    GpioPullNo,
+    GpioPullUp,
+    GpioPullDown,
+} GpioPull;
+
+/**
+ * Gpio speed modes
+ */
+typedef enum {
+    GpioSpeedLow,
+    GpioSpeedMedium,
+    GpioSpeedHigh,
+    GpioSpeedVeryHigh,
+} GpioSpeed;
+
+/**
+ * Gpio alternate functions
+ */
+typedef enum {
+    GpioAltFn0MCO = 0, /*!< MCO Alternate Function mapping */
+    GpioAltFn0LSCO = 0, /*!< LSCO Alternate Function mapping */
+    GpioAltFn0JTMS_SWDIO = 0, /*!< JTMS-SWDIO Alternate Function mapping */
+    GpioAltFn0JTCK_SWCLK = 0, /*!< JTCK-SWCLK Alternate Function mapping */
+    GpioAltFn0JTDI = 0, /*!< JTDI Alternate Function mapping */
+    GpioAltFn0RTC_OUT = 0, /*!< RCT_OUT Alternate Function mapping */
+    GpioAltFn0JTD_TRACE = 0, /*!< JTDO-TRACESWO Alternate Function mapping */
+    GpioAltFn0NJTRST = 0, /*!< NJTRST Alternate Function mapping */
+    GpioAltFn0RTC_REFIN = 0, /*!< RTC_REFIN Alternate Function mapping */
+    GpioAltFn0TRACED0 = 0, /*!< TRACED0 Alternate Function mapping */
+    GpioAltFn0TRACED1 = 0, /*!< TRACED1 Alternate Function mapping */
+    GpioAltFn0TRACED2 = 0, /*!< TRACED2 Alternate Function mapping */
+    GpioAltFn0TRACED3 = 0, /*!< TRACED3 Alternate Function mapping */
+    GpioAltFn0TRIG_INOUT = 0, /*!< TRIG_INOUT Alternate Function mapping */
+    GpioAltFn0TRACECK = 0, /*!< TRACECK Alternate Function mapping */
+    GpioAltFn0SYS = 0, /*!< System Function mapping */
+
+    GpioAltFn1TIM1 = 1, /*!< TIM1 Alternate Function mapping */
+    GpioAltFn1TIM2 = 1, /*!< TIM2 Alternate Function mapping */
+    GpioAltFn1LPTIM1 = 1, /*!< LPTIM1 Alternate Function mapping */
+
+    GpioAltFn2TIM2 = 2, /*!< TIM2 Alternate Function mapping */
+    GpioAltFn2TIM1 = 2, /*!< TIM1 Alternate Function mapping */
+
+    GpioAltFn3SAI1 = 3, /*!< SAI1_CK1 Alternate Function mapping */
+    GpioAltFn3SPI2 = 3, /*!< SPI2 Alternate Function mapping */
+    GpioAltFn3TIM1 = 3, /*!< TIM1 Alternate Function mapping */
+
+    GpioAltFn4I2C1 = 4, /*!< I2C1 Alternate Function mapping */
+    GpioAltFn4I2C3 = 4, /*!< I2C3 Alternate Function mapping */
+
+    GpioAltFn5SPI1 = 5, /*!< SPI1 Alternate Function mapping */
+    GpioAltFn5SPI2 = 5, /*!< SPI2 Alternate Function mapping */
+
+    GpioAltFn6MCO = 6, /*!< MCO Alternate Function mapping */
+    GpioAltFn6LSCO = 6, /*!< LSCO Alternate Function mapping */
+    GpioAltFn6RF_DTB0 = 6, /*!< RF_DTB0 Alternate Function mapping */
+    GpioAltFn6RF_DTB1 = 6, /*!< RF_DTB1 Alternate Function mapping */
+    GpioAltFn6RF_DTB2 = 6, /*!< RF_DTB2 Alternate Function mapping */
+    GpioAltFn6RF_DTB3 = 6, /*!< RF_DTB3 Alternate Function mapping */
+    GpioAltFn6RF_DTB4 = 6, /*!< RF_DTB4 Alternate Function mapping */
+    GpioAltFn6RF_DTB5 = 6, /*!< RF_DTB5 Alternate Function mapping */
+    GpioAltFn6RF_DTB6 = 6, /*!< RF_DTB6 Alternate Function mapping */
+    GpioAltFn6RF_DTB7 = 6, /*!< RF_DTB7 Alternate Function mapping */
+    GpioAltFn6RF_DTB8 = 6, /*!< RF_DTB8 Alternate Function mapping */
+    GpioAltFn6RF_DTB9 = 6, /*!< RF_DTB9 Alternate Function mapping */
+    GpioAltFn6RF_DTB10 = 6, /*!< RF_DTB10 Alternate Function mapping */
+    GpioAltFn6RF_DTB11 = 6, /*!< RF_DTB11 Alternate Function mapping */
+    GpioAltFn6RF_DTB12 = 6, /*!< RF_DTB12 Alternate Function mapping */
+    GpioAltFn6RF_DTB13 = 6, /*!< RF_DTB13 Alternate Function mapping */
+    GpioAltFn6RF_DTB14 = 6, /*!< RF_DTB14 Alternate Function mapping */
+    GpioAltFn6RF_DTB15 = 6, /*!< RF_DTB15 Alternate Function mapping */
+    GpioAltFn6RF_DTB16 = 6, /*!< RF_DTB16 Alternate Function mapping */
+    GpioAltFn6RF_DTB17 = 6, /*!< RF_DTB17 Alternate Function mapping */
+    GpioAltFn6RF_DTB18 = 6, /*!< RF_DTB18 Alternate Function mapping */
+    GpioAltFn6RF_MISO = 6, /*!< RF_MISO Alternate Function mapping */
+    GpioAltFn6RF_MOSI = 6, /*!< RF_MOSI Alternate Function mapping */
+    GpioAltFn6RF_SCK = 6, /*!< RF_SCK Alternate Function mapping */
+    GpioAltFn6RF_NSS = 6, /*!< RF_NSS Alternate Function mapping */
+
+    GpioAltFn7USART1 = 7, /*!< USART1 Alternate Function mapping */
+
+    GpioAltFn8LPUART1 = 8, /*!< LPUART1 Alternate Function mapping */
+    GpioAltFn8IR = 8, /*!< IR Alternate Function mapping */
+
+    GpioAltFn9TSC = 9, /*!< TSC Alternate Function mapping */
+
+    GpioAltFn10QUADSPI = 10, /*!< QUADSPI Alternate Function mapping */
+    GpioAltFn10USB = 10, /*!< USB Alternate Function mapping */
+
+    GpioAltFn11LCD = 11, /*!< LCD Alternate Function mapping */
+
+    GpioAltFn12COMP1 = 12, /*!< COMP1 Alternate Function mapping */
+    GpioAltFn12COMP2 = 12, /*!< COMP2 Alternate Function mapping */
+    GpioAltFn12TIM1 = 12, /*!< TIM1 Alternate Function mapping */
+
+    GpioAltFn13SAI1 = 13, /*!< SAI1 Alternate Function mapping */
+
+    GpioAltFn14TIM2 = 14, /*!< TIM2 Alternate Function mapping */
+    GpioAltFn14TIM16 = 14, /*!< TIM16 Alternate Function mapping */
+    GpioAltFn14TIM17 = 14, /*!< TIM17 Alternate Function mapping */
+    GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */
+
+    GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */
+
+    GpioAltFnUnused = 16, /*!< just dummy value */
+} GpioAltFn;
+
+/**
+ * Gpio structure
+ */
+typedef struct {
+    GPIO_TypeDef* port;
+    uint16_t pin;
+} GpioPin;
+
+/**
+ * GPIO initialization function, simple version
+ * @param gpio  GpioPin
+ * @param mode  GpioMode
+ */
+void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode);
+
+/**
+ * GPIO initialization function, normal version
+ * @param gpio  GpioPin
+ * @param mode  GpioMode
+ * @param pull  GpioPull
+ * @param speed GpioSpeed
+ */
+void hal_gpio_init(
+    const GpioPin* gpio,
+    const GpioMode mode,
+    const GpioPull pull,
+    const GpioSpeed speed);
+
+/**
+ * GPIO initialization function, extended version
+ * @param gpio  GpioPin
+ * @param mode  GpioMode
+ * @param pull  GpioPull
+ * @param speed GpioSpeed
+ * @param alt_fn GpioAltFn
+ */
+void hal_gpio_init_ex(
+    const GpioPin* gpio,
+    const GpioMode mode,
+    const GpioPull pull,
+    const GpioSpeed speed,
+    const GpioAltFn alt_fn);
+
+/**
+ * Add and enable interrupt
+ * @param gpio GpioPin
+ * @param cb   GpioExtiCallback
+ * @param ctx  context for callback
+ */
+void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx);
+
+/**
+ * Enable interrupt
+ * @param gpio GpioPin
+ */
+void hal_gpio_enable_int_callback(const GpioPin* gpio);
+
+/**
+ * Disable interrupt
+ * @param gpio GpioPin
+ */
+void hal_gpio_disable_int_callback(const GpioPin* gpio);
+
+/**
+ * Remove interrupt
+ * @param gpio GpioPin
+ */
+void hal_gpio_remove_int_callback(const GpioPin* gpio);
+
+/**
+ * GPIO write pin
+ * @param gpio  GpioPin
+ * @param state true / false
+ */
+static inline void hal_gpio_write(const GpioPin* gpio, const bool state) {
+    // writing to BSSR is an atomic operation
+    if(state == true) {
+        gpio->port->BSRR = gpio->pin;
+    } else {
+        gpio->port->BSRR = (uint32_t)gpio->pin << GPIO_NUMBER;
+    }
+}
+
+/**
+ * GPIO read pin
+ * @param gpio GpioPin
+ * @return true / false
+ */
+static inline bool hal_gpio_read(const GpioPin* gpio) {
+    if((gpio->port->IDR & gpio->pin) != 0x00U) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+/**
+ * Get RFID IN level
+ * @return false = LOW, true = HIGH
+ */
+bool hal_gpio_get_rfid_in_level();
+
+#ifdef __cplusplus
+}
+#endif

+ 137 - 0
bootloader/targets/f7/furi-hal/furi-hal-i2c.c

@@ -0,0 +1,137 @@
+#include <furi-hal-i2c.h>
+
+#include <stm32wbxx_ll_bus.h>
+#include <stm32wbxx_ll_i2c.h>
+#include <stm32wbxx_ll_rcc.h>
+#include <stm32wbxx_ll_gpio.h>
+#include <stm32wbxx_ll_cortex.h>
+
+void furi_hal_i2c_init() {
+    LL_I2C_InitTypeDef I2C_InitStruct = {0};
+    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+    LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
+
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
+    GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
+    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
+    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
+    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
+    GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
+    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
+
+    I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
+    I2C_InitStruct.Timing = POWER_I2C_TIMINGS;
+    I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
+    I2C_InitStruct.DigitalFilter = 0;
+    I2C_InitStruct.OwnAddress1 = 0;
+    I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
+    I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
+    LL_I2C_Init(I2C1, &I2C_InitStruct);
+    LL_I2C_EnableAutoEndMode(I2C1);
+    LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
+    LL_I2C_DisableOwnAddress2(I2C1);
+    LL_I2C_DisableGeneralCall(I2C1);
+    LL_I2C_EnableClockStretching(I2C1);
+}
+
+bool furi_hal_i2c_tx(
+    I2C_TypeDef* instance,
+    uint8_t address,
+    const uint8_t* data,
+    uint8_t size,
+    uint32_t timeout) {
+    uint32_t time_left = timeout;
+    bool ret = true;
+
+    while(LL_I2C_IsActiveFlag_BUSY(instance))
+        ;
+
+    LL_I2C_HandleTransfer(
+        instance,
+        address,
+        LL_I2C_ADDRSLAVE_7BIT,
+        size,
+        LL_I2C_MODE_AUTOEND,
+        LL_I2C_GENERATE_START_WRITE);
+
+    while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
+        if(LL_I2C_IsActiveFlag_TXIS(instance)) {
+            LL_I2C_TransmitData8(instance, (*data));
+            data++;
+            size--;
+            time_left = timeout;
+        }
+
+        if(LL_SYSTICK_IsActiveCounterFlag()) {
+            if(--time_left == 0) {
+                ret = false;
+                break;
+            }
+        }
+    }
+
+    LL_I2C_ClearFlag_STOP(instance);
+
+    return ret;
+}
+
+bool furi_hal_i2c_rx(
+    I2C_TypeDef* instance,
+    uint8_t address,
+    uint8_t* data,
+    uint8_t size,
+    uint32_t timeout) {
+    uint32_t time_left = timeout;
+    bool ret = true;
+
+    while(LL_I2C_IsActiveFlag_BUSY(instance))
+        ;
+
+    LL_I2C_HandleTransfer(
+        instance,
+        address,
+        LL_I2C_ADDRSLAVE_7BIT,
+        size,
+        LL_I2C_MODE_AUTOEND,
+        LL_I2C_GENERATE_START_READ);
+
+    while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
+        if(LL_I2C_IsActiveFlag_RXNE(instance)) {
+            *data = LL_I2C_ReceiveData8(instance);
+            data++;
+            size--;
+            time_left = timeout;
+        }
+
+        if(LL_SYSTICK_IsActiveCounterFlag()) {
+            if(--time_left == 0) {
+                ret = false;
+                break;
+            }
+        }
+    }
+
+    LL_I2C_ClearFlag_STOP(instance);
+
+    return ret;
+}
+
+bool furi_hal_i2c_trx(
+    I2C_TypeDef* instance,
+    uint8_t address,
+    const uint8_t* tx_data,
+    uint8_t tx_size,
+    uint8_t* rx_data,
+    uint8_t rx_size,
+    uint32_t timeout) {
+    if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
+       furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
+        return true;
+    } else {
+        return false;
+    }
+}

+ 43 - 0
bootloader/targets/f7/furi-hal/furi-hal-i2c.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <furi-hal-resources.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void furi_hal_i2c_init();
+
+bool furi_hal_i2c_tx(
+    I2C_TypeDef* instance,
+    const uint8_t address,
+    const uint8_t* data,
+    const uint8_t size,
+    uint32_t timeout);
+
+bool furi_hal_i2c_rx(
+    I2C_TypeDef* instance,
+    const uint8_t address,
+    uint8_t* data,
+    const uint8_t size,
+    uint32_t timeout);
+
+bool furi_hal_i2c_trx(
+    I2C_TypeDef* instance,
+    const uint8_t address,
+    const uint8_t* tx_data,
+    const uint8_t tx_size,
+    uint8_t* rx_data,
+    const uint8_t rx_size,
+    uint32_t timeout);
+
+#define with_furi_hal_i2c(type, pointer, function_body)       \
+    {                                                         \
+        *pointer = ({ type __fn__ function_body __fn__; })(); \
+    }
+
+#ifdef __cplusplus
+}
+#endif

+ 43 - 0
bootloader/targets/f7/furi-hal/furi-hal-light.c

@@ -0,0 +1,43 @@
+#include <furi-hal-light.h>
+#include <lp5562.h>
+
+#define LED_CURRENT_RED 50
+#define LED_CURRENT_GREEN 50
+#define LED_CURRENT_BLUE 50
+#define LED_CURRENT_WHITE 150
+
+void furi_hal_light_init() {
+    lp5562_reset();
+
+    lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
+    lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
+    lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
+    lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
+
+    lp5562_set_channel_value(LP5562ChannelRed, 0x00);
+    lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
+    lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
+    lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
+
+    lp5562_enable();
+    lp5562_configure();
+}
+
+void furi_hal_light_set(Light light, uint8_t value) {
+    switch(light) {
+    case LightRed:
+        lp5562_set_channel_value(LP5562ChannelRed, value);
+        break;
+    case LightGreen:
+        lp5562_set_channel_value(LP5562ChannelGreen, value);
+        break;
+    case LightBlue:
+        lp5562_set_channel_value(LP5562ChannelBlue, value);
+        break;
+    case LightBacklight:
+        lp5562_set_channel_value(LP5562ChannelWhite, value);
+        break;
+    default:
+        break;
+    }
+}

+ 17 - 0
bootloader/targets/f7/furi-hal/furi-hal-light.h

@@ -0,0 +1,17 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <furi-hal-resources.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void furi_hal_light_init();
+
+void furi_hal_light_set(Light light, uint8_t value);
+
+#ifdef __cplusplus
+}
+#endif

+ 41 - 0
bootloader/targets/f7/furi-hal/furi-hal-resources.c

@@ -0,0 +1,41 @@
+#include "furi-hal-resources.h"
+#include "main.h"
+
+const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin};
+const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin};
+
+const GpioPin gpio_cc1101_g0 = {.port = CC1101_G0_GPIO_Port, .pin = CC1101_G0_Pin};
+const GpioPin gpio_rf_sw_0 = {.port = RF_SW_0_GPIO_Port, .pin = RF_SW_0_Pin};
+
+const GpioPin gpio_subghz_cs = {.port = CC1101_CS_GPIO_Port, .pin = CC1101_CS_Pin};
+const GpioPin gpio_display_cs = {.port = DISPLAY_CS_GPIO_Port, .pin = DISPLAY_CS_Pin};
+const GpioPin gpio_display_rst = {.port = DISPLAY_RST_GPIO_Port, .pin = DISPLAY_RST_Pin};
+const GpioPin gpio_display_di = {.port = DISPLAY_DI_GPIO_Port, .pin = DISPLAY_DI_Pin};
+const GpioPin gpio_sdcard_cs = {.port = SD_CS_GPIO_Port, .pin = SD_CS_Pin};
+const GpioPin gpio_nfc_cs = {.port = NFC_CS_GPIO_Port, .pin = NFC_CS_Pin};
+
+const GpioPin gpio_spi_d_miso = {.port = SPI_D_MISO_GPIO_Port, .pin = SPI_D_MISO_Pin};
+const GpioPin gpio_spi_d_mosi = {.port = SPI_D_MOSI_GPIO_Port, .pin = SPI_D_MOSI_Pin};
+const GpioPin gpio_spi_d_sck = {.port = SPI_D_SCK_GPIO_Port, .pin = SPI_D_SCK_Pin};
+const GpioPin gpio_spi_r_miso = {.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin};
+const GpioPin gpio_spi_r_mosi = {.port = SPI_R_MOSI_GPIO_Port, .pin = SPI_R_MOSI_Pin};
+const GpioPin gpio_spi_r_sck = {.port = SPI_R_SCK_GPIO_Port, .pin = SPI_R_SCK_Pin};
+
+const GpioPin gpio_ext_pc0 = {.port = GPIOC, .pin = LL_GPIO_PIN_0};
+const GpioPin gpio_ext_pc1 = {.port = GPIOC, .pin = LL_GPIO_PIN_1};
+const GpioPin gpio_ext_pc3 = {.port = GPIOC, .pin = LL_GPIO_PIN_3};
+const GpioPin gpio_ext_pb2 = {.port = GPIOB, .pin = LL_GPIO_PIN_2};
+const GpioPin gpio_ext_pb3 = {.port = GPIOB, .pin = LL_GPIO_PIN_3};
+const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = LL_GPIO_PIN_4};
+const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = LL_GPIO_PIN_6};
+const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = LL_GPIO_PIN_7};
+
+const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
+const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin};
+const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin};
+
+const GpioPin gpio_irda_rx = {.port = IR_RX_GPIO_Port, .pin = IR_RX_Pin};
+const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
+
+const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
+const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};

+ 82 - 0
bootloader/targets/f7/furi-hal/furi-hal-resources.h

@@ -0,0 +1,82 @@
+#pragma once
+
+#include <stm32wbxx.h>
+#include <stm32wbxx_ll_gpio.h>
+#include <furi-hal-gpio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
+#define POWER_I2C_SCL_GPIO_Port GPIOA
+#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
+#define POWER_I2C_SDA_GPIO_Port GPIOA
+
+#define POWER_I2C I2C1
+/* Timing register value is computed with the STM32CubeMX Tool,
+  * Fast Mode @100kHz with I2CCLK = 64 MHz,
+  * rise time = 0ns, fall time = 0ns
+  */
+#define POWER_I2C_TIMINGS 0x10707DBC
+
+/* Input Keys */
+typedef enum {
+    InputKeyUp,
+    InputKeyDown,
+    InputKeyRight,
+    InputKeyLeft,
+    InputKeyOk,
+    InputKeyBack,
+} InputKey;
+
+/* Light */
+typedef enum {
+    LightRed,
+    LightGreen,
+    LightBlue,
+    LightBacklight,
+} Light;
+
+extern const GpioPin vibro_gpio;
+extern const GpioPin ibutton_gpio;
+
+extern const GpioPin gpio_cc1101_g0;
+extern const GpioPin gpio_rf_sw_0;
+
+extern const GpioPin gpio_subghz_cs;
+extern const GpioPin gpio_display_cs;
+extern const GpioPin gpio_display_rst;
+extern const GpioPin gpio_display_di;
+extern const GpioPin gpio_sdcard_cs;
+extern const GpioPin gpio_nfc_cs;
+
+extern const GpioPin gpio_spi_d_miso;
+extern const GpioPin gpio_spi_d_mosi;
+extern const GpioPin gpio_spi_d_sck;
+extern const GpioPin gpio_spi_r_miso;
+extern const GpioPin gpio_spi_r_mosi;
+extern const GpioPin gpio_spi_r_sck;
+
+extern const GpioPin gpio_ext_pc0;
+extern const GpioPin gpio_ext_pc1;
+extern const GpioPin gpio_ext_pc3;
+extern const GpioPin gpio_ext_pb2;
+extern const GpioPin gpio_ext_pb3;
+extern const GpioPin gpio_ext_pa4;
+extern const GpioPin gpio_ext_pa6;
+extern const GpioPin gpio_ext_pa7;
+
+extern const GpioPin gpio_rfid_pull;
+extern const GpioPin gpio_rfid_carrier_out;
+extern const GpioPin gpio_rfid_data_in;
+
+extern const GpioPin gpio_irda_rx;
+extern const GpioPin gpio_irda_tx;
+
+extern const GpioPin gpio_usart_tx;
+extern const GpioPin gpio_usart_rx;
+
+#ifdef __cplusplus
+}
+#endif

+ 114 - 0
bootloader/targets/f7/furi-hal/furi-hal-spi-config.c

@@ -0,0 +1,114 @@
+#include <furi-hal-spi-config.h>
+#include <furi-hal-resources.h>
+
+#define SPI_R SPI1
+#define SPI_D SPI2
+
+const LL_SPI_InitTypeDef furi_hal_spi_config_nfc = {
+    .Mode = LL_SPI_MODE_MASTER,
+    .TransferDirection = LL_SPI_FULL_DUPLEX,
+    .DataWidth = LL_SPI_DATAWIDTH_8BIT,
+    .ClockPolarity = LL_SPI_POLARITY_LOW,
+    .ClockPhase = LL_SPI_PHASE_2EDGE,
+    .NSS = LL_SPI_NSS_SOFT,
+    .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8,
+    .BitOrder = LL_SPI_MSB_FIRST,
+    .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE,
+    .CRCPoly = 7,
+};
+
+const LL_SPI_InitTypeDef furi_hal_spi_config_subghz = {
+    .Mode = LL_SPI_MODE_MASTER,
+    .TransferDirection = LL_SPI_FULL_DUPLEX,
+    .DataWidth = LL_SPI_DATAWIDTH_8BIT,
+    .ClockPolarity = LL_SPI_POLARITY_LOW,
+    .ClockPhase = LL_SPI_PHASE_1EDGE,
+    .NSS = LL_SPI_NSS_SOFT,
+    .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8,
+    .BitOrder = LL_SPI_MSB_FIRST,
+    .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE,
+    .CRCPoly = 7,
+};
+
+const LL_SPI_InitTypeDef furi_hal_spi_config_display = {
+    .Mode = LL_SPI_MODE_MASTER,
+    .TransferDirection = LL_SPI_FULL_DUPLEX,
+    .DataWidth = LL_SPI_DATAWIDTH_8BIT,
+    .ClockPolarity = LL_SPI_POLARITY_LOW,
+    .ClockPhase = LL_SPI_PHASE_1EDGE,
+    .NSS = LL_SPI_NSS_SOFT,
+    .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV16,
+    .BitOrder = LL_SPI_MSB_FIRST,
+    .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE,
+    .CRCPoly = 7,
+};
+
+/**
+ * SD Card in fast mode (after init)
+ */
+const LL_SPI_InitTypeDef furi_hal_spi_config_sd_fast = {
+    .Mode = LL_SPI_MODE_MASTER,
+    .TransferDirection = LL_SPI_FULL_DUPLEX,
+    .DataWidth = LL_SPI_DATAWIDTH_8BIT,
+    .ClockPolarity = LL_SPI_POLARITY_LOW,
+    .ClockPhase = LL_SPI_PHASE_1EDGE,
+    .NSS = LL_SPI_NSS_SOFT,
+    .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2,
+    .BitOrder = LL_SPI_MSB_FIRST,
+    .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE,
+    .CRCPoly = 7,
+};
+
+/**
+ * SD Card in slow mode (before init)
+ */
+const LL_SPI_InitTypeDef furi_hal_spi_config_sd_slow = {
+    .Mode = LL_SPI_MODE_MASTER,
+    .TransferDirection = LL_SPI_FULL_DUPLEX,
+    .DataWidth = LL_SPI_DATAWIDTH_8BIT,
+    .ClockPolarity = LL_SPI_POLARITY_LOW,
+    .ClockPhase = LL_SPI_PHASE_1EDGE,
+    .NSS = LL_SPI_NSS_SOFT,
+    .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV32,
+    .BitOrder = LL_SPI_MSB_FIRST,
+    .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE,
+    .CRCPoly = 7,
+};
+
+const FuriHalSpiBus spi_r = {
+    .spi = SPI_R,
+    .miso = &gpio_spi_r_miso,
+    .mosi = &gpio_spi_r_mosi,
+    .clk = &gpio_spi_r_sck,
+};
+
+const FuriHalSpiBus spi_d = {
+    .spi = SPI_D,
+    .miso = &gpio_spi_d_miso,
+    .mosi = &gpio_spi_d_mosi,
+    .clk = &gpio_spi_d_sck,
+};
+
+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},
+};

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

@@ -0,0 +1,61 @@
+#pragma once
+
+#include <furi-hal-gpio.h>
+#include <stm32wbxx_ll_spi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#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;
+
+/** 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;
+
+/** Furi Hal Spi Bus D
+ * Display, SdCard
+ */
+extern const FuriHalSpiBus spi_d;
+
+/** Furi Hal Spi devices */
+extern const FuriHalSpiDevice furi_hal_spi_devices[FuriHalSpiDeviceIdMax];
+
+#ifdef __cplusplus
+}
+#endif

+ 240 - 0
bootloader/targets/f7/furi-hal/furi-hal-spi.c

@@ -0,0 +1,240 @@
+#include "furi-hal-spi.h"
+#include "furi-hal-resources.h"
+
+#include <stdbool.h>
+#include <assert.h>
+
+#include <stm32wbxx_ll_spi.h>
+#include <stm32wbxx_ll_utils.h>
+#include <stm32wbxx_ll_cortex.h>
+
+extern void Enable_SPI(SPI_TypeDef* spi);
+
+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);
+}
+
+void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus) {
+    assert(bus);
+}
+
+void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus) {
+    assert(bus);
+}
+
+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_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);
+    }
+}
+
+bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
+    assert(bus);
+    assert(buffer);
+    assert(size > 0);
+
+    return furi_hal_spi_bus_trx(bus, buffer, buffer, size, timeout);
+}
+
+bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout) {
+    assert(bus);
+    assert(buffer);
+    assert(size > 0);
+    bool ret = true;
+
+    while(size > 0) {
+        if(LL_SPI_IsActiveFlag_TXE((SPI_TypeDef*)bus->spi)) {
+            LL_SPI_TransmitData8((SPI_TypeDef*)bus->spi, *buffer);
+            buffer++;
+            size--;
+        }
+    }
+
+    furi_hal_spi_bus_end_txrx(bus, timeout);
+    LL_SPI_ClearFlag_OVR((SPI_TypeDef*)bus->spi);
+
+    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) {
+    assert(bus);
+    assert(tx_buffer);
+    assert(rx_buffer);
+    assert(size > 0);
+    bool ret = true;
+    size_t tx_size = size;
+    bool tx_allowed = true;
+
+    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);
+            tx_buffer++;
+            tx_size--;
+            tx_allowed = false;
+        }
+
+        if(LL_SPI_IsActiveFlag_RXNE((SPI_TypeDef*)bus->spi)) {
+            *rx_buffer = LL_SPI_ReceiveData8((SPI_TypeDef*)bus->spi);
+            rx_buffer++;
+            size--;
+            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);
+    }
+
+    return ret;
+}

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

@@ -0,0 +1,129 @@
+#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

+ 7 - 0
bootloader/targets/f7/furi-hal/furi-hal.c

@@ -0,0 +1,7 @@
+#include <furi-hal.h>
+
+void furi_hal_init() {
+    furi_hal_i2c_init();
+    furi_hal_light_init();
+    furi_hal_spi_init();
+}

+ 8 - 0
bootloader/targets/f7/furi-hal/furi-hal.h

@@ -0,0 +1,8 @@
+#pragma once
+
+#include <furi-hal-i2c.h>
+#include <furi-hal-light.h>
+#include <furi-hal-resources.h>
+#include <furi-hal-spi.h>
+
+void furi_hal_init();

+ 108 - 0
bootloader/targets/f7/furi-hal/main.h

@@ -0,0 +1,108 @@
+#pragma once
+
+#include <stm32wbxx.h>
+#include <stm32wbxx_ll_gpio.h>
+#include <stm32wbxx_ll_spi.h>
+
+#define BUTTON_BACK_GPIO_Port GPIOC
+#define BUTTON_BACK_Pin LL_GPIO_PIN_13
+#define BUTTON_DOWN_GPIO_Port GPIOC
+#define BUTTON_DOWN_Pin LL_GPIO_PIN_6
+#define BUTTON_LEFT_GPIO_Port GPIOB
+#define BUTTON_LEFT_Pin LL_GPIO_PIN_11
+#define BUTTON_OK_GPIO_Port GPIOH
+#define BUTTON_OK_Pin LL_GPIO_PIN_3
+#define BUTTON_RIGHT_GPIO_Port GPIOB
+#define BUTTON_RIGHT_Pin LL_GPIO_PIN_12
+#define BUTTON_UP_GPIO_Port GPIOB
+#define BUTTON_UP_Pin LL_GPIO_PIN_10
+
+#define CC1101_CS_GPIO_Port GPIOD
+#define CC1101_CS_Pin LL_GPIO_PIN_0
+#define CC1101_G0_GPIO_Port GPIOA
+#define CC1101_G0_Pin LL_GPIO_PIN_1
+
+#define DISPLAY_CS_GPIO_Port GPIOC
+#define DISPLAY_CS_Pin LL_GPIO_PIN_11
+#define DISPLAY_DI_GPIO_Port GPIOB
+#define DISPLAY_DI_Pin LL_GPIO_PIN_1
+#define DISPLAY_RST_GPIO_Port GPIOB
+#define DISPLAY_RST_Pin LL_GPIO_PIN_0
+
+#define IR_RX_GPIO_Port GPIOA
+#define IR_RX_Pin LL_GPIO_PIN_0
+#define IR_TX_GPIO_Port GPIOB
+#define IR_TX_Pin LL_GPIO_PIN_9
+
+#define NFC_CS_GPIO_Port GPIOE
+#define NFC_CS_Pin LL_GPIO_PIN_4
+
+#define PA4_GPIO_Port GPIOA
+#define PA4_Pin LL_GPIO_PIN_4
+#define PA6_GPIO_Port GPIOA
+#define PA6_Pin LL_GPIO_PIN_6
+#define PA7_GPIO_Port GPIOA
+#define PA7_Pin LL_GPIO_PIN_7
+#define PB2_GPIO_Port GPIOB
+#define PB2_Pin LL_GPIO_PIN_2
+#define PB3_GPIO_Port GPIOB
+#define PB3_Pin LL_GPIO_PIN_3
+#define PC0_GPIO_Port GPIOC
+#define PC0_Pin LL_GPIO_PIN_0
+#define PC1_GPIO_Port GPIOC
+#define PC1_Pin LL_GPIO_PIN_1
+#define PC3_GPIO_Port GPIOC
+#define PC3_Pin LL_GPIO_PIN_3
+
+#define PERIPH_POWER_GPIO_Port GPIOA
+#define PERIPH_POWER_Pin LL_GPIO_PIN_3
+
+#define QUARTZ_32MHZ_IN_GPIO_Port GPIOC
+#define QUARTZ_32MHZ_IN_Pin LL_GPIO_PIN_14
+#define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC
+#define QUARTZ_32MHZ_OUT_Pin LL_GPIO_PIN_15
+
+#define RFID_OUT_GPIO_Port GPIOB
+#define RFID_OUT_Pin LL_GPIO_PIN_13
+#define RFID_PULL_GPIO_Port GPIOA
+#define RFID_PULL_Pin LL_GPIO_PIN_2
+#define RFID_RF_IN_GPIO_Port GPIOC
+#define RFID_RF_IN_Pin LL_GPIO_PIN_5
+#define RFID_TUNE_GPIO_Port GPIOA
+#define RFID_TUNE_Pin LL_GPIO_PIN_8
+
+#define RF_SW_0_GPIO_Port GPIOC
+#define RF_SW_0_Pin LL_GPIO_PIN_4
+
+#define SD_CD_GPIO_Port GPIOC
+#define SD_CD_Pin LL_GPIO_PIN_10
+#define SD_CS_GPIO_Port GPIOC
+#define SD_CS_Pin LL_GPIO_PIN_12
+
+#define SPEAKER_GPIO_Port GPIOB
+#define SPEAKER_Pin LL_GPIO_PIN_8
+
+#define VIBRO_GPIO_Port GPIOA
+#define VIBRO_Pin LL_GPIO_PIN_15
+
+#define iBTN_GPIO_Port GPIOB
+#define iBTN_Pin LL_GPIO_PIN_14
+
+#define USART1_TX_Pin LL_GPIO_PIN_6
+#define USART1_TX_Port GPIOB
+#define USART1_RX_Pin LL_GPIO_PIN_7
+#define USART1_RX_Port GPIOB
+
+#define SPI_D_MISO_GPIO_Port GPIOC
+#define SPI_D_MISO_Pin LL_GPIO_PIN_2
+#define SPI_D_MOSI_GPIO_Port GPIOB
+#define SPI_D_MOSI_Pin LL_GPIO_PIN_15
+#define SPI_D_SCK_GPIO_Port GPIOD
+#define SPI_D_SCK_Pin LL_GPIO_PIN_1
+
+#define SPI_R_MISO_GPIO_Port GPIOB
+#define SPI_R_MISO_Pin LL_GPIO_PIN_4
+#define SPI_R_MOSI_GPIO_Port GPIOB
+#define SPI_R_MOSI_Pin LL_GPIO_PIN_5
+#define SPI_R_SCK_GPIO_Port GPIOA
+#define SPI_R_SCK_Pin LL_GPIO_PIN_5

+ 69 - 0
bootloader/targets/f7/furi-hal/u8g2_periphery.c

@@ -0,0 +1,69 @@
+#include <u8g2.h>
+#include <assert.h>
+#include <furi-hal.h>
+#include <stm32wbxx_ll_utils.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) {
+    switch(msg) {
+    case U8X8_MSG_GPIO_AND_DELAY_INIT:
+        /* HAL initialization contains all what we need so we can skip this part. */
+        break;
+
+    case U8X8_MSG_DELAY_MILLI:
+        LL_mDelay(arg_int);
+        break;
+
+    case U8X8_MSG_DELAY_10MICRO:
+        LL_mDelay(1);
+        break;
+
+    case U8X8_MSG_DELAY_100NANO:
+        asm("nop");
+        break;
+
+    case U8X8_MSG_GPIO_RESET:
+        hal_gpio_write(&gpio_display_rst, arg_int);
+        break;
+
+    default:
+        return 0;
+    }
+
+    return 1;
+}
+
+uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
+    switch(msg) {
+    case U8X8_MSG_BYTE_SEND:
+        furi_hal_spi_bus_tx(u8g2_periphery_display->bus, (uint8_t*)arg_ptr, arg_int, 10000);
+        break;
+
+    case U8X8_MSG_BYTE_SET_DC:
+        hal_gpio_write(&gpio_display_di, arg_int);
+        break;
+
+    case U8X8_MSG_BYTE_INIT:
+        break;
+
+    case U8X8_MSG_BYTE_START_TRANSFER:
+        assert(u8g2_periphery_display == NULL);
+        u8g2_periphery_display =
+            (FuriHalSpiDevice*)furi_hal_spi_device_get(FuriHalSpiDeviceIdDisplay);
+        hal_gpio_write(u8g2_periphery_display->chip_select, false);
+        break;
+
+    case U8X8_MSG_BYTE_END_TRANSFER:
+        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;
+        break;
+
+    default:
+        return 0;
+    }
+
+    return 1;
+}

+ 187 - 0
bootloader/targets/f7/stm32wb55xx_flash_cm4.ld

@@ -0,0 +1,187 @@
+/**
+*****************************************************************************
+**
+**  File        : stm32wb55xx_flash_cm4.ld
+**
+**  Abstract    : System Workbench Minimal System calls file
+**
+** 		          For more information about which c-functions
+**                need which of these lowlevel functions
+**                please consult the Newlib libc-manual
+**
+**  Environment : System Workbench for MCU
+**
+**  Distribution: The file is distributed “as is,” without any warranty
+**                of any kind.
+**
+*****************************************************************************
+**
+** <h2><center>&copy; COPYRIGHT(c) 2019 Ac6</center></h2>
+**
+** Redistribution and use in source and binary forms, with or without modification,
+** are permitted provided that the following conditions are met:
+**   1. Redistributions of source code must retain the above copyright notice,
+**      this list of conditions and the following disclaimer.
+**   2. Redistributions in binary form must reproduce the above copyright notice,
+**      this list of conditions and the following disclaimer in the documentation
+**      and/or other materials provided with the distribution.
+**   3. Neither the name of Ac6 nor the names of its contributors
+**      may be used to endorse or promote products derived from this software
+**      without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*****************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = 0x20030000;    /* end of RAM */
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0x200;      /* required amount of heap  */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+FLASH (rx)                 : ORIGIN = 0x08000000, LENGTH = 32K
+RAM1 (xrw)                 : ORIGIN = 0x20000004, LENGTH = 0x2FFFC
+RAM_SHARED (xrw)           : ORIGIN = 0x20030000, LENGTH = 10K
+}
+
+/* Define output sections */
+SECTIONS
+{
+  /* The startup code goes first into FLASH */
+  .isr_vector :
+  {
+    . = ALIGN(4);
+    KEEP(*(.isr_vector)) /* Startup code */
+    . = ALIGN(4);
+  } >FLASH
+
+  /* The program code and other data goes into FLASH */
+  .text :
+  {
+    . = ALIGN(4);
+    *(.text)           /* .text sections (code) */
+    *(.text*)          /* .text* sections (code) */
+    *(.glue_7)         /* glue arm to thumb code */
+    *(.glue_7t)        /* glue thumb to arm code */
+    *(.eh_frame)
+
+    KEEP (*(.init))
+    KEEP (*(.fini))
+
+    . = ALIGN(4);
+    _etext = .;        /* define a global symbols at end of code */
+  } >FLASH
+
+  /* Constant data goes into FLASH */
+  .rodata :
+  {
+    . = ALIGN(4);
+    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
+    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
+    . = ALIGN(4);
+  } >FLASH
+
+  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
+  .ARM : {
+    __exidx_start = .;
+    *(.ARM.exidx*)
+    __exidx_end = .;
+  } >FLASH
+
+  .preinit_array     :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array*))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  } >FLASH
+  .init_array :
+  {
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array*))
+    PROVIDE_HIDDEN (__init_array_end = .);
+  } >FLASH
+  .fini_array :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT(.fini_array.*)))
+    KEEP (*(.fini_array*))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  } >FLASH
+
+  /* used by the startup to initialize data */
+  _sidata = LOADADDR(.data);
+
+  /* Initialized data sections goes into RAM, load LMA copy after code */
+  .data : 
+  {
+    . = ALIGN(4);
+    _sdata = .;        /* create a global symbol at data start */
+    *(.data)           /* .data sections */
+    *(.data*)          /* .data* sections */
+
+    . = ALIGN(4);
+    _edata = .;        /* define a global symbol at data end */
+  } >RAM1 AT> FLASH
+
+  
+  /* Uninitialized data section */
+  . = ALIGN(4);
+  .bss :
+  {
+    /* This is used by the startup in order to initialize the .bss secion */
+    _sbss = .;         /* define a global symbol at bss start */
+    __bss_start__ = _sbss;
+    *(.bss)
+    *(.bss*)
+    *(COMMON)
+
+    . = ALIGN(4);
+    _ebss = .;         /* define a global symbol at bss end */
+    __bss_end__ = _ebss;
+  } >RAM1
+
+  /* User_heap_stack section, used to check that there is enough RAM left */
+  ._user_heap_stack :
+  {
+    . = ALIGN(8);
+    PROVIDE ( end = . );
+    PROVIDE ( _end = . );
+    . = . + _Min_Heap_Size;
+    . = . + _Min_Stack_Size;
+    . = ALIGN(8);
+  } >RAM1
+
+  
+
+  /* Remove information from the standard libraries */
+  /DISCARD/ :
+  {
+    libc.a ( * )
+    libm.a ( * )
+    libgcc.a ( * )
+  }
+
+  .ARM.attributes 0       : { *(.ARM.attributes) }
+   MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED
+   MB_MEM1 (NOLOAD)       : { *(MB_MEM1) } >RAM_SHARED
+   MB_MEM2 (NOLOAD)       : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
+}
+
+

+ 264 - 0
bootloader/targets/f7/target.c

@@ -0,0 +1,264 @@
+#include <target.h>
+#include <stm32wbxx.h>
+#include <stm32wbxx_ll_system.h>
+#include <stm32wbxx_ll_bus.h>
+#include <stm32wbxx_ll_utils.h>
+#include <stm32wbxx_ll_rcc.h>
+#include <stm32wbxx_ll_rtc.h>
+#include <stm32wbxx_ll_pwr.h>
+#include <stm32wbxx_ll_gpio.h>
+#include <stm32wbxx_hal_flash.h>
+
+#include <lib/toolbox/version.h>
+#include <furi-hal.h>
+#include <u8g2.h>
+
+const uint8_t I_DFU_128x50[] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x75, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0A, 0x00, 0x00, 0x0F, 0x60, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xE0, 0x0F, 0x00, 0xC0, 0xE0, 0x4F, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x30, 0x1E, 0x90, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x8C, 0x01, 0xA0, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0xFF, 0x19, 0x00, 0x63, 0x00, 0xC0, 0xF0, 0x07,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x5E, 0x1F, 0x80, 0x18, 0x00, 0xE0, 0x0E, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x18, 0xAF, 0x0F, 0x40, 0x06, 0x00, 0xF8, 0x01, 0x20,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x57, 0x01, 0x20, 0x01, 0x00, 0x78, 0x00, 0x3E,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x81, 0xAF, 0x02, 0x90, 0x00, 0x00, 0x38, 0x80, 0x41,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x80, 0x57, 0x01, 0x48, 0x00, 0x00, 0x10, 0x60, 0x40,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x10, 0x80, 0xAB, 0x00, 0x24, 0x00, 0x00, 0x08, 0x10, 0x40,
+    0x3F, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0C, 0xC0, 0x57, 0x01, 0x12, 0x00, 0x00, 0x04, 0x08, 0x40,
+    0xC0, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x03, 0xF0, 0xAB, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x04, 0x40,
+    0x00, 0xF0, 0x1F, 0x80, 0x3F, 0xC0, 0x00, 0xFC, 0x55, 0x01, 0x05, 0xE0, 0x00, 0x01, 0x04, 0x40,
+    0x00, 0x00, 0xE0, 0x7F, 0x00, 0x30, 0x00, 0xFF, 0xAB, 0x00, 0x05, 0xE0, 0x80, 0x00, 0x02, 0x40,
+    0x0F, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xE0, 0xCF, 0x55, 0x81, 0x02, 0xF0, 0x40, 0x00, 0x02, 0x40,
+    0xF0, 0x0F, 0x00, 0x00, 0x7F, 0x00, 0xFE, 0xC3, 0xAB, 0x80, 0x02, 0x78, 0x20, 0x00, 0x01, 0x40,
+    0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xC0, 0xD5, 0x81, 0x01, 0x7E, 0x10, 0x80, 0x00, 0x20,
+    0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0xE0, 0xFA, 0x83, 0xC1, 0x3F, 0x08, 0x80, 0x00, 0x20,
+    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0xD8, 0x07, 0x83, 0xF1, 0x1F, 0x04, 0x40, 0x00, 0x20,
+    0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0x80, 0xC7, 0x01, 0x83, 0xF1, 0x0F, 0x00, 0x20, 0x00, 0x10,
+    0xE0, 0xFF, 0xFF, 0xFF, 0x3F, 0xC0, 0x7F, 0x40, 0x80, 0x83, 0xE1, 0x01, 0x00, 0x20, 0x00, 0x18,
+    0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x00, 0x20, 0xFC, 0x83, 0x01, 0x00, 0x00, 0x10, 0x00, 0x18,
+    0xFF, 0xFF, 0xFF, 0x3F, 0xF0, 0x00, 0x00, 0x10, 0xD7, 0x01, 0x03, 0x00, 0x00, 0x08, 0x00, 0x1C,
+    0xFF, 0xFF, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x88, 0xAB, 0x02, 0xE3, 0x01, 0x00, 0x08, 0x00, 0x0C,
+    0xFF, 0x07, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC4, 0x55, 0x05, 0x1E, 0x00, 0x00, 0x04, 0x00, 0x0E,
+    0x7F, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xA3, 0xAB, 0x02, 0x06, 0x00, 0x00, 0x02, 0x00, 0x0F,
+    0x0F, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x10, 0x57, 0x05, 0x02, 0x00, 0x00, 0x01, 0x80, 0x07,
+    0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0x08, 0xAB, 0x0A, 0x02, 0x00, 0xC0, 0x00, 0xC0, 0x07,
+    0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x84, 0x57, 0x15, 0x01, 0x00, 0x30, 0x00, 0xE0, 0x07,
+    0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0xC3, 0xFF, 0x2A, 0x01, 0x00, 0x0C, 0x00, 0xF0, 0x0F,
+    0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0xE0, 0xFE, 0x55, 0x01, 0x82, 0x03, 0x00, 0xF8, 0x15,
+    0x00, 0x30, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x78, 0xFE, 0xAA, 0x01, 0x7C, 0x00, 0x00, 0xFC, 0x23,
+    0x00, 0x0E, 0x00, 0x00, 0xC0, 0x03, 0x0C, 0x3C, 0x7F, 0x5D, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x45,
+    0xC0, 0x01, 0x00, 0x00, 0x3E, 0x00, 0x02, 0x8F, 0xBF, 0xAE, 0x03, 0x00, 0x00, 0xC0, 0xFF, 0x82,
+    0x30, 0x00, 0x00, 0xC0, 0x01, 0x80, 0xC1, 0x43, 0xFE, 0x5D, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x05,
+    0x0F, 0x00, 0x80, 0x3F, 0x00, 0x60, 0xF0, 0x31, 0xF6, 0xAE, 0x03, 0x00, 0x00, 0xFA, 0xAF, 0x02,
+    0xFC, 0xFF, 0x7F, 0x00, 0x00, 0x18, 0x7C, 0x08, 0x23, 0xFF, 0x05, 0x00, 0x00, 0xFD, 0x55, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x1F, 0x84, 0x30, 0xFE, 0x0A, 0x00, 0x00, 0xAA, 0xAA, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x80, 0xF1, 0x07, 0x43, 0x18, 0xFF, 0x15, 0x00, 0x00, 0x54, 0x15, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x80, 0x20, 0x8C, 0xFF, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+// Boot request enum
+#define BOOT_REQUEST_TAINTED 0x00000000
+#define BOOT_REQUEST_CLEAN 0xDADEDADE
+#define BOOT_REQUEST_DFU 0xDF00B000
+// Boot to DFU pin
+#define BOOT_DFU_PORT GPIOB
+#define BOOT_DFU_PIN LL_GPIO_PIN_11
+// USB pins
+#define BOOT_USB_PORT GPIOA
+#define BOOT_USB_DM_PIN LL_GPIO_PIN_11
+#define BOOT_USB_DP_PIN LL_GPIO_PIN_12
+#define BOOT_USB_PIN (BOOT_USB_DM_PIN | BOOT_USB_DP_PIN)
+
+#define RTC_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady())
+
+uint8_t u8g2_gpio_and_delay_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);
+
+void target_led_control(char* c) {
+    furi_hal_light_set(LightRed, 0x00);
+    furi_hal_light_set(LightGreen, 0x00);
+    furi_hal_light_set(LightBlue, 0x00);
+    do {
+        if(*c == 'R') {
+            furi_hal_light_set(LightRed, 0xFF);
+        } else if(*c == 'G') {
+            furi_hal_light_set(LightGreen, 0xFF);
+        } else if(*c == 'B') {
+            furi_hal_light_set(LightBlue, 0xFF);
+        } else if(*c == '.') {
+            LL_mDelay(125);
+            furi_hal_light_set(LightRed, 0x00);
+            furi_hal_light_set(LightGreen, 0x00);
+            furi_hal_light_set(LightBlue, 0x00);
+            LL_mDelay(125);
+        } else if(*c == '-') {
+            LL_mDelay(250);
+            furi_hal_light_set(LightRed, 0x00);
+            furi_hal_light_set(LightGreen, 0x00);
+            furi_hal_light_set(LightBlue, 0x00);
+            LL_mDelay(250);
+        } else if(*c == '|') {
+            furi_hal_light_set(LightRed, 0x00);
+            furi_hal_light_set(LightGreen, 0x00);
+            furi_hal_light_set(LightBlue, 0x00);
+        }
+        c++;
+    } while(*c != 0);
+}
+
+void target_clock_init() {
+    LL_Init1msTick(4000000);
+    LL_SetSystemCoreClock(4000000);
+
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD);
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE);
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH);
+
+    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
+    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
+}
+
+void target_gpio_init() {
+    // USB D+
+    LL_GPIO_SetPinMode(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_MODE_OUTPUT);
+    LL_GPIO_SetPinSpeed(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH);
+    LL_GPIO_SetPinOutputType(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_OUTPUT_OPENDRAIN);
+    // USB D-
+    LL_GPIO_SetPinMode(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_MODE_OUTPUT);
+    LL_GPIO_SetPinSpeed(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH);
+    LL_GPIO_SetPinOutputType(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_OUTPUT_OPENDRAIN);
+    // Button: back
+    LL_GPIO_SetPinMode(BOOT_DFU_PORT, BOOT_DFU_PIN, LL_GPIO_MODE_INPUT);
+    LL_GPIO_SetPinPull(BOOT_DFU_PORT, BOOT_DFU_PIN, LL_GPIO_PULL_UP);
+}
+
+void target_rtc_init() {
+    // LSE and RTC
+    LL_PWR_EnableBkUpAccess();
+    if(!RTC_CLOCK_IS_READY()) {
+        // Start LSI1 needed for CSS
+        LL_RCC_LSI1_Enable();
+        // Try to start LSE normal way
+        LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH);
+        LL_RCC_LSE_Enable();
+        uint32_t c = 0;
+        while(!RTC_CLOCK_IS_READY() && c < 200) {
+            LL_mDelay(10);
+            c++;
+        }
+        // Plan B: reset backup domain
+        if(!RTC_CLOCK_IS_READY()) {
+            target_led_control("-R.R.R.");
+            LL_RCC_ForceBackupDomainReset();
+            LL_RCC_ReleaseBackupDomainReset();
+            NVIC_SystemReset();
+        }
+        // Set RTC domain clock to LSE
+        LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
+        // Enable LSE CSS
+        LL_RCC_LSE_EnableCSS();
+    }
+    // Enable clocking
+    LL_RCC_EnableRTC();
+    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB);
+}
+
+void target_version_save(void) {
+    LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR1, (uint32_t)version_get());
+}
+
+void target_usb_wire_reset() {
+    LL_GPIO_ResetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN);
+}
+
+void target_display_init() {
+    // Prepare gpio
+    hal_gpio_init_simple(&gpio_display_rst, GpioModeOutputPushPull);
+    hal_gpio_init_simple(&gpio_display_di, GpioModeOutputPushPull);
+    // Initialize
+    u8g2_t fb;
+    u8g2_Setup_st7565_erc12864_alt_f(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32);
+    u8g2_InitDisplay(&fb);
+    u8g2_SetContrast(&fb, 36);
+    // Create payload
+    u8g2_ClearBuffer(&fb);
+    u8g2_SetDrawColor(&fb, 0x01);
+    u8g2_SetFont(&fb, u8g2_font_helvB08_tf);
+    u8g2_DrawXBM(&fb, 0, 64 - 50, 128, 50, I_DFU_128x50);
+    u8g2_DrawStr(&fb, 2, 8, "Update & Recovery Mode");
+    u8g2_DrawStr(&fb, 2, 21, "DFU started");
+    // Send buffer
+    u8g2_SetPowerSave(&fb, 0);
+    u8g2_SendBuffer(&fb);
+}
+
+void target_init() {
+    target_clock_init();
+    target_gpio_init();
+    furi_hal_init();
+    target_led_control("RGB");
+    target_rtc_init();
+    target_version_save();
+    target_usb_wire_reset();
+
+    // Errata 2.2.9, Flash OPTVERR flag is always set after system reset
+    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
+}
+
+int target_is_dfu_requested() {
+    if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) == BOOT_REQUEST_TAINTED) {
+        // Default system state is tainted
+        // We must ensure that MCU is cleanly booted
+        LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_CLEAN);
+        NVIC_SystemReset();
+    } else if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) == BOOT_REQUEST_DFU) {
+        return 1;
+    }
+    LL_mDelay(100);
+    if(!LL_GPIO_IsInputPinSet(BOOT_DFU_PORT, BOOT_DFU_PIN)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+void target_switch(void* offset) {
+    asm volatile("ldr    r3, [%0]    \n"
+                 "msr    msp, r3     \n"
+                 "ldr    r3, [%1]    \n"
+                 "mov    pc, r3      \n"
+                 :
+                 : "r"(offset), "r"(offset + 0x4)
+                 : "r3");
+}
+
+void target_switch2dfu() {
+    target_led_control("B");
+    furi_hal_light_set(LightBacklight, 0xFF);
+    target_display_init();
+    // Mark system as tainted, it will be soon
+    LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_TAINTED);
+    // Remap memory to system bootloader
+    LL_SYSCFG_SetRemapMemory(LL_SYSCFG_REMAP_SYSTEMFLASH);
+    // Jump
+    target_switch(0x0);
+}
+
+void target_switch2os() {
+    target_led_control("G");
+    SCB->VTOR = OS_OFFSET;
+    target_switch((void*)(BOOT_ADDRESS + OS_OFFSET));
+}

+ 48 - 0
bootloader/targets/f7/target.mk

@@ -0,0 +1,48 @@
+TOOLCHAIN = arm
+
+BOOT_ADDRESS	= 0x08000000
+FW_ADDRESS		= 0x08008000
+OS_OFFSET		= 0x00008000
+FLASH_ADDRESS	= 0x08000000
+
+OPENOCD_OPTS	= -f interface/stlink.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "init"
+BOOT_CFLAGS		= -DBOOT_ADDRESS=$(BOOT_ADDRESS) -DFW_ADDRESS=$(FW_ADDRESS) -DOS_OFFSET=$(OS_OFFSET)
+MCU_FLAGS		= -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
+
+CFLAGS			+= $(MCU_FLAGS) $(BOOT_CFLAGS) -DSTM32WB55xx -Wall -fdata-sections -ffunction-sections
+LDFLAGS			+= $(MCU_FLAGS) -specs=nosys.specs -specs=nano.specs 
+
+CUBE_DIR		= $(PROJECT_ROOT)/lib/STM32CubeWB
+
+# ST HAL
+CFLAGS			+=  -DUSE_FULL_LL_DRIVER
+ASM_SOURCES		+= $(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Source/Templates/gcc/startup_stm32wb55xx_cm4.s
+C_SOURCES		+= $(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Source/Templates/system_stm32wbxx.c
+C_SOURCES		+= $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c
+C_SOURCES		+= $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c
+C_SOURCES		+= $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c
+C_SOURCES		+= $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c
+
+CFLAGS			+= -I$(CUBE_DIR)/Drivers/CMSIS/Include
+CFLAGS			+= -I$(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Include
+CFLAGS			+= -I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc
+
+LDFLAGS			+= -T$(TARGET_DIR)/stm32wb55xx_flash_cm4.ld
+
+# Drivers
+DRIVERS_DIR		= $(PROJECT_ROOT)//lib/drivers
+CFLAGS			+= -I$(DRIVERS_DIR)
+C_SOURCES		+= $(DRIVERS_DIR)/lp5562.c
+
+# API-HAL
+CFLAGS			+= -I$(TARGET_DIR)/furi-hal
+C_SOURCES		+= $(wildcard $(TARGET_DIR)/furi-hal/*.c)
+
+# Version generation
+C_SOURCES		+= $(PROJECT_ROOT)/lib/toolbox/version.c
+
+ASM_SOURCES		+= $(wildcard $(TARGET_DIR)/*.s)
+C_SOURCES		+= $(wildcard $(TARGET_DIR)/*.c)
+CPP_SOURCES		+= $(wildcard $(TARGET_DIR)/*.cpp)
+
+SVD_FILE		= $(PROJECT_ROOT)/debug/STM32WB55_CM4.svd

+ 8 - 0
firmware/targets/f6/Inc/FreeRTOSConfig.h

@@ -118,6 +118,14 @@ to exclude the API function. */
 #define INCLUDE_xTaskGetSchedulerState       1
 #define INCLUDE_xTimerPendFunctionCall       1
 
+/* CMSIS-RTOS V2 flags */
+#define configUSE_OS2_THREAD_SUSPEND_RESUME  1
+#define configUSE_OS2_THREAD_ENUMERATE       1
+#define configUSE_OS2_EVENTFLAGS_FROM_ISR    1
+#define configUSE_OS2_THREAD_FLAGS           1
+#define configUSE_OS2_TIMER                  1
+#define configUSE_OS2_MUTEX                  1
+
 /*
  * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
  * by the application thus the correct define need to be enabled below

+ 16 - 4
firmware/targets/f6/cube/Inc/FreeRTOSConfig.h

@@ -1,6 +1,6 @@
 /* USER CODE BEGIN Header */
 /*
- * FreeRTOS Kernel V10.2.1
+ * FreeRTOS Kernel V10.3.1
  * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
  * Portion Copyright (C) 2019 StMicroelectronics, Inc.  All Rights Reserved.
  *
@@ -57,6 +57,10 @@
   extern unsigned long getRunTimeCounterValue(void);
 /* USER CODE END 0 */
 #endif
+#ifndef CMSIS_device_header
+#define CMSIS_device_header "stm32wbxx.h"
+#endif /* CMSIS_device_header */
+
 #define configENABLE_FPU                         1
 #define configENABLE_MPU                         0
 
@@ -99,6 +103,14 @@
 #define configTIMER_QUEUE_LENGTH                 10
 #define configTIMER_TASK_STACK_DEPTH             256
 
+/* CMSIS-RTOS V2 flags */
+#define configUSE_OS2_THREAD_SUSPEND_RESUME  1
+#define configUSE_OS2_THREAD_ENUMERATE       1
+#define configUSE_OS2_EVENTFLAGS_FROM_ISR    1
+#define configUSE_OS2_THREAD_FLAGS           1
+#define configUSE_OS2_TIMER                  1
+#define configUSE_OS2_MUTEX                  1
+
 /* Set the following definitions to 1 to include the API function, or zero
 to exclude the API function. */
 #define INCLUDE_vTaskPrioritySet             1
@@ -112,6 +124,7 @@ to exclude the API function. */
 #define INCLUDE_xTimerPendFunctionCall       1
 #define INCLUDE_xQueueGetMutexHolder         1
 #define INCLUDE_uxTaskGetStackHighWaterMark  1
+#define INCLUDE_xTaskGetCurrentTaskHandle    1
 #define INCLUDE_eTaskGetState                1
 
 /*
@@ -156,10 +169,9 @@ standard names. */
 #define vPortSVCHandler    SVC_Handler
 #define xPortPendSVHandler PendSV_Handler
 
-/* IMPORTANT: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick,
-              to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
+/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */
 
-/* #define xPortSysTickHandler SysTick_Handler */
+#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1
 
 /* USER CODE BEGIN 2 */
 /* Definitions needed when configGENERATE_RUN_TIME_STATS is on */

+ 1 - 37
firmware/targets/f6/cube/Inc/main.h

@@ -29,7 +29,7 @@ extern "C" {
 
 /* Includes ------------------------------------------------------------------*/
 #include "stm32wbxx_hal.h"
-#include "stm32wbxx.h"
+
 #include "stm32wbxx_ll_i2c.h"
 #include "stm32wbxx_ll_crs.h"
 #include "stm32wbxx_ll_rcc.h"
@@ -164,42 +164,6 @@ void Error_Handler(void);
 #define SPI_R_MOSI_GPIO_Port GPIOB
 /* USER CODE BEGIN Private defines */
 
-#define MISO_PIN GpioPin{.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin}
-
-#define SPI_R hspi1
-#define SPI_D hspi2
-#define SPI_SD_HANDLE SPI_D
-
-extern TIM_HandleTypeDef htim1;
-extern TIM_HandleTypeDef htim2;
-extern TIM_HandleTypeDef htim16;
-
-#define TIM_A htim1
-#define TIM_B htim2
-#define TIM_C htim16
-
-#define SPEAKER_TIM htim16
-#define SPEAKER_CH TIM_CHANNEL_1
-
-#define LFRFID_TIM htim1
-#define LFRFID_CH TIM_CHANNEL_1
-
-#define IRDA_TX_TIM htim1
-#define IRDA_TX_CH TIM_CHANNEL_3
-
-// only for reference
-// IRDA RX timer dont exist in F2
-// and timer need more data to init (NVIC IRQn to set priority)
-#define IRDA_RX_TIM htim2
-#define IRDA_RX_FALLING_CH TIM_CHANNEL_1
-#define IRDA_RX_RISING_CH TIM_CHANNEL_2
-
-#define NFC_IRQ_Pin RFID_PULL_Pin
-#define NFC_IRQ_GPIO_Port RFID_PULL_GPIO_Port
-
-#define VIBRO_Pin GPIO_PIN_10
-#define VIBRO_GPIO_Port GPIOC
-
 /* USER CODE END Private defines */
 
 #ifdef __cplusplus

+ 1 - 2
firmware/targets/f6/cube/Inc/usbd_cdc_if.h

@@ -48,11 +48,10 @@
   * @brief Defines.
   * @{
   */
-/* USER CODE BEGIN EXPORTED_DEFINES */
 /* Define size for the receive and transmit buffer over CDC */
-/* It's up to user to redefine and/or remove those define */
 #define APP_RX_DATA_SIZE  512
 #define APP_TX_DATA_SIZE  512
+/* USER CODE BEGIN EXPORTED_DEFINES */
 
 /* USER CODE END EXPORTED_DEFINES */
 

+ 63 - 63
firmware/targets/f6/cube/Makefile

@@ -1,5 +1,5 @@
 ##########################################################################################################################
-# File automatically-generated by tool: [projectgenerator] version: [3.13.0-B3] date: [Tue Jul 20 02:23:07 MSK 2021]
+# File automatically-generated by tool: [projectgenerator] version: [3.14.1] date: [Fri Sep 10 04:51:15 MSK 2021]
 ##########################################################################################################################
 
 # ------------------------------------------------
@@ -57,60 +57,60 @@ Src/usbd_desc.c \
 Src/usbd_cdc_if.c \
 Src/stm32wbxx_it.c \
 Src/stm32wbxx_hal_msp.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_exti.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_gpio.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_hsem.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cortex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_exti.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_adc.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_comp.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_dma.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pka.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rng.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim_ex.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_exti.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pcd_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usb.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_flash_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_gpio.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_hsem.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_dma_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cortex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_exti.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_adc_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_adc.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_cryp_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_comp.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_crc_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_dma.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pka.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rng.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_spi_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim_ex.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \
 Src/system_stm32wbxx.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/list.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/queue.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/timers.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
-/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c  
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/event_groups.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/list.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/queue.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/tasks.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/timers.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_core.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c \
+/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c  
 
 # ASM sources
 ASM_SOURCES =  \
@@ -170,15 +170,15 @@ AS_INCLUDES =  \
 # C includes
 C_INCLUDES =  \
 -IInc \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Inc \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/include \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/CMSIS/Device/ST/STM32WBxx/Include \
--I/Users/aku/STM32Cube/Repository/STM32Cube_FW_WB_V1.10.1/Drivers/CMSIS/Include
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc \
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/Legacy \
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include \
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F \
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/CMSIS/Device/ST/STM32WBxx/Include \
+-I/Users/aku/Work/flipper/flipperzero-firmware/lib/STM32CubeWB/Drivers/CMSIS/Include
 
 
 # compile gcc flags

+ 11 - 0
firmware/targets/f6/cube/Src/adc.c

@@ -29,8 +29,16 @@ ADC_HandleTypeDef hadc1;
 /* ADC1 init function */
 void MX_ADC1_Init(void)
 {
+
+  /* USER CODE BEGIN ADC1_Init 0 */
+
+  /* USER CODE END ADC1_Init 0 */
+
   ADC_ChannelConfTypeDef sConfig = {0};
 
+  /* USER CODE BEGIN ADC1_Init 1 */
+
+  /* USER CODE END ADC1_Init 1 */
   /** Common config
   */
   hadc1.Instance = ADC1;
@@ -64,6 +72,9 @@ void MX_ADC1_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN ADC1_Init 2 */
+
+  /* USER CODE END ADC1_Init 2 */
 
 }
 

+ 20 - 0
firmware/targets/f6/cube/Src/aes.c

@@ -35,6 +35,13 @@ __ALIGN_BEGIN static const uint32_t pKeyAES2[4] __ALIGN_END = {
 void MX_AES1_Init(void)
 {
 
+  /* USER CODE BEGIN AES1_Init 0 */
+
+  /* USER CODE END AES1_Init 0 */
+
+  /* USER CODE BEGIN AES1_Init 1 */
+
+  /* USER CODE END AES1_Init 1 */
   hcryp1.Instance = AES1;
   hcryp1.Init.DataType = CRYP_DATATYPE_32B;
   hcryp1.Init.KeySize = CRYP_KEYSIZE_128B;
@@ -46,12 +53,22 @@ void MX_AES1_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN AES1_Init 2 */
+
+  /* USER CODE END AES1_Init 2 */
 
 }
 /* AES2 init function */
 void MX_AES2_Init(void)
 {
 
+  /* USER CODE BEGIN AES2_Init 0 */
+
+  /* USER CODE END AES2_Init 0 */
+
+  /* USER CODE BEGIN AES2_Init 1 */
+
+  /* USER CODE END AES2_Init 1 */
   hcryp2.Instance = AES2;
   hcryp2.Init.DataType = CRYP_DATATYPE_32B;
   hcryp2.Init.KeySize = CRYP_KEYSIZE_128B;
@@ -63,6 +80,9 @@ void MX_AES2_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN AES2_Init 2 */
+
+  /* USER CODE END AES2_Init 2 */
 
 }
 

+ 10 - 0
firmware/targets/f6/cube/Src/comp.c

@@ -30,6 +30,13 @@ COMP_HandleTypeDef hcomp1;
 void MX_COMP1_Init(void)
 {
 
+  /* USER CODE BEGIN COMP1_Init 0 */
+
+  /* USER CODE END COMP1_Init 0 */
+
+  /* USER CODE BEGIN COMP1_Init 1 */
+
+  /* USER CODE END COMP1_Init 1 */
   hcomp1.Instance = COMP1;
   hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_4VREFINT;
   hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1;
@@ -43,6 +50,9 @@ void MX_COMP1_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN COMP1_Init 2 */
+
+  /* USER CODE END COMP1_Init 2 */
 
 }
 

+ 10 - 0
firmware/targets/f6/cube/Src/crc.c

@@ -30,6 +30,13 @@ CRC_HandleTypeDef hcrc;
 void MX_CRC_Init(void)
 {
 
+  /* USER CODE BEGIN CRC_Init 0 */
+
+  /* USER CODE END CRC_Init 0 */
+
+  /* USER CODE BEGIN CRC_Init 1 */
+
+  /* USER CODE END CRC_Init 1 */
   hcrc.Instance = CRC;
   hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;
   hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
@@ -40,6 +47,9 @@ void MX_CRC_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN CRC_Init 2 */
+
+  /* USER CODE END CRC_Init 2 */
 
 }
 

+ 11 - 0
firmware/targets/f6/cube/Src/i2c.c

@@ -27,6 +27,11 @@
 /* I2C1 init function */
 void MX_I2C1_Init(void)
 {
+
+  /* USER CODE BEGIN I2C1_Init 0 */
+
+  /* USER CODE END I2C1_Init 0 */
+
   LL_I2C_InitTypeDef I2C_InitStruct = {0};
 
   LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
@@ -47,6 +52,9 @@ void MX_I2C1_Init(void)
   /* Peripheral clock enable */
   LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
 
+  /* USER CODE BEGIN I2C1_Init 1 */
+
+  /* USER CODE END I2C1_Init 1 */
   /** I2C Initialization
   */
   I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
@@ -62,6 +70,9 @@ void MX_I2C1_Init(void)
   LL_I2C_DisableOwnAddress2(I2C1);
   LL_I2C_DisableGeneralCall(I2C1);
   LL_I2C_EnableClockStretching(I2C1);
+  /* USER CODE BEGIN I2C1_Init 2 */
+
+  /* USER CODE END I2C1_Init 2 */
 
 }
 

+ 6 - 2
firmware/targets/f6/cube/Src/main.c

@@ -163,6 +163,11 @@ void SystemClock_Config(void)
   }
 
   LL_PWR_EnableBkUpAccess();
+  if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE)
+  {
+    LL_RCC_ForceBackupDomainReset();
+    LL_RCC_ReleaseBackupDomainReset();
+  }
   LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_MEDIUMLOW);
   LL_RCC_LSE_Enable();
 
@@ -229,8 +234,6 @@ void SystemClock_Config(void)
   }
   if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE)
   {
-    LL_RCC_ForceBackupDomainReset();
-    LL_RCC_ReleaseBackupDomainReset();
     LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
   }
   LL_RCC_EnableRTC();
@@ -239,6 +242,7 @@ void SystemClock_Config(void)
   LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
   LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48);
   LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1);
+  LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1);
   LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE);
   LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1);
   LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE);

+ 10 - 0
firmware/targets/f6/cube/Src/pka.c

@@ -30,11 +30,21 @@ PKA_HandleTypeDef hpka;
 void MX_PKA_Init(void)
 {
 
+  /* USER CODE BEGIN PKA_Init 0 */
+
+  /* USER CODE END PKA_Init 0 */
+
+  /* USER CODE BEGIN PKA_Init 1 */
+
+  /* USER CODE END PKA_Init 1 */
   hpka.Instance = PKA;
   if (HAL_PKA_Init(&hpka) != HAL_OK)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN PKA_Init 2 */
+
+  /* USER CODE END PKA_Init 2 */
 
 }
 

+ 11 - 0
firmware/targets/f6/cube/Src/rf.c

@@ -28,6 +28,17 @@
 void MX_RF_Init(void)
 {
 
+  /* USER CODE BEGIN RF_Init 0 */
+
+  /* USER CODE END RF_Init 0 */
+
+  /* USER CODE BEGIN RF_Init 1 */
+
+  /* USER CODE END RF_Init 1 */
+  /* USER CODE BEGIN RF_Init 2 */
+
+  /* USER CODE END RF_Init 2 */
+
 }
 
 /* USER CODE BEGIN 1 */

+ 11 - 0
firmware/targets/f6/cube/Src/rng.c

@@ -30,11 +30,22 @@ RNG_HandleTypeDef hrng;
 void MX_RNG_Init(void)
 {
 
+  /* USER CODE BEGIN RNG_Init 0 */
+
+  /* USER CODE END RNG_Init 0 */
+
+  /* USER CODE BEGIN RNG_Init 1 */
+
+  /* USER CODE END RNG_Init 1 */
   hrng.Instance = RNG;
+  hrng.Init.ClockErrorDetection = RNG_CED_ENABLE;
   if (HAL_RNG_Init(&hrng) != HAL_OK)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN RNG_Init 2 */
+
+  /* USER CODE END RNG_Init 2 */
 
 }
 

+ 11 - 0
firmware/targets/f6/cube/Src/rtc.c

@@ -29,9 +29,17 @@ RTC_HandleTypeDef hrtc;
 /* RTC init function */
 void MX_RTC_Init(void)
 {
+
+  /* USER CODE BEGIN RTC_Init 0 */
+
+  /* USER CODE END RTC_Init 0 */
+
   RTC_TimeTypeDef sTime = {0};
   RTC_DateTypeDef sDate = {0};
 
+  /* USER CODE BEGIN RTC_Init 1 */
+
+  /* USER CODE END RTC_Init 1 */
   /** Initialize RTC Only
   */
   hrtc.Instance = RTC;
@@ -72,6 +80,9 @@ void MX_RTC_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN RTC_Init 2 */
+
+  /* USER CODE END RTC_Init 2 */
 
 }
 

+ 20 - 0
firmware/targets/f6/cube/Src/spi.c

@@ -31,6 +31,13 @@ SPI_HandleTypeDef hspi2;
 void MX_SPI1_Init(void)
 {
 
+  /* USER CODE BEGIN SPI1_Init 0 */
+
+  /* USER CODE END SPI1_Init 0 */
+
+  /* USER CODE BEGIN SPI1_Init 1 */
+
+  /* USER CODE END SPI1_Init 1 */
   hspi1.Instance = SPI1;
   hspi1.Init.Mode = SPI_MODE_MASTER;
   hspi1.Init.Direction = SPI_DIRECTION_2LINES;
@@ -49,12 +56,22 @@ void MX_SPI1_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN SPI1_Init 2 */
+
+  /* USER CODE END SPI1_Init 2 */
 
 }
 /* SPI2 init function */
 void MX_SPI2_Init(void)
 {
 
+  /* USER CODE BEGIN SPI2_Init 0 */
+
+  /* USER CODE END SPI2_Init 0 */
+
+  /* USER CODE BEGIN SPI2_Init 1 */
+
+  /* USER CODE END SPI2_Init 1 */
   hspi2.Instance = SPI2;
   hspi2.Init.Mode = SPI_MODE_MASTER;
   hspi2.Init.Direction = SPI_DIRECTION_2LINES;
@@ -73,6 +90,9 @@ void MX_SPI2_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN SPI2_Init 2 */
+
+  /* USER CODE END SPI2_Init 2 */
 
 }
 

+ 368 - 357
firmware/targets/f6/cube/Src/system_stm32wbxx.c

@@ -1,357 +1,368 @@
-/**
-  ******************************************************************************
-  * @file    system_stm32wbxx.c
-  * @author  MCD Application Team
-  * @brief   CMSIS Cortex Device Peripheral Access Layer System Source File
-  *
-  *   This file provides two functions and one global variable to be called from
-  *   user application:
-  *      - SystemInit(): This function is called at startup just after reset and
-  *                      before branch to main program. This call is made inside
-  *                      the "startup_stm32wbxx.s" file.
-  *
-  *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
-  *                                  by the user application to setup the SysTick
-  *                                  timer or configure other parameters.
-  *
-  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
-  *                                 be called whenever the core clock is changed
-  *                                 during program execution.
-  *
-  *   After each device reset the MSI (4 MHz) is used as system clock source.
-  *   Then SystemInit() function is called, in "startup_stm32wbxx.s" file, to
-  *   configure the system clock before to branch to main program.
-  *
-  *   This file configures the system clock as follows:
-  *=============================================================================
-  *-----------------------------------------------------------------------------
-  *        System Clock source                    | MSI
-  *-----------------------------------------------------------------------------
-  *        SYSCLK(Hz)                             | 4000000
-  *-----------------------------------------------------------------------------
-  *        HCLK(Hz)                               | 4000000
-  *-----------------------------------------------------------------------------
-  *        AHB Prescaler                          | 1
-  *-----------------------------------------------------------------------------
-  *        APB1 Prescaler                         | 1
-  *-----------------------------------------------------------------------------
-  *        APB2 Prescaler                         | 1
-  *-----------------------------------------------------------------------------
-  *        PLL_M                                  | 1
-  *-----------------------------------------------------------------------------
-  *        PLL_N                                  | 8
-  *-----------------------------------------------------------------------------
-  *        PLL_P                                  | 7
-  *-----------------------------------------------------------------------------
-  *        PLL_Q                                  | 2
-  *-----------------------------------------------------------------------------
-  *        PLL_R                                  | 2
-  *-----------------------------------------------------------------------------
-  *        PLLSAI1_P                              | NA
-  *-----------------------------------------------------------------------------
-  *        PLLSAI1_Q                              | NA
-  *-----------------------------------------------------------------------------
-  *        PLLSAI1_R                              | NA
-  *-----------------------------------------------------------------------------
-  *        Require 48MHz for USB OTG FS,          | Disabled
-  *        SDIO and RNG clock                     |
-  *-----------------------------------------------------------------------------
-  *=============================================================================
-  ******************************************************************************
-  * @attention
-  *
-  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics. 
-  * All rights reserved.</center></h2>
-  *
-  * This software component is licensed by ST under BSD 3-Clause license,
-  * the "License"; You may not use this file except in compliance with the 
-  * License. You may obtain a copy of the License at:
-  *                        opensource.org/licenses/BSD-3-Clause
-  *
-  ******************************************************************************
-  */
-
-/** @addtogroup CMSIS
-  * @{
-  */
-
-/** @addtogroup stm32WBxx_system
-  * @{
-  */
-
-/** @addtogroup stm32WBxx_System_Private_Includes
-  * @{
-  */
-
-#include "stm32wbxx.h"
-
-#if !defined  (HSE_VALUE)
-  #define HSE_VALUE    (32000000UL) /*!< Value of the External oscillator in Hz */
-#endif /* HSE_VALUE */
-
-#if !defined  (MSI_VALUE)
-   #define MSI_VALUE    (4000000UL) /*!< Value of the Internal oscillator in Hz*/
-#endif /* MSI_VALUE */
-
-#if !defined  (HSI_VALUE)
-  #define HSI_VALUE    (16000000UL) /*!< Value of the Internal oscillator in Hz*/
-#endif /* HSI_VALUE */
-
-#if !defined  (LSI_VALUE) 
- #define LSI_VALUE  (32000UL)       /*!< Value of LSI in Hz*/
-#endif /* LSI_VALUE */ 
-
-#if !defined  (LSE_VALUE)
-  #define LSE_VALUE    (32768UL)    /*!< Value of LSE in Hz*/
-#endif /* LSE_VALUE */
-
-/**
-  * @}
-  */
-
-/** @addtogroup STM32WBxx_System_Private_TypesDefinitions
-  * @{
-  */
-
-/**
-  * @}
-  */
-
-/** @addtogroup STM32WBxx_System_Private_Defines
-  * @{
-  */
-
-/*!< Uncomment the following line if you need to relocate your vector Table in
-     Internal SRAM. */
-/* #define VECT_TAB_SRAM */
-#define VECT_TAB_OFFSET         0x0U            /*!< Vector Table base offset field.
-                                                     This value must be a multiple of 0x200. */
-
-#define VECT_TAB_BASE_ADDRESS   SRAM1_BASE       /*!< Vector Table base offset field.
-                                                     This value must be a multiple of 0x200. */
-/**
-  * @}
-  */
-
-/** @addtogroup STM32WBxx_System_Private_Macros
-  * @{
-  */
-
-/**
-  * @}
-  */
-
-/** @addtogroup STM32WBxx_System_Private_Variables
-  * @{
-  */
-  /* The SystemCoreClock variable is updated in three ways:
-      1) by calling CMSIS function SystemCoreClockUpdate()
-      2) by calling HAL API function HAL_RCC_GetHCLKFreq()
-      3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
-         Note: If you use this function to configure the system clock; then there
-               is no need to call the 2 first functions listed above, since SystemCoreClock
-               variable is updated automatically.
-  */
-  uint32_t SystemCoreClock  = 4000000UL ; /*CPU1: M4 on MSI clock after startup (4MHz)*/
-
-  const uint32_t AHBPrescTable[16UL] = {1UL, 3UL, 5UL, 1UL, 1UL, 6UL, 10UL, 32UL, 2UL, 4UL, 8UL, 16UL, 64UL, 128UL, 256UL, 512UL};
-
-  const uint32_t APBPrescTable[8UL]  = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL};
-
-  const uint32_t MSIRangeTable[16UL] = {100000UL, 200000UL, 400000UL, 800000UL, 1000000UL, 2000000UL, \
-                                      4000000UL, 8000000UL, 16000000UL, 24000000UL, 32000000UL, 48000000UL, 0UL, 0UL, 0UL, 0UL}; /* 0UL values are incorrect cases */
-
-#if defined(STM32WB55xx) || defined(STM32WB5Mxx) || defined(STM32WB35xx)
-  const uint32_t SmpsPrescalerTable[4UL][6UL]={{1UL,3UL,2UL,2UL,1UL,2UL}, \
-                                        {2UL,6UL,4UL,3UL,2UL,4UL}, \
-                                        {4UL,12UL,8UL,6UL,4UL,8UL}, \
-                                        {4UL,12UL,8UL,6UL,4UL,8UL}};
-#endif
-
-/**
-  * @}
-  */
-
-/** @addtogroup STM32WBxx_System_Private_FunctionPrototypes
-  * @{
-  */
-
-/**
-  * @}
-  */
-
-/** @addtogroup STM32WBxx_System_Private_Functions
-  * @{
-  */
-
-/**
-  * @brief  Setup the microcontroller system.
-  * @param  None
-  * @retval None
-  */
-void SystemInit(void)
-{
-  /* Configure the Vector Table location add offset address ------------------*/
-#if defined(VECT_TAB_SRAM) && defined(VECT_TAB_BASE_ADDRESS)  
-  /* program in SRAMx */
-  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET;  /* Vector Table Relocation in Internal SRAMx for CPU1 */
-#else    /* program in FLASH */
-  SCB->VTOR = VECT_TAB_OFFSET;              /* Vector Table Relocation in Internal FLASH */
-#endif
-
-  /* FPU settings ------------------------------------------------------------*/
-  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
-    SCB->CPACR |= ((3UL << (10UL*2UL))|(3UL << (11UL*2UL)));  /* set CP10 and CP11 Full Access */
-  #endif
-  
-  /* Reset the RCC clock configuration to the default reset state ------------*/
-  /* Set MSION bit */
-  RCC->CR |= RCC_CR_MSION;
-
-  /* Reset CFGR register */
-  RCC->CFGR = 0x00070000U;
-
-  /* Reset PLLSAI1ON, PLLON, HSECSSON, HSEON, HSION, and MSIPLLON bits */
-  RCC->CR &= (uint32_t)0xFAF6FEFBU;
-
-  /*!< Reset LSI1 and LSI2 bits */
-  RCC->CSR &= (uint32_t)0xFFFFFFFAU;
-  
-  /*!< Reset HSI48ON  bit */
-  RCC->CRRCR &= (uint32_t)0xFFFFFFFEU;
-    
-  /* Reset PLLCFGR register */
-  RCC->PLLCFGR = 0x22041000U;
-
-#if defined(STM32WB55xx) || defined(STM32WB5Mxx)
-  /* Reset PLLSAI1CFGR register */
-  RCC->PLLSAI1CFGR = 0x22041000U;
-#endif
-  
-  /* Reset HSEBYP bit */
-  RCC->CR &= 0xFFFBFFFFU;
-
-  /* Disable all interrupts */
-  RCC->CIER = 0x00000000;
-}
-
-/**
-  * @brief  Update SystemCoreClock variable according to Clock Register Values.
-  *         The SystemCoreClock variable contains the core clock (HCLK), it can
-  *         be used by the user application to setup the SysTick timer or configure
-  *         other parameters.
-  *
-  * @note   Each time the core clock (HCLK) changes, this function must be called
-  *         to update SystemCoreClock variable value. Otherwise, any configuration
-  *         based on this variable will be incorrect.
-  *
-  * @note   - The system frequency computed by this function is not the real
-  *           frequency in the chip. It is calculated based on the predefined
-  *           constant and the selected clock source:
-  *
-  *           - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*)
-  *
-  *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**)
-  *
-  *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***)
-  *
-  *           - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***)
-  *             or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors.
-  *
-  *         (*) MSI_VALUE is a constant defined in stm32wbxx_hal.h file (default value
-  *             4 MHz) but the real value may vary depending on the variations
-  *             in voltage and temperature.
-  *
-  *         (**) HSI_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value
-  *              16 MHz) but the real value may vary depending on the variations
-  *              in voltage and temperature.
-  *
-  *         (***) HSE_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value
-  *              32 MHz), user has to ensure that HSE_VALUE is same as the real
-  *              frequency of the crystal used. Otherwise, this function may
-  *              have wrong result.
-  *
-  *         - The result of this function could be not correct when using fractional
-  *           value for HSE crystal.
-  *
-  * @param  None
-  * @retval None
-  */
-void SystemCoreClockUpdate(void)
-{
-  uint32_t tmp, msirange, pllvco, pllr, pllsource , pllm;
-
-  /* Get MSI Range frequency--------------------------------------------------*/
-
-  /*MSI frequency range in Hz*/
-  msirange = MSIRangeTable[(RCC->CR & RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos];
-
-  /* Get SYSCLK source -------------------------------------------------------*/
-  switch (RCC->CFGR & RCC_CFGR_SWS)
-  {
-    case 0x00:   /* MSI used as system clock source */
-      SystemCoreClock = msirange;
-      break;
-
-    case 0x04:  /* HSI used as system clock source */
-      /* HSI used as system clock source */
-        SystemCoreClock = HSI_VALUE;
-      break;
-
-    case 0x08:  /* HSE used as system clock source */
-      SystemCoreClock = HSE_VALUE;
-      break;
-
-    case 0x0C: /* PLL used as system clock  source */
-      /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN
-         SYSCLK = PLL_VCO / PLLR
-         */
-      pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC);
-      pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL ;
-
-      if(pllsource == 0x02UL) /* HSI used as PLL clock source */
-      {
-        pllvco = (HSI_VALUE / pllm);
-      }
-      else if(pllsource == 0x03UL) /* HSE used as PLL clock source */
-      {
-        pllvco = (HSE_VALUE / pllm);
-      }
-      else /* MSI used as PLL clock source */
-      {
-        pllvco = (msirange / pllm);
-      }
-      
-      pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos);
-      pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL);
-      
-      SystemCoreClock = pllvco/pllr;
-      break;
-
-    default:
-      SystemCoreClock = msirange;
-      break;
-  }
-  
-  /* Compute HCLK clock frequency --------------------------------------------*/
-  /* Get HCLK1 prescaler */
-  tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)];
-  /* HCLK clock frequency */
-  SystemCoreClock = SystemCoreClock / tmp;
-
-}
-
-
-/**
-  * @}
-  */
-
-/**
-  * @}
-  */
-
-/**
-  * @}
-  */
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+  ******************************************************************************
+  * @file    system_stm32wbxx.c
+  * @author  MCD Application Team
+  * @brief   CMSIS Cortex Device Peripheral Access Layer System Source File
+  *
+  *   This file provides two functions and one global variable to be called from
+  *   user application:
+  *      - SystemInit(): This function is called at startup just after reset and
+  *                      before branch to main program. This call is made inside
+  *                      the "startup_stm32wbxx.s" file.
+  *
+  *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+  *                                  by the user application to setup the SysTick
+  *                                  timer or configure other parameters.
+  *
+  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+  *                                 be called whenever the core clock is changed
+  *                                 during program execution.
+  *
+  *   After each device reset the MSI (4 MHz) is used as system clock source.
+  *   Then SystemInit() function is called, in "startup_stm32wbxx.s" file, to
+  *   configure the system clock before to branch to main program.
+  *
+  *   This file configures the system clock as follows:
+  *=============================================================================
+  *-----------------------------------------------------------------------------
+  *        System Clock source                    | MSI
+  *-----------------------------------------------------------------------------
+  *        SYSCLK(Hz)                             | 4000000
+  *-----------------------------------------------------------------------------
+  *        HCLK(Hz)                               | 4000000
+  *-----------------------------------------------------------------------------
+  *        AHB Prescaler                          | 1
+  *-----------------------------------------------------------------------------
+  *        APB1 Prescaler                         | 1
+  *-----------------------------------------------------------------------------
+  *        APB2 Prescaler                         | 1
+  *-----------------------------------------------------------------------------
+  *        PLL_M                                  | 1
+  *-----------------------------------------------------------------------------
+  *        PLL_N                                  | 8
+  *-----------------------------------------------------------------------------
+  *        PLL_P                                  | 7
+  *-----------------------------------------------------------------------------
+  *        PLL_Q                                  | 2
+  *-----------------------------------------------------------------------------
+  *        PLL_R                                  | 2
+  *-----------------------------------------------------------------------------
+  *        PLLSAI1_P                              | NA
+  *-----------------------------------------------------------------------------
+  *        PLLSAI1_Q                              | NA
+  *-----------------------------------------------------------------------------
+  *        PLLSAI1_R                              | NA
+  *-----------------------------------------------------------------------------
+  *        Require 48MHz for USB OTG FS,          | Disabled
+  *        SDIO and RNG clock                     |
+  *-----------------------------------------------------------------------------
+  *=============================================================================
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2019-2021 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+/** @addtogroup CMSIS
+  * @{
+  */
+
+/** @addtogroup stm32WBxx_system
+  * @{
+  */
+
+/** @addtogroup stm32WBxx_System_Private_Includes
+  * @{
+  */
+
+#include "stm32wbxx.h"
+
+#if !defined  (HSE_VALUE)
+  #define HSE_VALUE    (32000000UL) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined  (MSI_VALUE)
+   #define MSI_VALUE    (4000000UL) /*!< Value of the Internal oscillator in Hz*/
+#endif /* MSI_VALUE */
+
+#if !defined  (HSI_VALUE)
+  #define HSI_VALUE    (16000000UL) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+#if !defined  (LSI_VALUE) 
+ #define LSI_VALUE  (32000UL)       /*!< Value of LSI in Hz*/
+#endif /* LSI_VALUE */ 
+
+#if !defined  (LSE_VALUE)
+  #define LSE_VALUE    (32768UL)    /*!< Value of LSE in Hz*/
+#endif /* LSE_VALUE */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_TypesDefinitions
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_Defines
+  * @{
+  */
+
+/* Note: Following vector table addresses must be defined in line with linker
+         configuration. */
+/*!< Uncomment the following line if you need to relocate CPU1 CM4 and/or CPU2
+     CM0+ vector table anywhere in Sram or Flash. Else vector table will be kept
+     at address 0x00 which correspond to automatic remap of boot address selected */
+/* #define USER_VECT_TAB_ADDRESS */
+#if defined(USER_VECT_TAB_ADDRESS)
+ /*!< Uncomment this line for user vector table remap in Sram else user remap
+      will be done in Flash. */
+/* #define VECT_TAB_SRAM */
+#if defined(VECT_TAB_SRAM)
+#define VECT_TAB_BASE_ADDRESS   SRAM1_BASE      /*!< Vector Table base address field.
+                                                     This value must be a multiple of 0x200. */
+#define VECT_TAB_OFFSET         0x00000000U     /*!< Vector Table base offset field.
+                                                     This value must be a multiple of 0x200. */
+#else
+#define VECT_TAB_BASE_ADDRESS   FLASH_BASE      /*!< Vector Table base address field.
+                                                     This value must be a multiple of 0x200. */
+#define VECT_TAB_OFFSET         0x00000000U     /*!< Vector Table base offset field.
+                                                     This value must be a multiple of 0x200. */
+#endif
+#endif
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_Macros
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_Variables
+  * @{
+  */
+  /* The SystemCoreClock variable is updated in three ways:
+      1) by calling CMSIS function SystemCoreClockUpdate()
+      2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+      3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
+         Note: If you use this function to configure the system clock; then there
+               is no need to call the 2 first functions listed above, since SystemCoreClock
+               variable is updated automatically.
+  */
+  uint32_t SystemCoreClock  = 4000000UL ; /*CPU1: M4 on MSI clock after startup (4MHz)*/
+
+  const uint32_t AHBPrescTable[16UL] = {1UL, 3UL, 5UL, 1UL, 1UL, 6UL, 10UL, 32UL, 2UL, 4UL, 8UL, 16UL, 64UL, 128UL, 256UL, 512UL};
+
+  const uint32_t APBPrescTable[8UL]  = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL};
+
+  const uint32_t MSIRangeTable[16UL] = {100000UL, 200000UL, 400000UL, 800000UL, 1000000UL, 2000000UL, \
+                                      4000000UL, 8000000UL, 16000000UL, 24000000UL, 32000000UL, 48000000UL, 0UL, 0UL, 0UL, 0UL}; /* 0UL values are incorrect cases */
+
+#if defined(STM32WB55xx) || defined(STM32WB5Mxx) || defined(STM32WB35xx) || defined (STM32WB15xx) || defined (STM32WB10xx)
+  const uint32_t SmpsPrescalerTable[4UL][6UL]={{1UL,3UL,2UL,2UL,1UL,2UL}, \
+                                        {2UL,6UL,4UL,3UL,2UL,4UL}, \
+                                        {4UL,12UL,8UL,6UL,4UL,8UL}, \
+                                        {4UL,12UL,8UL,6UL,4UL,8UL}};
+#endif
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_FunctionPrototypes
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_Functions
+  * @{
+  */
+
+/**
+  * @brief  Setup the microcontroller system.
+  * @param  None
+  * @retval None
+  */
+void SystemInit(void)
+{
+#if defined(USER_VECT_TAB_ADDRESS)
+  /* Configure the Vector Table location add offset address ------------------*/
+  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET;
+#endif
+
+  /* FPU settings ------------------------------------------------------------*/
+  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+    SCB->CPACR |= ((3UL << (10UL*2UL))|(3UL << (11UL*2UL)));  /* set CP10 and CP11 Full Access */
+  #endif
+  
+  /* Reset the RCC clock configuration to the default reset state ------------*/
+  /* Set MSION bit */
+  RCC->CR |= RCC_CR_MSION;
+
+  /* Reset CFGR register */
+  RCC->CFGR = 0x00070000U;
+
+  /* Reset PLLSAI1ON, PLLON, HSECSSON, HSEON, HSION, and MSIPLLON bits */
+  RCC->CR &= (uint32_t)0xFAF6FEFBU;
+
+  /*!< Reset LSI1 and LSI2 bits */
+  RCC->CSR &= (uint32_t)0xFFFFFFFAU;
+  
+  /*!< Reset HSI48ON  bit */
+  RCC->CRRCR &= (uint32_t)0xFFFFFFFEU;
+    
+  /* Reset PLLCFGR register */
+  RCC->PLLCFGR = 0x22041000U;
+
+#if defined(STM32WB55xx) || defined(STM32WB5Mxx)
+  /* Reset PLLSAI1CFGR register */
+  RCC->PLLSAI1CFGR = 0x22041000U;
+#endif
+  
+  /* Reset HSEBYP bit */
+  RCC->CR &= 0xFFFBFFFFU;
+
+  /* Disable all interrupts */
+  RCC->CIER = 0x00000000;
+}
+
+/**
+  * @brief  Update SystemCoreClock variable according to Clock Register Values.
+  *         The SystemCoreClock variable contains the core clock (HCLK), it can
+  *         be used by the user application to setup the SysTick timer or configure
+  *         other parameters.
+  *
+  * @note   Each time the core clock (HCLK) changes, this function must be called
+  *         to update SystemCoreClock variable value. Otherwise, any configuration
+  *         based on this variable will be incorrect.
+  *
+  * @note   - The system frequency computed by this function is not the real
+  *           frequency in the chip. It is calculated based on the predefined
+  *           constant and the selected clock source:
+  *
+  *           - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*)
+  *
+  *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**)
+  *
+  *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***)
+  *
+  *           - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***)
+  *             or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors.
+  *
+  *         (*) MSI_VALUE is a constant defined in stm32wbxx_hal.h file (default value
+  *             4 MHz) but the real value may vary depending on the variations
+  *             in voltage and temperature.
+  *
+  *         (**) HSI_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value
+  *              16 MHz) but the real value may vary depending on the variations
+  *              in voltage and temperature.
+  *
+  *         (***) HSE_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value
+  *              32 MHz), user has to ensure that HSE_VALUE is same as the real
+  *              frequency of the crystal used. Otherwise, this function may
+  *              have wrong result.
+  *
+  *         - The result of this function could be not correct when using fractional
+  *           value for HSE crystal.
+  *
+  * @param  None
+  * @retval None
+  */
+void SystemCoreClockUpdate(void)
+{
+  uint32_t tmp, msirange, pllvco, pllr, pllsource , pllm;
+
+  /* Get MSI Range frequency--------------------------------------------------*/
+
+  /*MSI frequency range in Hz*/
+  msirange = MSIRangeTable[(RCC->CR & RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos];
+
+  /* Get SYSCLK source -------------------------------------------------------*/
+  switch (RCC->CFGR & RCC_CFGR_SWS)
+  {
+    case 0x00:   /* MSI used as system clock source */
+      SystemCoreClock = msirange;
+      break;
+
+    case 0x04:  /* HSI used as system clock source */
+      /* HSI used as system clock source */
+        SystemCoreClock = HSI_VALUE;
+      break;
+
+    case 0x08:  /* HSE used as system clock source */
+      SystemCoreClock = HSE_VALUE;
+      break;
+
+    case 0x0C: /* PLL used as system clock  source */
+      /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN
+         SYSCLK = PLL_VCO / PLLR
+         */
+      pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC);
+      pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL ;
+
+      if(pllsource == 0x02UL) /* HSI used as PLL clock source */
+      {
+        pllvco = (HSI_VALUE / pllm);
+      }
+      else if(pllsource == 0x03UL) /* HSE used as PLL clock source */
+      {
+        pllvco = (HSE_VALUE / pllm);
+      }
+      else /* MSI used as PLL clock source */
+      {
+        pllvco = (msirange / pllm);
+      }
+      
+      pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos);
+      pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL);
+      
+      SystemCoreClock = pllvco/pllr;
+      break;
+
+    default:
+      SystemCoreClock = msirange;
+      break;
+  }
+  
+  /* Compute HCLK clock frequency --------------------------------------------*/
+  /* Get HCLK1 prescaler */
+  tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)];
+  /* HCLK clock frequency */
+  SystemCoreClock = SystemCoreClock / tmp;
+
+}
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 33 - 0
firmware/targets/f6/cube/Src/tim.c

@@ -31,11 +31,19 @@ TIM_HandleTypeDef htim16;
 /* TIM1 init function */
 void MX_TIM1_Init(void)
 {
+
+  /* USER CODE BEGIN TIM1_Init 0 */
+
+  /* USER CODE END TIM1_Init 0 */
+
   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
   TIM_MasterConfigTypeDef sMasterConfig = {0};
   TIM_OC_InitTypeDef sConfigOC = {0};
   TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
 
+  /* USER CODE BEGIN TIM1_Init 1 */
+
+  /* USER CODE END TIM1_Init 1 */
   htim1.Instance = TIM1;
   htim1.Init.Prescaler = 0;
   htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
@@ -100,16 +108,27 @@ void MX_TIM1_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN TIM1_Init 2 */
+
+  /* USER CODE END TIM1_Init 2 */
   HAL_TIM_MspPostInit(&htim1);
 
 }
 /* TIM2 init function */
 void MX_TIM2_Init(void)
 {
+
+  /* USER CODE BEGIN TIM2_Init 0 */
+
+  /* USER CODE END TIM2_Init 0 */
+
   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
   TIM_MasterConfigTypeDef sMasterConfig = {0};
   TIM_IC_InitTypeDef sConfigIC = {0};
 
+  /* USER CODE BEGIN TIM2_Init 1 */
+
+  /* USER CODE END TIM2_Init 1 */
   htim2.Instance = TIM2;
   htim2.Init.Prescaler = 64-1;
   htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
@@ -149,14 +168,25 @@ void MX_TIM2_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN TIM2_Init 2 */
+
+  /* USER CODE END TIM2_Init 2 */
 
 }
 /* TIM16 init function */
 void MX_TIM16_Init(void)
 {
+
+  /* USER CODE BEGIN TIM16_Init 0 */
+
+  /* USER CODE END TIM16_Init 0 */
+
   TIM_OC_InitTypeDef sConfigOC = {0};
   TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
 
+  /* USER CODE BEGIN TIM16_Init 1 */
+
+  /* USER CODE END TIM16_Init 1 */
   htim16.Instance = TIM16;
   htim16.Init.Prescaler = 500 - 1;
   htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
@@ -195,6 +225,9 @@ void MX_TIM16_Init(void)
   {
     Error_Handler();
   }
+  /* USER CODE BEGIN TIM16_Init 2 */
+
+  /* USER CODE END TIM16_Init 2 */
   HAL_TIM_MspPostInit(&htim16);
 
 }

+ 12 - 1
firmware/targets/f6/cube/Src/usart.c

@@ -28,6 +28,11 @@
 
 void MX_USART1_UART_Init(void)
 {
+
+  /* USER CODE BEGIN USART1_Init 0 */
+
+  /* USER CODE END USART1_Init 0 */
+
   LL_USART_InitTypeDef USART_InitStruct = {0};
 
   LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
@@ -48,6 +53,9 @@ void MX_USART1_UART_Init(void)
   GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
   LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
+  /* USER CODE BEGIN USART1_Init 1 */
+
+  /* USER CODE END USART1_Init 1 */
   USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
   USART_InitStruct.BaudRate = 115200;
   USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
@@ -71,9 +79,12 @@ void MX_USART1_UART_Init(void)
   LL_USART_Enable(USART1);
 
   /* Polling USART1 initialisation */
-  while((!(LL_USART_IsActiveFlag_TEACK(USART1))) || (!(LL_USART_IsActiveFlag_REACK(USART1))))
+  while(!(LL_USART_IsActiveFlag_TEACK(USART1)))
   {
   }
+  /* USER CODE BEGIN USART1_Init 2 */
+
+  /* USER CODE END USART1_Init 2 */
 
 }
 

+ 1 - 1
firmware/targets/f6/cube/Src/usbd_cdc_if.c

@@ -295,7 +295,7 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
 
 /**
   * @brief  CDC_TransmitCplt_FS
-  *         Data transmited callback
+  *         Data transmitted callback
   *
   *         @note
   *         This function is IN transfer complete callback used to inform user that

+ 3 - 3
firmware/targets/f6/cube/Src/usbd_conf.c

@@ -685,10 +685,10 @@ USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_a
 }
 
 /**
-  * @brief  Returns the last transfered packet size.
+  * @brief  Returns the last transferred packet size.
   * @param  pdev: Device handle
   * @param  ep_addr: Endpoint number
-  * @retval Recived Data Size
+  * @retval Received Data Size
   */
 uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
 {
@@ -779,7 +779,7 @@ static void SystemClockConfig_Resume(void)
 /* USER CODE END 5 */
 
 /**
-  * @brief  Retuns the USB status depending on the HAL status:
+  * @brief  Returns the USB status depending on the HAL status:
   * @param  hal_status: HAL status
   * @retval USB status
   */

+ 1 - 1
firmware/targets/f6/cube/Src/usbd_desc.c

@@ -182,7 +182,7 @@ __ALIGN_BEGIN uint8_t USBD_CDC_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
   #pragma data_alignment=4
 #endif /* defined ( __ICCARM__ ) */
 
-/** USB lang indentifier descriptor. */
+/** USB lang identifier descriptor. */
 __ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
 {
      USB_LEN_LANGID_STR_DESC,

+ 16 - 7
firmware/targets/f6/cube/f6.ioc

@@ -135,8 +135,8 @@ Mcu.PinsNb=69
 Mcu.ThirdPartyNb=0
 Mcu.UserConstants=
 Mcu.UserName=STM32WB55RGVx
-MxCube.Version=6.1.2
-MxDb.Version=DB.6.0.10
+MxCube.Version=6.3.0
+MxDb.Version=DB.6.0.30
 NVIC.ADC1_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
 NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
 NVIC.COMP_IRQn=true\:5\:0\:true\:false\:true\:false\:false\:true
@@ -178,8 +178,9 @@ PA1.GPIOParameters=GPIO_Label
 PA1.GPIO_Label=CC1101_G0
 PA1.Locked=true
 PA1.Signal=GPIO_Analog
-PA10.GPIOParameters=GPIO_Speed,GPIO_Label
+PA10.GPIOParameters=GPIO_Speed,GPIO_Label,GPIO_Pu
 PA10.GPIO_Label=I2C_SDA
+PA10.GPIO_Pu=GPIO_PULLUP
 PA10.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
 PA10.Locked=true
 PA10.Mode=I2C
@@ -233,8 +234,9 @@ PA8.GPIOParameters=GPIO_Label
 PA8.GPIO_Label=RFID_TUNE
 PA8.Locked=true
 PA8.Signal=GPIO_Output
-PA9.GPIOParameters=GPIO_Speed,GPIO_Label
+PA9.GPIOParameters=GPIO_Speed,GPIO_Label,GPIO_Pu
 PA9.GPIO_Label=I2C_SCL
+PA9.GPIO_Pu=GPIO_PULLUP
 PA9.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
 PA9.Locked=true
 PA9.Mode=I2C
@@ -371,8 +373,15 @@ PC6.Locked=true
 PC6.Signal=GPIO_Input
 PCC.Ble.ConnectionInterval=1000.0
 PCC.Ble.DataLength=6
+PCC.Ble.IsUsed=false
 PCC.Ble.Mode=NOT_SELECTED
 PCC.Ble.PowerLevel=Min
+PCC.Zigbee.IsUsed=false
+PCC.Zigbee.Mode=Sleepy End Device
+PCC.Zigbee.Payload=15
+PCC.Zigbee.PoolPeriodicity=480.0
+PCC.Zigbee.PowerLevel=Min
+PCC.Zigbee.RequestPeriodicity=1500.0
 PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
 PD0.GPIO_Label=CC1101_CS
 PD0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
@@ -401,11 +410,11 @@ ProjectManager.BackupPrevious=false
 ProjectManager.CompilerOptimize=6
 ProjectManager.ComputerToolchain=false
 ProjectManager.CoupleFile=true
-ProjectManager.CustomerFirmwarePackage=
-ProjectManager.DefaultFWLocation=true
+ProjectManager.CustomerFirmwarePackage=../../../../lib/STM32CubeWB
+ProjectManager.DefaultFWLocation=false
 ProjectManager.DeletePrevious=true
 ProjectManager.DeviceId=STM32WB55RGVx
-ProjectManager.FirmwarePackage=STM32Cube FW_WB V1.10.1
+ProjectManager.FirmwarePackage=STM32Cube FW_WB V1.12.1
 ProjectManager.FreePins=false
 ProjectManager.HalAssertFull=false
 ProjectManager.HeapSize=0x400

+ 444 - 445
firmware/targets/f6/cube/startup_stm32wb55xx_cm4.s

@@ -1,445 +1,444 @@
-/**
-  ******************************************************************************
-  * @file      startup_stm32wb55xx_cm4.s
-  * @author    MCD Application Team
-  * @brief     STM32WB55xx devices vector table GCC toolchain.
-  *            This module performs:
-  *                - Set the initial SP
-  *                - Set the initial PC == Reset_Handler,
-  *                - Set the vector table entries with the exceptions ISR address
-  *                - Branches to main in the C library (which eventually
-  *                  calls main()).
-  *            After Reset the Cortex-M4 processor is in Thread mode,
-  *            priority is Privileged, and the Stack is set to Main.
-  ******************************************************************************
-  * @attention
-  *
-  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics. 
-  * All rights reserved.</center></h2>
-  *
-  * This software component is licensed by ST under BSD 3-Clause license,
-  * the "License"; You may not use this file except in compliance with the 
-  * License. You may obtain a copy of the License at:
-  *                        opensource.org/licenses/BSD-3-Clause
-  *
-  ******************************************************************************
-  */
-
-  .syntax unified
-	.cpu cortex-m4
-	.fpu softvfp
-	.thumb
-
-.global	g_pfnVectors
-.global	Default_Handler
-
-/* start address for the initialization values of the .data section.
-defined in linker script */
-.word	_sidata
-/* start address for the .data section. defined in linker script */
-.word	_sdata
-/* end address for the .data section. defined in linker script */
-.word	_edata
-/* start address for the .bss section. defined in linker script */
-.word	_sbss
-/* end address for the .bss section. defined in linker script */
-.word	_ebss
-/* start address for the .MB_MEM2 section. defined in linker script */
-.word _sMB_MEM2
-/* end address for the .MB_MEM2 section. defined in linker script */
-.word _eMB_MEM2
-
-/* INIT_BSS macro is used to fill the specified region [start : end] with zeros */
-.macro INIT_BSS start, end
-  ldr r0, =\start
-  ldr r1, =\end
-  movs r3, #0
-  bl LoopFillZerobss
-.endm
-
-/* INIT_DATA macro is used to copy data in the region [start : end] starting from 'src' */
-.macro INIT_DATA start, end, src
-  ldr r0, =\start
-  ldr r1, =\end
-  ldr r2, =\src
-  movs r3, #0
-  bl LoopCopyDataInit
-.endm
-
-.section  .text.data_initializers
-CopyDataInit:
-  ldr r4, [r2, r3]
-  str r4, [r0, r3]
-  adds r3, r3, #4
-
-LoopCopyDataInit:
-  adds r4, r0, r3
-  cmp r4, r1
-  bcc  CopyDataInit
-  bx lr
-
-FillZerobss:
-  str  r3, [r0]
-  adds r0, r0, #4
-
-LoopFillZerobss:
-  cmp r0, r1
-  bcc FillZerobss
-  bx lr
-
-  .section .text.Reset_Handler
-  .weak Reset_Handler
-  .type Reset_Handler, %function
-Reset_Handler:
-  ldr   r0, =_estack
-  mov   sp, r0          /* set stack pointer */
-/* Call the clock system intitialization function.*/
-  bl  SystemInit
-
-/* Copy the data segment initializers from flash to SRAM */
-  INIT_DATA _sdata, _edata, _sidata
-
-/* Zero fill the bss segments. */
-  INIT_BSS _sbss, _ebss
-  INIT_BSS _sMB_MEM2, _eMB_MEM2
-
-/* Call static constructors */
-  bl __libc_init_array
-/* Call the application s entry point.*/
-	bl	main
-
-LoopForever:
-  b LoopForever
-    
-.size	Reset_Handler, .-Reset_Handler
-
-/**
- * @brief  This is the code that gets called when the processor receives an
- *         unexpected interrupt.  This simply enters an infinite loop, preserving
- *         the system state for examination by a debugger.
- *
- * @param  None
- * @retval None
-*/
-  .section .text.Default_Handler,"ax",%progbits
-Default_Handler:
-Infinite_Loop:
-	b	Infinite_Loop
-	.size	Default_Handler, .-Default_Handler
-/******************************************************************************
-*
-* The minimal vector table for a Cortex-M4.  Note that the proper constructs
-* must be placed on this to ensure that it ends up at physical address
-* 0x0000.0000.
-*
-******************************************************************************/
- 	.section	.isr_vector,"a",%progbits
-	.type	g_pfnVectors, %object
-	.size	g_pfnVectors, .-g_pfnVectors
-
-
-g_pfnVectors:
-  .word _estack
-  .word Reset_Handler
-	.word	NMI_Handler
-  .word HardFault_Handler
-  .word MemManage_Handler
-  .word BusFault_Handler
-  .word UsageFault_Handler
-  .word 0
-  .word 0
-  .word 0
-  .word 0
-  .word SVC_Handler
-  .word DebugMon_Handler
-  .word 0
-  .word PendSV_Handler
-  .word SysTick_Handler
-  .word WWDG_IRQHandler
-  .word PVD_PVM_IRQHandler
-  .word TAMP_STAMP_LSECSS_IRQHandler
-  .word RTC_WKUP_IRQHandler
-  .word FLASH_IRQHandler
-  .word RCC_IRQHandler
-  .word EXTI0_IRQHandler
-  .word EXTI1_IRQHandler
-  .word EXTI2_IRQHandler
-  .word EXTI3_IRQHandler
-  .word EXTI4_IRQHandler
-  .word DMA1_Channel1_IRQHandler
-  .word DMA1_Channel2_IRQHandler
-  .word DMA1_Channel3_IRQHandler
-  .word DMA1_Channel4_IRQHandler
-  .word DMA1_Channel5_IRQHandler
-  .word DMA1_Channel6_IRQHandler
-  .word DMA1_Channel7_IRQHandler
-  .word ADC1_IRQHandler
-  .word USB_HP_IRQHandler
-  .word USB_LP_IRQHandler
-  .word C2SEV_PWR_C2H_IRQHandler
-  .word COMP_IRQHandler
-  .word EXTI9_5_IRQHandler
-  .word TIM1_BRK_IRQHandler
-  .word TIM1_UP_TIM16_IRQHandler
-  .word TIM1_TRG_COM_TIM17_IRQHandler
-  .word TIM1_CC_IRQHandler
-  .word TIM2_IRQHandler
-  .word PKA_IRQHandler
-  .word I2C1_EV_IRQHandler
-  .word I2C1_ER_IRQHandler
-  .word I2C3_EV_IRQHandler
-  .word I2C3_ER_IRQHandler
-  .word SPI1_IRQHandler
-  .word SPI2_IRQHandler
-  .word USART1_IRQHandler
-  .word LPUART1_IRQHandler
-  .word SAI1_IRQHandler
-  .word TSC_IRQHandler
-  .word EXTI15_10_IRQHandler
-  .word RTC_Alarm_IRQHandler
-  .word CRS_IRQHandler
-  .word PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler
-  .word IPCC_C1_RX_IRQHandler
-  .word IPCC_C1_TX_IRQHandler
-  .word HSEM_IRQHandler
-  .word LPTIM1_IRQHandler
-  .word LPTIM2_IRQHandler
-  .word LCD_IRQHandler
-  .word QUADSPI_IRQHandler
-  .word AES1_IRQHandler
-  .word AES2_IRQHandler
-  .word RNG_IRQHandler
-  .word FPU_IRQHandler
-  .word DMA2_Channel1_IRQHandler
-  .word DMA2_Channel2_IRQHandler
-  .word DMA2_Channel3_IRQHandler
-  .word DMA2_Channel4_IRQHandler
-  .word DMA2_Channel5_IRQHandler
-  .word DMA2_Channel6_IRQHandler
-  .word DMA2_Channel7_IRQHandler
-  .word DMAMUX1_OVR_IRQHandler
-
-/*******************************************************************************
-*
-* Provide weak aliases for each Exception handler to the Default_Handler.
-* As they are weak aliases, any function with the same name will override
-* this definition.
-*
-*******************************************************************************/
-  .weak	NMI_Handler
-  .thumb_set NMI_Handler,Default_Handler
-  
-  .weak  HardFault_Handler
-  .thumb_set HardFault_Handler,Default_Handler
-
-  .weak  MemManage_Handler
-  .thumb_set MemManage_Handler,Default_Handler
-
-  .weak  BusFault_Handler
-  .thumb_set BusFault_Handler,Default_Handler
-
-  .weak  UsageFault_Handler
-  .thumb_set UsageFault_Handler,Default_Handler
-
-  .weak  SVC_Handler
-  .thumb_set SVC_Handler,Default_Handler
-
-  .weak  DebugMon_Handler
-  .thumb_set DebugMon_Handler,Default_Handler
-
-  .weak  PendSV_Handler
-  .thumb_set PendSV_Handler,Default_Handler
-
-  .weak  SysTick_Handler
-  .thumb_set SysTick_Handler,Default_Handler
-
-  .weak  WWDG_IRQHandler
-  .thumb_set WWDG_IRQHandler,Default_Handler
-
-  .weak  PVD_PVM_IRQHandler
-  .thumb_set PVD_PVM_IRQHandler,Default_Handler
-
-  .weak  TAMP_STAMP_LSECSS_IRQHandler
-  .thumb_set TAMP_STAMP_LSECSS_IRQHandler,Default_Handler
-
-  .weak  RTC_WKUP_IRQHandler
-  .thumb_set RTC_WKUP_IRQHandler,Default_Handler
-
-  .weak  FLASH_IRQHandler
-  .thumb_set FLASH_IRQHandler,Default_Handler
-
-  .weak  RCC_IRQHandler
-  .thumb_set RCC_IRQHandler,Default_Handler
-
-  .weak  EXTI0_IRQHandler
-  .thumb_set EXTI0_IRQHandler,Default_Handler
-
-  .weak  EXTI1_IRQHandler
-  .thumb_set EXTI1_IRQHandler,Default_Handler
-
-  .weak  EXTI2_IRQHandler
-  .thumb_set EXTI2_IRQHandler,Default_Handler
-
-  .weak  EXTI3_IRQHandler
-  .thumb_set EXTI3_IRQHandler,Default_Handler
-
-  .weak  EXTI4_IRQHandler
-  .thumb_set EXTI4_IRQHandler,Default_Handler
-
-  .weak  DMA1_Channel1_IRQHandler
-  .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
-
-  .weak  DMA1_Channel2_IRQHandler
-  .thumb_set DMA1_Channel2_IRQHandler,Default_Handler
-
-  .weak  DMA1_Channel3_IRQHandler
-  .thumb_set DMA1_Channel3_IRQHandler,Default_Handler
-
-  .weak  DMA1_Channel4_IRQHandler
-  .thumb_set DMA1_Channel4_IRQHandler,Default_Handler
-
-  .weak  DMA1_Channel5_IRQHandler
-  .thumb_set DMA1_Channel5_IRQHandler,Default_Handler
-
-  .weak  DMA1_Channel6_IRQHandler
-  .thumb_set DMA1_Channel6_IRQHandler,Default_Handler
-
-  .weak  DMA1_Channel7_IRQHandler
-  .thumb_set DMA1_Channel7_IRQHandler,Default_Handler
-
-  .weak  ADC1_IRQHandler
-  .thumb_set ADC1_IRQHandler,Default_Handler
-
-  .weak  USB_HP_IRQHandler
-  .thumb_set USB_HP_IRQHandler,Default_Handler
-
-  .weak  USB_LP_IRQHandler
-  .thumb_set USB_LP_IRQHandler,Default_Handler
-
-  .weak  C2SEV_PWR_C2H_IRQHandler
-  .thumb_set C2SEV_PWR_C2H_IRQHandler,Default_Handler
-
-  .weak  COMP_IRQHandler
-  .thumb_set COMP_IRQHandler,Default_Handler
-
-  .weak  EXTI9_5_IRQHandler
-  .thumb_set EXTI9_5_IRQHandler,Default_Handler
-
-  .weak  TIM1_BRK_IRQHandler
-  .thumb_set TIM1_BRK_IRQHandler,Default_Handler
-
-  .weak  TIM1_UP_TIM16_IRQHandler
-  .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler
-
-  .weak  TIM1_TRG_COM_TIM17_IRQHandler
-  .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler
-
-  .weak  TIM1_CC_IRQHandler
-  .thumb_set TIM1_CC_IRQHandler,Default_Handler
-
-  .weak  TIM2_IRQHandler
-  .thumb_set TIM2_IRQHandler,Default_Handler
-
-  .weak  PKA_IRQHandler
-  .thumb_set PKA_IRQHandler,Default_Handler
-
-  .weak  I2C1_EV_IRQHandler
-  .thumb_set I2C1_EV_IRQHandler,Default_Handler
-
-  .weak  I2C1_ER_IRQHandler
-  .thumb_set I2C1_ER_IRQHandler,Default_Handler
-
-  .weak  I2C3_EV_IRQHandler
-  .thumb_set I2C3_EV_IRQHandler,Default_Handler
-
-  .weak  I2C3_ER_IRQHandler
-  .thumb_set I2C3_ER_IRQHandler,Default_Handler
-
-  .weak  SPI1_IRQHandler
-  .thumb_set SPI1_IRQHandler,Default_Handler
-
-  .weak  SPI2_IRQHandler
-  .thumb_set SPI2_IRQHandler,Default_Handler
-
-  .weak  USART1_IRQHandler
-  .thumb_set USART1_IRQHandler,Default_Handler
-
-  .weak  LPUART1_IRQHandler
-  .thumb_set LPUART1_IRQHandler,Default_Handler
-
-  .weak  SAI1_IRQHandler
-  .thumb_set SAI1_IRQHandler,Default_Handler
-
-  .weak  TSC_IRQHandler
-  .thumb_set TSC_IRQHandler,Default_Handler
-
-  .weak  EXTI15_10_IRQHandler
-  .thumb_set EXTI15_10_IRQHandler,Default_Handler
-
-  .weak  RTC_Alarm_IRQHandler
-  .thumb_set RTC_Alarm_IRQHandler,Default_Handler
-
-  .weak  CRS_IRQHandler
-  .thumb_set CRS_IRQHandler,Default_Handler
-
-  .weak  PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler
-  .thumb_set PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler,Default_Handler
-
-  .weak  IPCC_C1_RX_IRQHandler
-  .thumb_set IPCC_C1_RX_IRQHandler,Default_Handler
-
-  .weak  IPCC_C1_TX_IRQHandler
-  .thumb_set IPCC_C1_TX_IRQHandler,Default_Handler
-
-  .weak  HSEM_IRQHandler
-  .thumb_set HSEM_IRQHandler,Default_Handler
-
-  .weak  LPTIM1_IRQHandler
-  .thumb_set LPTIM1_IRQHandler,Default_Handler
-
-  .weak  LPTIM2_IRQHandler
-  .thumb_set LPTIM2_IRQHandler,Default_Handler
-
-  .weak  LCD_IRQHandler
-  .thumb_set LCD_IRQHandler,Default_Handler
-
-  .weak  QUADSPI_IRQHandler
-  .thumb_set QUADSPI_IRQHandler,Default_Handler
-
-  .weak  AES1_IRQHandler
-  .thumb_set AES1_IRQHandler,Default_Handler
-
-  .weak  AES2_IRQHandler
-  .thumb_set AES2_IRQHandler,Default_Handler
-
-  .weak  RNG_IRQHandler
-  .thumb_set RNG_IRQHandler,Default_Handler
-
-  .weak  FPU_IRQHandler
-  .thumb_set FPU_IRQHandler,Default_Handler
-
-  .weak  DMA2_Channel1_IRQHandler
-  .thumb_set DMA2_Channel1_IRQHandler,Default_Handler
-
-  .weak  DMA2_Channel2_IRQHandler
-  .thumb_set DMA2_Channel2_IRQHandler,Default_Handler
-
-  .weak  DMA2_Channel3_IRQHandler
-  .thumb_set DMA2_Channel3_IRQHandler,Default_Handler
-
-  .weak  DMA2_Channel4_IRQHandler
-  .thumb_set DMA2_Channel4_IRQHandler,Default_Handler
-
-  .weak  DMA2_Channel5_IRQHandler
-  .thumb_set DMA2_Channel5_IRQHandler,Default_Handler
-
-  .weak  DMA2_Channel6_IRQHandler
-  .thumb_set DMA2_Channel6_IRQHandler,Default_Handler
-
-  .weak  DMA2_Channel7_IRQHandler
-  .thumb_set DMA2_Channel7_IRQHandler,Default_Handler
-
-  .weak  DMAMUX1_OVR_IRQHandler
-  .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler
-
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+/**
+  ******************************************************************************
+  * @file      startup_stm32wb55xx_cm4.s
+  * @author    MCD Application Team
+  * @brief     STM32WB55xx devices vector table GCC toolchain.
+  *            This module performs:
+  *                - Set the initial SP
+  *                - Set the initial PC == Reset_Handler,
+  *                - Set the vector table entries with the exceptions ISR address
+  *                - Branches to main in the C library (which eventually
+  *                  calls main()).
+  *            After Reset the Cortex-M4 processor is in Thread mode,
+  *            priority is Privileged, and the Stack is set to Main.
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2019-2021 STMicroelectronics.
+  * All rights reserved.
+  *
+  * This software is licensed under terms that can be found in the LICENSE file
+  * in the root directory of this software component.
+  * If no LICENSE file comes with this software, it is provided AS-IS.
+  *
+  ******************************************************************************
+  */
+
+  .syntax unified
+	.cpu cortex-m4
+	.fpu softvfp
+	.thumb
+
+.global	g_pfnVectors
+.global	Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word	_sidata
+/* start address for the .data section. defined in linker script */
+.word	_sdata
+/* end address for the .data section. defined in linker script */
+.word	_edata
+/* start address for the .bss section. defined in linker script */
+.word	_sbss
+/* end address for the .bss section. defined in linker script */
+.word	_ebss
+/* start address for the .MB_MEM2 section. defined in linker script */
+.word _sMB_MEM2
+/* end address for the .MB_MEM2 section. defined in linker script */
+.word _eMB_MEM2
+
+/* INIT_BSS macro is used to fill the specified region [start : end] with zeros */
+.macro INIT_BSS start, end
+  ldr r0, =\start
+  ldr r1, =\end
+  movs r3, #0
+  bl LoopFillZerobss
+.endm
+
+/* INIT_DATA macro is used to copy data in the region [start : end] starting from 'src' */
+.macro INIT_DATA start, end, src
+  ldr r0, =\start
+  ldr r1, =\end
+  ldr r2, =\src
+  movs r3, #0
+  bl LoopCopyDataInit
+.endm
+
+.section  .text.data_initializers
+CopyDataInit:
+  ldr r4, [r2, r3]
+  str r4, [r0, r3]
+  adds r3, r3, #4
+
+LoopCopyDataInit:
+  adds r4, r0, r3
+  cmp r4, r1
+  bcc  CopyDataInit
+  bx lr
+
+FillZerobss:
+  str  r3, [r0]
+  adds r0, r0, #4
+
+LoopFillZerobss:
+  cmp r0, r1
+  bcc FillZerobss
+  bx lr
+
+  .section .text.Reset_Handler
+  .weak Reset_Handler
+  .type Reset_Handler, %function
+Reset_Handler:
+  ldr   r0, =_estack
+  mov   sp, r0          /* set stack pointer */
+/* Call the clock system intitialization function.*/
+  bl  SystemInit
+
+/* Copy the data segment initializers from flash to SRAM */
+  INIT_DATA _sdata, _edata, _sidata
+
+/* Zero fill the bss segments. */
+  INIT_BSS _sbss, _ebss
+  INIT_BSS _sMB_MEM2, _eMB_MEM2
+
+/* Call static constructors */
+  bl __libc_init_array
+/* Call the application s entry point.*/
+	bl	main
+
+LoopForever:
+  b LoopForever
+    
+.size	Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief  This is the code that gets called when the processor receives an
+ *         unexpected interrupt.  This simply enters an infinite loop, preserving
+ *         the system state for examination by a debugger.
+ *
+ * @param  None
+ * @retval None
+*/
+  .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+	b	Infinite_Loop
+	.size	Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex-M4.  Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+******************************************************************************/
+ 	.section	.isr_vector,"a",%progbits
+	.type	g_pfnVectors, %object
+	.size	g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+  .word _estack
+  .word Reset_Handler
+	.word	NMI_Handler
+  .word HardFault_Handler
+  .word MemManage_Handler
+  .word BusFault_Handler
+  .word UsageFault_Handler
+  .word 0
+  .word 0
+  .word 0
+  .word 0
+  .word SVC_Handler
+  .word DebugMon_Handler
+  .word 0
+  .word PendSV_Handler
+  .word SysTick_Handler
+  .word WWDG_IRQHandler
+  .word PVD_PVM_IRQHandler
+  .word TAMP_STAMP_LSECSS_IRQHandler
+  .word RTC_WKUP_IRQHandler
+  .word FLASH_IRQHandler
+  .word RCC_IRQHandler
+  .word EXTI0_IRQHandler
+  .word EXTI1_IRQHandler
+  .word EXTI2_IRQHandler
+  .word EXTI3_IRQHandler
+  .word EXTI4_IRQHandler
+  .word DMA1_Channel1_IRQHandler
+  .word DMA1_Channel2_IRQHandler
+  .word DMA1_Channel3_IRQHandler
+  .word DMA1_Channel4_IRQHandler
+  .word DMA1_Channel5_IRQHandler
+  .word DMA1_Channel6_IRQHandler
+  .word DMA1_Channel7_IRQHandler
+  .word ADC1_IRQHandler
+  .word USB_HP_IRQHandler
+  .word USB_LP_IRQHandler
+  .word C2SEV_PWR_C2H_IRQHandler
+  .word COMP_IRQHandler
+  .word EXTI9_5_IRQHandler
+  .word TIM1_BRK_IRQHandler
+  .word TIM1_UP_TIM16_IRQHandler
+  .word TIM1_TRG_COM_TIM17_IRQHandler
+  .word TIM1_CC_IRQHandler
+  .word TIM2_IRQHandler
+  .word PKA_IRQHandler
+  .word I2C1_EV_IRQHandler
+  .word I2C1_ER_IRQHandler
+  .word I2C3_EV_IRQHandler
+  .word I2C3_ER_IRQHandler
+  .word SPI1_IRQHandler
+  .word SPI2_IRQHandler
+  .word USART1_IRQHandler
+  .word LPUART1_IRQHandler
+  .word SAI1_IRQHandler
+  .word TSC_IRQHandler
+  .word EXTI15_10_IRQHandler
+  .word RTC_Alarm_IRQHandler
+  .word CRS_IRQHandler
+  .word PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler
+  .word IPCC_C1_RX_IRQHandler
+  .word IPCC_C1_TX_IRQHandler
+  .word HSEM_IRQHandler
+  .word LPTIM1_IRQHandler
+  .word LPTIM2_IRQHandler
+  .word LCD_IRQHandler
+  .word QUADSPI_IRQHandler
+  .word AES1_IRQHandler
+  .word AES2_IRQHandler
+  .word RNG_IRQHandler
+  .word FPU_IRQHandler
+  .word DMA2_Channel1_IRQHandler
+  .word DMA2_Channel2_IRQHandler
+  .word DMA2_Channel3_IRQHandler
+  .word DMA2_Channel4_IRQHandler
+  .word DMA2_Channel5_IRQHandler
+  .word DMA2_Channel6_IRQHandler
+  .word DMA2_Channel7_IRQHandler
+  .word DMAMUX1_OVR_IRQHandler
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+  .weak	NMI_Handler
+  .thumb_set NMI_Handler,Default_Handler
+  
+  .weak  HardFault_Handler
+  .thumb_set HardFault_Handler,Default_Handler
+
+  .weak  MemManage_Handler
+  .thumb_set MemManage_Handler,Default_Handler
+
+  .weak  BusFault_Handler
+  .thumb_set BusFault_Handler,Default_Handler
+
+  .weak  UsageFault_Handler
+  .thumb_set UsageFault_Handler,Default_Handler
+
+  .weak  SVC_Handler
+  .thumb_set SVC_Handler,Default_Handler
+
+  .weak  DebugMon_Handler
+  .thumb_set DebugMon_Handler,Default_Handler
+
+  .weak  PendSV_Handler
+  .thumb_set PendSV_Handler,Default_Handler
+
+  .weak  SysTick_Handler
+  .thumb_set SysTick_Handler,Default_Handler
+
+  .weak  WWDG_IRQHandler
+  .thumb_set WWDG_IRQHandler,Default_Handler
+
+  .weak  PVD_PVM_IRQHandler
+  .thumb_set PVD_PVM_IRQHandler,Default_Handler
+
+  .weak  TAMP_STAMP_LSECSS_IRQHandler
+  .thumb_set TAMP_STAMP_LSECSS_IRQHandler,Default_Handler
+
+  .weak  RTC_WKUP_IRQHandler
+  .thumb_set RTC_WKUP_IRQHandler,Default_Handler
+
+  .weak  FLASH_IRQHandler
+  .thumb_set FLASH_IRQHandler,Default_Handler
+
+  .weak  RCC_IRQHandler
+  .thumb_set RCC_IRQHandler,Default_Handler
+
+  .weak  EXTI0_IRQHandler
+  .thumb_set EXTI0_IRQHandler,Default_Handler
+
+  .weak  EXTI1_IRQHandler
+  .thumb_set EXTI1_IRQHandler,Default_Handler
+
+  .weak  EXTI2_IRQHandler
+  .thumb_set EXTI2_IRQHandler,Default_Handler
+
+  .weak  EXTI3_IRQHandler
+  .thumb_set EXTI3_IRQHandler,Default_Handler
+
+  .weak  EXTI4_IRQHandler
+  .thumb_set EXTI4_IRQHandler,Default_Handler
+
+  .weak  DMA1_Channel1_IRQHandler
+  .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
+
+  .weak  DMA1_Channel2_IRQHandler
+  .thumb_set DMA1_Channel2_IRQHandler,Default_Handler
+
+  .weak  DMA1_Channel3_IRQHandler
+  .thumb_set DMA1_Channel3_IRQHandler,Default_Handler
+
+  .weak  DMA1_Channel4_IRQHandler
+  .thumb_set DMA1_Channel4_IRQHandler,Default_Handler
+
+  .weak  DMA1_Channel5_IRQHandler
+  .thumb_set DMA1_Channel5_IRQHandler,Default_Handler
+
+  .weak  DMA1_Channel6_IRQHandler
+  .thumb_set DMA1_Channel6_IRQHandler,Default_Handler
+
+  .weak  DMA1_Channel7_IRQHandler
+  .thumb_set DMA1_Channel7_IRQHandler,Default_Handler
+
+  .weak  ADC1_IRQHandler
+  .thumb_set ADC1_IRQHandler,Default_Handler
+
+  .weak  USB_HP_IRQHandler
+  .thumb_set USB_HP_IRQHandler,Default_Handler
+
+  .weak  USB_LP_IRQHandler
+  .thumb_set USB_LP_IRQHandler,Default_Handler
+
+  .weak  C2SEV_PWR_C2H_IRQHandler
+  .thumb_set C2SEV_PWR_C2H_IRQHandler,Default_Handler
+
+  .weak  COMP_IRQHandler
+  .thumb_set COMP_IRQHandler,Default_Handler
+
+  .weak  EXTI9_5_IRQHandler
+  .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+  .weak  TIM1_BRK_IRQHandler
+  .thumb_set TIM1_BRK_IRQHandler,Default_Handler
+
+  .weak  TIM1_UP_TIM16_IRQHandler
+  .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler
+
+  .weak  TIM1_TRG_COM_TIM17_IRQHandler
+  .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler
+
+  .weak  TIM1_CC_IRQHandler
+  .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+  .weak  TIM2_IRQHandler
+  .thumb_set TIM2_IRQHandler,Default_Handler
+
+  .weak  PKA_IRQHandler
+  .thumb_set PKA_IRQHandler,Default_Handler
+
+  .weak  I2C1_EV_IRQHandler
+  .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+  .weak  I2C1_ER_IRQHandler
+  .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+  .weak  I2C3_EV_IRQHandler
+  .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+  .weak  I2C3_ER_IRQHandler
+  .thumb_set I2C3_ER_IRQHandler,Default_Handler
+
+  .weak  SPI1_IRQHandler
+  .thumb_set SPI1_IRQHandler,Default_Handler
+
+  .weak  SPI2_IRQHandler
+  .thumb_set SPI2_IRQHandler,Default_Handler
+
+  .weak  USART1_IRQHandler
+  .thumb_set USART1_IRQHandler,Default_Handler
+
+  .weak  LPUART1_IRQHandler
+  .thumb_set LPUART1_IRQHandler,Default_Handler
+
+  .weak  SAI1_IRQHandler
+  .thumb_set SAI1_IRQHandler,Default_Handler
+
+  .weak  TSC_IRQHandler
+  .thumb_set TSC_IRQHandler,Default_Handler
+
+  .weak  EXTI15_10_IRQHandler
+  .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+  .weak  RTC_Alarm_IRQHandler
+  .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+  .weak  CRS_IRQHandler
+  .thumb_set CRS_IRQHandler,Default_Handler
+
+  .weak  PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler
+  .thumb_set PWR_SOTF_BLEACT_802ACT_RFPHASE_IRQHandler,Default_Handler
+
+  .weak  IPCC_C1_RX_IRQHandler
+  .thumb_set IPCC_C1_RX_IRQHandler,Default_Handler
+
+  .weak  IPCC_C1_TX_IRQHandler
+  .thumb_set IPCC_C1_TX_IRQHandler,Default_Handler
+
+  .weak  HSEM_IRQHandler
+  .thumb_set HSEM_IRQHandler,Default_Handler
+
+  .weak  LPTIM1_IRQHandler
+  .thumb_set LPTIM1_IRQHandler,Default_Handler
+
+  .weak  LPTIM2_IRQHandler
+  .thumb_set LPTIM2_IRQHandler,Default_Handler
+
+  .weak  LCD_IRQHandler
+  .thumb_set LCD_IRQHandler,Default_Handler
+
+  .weak  QUADSPI_IRQHandler
+  .thumb_set QUADSPI_IRQHandler,Default_Handler
+
+  .weak  AES1_IRQHandler
+  .thumb_set AES1_IRQHandler,Default_Handler
+
+  .weak  AES2_IRQHandler
+  .thumb_set AES2_IRQHandler,Default_Handler
+
+  .weak  RNG_IRQHandler
+  .thumb_set RNG_IRQHandler,Default_Handler
+
+  .weak  FPU_IRQHandler
+  .thumb_set FPU_IRQHandler,Default_Handler
+
+  .weak  DMA2_Channel1_IRQHandler
+  .thumb_set DMA2_Channel1_IRQHandler,Default_Handler
+
+  .weak  DMA2_Channel2_IRQHandler
+  .thumb_set DMA2_Channel2_IRQHandler,Default_Handler
+
+  .weak  DMA2_Channel3_IRQHandler
+  .thumb_set DMA2_Channel3_IRQHandler,Default_Handler
+
+  .weak  DMA2_Channel4_IRQHandler
+  .thumb_set DMA2_Channel4_IRQHandler,Default_Handler
+
+  .weak  DMA2_Channel5_IRQHandler
+  .thumb_set DMA2_Channel5_IRQHandler,Default_Handler
+
+  .weak  DMA2_Channel6_IRQHandler
+  .thumb_set DMA2_Channel6_IRQHandler,Default_Handler
+
+  .weak  DMA2_Channel7_IRQHandler
+  .thumb_set DMA2_Channel7_IRQHandler,Default_Handler
+
+  .weak  DMAMUX1_OVR_IRQHandler
+  .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 1 - 1
firmware/targets/f6/cube/stm32wb55xx_flash_cm4.ld

@@ -56,7 +56,7 @@ _Min_Stack_Size = 0x1000; /* required amount of stack */
 MEMORY
 {
 FLASH (rx)                 : ORIGIN = 0x08000000, LENGTH = 512K
-RAM1 (xrw)                 : ORIGIN = 0x20000004, LENGTH = 0x2FFFC
+RAM1 (xrw)                 : ORIGIN = 0x20000008, LENGTH = 0x2FFF8
 RAM_SHARED (xrw)           : ORIGIN = 0x20030000, LENGTH = 10K
 }
 

+ 1 - 0
firmware/targets/f6/furi-hal/furi-hal-clock.c

@@ -88,6 +88,7 @@ void furi_hal_clock_init() {
     LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
     LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48);
     LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1);
+    LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1);
     LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSE);
     LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1);
     LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE);

+ 4 - 0
firmware/targets/f6/furi-hal/furi-hal-rfid.c

@@ -9,6 +9,10 @@
 #define LFRFID_EMULATE_TIM htim2
 #define LFRFID_EMULATE_CHANNEL TIM_CHANNEL_3
 
+void furi_hal_rfid_init() {
+    furi_hal_rfid_pins_reset();
+}
+
 void furi_hal_rfid_pins_reset() {
     // ibutton bus disable
     furi_hal_ibutton_stop();

+ 1 - 0
firmware/targets/f6/furi-hal/furi-hal.c

@@ -58,6 +58,7 @@ void furi_hal_init() {
     furi_hal_vibro_init();
     furi_hal_subghz_init();
     furi_hal_nfc_init();
+    furi_hal_rfid_init();
 
     // FreeRTOS glue
     furi_hal_os_init();

+ 1 - 1
firmware/targets/f6/stm32wb55xx_flash_cm4_boot.ld

@@ -56,7 +56,7 @@ _Min_Stack_Size = 0x1000; /* required amount of stack */
 MEMORY
 {
 FLASH (rx)                 : ORIGIN = 0x08008000, LENGTH = 992K
-RAM1 (xrw)                 : ORIGIN = 0x20000004, LENGTH = 0x2FFFC
+RAM1 (xrw)                 : ORIGIN = 0x20000008, LENGTH = 0x2FFF8
 RAM_SHARED (xrw)           : ORIGIN = 0x20030000, LENGTH = 10K
 }
 

+ 1 - 1
firmware/targets/f6/stm32wb55xx_flash_cm4_no_boot.ld

@@ -56,7 +56,7 @@ _Min_Stack_Size = 0x1000; /* required amount of stack */
 MEMORY
 {
 FLASH (rx)                 : ORIGIN = 0x08000000, LENGTH = 1024K
-RAM1 (xrw)                 : ORIGIN = 0x20000004, LENGTH = 0x2FFFC
+RAM1 (xrw)                 : ORIGIN = 0x20000008, LENGTH = 0x2FFF8
 RAM_SHARED (xrw)           : ORIGIN = 0x20030000, LENGTH = 10K
 }
 

+ 180 - 0
firmware/targets/f7/Inc/FreeRTOSConfig.h

@@ -0,0 +1,180 @@
+/* USER CODE BEGIN Header */
+/*
+ * FreeRTOS Kernel V10.2.1
+ * Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ * Portion Copyright (C) 2019 StMicroelectronics, Inc.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+/* USER CODE END Header */
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * These parameters and more are described within the 'configuration' section of the
+ * FreeRTOS API documentation available on the FreeRTOS.org web site.
+ *
+ * See http://www.freertos.org/a00110.html
+ *----------------------------------------------------------*/
+
+/* USER CODE BEGIN Includes */
+/* Section where include file can be added */
+/* USER CODE END Includes */
+
+/* Ensure definitions are only used by the compiler, and not by the assembler. */
+#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
+  #include <stdint.h>
+  extern uint32_t SystemCoreClock;
+#endif
+#ifndef CMSIS_device_header
+#define CMSIS_device_header "stm32wbxx.h"
+#endif /* CMSIS_device_header */
+
+#define configENABLE_FPU                         1
+#define configENABLE_MPU                         1
+
+#define configUSE_PREEMPTION                     1
+#define configSUPPORT_STATIC_ALLOCATION          0
+#define configSUPPORT_DYNAMIC_ALLOCATION         1
+#define configUSE_IDLE_HOOK                      0
+#define configUSE_TICK_HOOK                      0
+#define configCPU_CLOCK_HZ                       ( SystemCoreClock )
+#define configTICK_RATE_HZ                       ((TickType_t)1024)
+#define configMAX_PRIORITIES                     ( 56 )
+#define configMINIMAL_STACK_SIZE                 ((uint16_t)128)
+/* Heap size determined automatically by linker */
+// #define configTOTAL_HEAP_SIZE                    ((size_t)0)
+#define configMAX_TASK_NAME_LEN                  ( 16 )
+#define configGENERATE_RUN_TIME_STATS            0
+#define configUSE_TRACE_FACILITY                 1
+#define configUSE_16_BIT_TICKS                   0
+#define configUSE_MUTEXES                        1
+#define configQUEUE_REGISTRY_SIZE                8
+#define configCHECK_FOR_STACK_OVERFLOW           1
+#define configUSE_RECURSIVE_MUTEXES              1
+#define configUSE_COUNTING_SEMAPHORES            1
+#define configENABLE_BACKWARD_COMPATIBILITY      0
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION  0
+#define configUSE_TICKLESS_IDLE                  2
+#define configRECORD_STACK_HIGH_ADDRESS          1
+#define configUSE_NEWLIB_REENTRANT               0
+/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
+/* Defaults to size_t for backward compatibility, but can be changed
+   if lengths will always be less than the number of bytes in a size_t. */
+#define configMESSAGE_BUFFER_LENGTH_TYPE         size_t
+#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1
+#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP   8
+/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES                    0
+#define configMAX_CO_ROUTINE_PRIORITIES          ( 2 )
+
+/* Software timer definitions. */
+#define configUSE_TIMERS                         1
+#define configTIMER_TASK_PRIORITY                ( 2 )
+#define configTIMER_QUEUE_LENGTH                 32
+#define configTIMER_TASK_STACK_DEPTH             256
+
+/* Set the following definitions to 1 to include the API function, or zero
+to exclude the API function. */
+#define INCLUDE_eTaskGetState                1
+#define INCLUDE_uxTaskGetStackHighWaterMark  1
+#define INCLUDE_uxTaskPriorityGet            1
+#define INCLUDE_vTaskCleanUpResources        0
+#define INCLUDE_vTaskDelay                   1
+#define INCLUDE_vTaskDelayUntil              1
+#define INCLUDE_vTaskDelete                  1
+#define INCLUDE_vTaskPrioritySet             1
+#define INCLUDE_vTaskSuspend                 1
+#define INCLUDE_xQueueGetMutexHolder         1
+#define INCLUDE_xTaskGetCurrentTaskHandle    1
+#define INCLUDE_xTaskGetSchedulerState       1
+#define INCLUDE_xTimerPendFunctionCall       1
+
+/* CMSIS-RTOS V2 flags */
+#define configUSE_OS2_THREAD_SUSPEND_RESUME  1
+#define configUSE_OS2_THREAD_ENUMERATE       1
+#define configUSE_OS2_EVENTFLAGS_FROM_ISR    1
+#define configUSE_OS2_THREAD_FLAGS           1
+#define configUSE_OS2_TIMER                  1
+#define configUSE_OS2_MUTEX                  1
+
+/*
+ * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
+ * by the application thus the correct define need to be enabled below
+ */
+#define USE_FreeRTOS_HEAP_4
+
+/* Cortex-M specific definitions. */
+#ifdef __NVIC_PRIO_BITS
+ /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
+ #define configPRIO_BITS         __NVIC_PRIO_BITS
+#else
+ #define configPRIO_BITS         4
+#endif
+
+/* The lowest interrupt priority that can be used in a call to a "set priority"
+function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
+
+/* The highest interrupt priority that can be used by any interrupt service
+routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
+INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
+PRIORITY THAN THIS! (higher priorities are lower numeric values. */
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
+
+/* Interrupt priorities used by the kernel port layer itself.  These are generic
+to all Cortex-M ports, and do not rely on any particular library functions. */
+#define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
+See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY    ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
+/* Normal assert() semantics without relying on the provision of an assert.h
+header file. */
+/* USER CODE BEGIN 1 */
+#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); asm("bkpt 1"); for( ;; );}
+/* USER CODE END 1 */
+
+/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
+standard names. */
+#define vPortSVCHandler    SVC_Handler
+#define xPortPendSVHandler PendSV_Handler
+
+/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */
+
+#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1
+
+/* USER CODE BEGIN Defines */
+/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
+#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1  /* required only for Keil but does not hurt otherwise */
+/* USER CODE END Defines */
+
+#endif /* FREERTOS_CONFIG_H */

+ 54 - 0
firmware/targets/f7/Inc/aes.h

@@ -0,0 +1,54 @@
+/**
+  ******************************************************************************
+  * @file    aes.h
+  * @brief   This file contains all the function prototypes for
+  *          the aes.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __AES_H__
+#define __AES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern CRYP_HandleTypeDef hcryp1;
+extern CRYP_HandleTypeDef hcryp2;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_AES1_Init(void);
+void MX_AES2_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AES_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 52 - 0
firmware/targets/f7/Inc/comp.h

@@ -0,0 +1,52 @@
+/**
+  ******************************************************************************
+  * @file    comp.h
+  * @brief   This file contains all the function prototypes for
+  *          the comp.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __COMP_H__
+#define __COMP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern COMP_HandleTypeDef hcomp1;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_COMP1_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __COMP_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 49 - 0
firmware/targets/f7/Inc/gpio.h

@@ -0,0 +1,49 @@
+/**
+  ******************************************************************************
+  * @file    gpio.h
+  * @brief   This file contains all the function prototypes for
+  *          the gpio.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __GPIO_H__
+#define __GPIO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_GPIO_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*__ GPIO_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 149 - 0
firmware/targets/f7/Inc/main.h

@@ -0,0 +1,149 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stm32wbxx_hal.h"
+
+void Error_Handler(void);
+
+#define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn
+#define BUTTON_BACK_GPIO_Port GPIOC
+#define BUTTON_BACK_Pin GPIO_PIN_13
+#define BUTTON_DOWN_EXTI_IRQn EXTI6_IRQn
+#define BUTTON_DOWN_GPIO_Port GPIOC
+#define BUTTON_DOWN_Pin GPIO_PIN_6
+#define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn
+#define BUTTON_LEFT_GPIO_Port GPIOB
+#define BUTTON_LEFT_Pin GPIO_PIN_11
+#define BUTTON_OK_EXTI_IRQn EXTI3_IRQn
+#define BUTTON_OK_GPIO_Port GPIOH
+#define BUTTON_OK_Pin GPIO_PIN_3
+#define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn
+#define BUTTON_RIGHT_GPIO_Port GPIOB
+#define BUTTON_RIGHT_Pin GPIO_PIN_12
+#define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn
+#define BUTTON_UP_GPIO_Port GPIOB
+#define BUTTON_UP_Pin GPIO_PIN_10
+
+#define CC1101_CS_GPIO_Port GPIOD
+#define CC1101_CS_Pin GPIO_PIN_0
+#define CC1101_G0_GPIO_Port GPIOA
+#define CC1101_G0_Pin GPIO_PIN_1
+
+#define DISPLAY_CS_GPIO_Port GPIOC
+#define DISPLAY_CS_Pin GPIO_PIN_11
+#define DISPLAY_DI_GPIO_Port GPIOB
+#define DISPLAY_DI_Pin GPIO_PIN_1
+#define DISPLAY_RST_GPIO_Port GPIOB
+#define DISPLAY_RST_Pin GPIO_PIN_0
+
+#define IR_RX_GPIO_Port GPIOA
+#define IR_RX_Pin GPIO_PIN_0
+#define IR_TX_GPIO_Port GPIOB
+#define IR_TX_Pin GPIO_PIN_9
+
+#define NFC_CS_GPIO_Port GPIOE
+#define NFC_CS_Pin GPIO_PIN_4
+
+#define PA4_GPIO_Port GPIOA
+#define PA4_Pin GPIO_PIN_4
+#define PA6_GPIO_Port GPIOA
+#define PA6_Pin GPIO_PIN_6
+#define PA7_GPIO_Port GPIOA
+#define PA7_Pin GPIO_PIN_7
+#define PB2_GPIO_Port GPIOB
+#define PB2_Pin GPIO_PIN_2
+#define PB3_GPIO_Port GPIOB
+#define PB3_Pin GPIO_PIN_3
+#define PC0_GPIO_Port GPIOC
+#define PC0_Pin GPIO_PIN_0
+#define PC1_GPIO_Port GPIOC
+#define PC1_Pin GPIO_PIN_1
+#define PC3_GPIO_Port GPIOC
+#define PC3_Pin GPIO_PIN_3
+
+#define PERIPH_POWER_GPIO_Port GPIOA
+#define PERIPH_POWER_Pin GPIO_PIN_3
+
+#define QUARTZ_32MHZ_IN_GPIO_Port GPIOC
+#define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14
+#define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC
+#define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15
+
+#define RFID_OUT_GPIO_Port GPIOB
+#define RFID_OUT_Pin GPIO_PIN_13
+#define RFID_PULL_GPIO_Port GPIOA
+#define RFID_PULL_Pin GPIO_PIN_2
+#define RFID_RF_IN_GPIO_Port GPIOC
+#define RFID_RF_IN_Pin GPIO_PIN_5
+#define RFID_CARRIER_GPIO_Port GPIOA
+#define RFID_CARRIER_Pin GPIO_PIN_15
+
+#define RF_SW_0_GPIO_Port GPIOC
+#define RF_SW_0_Pin GPIO_PIN_4
+
+#define SD_CD_GPIO_Port GPIOC
+#define SD_CD_Pin GPIO_PIN_10
+#define SD_CS_GPIO_Port GPIOC
+#define SD_CS_Pin GPIO_PIN_12
+
+#define SPEAKER_GPIO_Port GPIOB
+#define SPEAKER_Pin GPIO_PIN_8
+
+#define VIBRO_GPIO_Port GPIOA
+#define VIBRO_Pin GPIO_PIN_8
+
+#define iBTN_GPIO_Port GPIOB
+#define iBTN_Pin GPIO_PIN_14
+
+#define USART1_TX_Pin GPIO_PIN_6
+#define USART1_TX_Port GPIOB
+#define USART1_RX_Pin GPIO_PIN_7
+#define USART1_RX_Port GPIOB
+
+#define SPI_D_MISO_GPIO_Port GPIOC
+#define SPI_D_MISO_Pin GPIO_PIN_2
+#define SPI_D_MOSI_GPIO_Port GPIOB
+#define SPI_D_MOSI_Pin GPIO_PIN_15
+#define SPI_D_SCK_GPIO_Port GPIOD
+#define SPI_D_SCK_Pin GPIO_PIN_1
+
+#define SPI_R_MISO_GPIO_Port GPIOB
+#define SPI_R_MISO_Pin GPIO_PIN_4
+#define SPI_R_MOSI_GPIO_Port GPIOB
+#define SPI_R_MOSI_Pin GPIO_PIN_5
+#define SPI_R_SCK_GPIO_Port GPIOA
+#define SPI_R_SCK_Pin GPIO_PIN_5
+
+extern TIM_HandleTypeDef htim1;
+extern TIM_HandleTypeDef htim2;
+extern TIM_HandleTypeDef htim16;
+
+#define TIM_A htim1
+#define TIM_B htim2
+#define TIM_C htim16
+
+#define SPEAKER_TIM htim16
+#define SPEAKER_CH TIM_CHANNEL_1
+
+#define LFRFID_TIM htim1
+#define LFRFID_CH TIM_CHANNEL_1
+
+#define IRDA_TX_TIM htim1
+#define IRDA_TX_CH TIM_CHANNEL_3
+
+// only for reference
+// IRDA RX timer dont exist in F2
+// and timer need more data to init (NVIC IRQn to set priority)
+#define IRDA_RX_TIM htim2
+#define IRDA_RX_FALLING_CH TIM_CHANNEL_1
+#define IRDA_RX_RISING_CH TIM_CHANNEL_2
+
+#define NFC_IRQ_Pin RFID_PULL_Pin
+#define NFC_IRQ_GPIO_Port RFID_PULL_GPIO_Port
+
+#ifdef __cplusplus
+}
+#endif

+ 52 - 0
firmware/targets/f7/Inc/pka.h

@@ -0,0 +1,52 @@
+/**
+  ******************************************************************************
+  * @file    pka.h
+  * @brief   This file contains all the function prototypes for
+  *          the pka.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __PKA_H__
+#define __PKA_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern PKA_HandleTypeDef hpka;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_PKA_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PKA_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 50 - 0
firmware/targets/f7/Inc/rf.h

@@ -0,0 +1,50 @@
+/**
+  ******************************************************************************
+  * @file    rf.h
+  * @brief   This file contains all the function prototypes for
+  *          the rf.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __RF_H__
+#define __RF_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_RF_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RF_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 52 - 0
firmware/targets/f7/Inc/rng.h

@@ -0,0 +1,52 @@
+/**
+  ******************************************************************************
+  * @file    rng.h
+  * @brief   This file contains all the function prototypes for
+  *          the rng.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __RNG_H__
+#define __RNG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern RNG_HandleTypeDef hrng;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_RNG_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RNG_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 52 - 0
firmware/targets/f7/Inc/rtc.h

@@ -0,0 +1,52 @@
+/**
+  ******************************************************************************
+  * @file    rtc.h
+  * @brief   This file contains all the function prototypes for
+  *          the rtc.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __RTC_H__
+#define __RTC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern RTC_HandleTypeDef hrtc;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_RTC_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RTC_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 353 - 0
firmware/targets/f7/Inc/stm32wbxx_hal_conf.h

@@ -0,0 +1,353 @@
+/**
+  ******************************************************************************
+  * @file    stm32wbxx_hal_conf.h
+  * @author  MCD Application Team
+  * @brief   HAL configuration file.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32WBxx_HAL_CONF_H
+#define __STM32WBxx_HAL_CONF_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* ########################## Module Selection ############################## */
+/**
+  * @brief This is the list of modules to be used in the HAL driver
+  */
+#define HAL_MODULE_ENABLED
+/*#define HAL_ADC_MODULE_ENABLED    */
+#define HAL_CRYP_MODULE_ENABLED
+#define HAL_COMP_MODULE_ENABLED
+/*#define HAL_CRC_MODULE_ENABLED    */
+#define HAL_HSEM_MODULE_ENABLED
+/*#define HAL_I2C_MODULE_ENABLED    */
+/*#define HAL_IPCC_MODULE_ENABLED   */
+/*#define HAL_IRDA_MODULE_ENABLED   */
+/*#define HAL_IWDG_MODULE_ENABLED   */
+/*#define HAL_LCD_MODULE_ENABLED    */
+/*#define HAL_LPTIM_MODULE_ENABLED  */
+#define HAL_PCD_MODULE_ENABLED
+#define HAL_PKA_MODULE_ENABLED
+/*#define HAL_QSPI_MODULE_ENABLED   */
+#define HAL_RNG_MODULE_ENABLED
+#define HAL_RTC_MODULE_ENABLED
+/*#define HAL_SAI_MODULE_ENABLED    */
+/*#define HAL_SMBUS_MODULE_ENABLED  */
+/*#define HAL_SMARTCARD_MODULE_ENABLED   */
+/*#define HAL_SPI_MODULE_ENABLED    */
+#define HAL_TIM_MODULE_ENABLED
+/*#define HAL_TSC_MODULE_ENABLED    */
+/*#define HAL_UART_MODULE_ENABLED   */
+/*#define HAL_USART_MODULE_ENABLED  */
+/*#define HAL_WWDG_MODULE_ENABLED   */
+#define HAL_EXTI_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+#define HAL_DMA_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+
+#define USE_HAL_ADC_REGISTER_CALLBACKS       0u
+#define USE_HAL_COMP_REGISTER_CALLBACKS      0u
+#define USE_HAL_CRYP_REGISTER_CALLBACKS      0u
+#define USE_HAL_I2C_REGISTER_CALLBACKS       0u
+#define USE_HAL_IRDA_REGISTER_CALLBACKS      0u
+#define USE_HAL_LPTIM_REGISTER_CALLBACKS     0u
+#define USE_HAL_PCD_REGISTER_CALLBACKS       0u
+#define USE_HAL_PKA_REGISTER_CALLBACKS       0u
+#define USE_HAL_QSPI_REGISTER_CALLBACKS      0u
+#define USE_HAL_RNG_REGISTER_CALLBACKS       0u
+#define USE_HAL_RTC_REGISTER_CALLBACKS       0u
+#define USE_HAL_SAI_REGISTER_CALLBACKS       0u
+#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0u
+#define USE_HAL_SMBUS_REGISTER_CALLBACKS     0u
+#define USE_HAL_SPI_REGISTER_CALLBACKS       0u
+#define USE_HAL_TIM_REGISTER_CALLBACKS       0u
+#define USE_HAL_TSC_REGISTER_CALLBACKS       0u
+#define USE_HAL_UART_REGISTER_CALLBACKS      0u
+#define USE_HAL_USART_REGISTER_CALLBACKS     0u
+#define USE_HAL_WWDG_REGISTER_CALLBACKS      0u
+
+/* ########################## Oscillator Values adaptation ####################*/
+/**
+  * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
+  *        This value is used by the RCC HAL module to compute the system frequency
+  *        (when HSE is used as system clock source, directly or through the PLL).
+  */
+#if !defined  (HSE_VALUE)
+#define HSE_VALUE    32000000U             /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined  (HSE_STARTUP_TIMEOUT)
+  #define HSE_STARTUP_TIMEOUT    ((uint32_t)100)   /*!< Time out for HSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+  * @brief Internal Multiple Speed oscillator (MSI) default value.
+  *        This value is the default MSI range value after Reset.
+  */
+#if !defined  (MSI_VALUE)
+  #define MSI_VALUE    ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* MSI_VALUE */
+
+/**
+  * @brief Internal High Speed oscillator (HSI) value.
+  *        This value is used by the RCC HAL module to compute the system frequency
+  *        (when HSI is used as system clock source, directly or through the PLL).
+  */
+#if !defined  (HSI_VALUE)
+#define HSI_VALUE    16000000U            /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+  * @brief Internal Low Speed oscillator (LSI1) value.
+  */
+#if !defined  (LSI1_VALUE)
+ #define LSI1_VALUE  ((uint32_t)32000)       /*!< LSI1 Typical Value in Hz*/
+#endif /* LSI1_VALUE */                      /*!< Value of the Internal Low Speed oscillator in Hz
+                                             The real value may vary depending on the variations
+                                             in voltage and temperature.*/
+/**
+  * @brief Internal Low Speed oscillator (LSI2) value.
+  */
+#if !defined  (LSI2_VALUE)
+ #define LSI2_VALUE  ((uint32_t)32000)       /*!< LSI2 Typical Value in Hz*/
+#endif /* LSI2_VALUE */                      /*!< Value of the Internal Low Speed oscillator in Hz
+                                             The real value may vary depending on the variations
+                                             in voltage and temperature.*/
+
+/**
+  * @brief External Low Speed oscillator (LSE) value.
+  *        This value is used by the UART, RTC HAL module to compute the system frequency
+  */
+#if !defined  (LSE_VALUE)
+#define LSE_VALUE    32768U               /*!< Value of the External oscillator in Hz*/
+#endif /* LSE_VALUE */
+
+/**
+  * @brief Internal Multiple Speed oscillator (HSI48) default value.
+  *        This value is the default HSI48 range value after Reset.
+  */
+#if !defined (HSI48_VALUE)
+  #define HSI48_VALUE    ((uint32_t)48000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI48_VALUE */
+
+#if !defined  (LSE_STARTUP_TIMEOUT)
+#define LSE_STARTUP_TIMEOUT    1000U      /*!< Time out for LSE start up, in ms */
+#endif /* HSE_STARTUP_TIMEOUT */
+
+/**
+  * @brief External clock source for SAI1 peripheral
+  *        This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source
+  *        frequency.
+  */
+#if !defined (EXTERNAL_SAI1_CLOCK_VALUE)
+  #define EXTERNAL_SAI1_CLOCK_VALUE    ((uint32_t)2097000) /*!< Value of the SAI1 External clock source in Hz*/
+#endif /* EXTERNAL_SAI1_CLOCK_VALUE */
+
+/* Tip: To avoid modifying this file each time you need to use different HSE,
+   ===  you can define the HSE value in your toolchain compiler preprocessor. */
+
+/* ########################### System Configuration ######################### */
+/**
+  * @brief This is the HAL system configuration section
+  */
+
+#define  VDD_VALUE                    3300U   /*!< Value of VDD in mv */
+#define  TICK_INT_PRIORITY            0U      /*!< tick interrupt priority */
+#define  USE_RTOS                     0U
+#define  PREFETCH_ENABLE              1U
+#define  INSTRUCTION_CACHE_ENABLE     1U
+#define  DATA_CACHE_ENABLE            1U
+
+/* ########################## Assert Selection ############################## */
+/**
+  * @brief Uncomment the line below to expanse the "assert_param" macro in the
+  *        HAL drivers code
+  */
+/* #define USE_FULL_ASSERT    1U */
+
+/* ################## SPI peripheral configuration ########################## */
+
+/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
+ * Activated: CRC code is present inside driver
+ * Deactivated: CRC code cleaned from driver
+ */
+
+#define USE_SPI_CRC                   0U
+
+/* Includes ------------------------------------------------------------------*/
+/**
+  * @brief Include module's header file
+  */
+#ifdef HAL_DMA_MODULE_ENABLED
+  #include "stm32wbxx_hal_dma.h"
+#endif /* HAL_DMA_MODULE_ENABLED */
+
+#ifdef HAL_ADC_MODULE_ENABLED
+  #include "stm32wbxx_hal_adc.h"
+#endif /* HAL_ADC_MODULE_ENABLED */
+
+#ifdef HAL_COMP_MODULE_ENABLED
+  #include "stm32wbxx_hal_comp.h"
+#endif /* HAL_COMP_MODULE_ENABLED */
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+  #include "stm32wbxx_hal_cortex.h"
+#endif /* HAL_CORTEX_MODULE_ENABLED */
+
+#ifdef HAL_CRC_MODULE_ENABLED
+  #include "stm32wbxx_hal_crc.h"
+#endif /* HAL_CRC_MODULE_ENABLED */
+
+#ifdef HAL_CRYP_MODULE_ENABLED
+  #include "stm32wbxx_hal_cryp.h"
+#endif /* HAL_CRYP_MODULE_ENABLED */
+
+#ifdef HAL_EXTI_MODULE_ENABLED
+  #include "stm32wbxx_hal_exti.h"
+#endif /* HAL_EXTI_MODULE_ENABLED */
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+  #include "stm32wbxx_hal_flash.h"
+#endif /* HAL_FLASH_MODULE_ENABLED */
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+  #include "stm32wbxx_hal_gpio.h"
+#endif /* HAL_GPIO_MODULE_ENABLED */
+
+#ifdef HAL_HSEM_MODULE_ENABLED
+  #include "stm32wbxx_hal_hsem.h"
+#endif /* HAL_HSEM_MODULE_ENABLED */
+
+#ifdef HAL_I2C_MODULE_ENABLED
+ #include "stm32wbxx_hal_i2c.h"
+#endif /* HAL_I2C_MODULE_ENABLED */
+
+#ifdef HAL_IPCC_MODULE_ENABLED
+ #include "stm32wbxx_hal_ipcc.h"
+#endif /* HAL_IPCC_MODULE_ENABLED */
+
+#ifdef HAL_IRDA_MODULE_ENABLED
+ #include "stm32wbxx_hal_irda.h"
+#endif /* HAL_IRDA_MODULE_ENABLED */
+
+#ifdef HAL_IWDG_MODULE_ENABLED
+ #include "stm32wbxx_hal_iwdg.h"
+#endif /* HAL_IWDG_MODULE_ENABLED */
+
+#ifdef HAL_LCD_MODULE_ENABLED
+ #include "stm32wbxx_hal_lcd.h"
+#endif /* HAL_LCD_MODULE_ENABLED */
+
+#ifdef HAL_LPTIM_MODULE_ENABLED
+  #include "stm32wbxx_hal_lptim.h"
+#endif /* HAL_LPTIM_MODULE_ENABLED */
+
+#ifdef HAL_PCD_MODULE_ENABLED
+  #include "stm32wbxx_hal_pcd.h"
+#endif /* HAL_PCD_MODULE_ENABLED */
+
+#ifdef HAL_PKA_MODULE_ENABLED
+  #include "stm32wbxx_hal_pka.h"
+#endif /* HAL_PKA_MODULE_ENABLED */
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "stm32wbxx_hal_pwr.h"
+#endif /* HAL_PWR_MODULE_ENABLED */
+
+#ifdef HAL_QSPI_MODULE_ENABLED
+ #include "stm32wbxx_hal_qspi.h"
+#endif /* HAL_QSPI_MODULE_ENABLED */
+
+#ifdef HAL_RCC_MODULE_ENABLED
+  #include "stm32wbxx_hal_rcc.h"
+#endif /* HAL_RCC_MODULE_ENABLED */
+
+#ifdef HAL_RNG_MODULE_ENABLED
+  #include "stm32wbxx_hal_rng.h"
+#endif /* HAL_RNG_MODULE_ENABLED */
+
+#ifdef HAL_RTC_MODULE_ENABLED
+ #include "stm32wbxx_hal_rtc.h"
+#endif /* HAL_RTC_MODULE_ENABLED */
+
+#ifdef HAL_SAI_MODULE_ENABLED
+ #include "stm32wbxx_hal_sai.h"
+#endif /* HAL_SAI_MODULE_ENABLED */
+
+#ifdef HAL_SMARTCARD_MODULE_ENABLED
+ #include "stm32wbxx_hal_smartcard.h"
+#endif /* HAL_SMARTCARD_MODULE_ENABLED */
+
+#ifdef HAL_SMBUS_MODULE_ENABLED
+ #include "stm32wbxx_hal_smbus.h"
+#endif /* HAL_SMBUS_MODULE_ENABLED */
+
+#ifdef HAL_SPI_MODULE_ENABLED
+ #include "stm32wbxx_hal_spi.h"
+#endif /* HAL_SPI_MODULE_ENABLED */
+
+#ifdef HAL_TIM_MODULE_ENABLED
+ #include "stm32wbxx_hal_tim.h"
+#endif /* HAL_TIM_MODULE_ENABLED */
+
+#ifdef HAL_TSC_MODULE_ENABLED
+  #include "stm32wbxx_hal_tsc.h"
+#endif /* HAL_TSC_MODULE_ENABLED */
+
+#ifdef HAL_UART_MODULE_ENABLED
+ #include "stm32wbxx_hal_uart.h"
+#endif /* HAL_UART_MODULE_ENABLED */
+
+#ifdef HAL_USART_MODULE_ENABLED
+ #include "stm32wbxx_hal_usart.h"
+#endif /* HAL_USART_MODULE_ENABLED */
+
+#ifdef HAL_WWDG_MODULE_ENABLED
+ #include "stm32wbxx_hal_wwdg.h"
+#endif /* HAL_WWDG_MODULE_ENABLED */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef  USE_FULL_ASSERT
+/**
+  * @brief  The assert_param macro is used for function's parameters check.
+  * @param expr If expr is false, it calls assert_failed function
+  *         which reports the name of the source file and the source
+  *         line number of the call that failed.
+  *         If expr is true, it returns no value.
+  * @retval None
+  */
+  #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+  void assert_failed(uint8_t* file, uint32_t line);
+#else
+  #define assert_param(expr) ((void)0U)
+#endif /* USE_FULL_ASSERT */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32WBxx_HAL_CONF_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 69 - 0
firmware/targets/f7/Inc/stm32wbxx_it.h

@@ -0,0 +1,69 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file    stm32wbxx_it.h
+  * @brief   This file contains the headers of the interrupt handlers.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+ ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32WBxx_IT_H
+#define __STM32WBxx_IT_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Private includes ----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* Exported types ------------------------------------------------------------*/
+/* USER CODE BEGIN ET */
+
+/* USER CODE END ET */
+
+/* Exported constants --------------------------------------------------------*/
+/* USER CODE BEGIN EC */
+
+/* USER CODE END EC */
+
+/* Exported macro ------------------------------------------------------------*/
+/* USER CODE BEGIN EM */
+
+/* USER CODE END EM */
+
+/* Exported functions prototypes ---------------------------------------------*/
+void SysTick_Handler(void);
+void ADC1_IRQHandler(void);
+void USB_LP_IRQHandler(void);
+void COMP_IRQHandler(void);
+void TIM1_UP_TIM16_IRQHandler(void);
+void TIM1_TRG_COM_TIM17_IRQHandler(void);
+void TIM1_CC_IRQHandler(void);
+void TIM2_IRQHandler(void);
+void HSEM_IRQHandler(void);
+/* USER CODE BEGIN EFP */
+
+/* USER CODE END EFP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32WBxx_IT_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 58 - 0
firmware/targets/f7/Inc/tim.h

@@ -0,0 +1,58 @@
+/**
+  ******************************************************************************
+  * @file    tim.h
+  * @brief   This file contains all the function prototypes for
+  *          the tim.c file
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __TIM_H__
+#define __TIM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern TIM_HandleTypeDef htim1;
+extern TIM_HandleTypeDef htim2;
+extern TIM_HandleTypeDef htim16;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_TIM1_Init(void);
+void MX_TIM2_Init(void);
+void MX_TIM16_Init(void);
+
+void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TIM_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 127 - 0
firmware/targets/f7/Src/aes.c

@@ -0,0 +1,127 @@
+/**
+  ******************************************************************************
+  * @file    aes.c
+  * @brief   This file provides code for the configuration
+  *          of the AES instances.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "aes.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+CRYP_HandleTypeDef hcryp1;
+__ALIGN_BEGIN static const uint32_t pKeyAES1[4] __ALIGN_END = {
+                            0x00000000,0x00000000,0x00000000,0x00000000};
+CRYP_HandleTypeDef hcryp2;
+__ALIGN_BEGIN static const uint32_t pKeyAES2[4] __ALIGN_END = {
+                            0x00000000,0x00000000,0x00000000,0x00000000};
+
+/* AES1 init function */
+void MX_AES1_Init(void)
+{
+
+  hcryp1.Instance = AES1;
+  hcryp1.Init.DataType = CRYP_DATATYPE_32B;
+  hcryp1.Init.KeySize = CRYP_KEYSIZE_128B;
+  hcryp1.Init.pKey = (uint32_t *)pKeyAES1;
+  hcryp1.Init.Algorithm = CRYP_AES_ECB;
+  hcryp1.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD;
+  hcryp1.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS;
+  if (HAL_CRYP_Init(&hcryp1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+/* AES2 init function */
+void MX_AES2_Init(void)
+{
+
+  hcryp2.Instance = AES2;
+  hcryp2.Init.DataType = CRYP_DATATYPE_32B;
+  hcryp2.Init.KeySize = CRYP_KEYSIZE_128B;
+  hcryp2.Init.pKey = (uint32_t *)pKeyAES2;
+  hcryp2.Init.Algorithm = CRYP_AES_ECB;
+  hcryp2.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD;
+  hcryp2.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS;
+  if (HAL_CRYP_Init(&hcryp2) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_CRYP_MspInit(CRYP_HandleTypeDef* crypHandle)
+{
+
+  if(crypHandle->Instance==AES1)
+  {
+  /* USER CODE BEGIN AES1_MspInit 0 */
+
+  /* USER CODE END AES1_MspInit 0 */
+    /* AES1 clock enable */
+    __HAL_RCC_AES1_CLK_ENABLE();
+  /* USER CODE BEGIN AES1_MspInit 1 */
+
+  /* USER CODE END AES1_MspInit 1 */
+  }
+  else if(crypHandle->Instance==AES2)
+  {
+  /* USER CODE BEGIN AES2_MspInit 0 */
+
+  /* USER CODE END AES2_MspInit 0 */
+    /* AES2 clock enable */
+    __HAL_RCC_AES2_CLK_ENABLE();
+  /* USER CODE BEGIN AES2_MspInit 1 */
+
+  /* USER CODE END AES2_MspInit 1 */
+  }
+}
+
+void HAL_CRYP_MspDeInit(CRYP_HandleTypeDef* crypHandle)
+{
+
+  if(crypHandle->Instance==AES1)
+  {
+  /* USER CODE BEGIN AES1_MspDeInit 0 */
+
+  /* USER CODE END AES1_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_AES1_CLK_DISABLE();
+  /* USER CODE BEGIN AES1_MspDeInit 1 */
+
+  /* USER CODE END AES1_MspDeInit 1 */
+  }
+  else if(crypHandle->Instance==AES2)
+  {
+  /* USER CODE BEGIN AES2_MspDeInit 0 */
+
+  /* USER CODE END AES2_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_AES2_CLK_DISABLE();
+  /* USER CODE BEGIN AES2_MspDeInit 1 */
+
+  /* USER CODE END AES2_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 103 - 0
firmware/targets/f7/Src/comp.c

@@ -0,0 +1,103 @@
+/**
+  ******************************************************************************
+  * @file    comp.c
+  * @brief   This file provides code for the configuration
+  *          of the COMP instances.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "comp.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+COMP_HandleTypeDef hcomp1;
+
+/* COMP1 init function */
+void MX_COMP1_Init(void)
+{
+
+  hcomp1.Instance = COMP1;
+  hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_4VREFINT;
+  hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1;
+  hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED;
+  hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH;
+  hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE;
+  hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED;
+  hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE;
+  hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING;
+  if (HAL_COMP_Init(&hcomp1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_COMP_MspInit(COMP_HandleTypeDef* compHandle)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(compHandle->Instance==COMP1)
+  {
+  /* USER CODE BEGIN COMP1_MspInit 0 */
+
+  /* USER CODE END COMP1_MspInit 0 */
+
+    __HAL_RCC_GPIOC_CLK_ENABLE();
+    /**COMP1 GPIO Configuration
+    PC5     ------> COMP1_INP
+    */
+    GPIO_InitStruct.Pin = RFID_RF_IN_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    HAL_GPIO_Init(RFID_RF_IN_GPIO_Port, &GPIO_InitStruct);
+
+    /* COMP1 interrupt Init */
+    HAL_NVIC_SetPriority(COMP_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(COMP_IRQn);
+  /* USER CODE BEGIN COMP1_MspInit 1 */
+
+  /* USER CODE END COMP1_MspInit 1 */
+  }
+}
+
+void HAL_COMP_MspDeInit(COMP_HandleTypeDef* compHandle)
+{
+
+  if(compHandle->Instance==COMP1)
+  {
+  /* USER CODE BEGIN COMP1_MspDeInit 0 */
+
+  /* USER CODE END COMP1_MspDeInit 0 */
+
+    /**COMP1 GPIO Configuration
+    PC5     ------> COMP1_INP
+    */
+    HAL_GPIO_DeInit(RFID_RF_IN_GPIO_Port, RFID_RF_IN_Pin);
+
+    /* COMP1 interrupt Deinit */
+    HAL_NVIC_DisableIRQ(COMP_IRQn);
+  /* USER CODE BEGIN COMP1_MspDeInit 1 */
+
+  /* USER CODE END COMP1_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 56 - 0
firmware/targets/f7/Src/fatfs/fatfs.c

@@ -0,0 +1,56 @@
+/**
+  ******************************************************************************
+  * @file   fatfs.c
+  * @brief  Code for fatfs applications
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+#include "fatfs.h"
+
+uint8_t retUSER;    /* Return value for USER */
+char USERPath[4];   /* USER logical drive path */
+FATFS USERFatFS;    /* File system object for USER logical drive */
+FIL USERFile;       /* File object for USER */
+
+/* USER CODE BEGIN Variables */
+
+/* USER CODE END Variables */    
+
+void MX_FATFS_Init(void) 
+{
+  /*## FatFS: Link the USER driver ###########################*/
+  retUSER = FATFS_LinkDriver(&USER_Driver, USERPath);
+
+  /* USER CODE BEGIN Init */
+  /* additional user code for init */     
+  /* USER CODE END Init */
+}
+
+/**
+  * @brief  Gets Time from RTC 
+  * @param  None
+  * @retval Time in DWORD
+  */
+DWORD get_fattime(void)
+{
+  /* USER CODE BEGIN get_fattime */
+  return 0;
+  /* USER CODE END get_fattime */  
+}
+
+/* USER CODE BEGIN Application */
+     
+/* USER CODE END Application */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 49 - 0
firmware/targets/f7/Src/fatfs/fatfs.h

@@ -0,0 +1,49 @@
+/**
+  ******************************************************************************
+  * @file   fatfs.h
+  * @brief  Header for fatfs applications
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __fatfs_H
+#define __fatfs_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "fatfs/ff.h"
+#include "fatfs/ff_gen_drv.h"
+#include "user_diskio.h" /* defines USER_Driver as external */
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern uint8_t retUSER; /* Return value for USER */
+extern char USERPath[4]; /* USER logical drive path */
+extern FATFS USERFatFS; /* File system object for USER logical drive */
+extern FIL USERFile; /* File object for USER */
+
+void MX_FATFS_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+#ifdef __cplusplus
+}
+#endif
+#endif /*__fatfs_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 270 - 0
firmware/targets/f7/Src/fatfs/ffconf.h

@@ -0,0 +1,270 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  *  FatFs - Generic FAT file system module  R0.12c (C)ChaN, 2017
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+#ifndef _FFCONF
+#define _FFCONF 68300	/* Revision ID */
+
+/*-----------------------------------------------------------------------------/
+/ Additional user header to be used  
+/-----------------------------------------------------------------------------*/
+
+#include "main.h"
+#include "stm32wbxx_hal.h"
+#include "cmsis_os.h" /* _FS_REENTRANT set to 1 and CMSIS API chosen */
+
+/*-----------------------------------------------------------------------------/
+/ Function Configurations
+/-----------------------------------------------------------------------------*/
+
+#define _FS_READONLY         0      /* 0:Read/Write or 1:Read only */
+/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
+/  Read-only configuration removes writing API functions, f_write(), f_sync(),
+/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
+/  and optional writing functions as well. */
+
+#define _FS_MINIMIZE         0      /* 0 to 3 */
+/* This option defines minimization level to remove some basic API functions.
+/
+/   0: All basic functions are enabled.
+/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
+/      are removed.
+/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
+/   3: f_lseek() function is removed in addition to 2. */
+
+#define _USE_STRFUNC         0      /* 0:Disable or 1-2:Enable */
+/* This option switches string functions, f_gets(), f_putc(), f_puts() and
+/  f_printf().
+/
+/  0: Disable string functions.
+/  1: Enable without LF-CRLF conversion.
+/  2: Enable with LF-CRLF conversion. */
+
+#define _USE_FIND            0
+/* This option switches filtered directory read functions, f_findfirst() and
+/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
+
+#define _USE_MKFS            1
+/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
+
+#define _USE_FASTSEEK        1
+/* This option switches fast seek feature. (0:Disable or 1:Enable) */
+
+#define	_USE_EXPAND		0
+/* This option switches f_expand function. (0:Disable or 1:Enable) */
+
+#define _USE_CHMOD		0
+/* This option switches attribute manipulation functions, f_chmod() and f_utime().
+/  (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
+
+#define _USE_LABEL           1
+/* This option switches volume label functions, f_getlabel() and f_setlabel().
+/  (0:Disable or 1:Enable) */
+
+#define _USE_FORWARD         0
+/* This option switches f_forward() function. (0:Disable or 1:Enable) */
+
+/*-----------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/-----------------------------------------------------------------------------*/
+
+#define _CODE_PAGE         850
+/* This option specifies the OEM code page to be used on the target system.
+/  Incorrect setting of the code page can cause a file open failure.
+/
+/   1   - ASCII (No extended character. Non-LFN cfg. only)
+/   437 - U.S.
+/   720 - Arabic
+/   737 - Greek
+/   771 - KBL
+/   775 - Baltic
+/   850 - Latin 1
+/   852 - Latin 2
+/   855 - Cyrillic
+/   857 - Turkish
+/   860 - Portuguese
+/   861 - Icelandic
+/   862 - Hebrew
+/   863 - Canadian French
+/   864 - Arabic
+/   865 - Nordic
+/   866 - Russian
+/   869 - Greek 2
+/   932 - Japanese (DBCS)
+/   936 - Simplified Chinese (DBCS)
+/   949 - Korean (DBCS)
+/   950 - Traditional Chinese (DBCS)
+*/
+
+#define _USE_LFN     2    /* 0 to 3 */
+#define _MAX_LFN     255  /* Maximum LFN length to handle (12 to 255) */
+/* The _USE_LFN switches the support of long file name (LFN).
+/
+/   0: Disable support of LFN. _MAX_LFN has no effect.
+/   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
+/   2: Enable LFN with dynamic working buffer on the STACK.
+/   3: Enable LFN with dynamic working buffer on the HEAP.
+/
+/  To enable the LFN, Unicode handling functions (option/unicode.c) must be added
+/  to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
+/  additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
+/  It should be set 255 to support full featured LFN operations.
+/  When use stack for the working buffer, take care on stack overflow. When use heap
+/  memory for the working buffer, memory management functions, ff_memalloc() and
+/  ff_memfree(), must be added to the project. */
+
+#define _LFN_UNICODE    0 /* 0:ANSI/OEM or 1:Unicode */
+/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
+/  To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
+/  This option also affects behavior of string I/O functions. */
+
+#define _STRF_ENCODE    0
+/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
+/  be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
+/
+/  0: ANSI/OEM
+/  1: UTF-16LE
+/  2: UTF-16BE
+/  3: UTF-8
+/
+/  This option has no effect when _LFN_UNICODE == 0. */
+
+#define _FS_RPATH       0 /* 0 to 2 */
+/* This option configures support of relative path.
+/
+/   0: Disable relative path and remove related functions.
+/   1: Enable relative path. f_chdir() and f_chdrive() are available.
+/   2: f_getcwd() function is available in addition to 1.
+*/
+
+/*---------------------------------------------------------------------------/
+/ Drive/Volume Configurations
+/----------------------------------------------------------------------------*/
+
+#define _VOLUMES    1
+/* Number of volumes (logical drives) to be used. */
+
+/* USER CODE BEGIN Volumes */  
+#define _STR_VOLUME_ID          0	/* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */
+#define _VOLUME_STRS            "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
+/* _STR_VOLUME_ID switches string support of volume ID.
+/  When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
+/  number in the path name. _VOLUME_STRS defines the drive ID strings for each
+/  logical drives. Number of items must be equal to _VOLUMES. Valid characters for
+/  the drive ID strings are: A-Z and 0-9. */
+/* USER CODE END Volumes */  
+
+#define _MULTI_PARTITION     0 /* 0:Single partition, 1:Multiple partition */
+/* This option switches support of multi-partition on a physical drive.
+/  By default (0), each logical drive number is bound to the same physical drive
+/  number and only an FAT volume found on the physical drive will be mounted.
+/  When multi-partition is enabled (1), each logical drive number can be bound to
+/  arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
+/  funciton will be available. */
+#define _MIN_SS    512  /* 512, 1024, 2048 or 4096 */
+#define _MAX_SS    512  /* 512, 1024, 2048 or 4096 */
+/* These options configure the range of sector size to be supported. (512, 1024,
+/  2048 or 4096) Always set both 512 for most systems, all type of memory cards and
+/  harddisk. But a larger value may be required for on-board flash memory and some
+/  type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
+/  to variable sector size and GET_SECTOR_SIZE command must be implemented to the
+/  disk_ioctl() function. */
+
+#define	_USE_TRIM      0
+/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
+/  To enable Trim function, also CTRL_TRIM command should be implemented to the
+/  disk_ioctl() function. */
+
+#define _FS_NOFSINFO    0 /* 0,1,2 or 3 */
+/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
+/  option, and f_getfree() function at first time after volume mount will force
+/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.
+/
+/  bit0=0: Use free cluster count in the FSINFO if available.
+/  bit0=1: Do not trust free cluster count in the FSINFO.
+/  bit1=0: Use last allocated cluster number in the FSINFO if available.
+/  bit1=1: Do not trust last allocated cluster number in the FSINFO.
+*/
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/----------------------------------------------------------------------------*/
+
+#define _FS_TINY    0      /* 0:Normal or 1:Tiny */
+/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
+/  At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes.
+/  Instead of private sector buffer eliminated from the file object, common sector
+/  buffer in the file system object (FATFS) is used for the file data transfer. */
+
+#define _FS_EXFAT	1
+/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
+/  When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
+/  Note that enabling exFAT discards C89 compatibility. */
+
+#define _FS_NORTC	1
+#define _NORTC_MON	7
+#define _NORTC_MDAY	20
+#define _NORTC_YEAR	2021
+/* The option _FS_NORTC switches timestamp functiton. If the system does not have
+/  any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
+/  the timestamp function. All objects modified by FatFs will have a fixed timestamp
+/  defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
+/  To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
+/  added to the project to get current time form real-time clock. _NORTC_MON,
+/  _NORTC_MDAY and _NORTC_YEAR have no effect. 
+/  These options have no effect at read-only configuration (_FS_READONLY = 1). */
+
+#define _FS_LOCK    0     /* 0:Disable or >=1:Enable */
+/* The option _FS_LOCK switches file lock function to control duplicated file open
+/  and illegal operation to open objects. This option must be 0 when _FS_READONLY
+/  is 1.
+/
+/  0:  Disable file lock function. To avoid volume corruption, application program
+/      should avoid illegal open, remove and rename to the open objects.
+/  >0: Enable file lock function. The value defines how many files/sub-directories
+/      can be opened simultaneously under file lock control. Note that the file
+/      lock control is independent of re-entrancy. */
+
+#define _FS_REENTRANT    0  /* 0:Disable or 1:Enable */
+#define _FS_TIMEOUT      1000 /* Timeout period in unit of time ticks */
+#define _SYNC_t          osMutexId_t
+/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
+/  module itself. Note that regardless of this option, file access to different
+/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
+/  and f_fdisk() function, are always not re-entrant. Only file/directory access
+/  to the same volume is under control of this function.
+/
+/   0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
+/   1: Enable re-entrancy. Also user provided synchronization handlers,
+/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
+/      function, must be added to the project. Samples are available in
+/      option/syscall.c.
+/
+/  The _FS_TIMEOUT defines timeout period in unit of time tick.
+/  The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
+/  SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
+/  included somewhere in the scope of ff.h. */
+
+/* define the ff_malloc ff_free macros as standard malloc free */
+#if !defined(ff_malloc) && !defined(ff_free)
+#include <stdlib.h>
+#define ff_malloc  malloc
+#define ff_free  free
+#endif
+
+#endif /* _FFCONF */

+ 100 - 0
firmware/targets/f7/Src/fatfs/spi_sd_hal.c

@@ -0,0 +1,100 @@
+#include "main.h"
+#include <furi-hal.h>
+#include <furi.h>
+
+#define SD_DUMMY_BYTE 0xFF
+
+const uint32_t SpiTimeout = 1000;
+uint8_t SD_IO_WriteByte(uint8_t Data);
+
+static const FuriHalSpiDevice* sd_spi_dev = &furi_hal_spi_devices[FuriHalSpiDeviceIdSdCardFast];
+
+/******************************************************************************
+                            BUS OPERATIONS
+ *******************************************************************************/
+
+/**
+ * @brief  SPI Write byte(s) to device
+ * @param  DataIn: Pointer to data buffer to write
+ * @param  DataOut: Pointer to data buffer for read data
+ * @param  DataLength: number of bytes to write
+ * @retval None
+ */
+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));
+}
+
+/**
+ * @brief  SPI Write a byte to device
+ * @param  Value: value to be written
+ * @retval None
+ */
+__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));
+}
+
+/******************************************************************************
+                            LINK OPERATIONS
+ *******************************************************************************/
+
+/********************************* LINK SD ************************************/
+/**
+ * @brief  Initialize the SD Card and put it into StandBy State (Ready for
+ *         data transfer).
+ * @retval None
+ */
+void SD_IO_Init(void) {
+    uint8_t counter = 0;
+
+    /* SD chip select high */
+    hal_gpio_write(sd_spi_dev->chip_select, true);
+    delay_us(10);
+
+    /* Send dummy byte 0xFF, 10 times with CS high */
+    /* Rise CS and MOSI for 80 clocks cycles */
+    for(counter = 0; counter <= 200; counter++) {
+        /* Send dummy byte 0xFF */
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+    }
+}
+
+/**
+ * @brief  Set SD interface Chip Select state
+ * @param  val: 0 (low) or 1 (high) state
+ * @retval None
+ */
+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 */
+    if(val == 1) {
+        delay_us(10); // Exit guard time for some SD cards
+        hal_gpio_write(sd_spi_dev->chip_select, true);
+    } else {
+        hal_gpio_write(sd_spi_dev->chip_select, false);
+        delay_us(10); // Entry guard time for some SD cards
+    }
+}
+
+/**
+ * @brief  Write byte(s) on the SD
+ * @param  DataIn: Pointer to data buffer to write
+ * @param  DataOut: Pointer to data buffer for read data
+ * @param  DataLength: number of bytes to write
+ * @retval None
+ */
+void SD_IO_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) {
+    /* Send the byte */
+    SPIx_WriteReadData(DataIn, DataOut, DataLength);
+}
+
+/**
+ * @brief  Write a byte on the SD.
+ * @param  Data: byte to send.
+ * @retval Data written
+ */
+uint8_t SD_IO_WriteByte(uint8_t Data) {
+    uint8_t tmp;
+
+    /* Send the byte */
+    SPIx_WriteReadData(&Data, &tmp, 1);
+    return tmp;
+}

+ 1073 - 0
firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.c

@@ -0,0 +1,1073 @@
+/**
+  ******************************************************************************
+  * @file    stm32_adafruit_sd.c
+  * @author  MCD Application Team
+  * @version V3.0.0
+  * @date    23-December-2016
+  * @brief   This file provides a set of functions needed to manage the SD card
+  *          mounted on the Adafruit 1.8" TFT LCD shield (reference ID 802),
+  *          that is used with the STM32 Nucleo board through SPI interface.
+  *          It implements a high level communication layer for read and write 
+  *          from/to this memory. The needed STM32XXxx hardware resources (SPI and 
+  *          GPIO) are defined in stm32XXxx_nucleo.h file, and the initialization is 
+  *          performed in SD_IO_Init() function declared in stm32XXxx_nucleo.c 
+  *          file.
+  *          You can easily tailor this driver to any other development board, 
+  *          by just adapting the defines for hardware resources and 
+  *          SD_IO_Init() function.
+  *            
+  *          +-------------------------------------------------------+
+  *          |                     Pin assignment                    |
+  *          +-------------------------+---------------+-------------+
+  *          |  STM32XXxx SPI Pins     |     SD        |    Pin      |
+  *          +-------------------------+---------------+-------------+
+  *          | SD_SPI_CS_PIN           |   ChipSelect  |    1        |
+  *          | SD_SPI_MOSI_PIN / MOSI  |   DataIn      |    2        |
+  *          |                         |   GND         |    3 (0 V)  |
+  *          |                         |   VDD         |    4 (3.3 V)|
+  *          | SD_SPI_SCK_PIN / SCLK   |   Clock       |    5        |
+  *          |                         |   GND         |    6 (0 V)  |
+  *          | SD_SPI_MISO_PIN / MISO  |   DataOut     |    7        |
+  *          +-------------------------+---------------+-------------+
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */
+
+/* File Info : -----------------------------------------------------------------
+                                   User NOTES
+1. How to use this driver:
+--------------------------
+   - This driver does not need a specific component driver for the micro SD device
+     to be included with.
+
+2. Driver description:
+---------------------
+  + Initialization steps:
+     o Initialize the micro SD card using the BSP_SD_Init() function. 
+     o Checking the SD card presence is not managed because SD detection pin is
+       not physically mapped on the Adafruit shield.
+     o The function BSP_SD_GetCardInfo() is used to get the micro SD card information 
+       which is stored in the structure "SD_CardInfo".
+  
+  + Micro SD card operations
+     o The micro SD card can be accessed with read/write block(s) operations once 
+       it is ready for access. The access can be performed in polling 
+       mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks()
+       
+     o The SD erase block(s) is performed using the function BSP_SD_Erase() with 
+       specifying the number of blocks to erase.
+     o The SD runtime status is returned when calling the function BSP_SD_GetStatus().
+     
+------------------------------------------------------------------------------*/
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_adafruit_sd.h"
+#include "stdlib.h"
+#include "string.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>
+
+/** @addtogroup BSP
+  * @{
+  */
+
+/** @addtogroup STM32_ADAFRUIT
+  * @{
+  */
+
+/** @defgroup STM32_ADAFRUIT_SD
+  * @{
+  */
+
+/* Private typedef -----------------------------------------------------------*/
+
+/** @defgroup STM32_ADAFRUIT_SD_Private_Types_Definitions
+  * @{
+  */
+typedef struct {
+    uint8_t r1;
+    uint8_t r2;
+    uint8_t r3;
+    uint8_t r4;
+    uint8_t r5;
+} SD_CmdAnswer_typedef;
+
+/**
+  * @}
+  */
+
+/* Private define ------------------------------------------------------------*/
+
+/** @defgroup STM32_ADAFRUIT_SD_Private_Defines
+  * @{
+  */
+#define SD_DUMMY_BYTE 0xFF
+
+#define SD_MAX_FRAME_LENGTH 17 /* Lenght = 16 + 1 */
+#define SD_CMD_LENGTH 6
+
+#define SD_MAX_TRY 100 /* Number of try */
+
+#define SD_CSD_STRUCT_V1 0x2 /* CSD struct version V1 */
+#define SD_CSD_STRUCT_V2 0x1 /* CSD struct version V2 */
+
+/**
+  * @brief  SD ansewer format
+  */
+typedef enum {
+    SD_ANSWER_R1_EXPECTED,
+    SD_ANSWER_R1B_EXPECTED,
+    SD_ANSWER_R2_EXPECTED,
+    SD_ANSWER_R3_EXPECTED,
+    SD_ANSWER_R4R5_EXPECTED,
+    SD_ANSWER_R7_EXPECTED,
+} SD_Answer_type;
+
+/**
+  * @brief  Start Data tokens:
+  *         Tokens (necessary because at nop/idle (and CS active) only 0xff is 
+  *         on the data/command line)  
+  */
+#define SD_TOKEN_START_DATA_SINGLE_BLOCK_READ \
+    0xFE /* Data token start byte, Start Single Block Read */
+#define SD_TOKEN_START_DATA_MULTIPLE_BLOCK_READ \
+    0xFE /* Data token start byte, Start Multiple Block Read */
+#define SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE \
+    0xFE /* Data token start byte, Start Single Block Write */
+#define SD_TOKEN_START_DATA_MULTIPLE_BLOCK_WRITE \
+    0xFD /* Data token start byte, Start Multiple Block Write */
+#define SD_TOKEN_STOP_DATA_MULTIPLE_BLOCK_WRITE \
+    0xFD /* Data toke stop byte, Stop Multiple Block Write */
+
+/**
+  * @brief  Commands: CMDxx = CMD-number | 0x40
+  */
+#define SD_CMD_GO_IDLE_STATE 0 /* CMD0 = 0x40  */
+#define SD_CMD_SEND_OP_COND 1 /* CMD1 = 0x41  */
+#define SD_CMD_SEND_IF_COND 8 /* CMD8 = 0x48  */
+#define SD_CMD_SEND_CSD 9 /* CMD9 = 0x49  */
+#define SD_CMD_SEND_CID 10 /* CMD10 = 0x4A */
+#define SD_CMD_STOP_TRANSMISSION 12 /* CMD12 = 0x4C */
+#define SD_CMD_SEND_STATUS 13 /* CMD13 = 0x4D */
+#define SD_CMD_SET_BLOCKLEN 16 /* CMD16 = 0x50 */
+#define SD_CMD_READ_SINGLE_BLOCK 17 /* CMD17 = 0x51 */
+#define SD_CMD_READ_MULT_BLOCK 18 /* CMD18 = 0x52 */
+#define SD_CMD_SET_BLOCK_COUNT 23 /* CMD23 = 0x57 */
+#define SD_CMD_WRITE_SINGLE_BLOCK 24 /* CMD24 = 0x58 */
+#define SD_CMD_WRITE_MULT_BLOCK 25 /* CMD25 = 0x59 */
+#define SD_CMD_PROG_CSD 27 /* CMD27 = 0x5B */
+#define SD_CMD_SET_WRITE_PROT 28 /* CMD28 = 0x5C */
+#define SD_CMD_CLR_WRITE_PROT 29 /* CMD29 = 0x5D */
+#define SD_CMD_SEND_WRITE_PROT 30 /* CMD30 = 0x5E */
+#define SD_CMD_SD_ERASE_GRP_START 32 /* CMD32 = 0x60 */
+#define SD_CMD_SD_ERASE_GRP_END 33 /* CMD33 = 0x61 */
+#define SD_CMD_UNTAG_SECTOR 34 /* CMD34 = 0x62 */
+#define SD_CMD_ERASE_GRP_START 35 /* CMD35 = 0x63 */
+#define SD_CMD_ERASE_GRP_END 36 /* CMD36 = 0x64 */
+#define SD_CMD_UNTAG_ERASE_GROUP 37 /* CMD37 = 0x65 */
+#define SD_CMD_ERASE 38 /* CMD38 = 0x66 */
+#define SD_CMD_SD_APP_OP_COND 41 /* CMD41 = 0x69 */
+#define SD_CMD_APP_CMD 55 /* CMD55 = 0x77 */
+#define SD_CMD_READ_OCR 58 /* CMD55 = 0x79 */
+
+/**
+  * @brief  SD reponses and error flags
+  */
+typedef enum {
+    /* R1 answer value */
+    SD_R1_NO_ERROR = (0x00),
+    SD_R1_IN_IDLE_STATE = (0x01),
+    SD_R1_ERASE_RESET = (0x02),
+    SD_R1_ILLEGAL_COMMAND = (0x04),
+    SD_R1_COM_CRC_ERROR = (0x08),
+    SD_R1_ERASE_SEQUENCE_ERROR = (0x10),
+    SD_R1_ADDRESS_ERROR = (0x20),
+    SD_R1_PARAMETER_ERROR = (0x40),
+
+    /* R2 answer value */
+    SD_R2_NO_ERROR = 0x00,
+    SD_R2_CARD_LOCKED = 0x01,
+    SD_R2_LOCKUNLOCK_ERROR = 0x02,
+    SD_R2_ERROR = 0x04,
+    SD_R2_CC_ERROR = 0x08,
+    SD_R2_CARD_ECC_FAILED = 0x10,
+    SD_R2_WP_VIOLATION = 0x20,
+    SD_R2_ERASE_PARAM = 0x40,
+    SD_R2_OUTOFRANGE = 0x80,
+
+    /**
+  * @brief  Data response error
+  */
+    SD_DATA_OK = (0x05),
+    SD_DATA_CRC_ERROR = (0x0B),
+    SD_DATA_WRITE_ERROR = (0x0D),
+    SD_DATA_OTHER_ERROR = (0xFF)
+} SD_Error;
+
+/**
+  * @}
+  */
+
+/* Private macro -------------------------------------------------------------*/
+
+/** @defgroup STM32_ADAFRUIT_SD_Private_Macros
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/* Private variables ---------------------------------------------------------*/
+
+/** @defgroup STM32_ADAFRUIT_SD_Private_Variables
+  * @{
+  */
+__IO uint8_t SdStatus = SD_NOT_PRESENT;
+
+/* flag_SDHC :
+      0 :  Standard capacity
+      1 : High capacity
+*/
+uint16_t flag_SDHC = 0;
+
+/**
+  * @}
+  */
+
+/* Private function prototypes -----------------------------------------------*/
+static uint8_t SD_GetCIDRegister(SD_CID* Cid);
+static uint8_t SD_GetCSDRegister(SD_CSD* Csd);
+static uint8_t SD_GetDataResponse(void);
+static uint8_t SD_GoIdleState(void);
+static SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t Answer);
+static uint8_t SD_WaitData(uint8_t data);
+static uint8_t SD_ReadData(void);
+/** @defgroup STM32_ADAFRUIT_SD_Private_Function_Prototypes
+  * @{
+  */
+/**
+  * @}
+  */
+
+/* Private functions ---------------------------------------------------------*/
+
+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);
+}
+
+void SD_SPI_Bus_To_Normal_State(){
+    hal_gpio_write(&gpio_sdcard_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);
+}
+
+/** @defgroup STM32_ADAFRUIT_SD_Private_Functions
+  * @{
+  */
+
+/**
+  * @brief  Initializes the SD/SD communication.
+  * @param  None
+  * @retval The SD Response: 
+  *         - MSD_ERROR: Sequence failed
+  *         - MSD_OK: Sequence succeed
+  */
+uint8_t BSP_SD_Init(bool reset_card) {
+    /* Slow speed init */
+    const FuriHalSpiDevice* sd_spi_slow_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardSlow);
+
+    /* We must reset card in spi_lock context */
+    if(reset_card) {
+        /* disable power and set low on all bus pins */
+        furi_hal_power_disable_external_3_3v();
+        SD_SPI_Bus_To_Down_State();
+        hal_sd_detect_set_low();
+        delay(250);
+
+        /* reinit bus and enable power */
+        SD_SPI_Bus_To_Normal_State();
+        hal_sd_detect_init();
+        furi_hal_power_enable_external_3_3v();
+        delay(100);
+    }
+
+    /* Configure IO functionalities for SD pin */
+    SD_IO_Init();
+
+    /* SD detection pin is not physically mapped on the Adafruit shield */
+    SdStatus = SD_PRESENT;
+    uint8_t res = BSP_SD_ERROR;
+
+    for(uint8_t i = 0; i < 128; i++) {
+        res = SD_GoIdleState();
+        if(res == BSP_SD_OK) break;
+    }
+
+    furi_hal_spi_device_return(sd_spi_slow_dev);
+
+    /* SD initialized and set to SPI mode properly */
+    return res;
+}
+
+/**
+  * @brief  Returns information about specific card.
+  * @param  pCardInfo: Pointer to a SD_CardInfo structure that contains all SD 
+  *         card information.
+  * @retval The SD Response:
+  *         - MSD_ERROR: Sequence failed
+  *         - MSD_OK: Sequence succeed
+  */
+uint8_t BSP_SD_GetCardInfo(SD_CardInfo* pCardInfo) {
+    uint8_t status;
+
+    status = SD_GetCSDRegister(&(pCardInfo->Csd));
+    status |= SD_GetCIDRegister(&(pCardInfo->Cid));
+    if(flag_SDHC == 1) {
+        pCardInfo->LogBlockSize = 512;
+        pCardInfo->CardBlockSize = 512;
+        pCardInfo->CardCapacity = ((uint64_t)pCardInfo->Csd.version.v2.DeviceSize + 1UL) * 1024UL *
+                                  (uint64_t)pCardInfo->LogBlockSize;
+        pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize);
+    } else {
+        pCardInfo->CardCapacity = (pCardInfo->Csd.version.v1.DeviceSize + 1);
+        pCardInfo->CardCapacity *= (1 << (pCardInfo->Csd.version.v1.DeviceSizeMul + 2));
+        pCardInfo->LogBlockSize = 512;
+        pCardInfo->CardBlockSize = 1 << (pCardInfo->Csd.RdBlockLen);
+        pCardInfo->CardCapacity *= pCardInfo->CardBlockSize;
+        pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize);
+    }
+
+    return status;
+}
+
+/**
+  * @brief  Reads block(s) from a specified address in the SD card, in polling mode. 
+  * @param  pData: Pointer to the buffer that will contain the data to transmit
+  * @param  ReadAddr: Address from where data is to be read. The address is counted 
+  *                   in blocks of 512bytes
+  * @param  NumOfBlocks: Number of SD blocks to read
+  * @param  Timeout: This parameter is used for compatibility with BSP implementation
+  * @retval SD status
+  */
+uint8_t
+BSP_SD_ReadBlocks(uint32_t* pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) {
+    uint32_t offset = 0;
+    uint32_t addr;
+    uint8_t retr = BSP_SD_ERROR;
+    uint8_t* ptr = NULL;
+    SD_CmdAnswer_typedef response;
+    uint16_t BlockSize = 512;
+
+    /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and 
+     Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */
+    response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED);
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+    if(response.r1 != SD_R1_NO_ERROR) {
+        goto error;
+    }
+
+    ptr = malloc(sizeof(uint8_t) * BlockSize);
+    if(ptr == NULL) {
+        goto error;
+    }
+    memset(ptr, SD_DUMMY_BYTE, sizeof(uint8_t) * BlockSize);
+
+    /* Initialize the address */
+    addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize));
+
+    /* Data transfer */
+    while(NumOfBlocks--) {
+        /* Send CMD17 (SD_CMD_READ_SINGLE_BLOCK) to read one block */
+        /* Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */
+        response = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, addr, 0xFF, SD_ANSWER_R1_EXPECTED);
+        if(response.r1 != SD_R1_NO_ERROR) {
+            goto error;
+        }
+
+        /* Now look for the data token to signify the start of the data */
+        if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) {
+            /* Read the SD block data : read NumByteToRead data */
+            SD_IO_WriteReadData(ptr, (uint8_t*)pData + offset, BlockSize);
+
+            /* Set next read address*/
+            offset += BlockSize;
+            addr = ((flag_SDHC == 1) ? (addr + 1) : (addr + BlockSize));
+
+            /* get CRC bytes (not really needed by us, but required by SD) */
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+        } else {
+            goto error;
+        }
+
+        /* End the command data read cycle */
+        SD_IO_CSState(1);
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+    }
+
+    retr = BSP_SD_OK;
+
+error:
+    /* Send dummy byte: 8 Clock pulses of delay */
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+    if(ptr != NULL) free(ptr);
+
+    /* Return the reponse */
+    return retr;
+}
+
+/**
+  * @brief  Writes block(s) to a specified address in the SD card, in polling mode. 
+  * @param  pData: Pointer to the buffer that will contain the data to transmit
+  * @param  WriteAddr: Address from where data is to be written. The address is counted 
+  *                   in blocks of 512bytes
+  * @param  NumOfBlocks: Number of SD blocks to write
+  * @param  Timeout: This parameter is used for compatibility with BSP implementation
+  * @retval SD status
+  */
+uint8_t
+BSP_SD_WriteBlocks(uint32_t* pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) {
+    uint32_t offset = 0;
+    uint32_t addr;
+    uint8_t retr = BSP_SD_ERROR;
+    uint8_t* ptr = NULL;
+    SD_CmdAnswer_typedef response;
+    uint16_t BlockSize = 512;
+
+    /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and 
+     Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */
+    response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED);
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+    if(response.r1 != SD_R1_NO_ERROR) {
+        goto error;
+    }
+
+    ptr = malloc(sizeof(uint8_t) * BlockSize);
+    if(ptr == NULL) {
+        goto error;
+    }
+
+    /* Initialize the address */
+    addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize));
+
+    /* Data transfer */
+    while(NumOfBlocks--) {
+        /* Send CMD24 (SD_CMD_WRITE_SINGLE_BLOCK) to write blocks  and
+       Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */
+        response = SD_SendCmd(SD_CMD_WRITE_SINGLE_BLOCK, addr, 0xFF, SD_ANSWER_R1_EXPECTED);
+        if(response.r1 != SD_R1_NO_ERROR) {
+            goto error;
+        }
+
+        /* Send dummy byte for NWR timing : one byte between CMDWRITE and TOKEN */
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+        /* Send the data token to signify the start of the data */
+        SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE);
+
+        /* Write the block data to SD */
+        SD_IO_WriteReadData((uint8_t*)pData + offset, ptr, BlockSize);
+
+        /* Set next write address */
+        offset += BlockSize;
+        addr = ((flag_SDHC == 1) ? (addr + 1) : (addr + BlockSize));
+        
+        /* Put CRC bytes (not really needed by us, but required by SD) */
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+        /* Read data response */
+        if(SD_GetDataResponse() != SD_DATA_OK) {
+            /* Set response value to failure */
+            goto error;
+        }
+
+        SD_IO_CSState(1);
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+    }
+    retr = BSP_SD_OK;
+
+error:
+    if(ptr != NULL) free(ptr);
+    /* Send dummy byte: 8 Clock pulses of delay */
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+    /* Return the reponse */
+    return retr;
+}
+
+/**
+  * @brief  Erases the specified memory area of the given SD card. 
+  * @param  StartAddr: Start address in Blocks (Size of a block is 512bytes)
+  * @param  EndAddr: End address in Blocks (Size of a block is 512bytes)
+  * @retval SD status
+  */
+uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) {
+    uint8_t retr = BSP_SD_ERROR;
+    SD_CmdAnswer_typedef response;
+    uint16_t BlockSize = 512;
+
+    /* Send CMD32 (Erase group start) and check if the SD acknowledged the erase command: R1 response (0x00: no errors) */
+    response = SD_SendCmd(
+        SD_CMD_SD_ERASE_GRP_START,
+        (StartAddr) * (flag_SDHC == 1 ? 1 : BlockSize),
+        0xFF,
+        SD_ANSWER_R1_EXPECTED);
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+    if(response.r1 == SD_R1_NO_ERROR) {
+        /* Send CMD33 (Erase group end) and Check if the SD acknowledged the erase command: R1 response (0x00: no errors) */
+        response = SD_SendCmd(
+            SD_CMD_SD_ERASE_GRP_END,
+            (EndAddr * 512) * (flag_SDHC == 1 ? 1 : BlockSize),
+            0xFF,
+            SD_ANSWER_R1_EXPECTED);
+        SD_IO_CSState(1);
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+        if(response.r1 == SD_R1_NO_ERROR) {
+            /* Send CMD38 (Erase) and Check if the SD acknowledged the erase command: R1 response (0x00: no errors) */
+            response = SD_SendCmd(SD_CMD_ERASE, 0, 0xFF, SD_ANSWER_R1B_EXPECTED);
+            if(response.r1 == SD_R1_NO_ERROR) {
+                retr = BSP_SD_OK;
+            }
+            SD_IO_CSState(1);
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+        }
+    }
+
+    /* Return the reponse */
+    return retr;
+}
+
+/**
+  * @brief  Returns the SD status.
+  * @param  None
+  * @retval The SD status.
+  */
+uint8_t BSP_SD_GetCardState(void) {
+    SD_CmdAnswer_typedef retr;
+
+    /* Send CMD13 (SD_SEND_STATUS) to get SD status */
+    retr = SD_SendCmd(SD_CMD_SEND_STATUS, 0, 0xFF, SD_ANSWER_R2_EXPECTED);
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+    /* Find SD status according to card state */
+    if((retr.r1 == SD_R1_NO_ERROR) && (retr.r2 == SD_R2_NO_ERROR)) {
+        return BSP_SD_OK;
+    }
+
+    return BSP_SD_ERROR;
+}
+
+/**
+  * @brief  Reads the SD card SCD register.
+  *         Reading the contents of the CSD register in SPI mode is a simple 
+  *         read-block transaction.
+  * @param  Csd: pointer on an SCD register structure
+  * @retval SD status
+  */
+uint8_t SD_GetCSDRegister(SD_CSD* Csd) {
+    uint16_t counter = 0;
+    uint8_t CSD_Tab[16];
+    uint8_t retr = BSP_SD_ERROR;
+    SD_CmdAnswer_typedef response;
+
+    /* Send CMD9 (CSD register) or CMD10(CSD register) and Wait for response in the R1 format (0x00 is no errors) */
+    response = SD_SendCmd(SD_CMD_SEND_CSD, 0, 0xFF, SD_ANSWER_R1_EXPECTED);
+    if(response.r1 == SD_R1_NO_ERROR) {
+        if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) {
+            for(counter = 0; counter < 16; counter++) {
+                /* Store CSD register value on CSD_Tab */
+                CSD_Tab[counter] = SD_IO_WriteByte(SD_DUMMY_BYTE);
+            }
+
+            /* Get CRC bytes (not really needed by us, but required by SD) */
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+            /*************************************************************************
+        CSD header decoding 
+      *************************************************************************/
+
+            /* Byte 0 */
+            Csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6;
+            Csd->Reserved1 = CSD_Tab[0] & 0x3F;
+
+            /* Byte 1 */
+            Csd->TAAC = CSD_Tab[1];
+
+            /* Byte 2 */
+            Csd->NSAC = CSD_Tab[2];
+
+            /* Byte 3 */
+            Csd->MaxBusClkFrec = CSD_Tab[3];
+
+            /* Byte 4/5 */
+            Csd->CardComdClasses = (CSD_Tab[4] << 4) | ((CSD_Tab[5] & 0xF0) >> 4);
+            Csd->RdBlockLen = CSD_Tab[5] & 0x0F;
+
+            /* Byte 6 */
+            Csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7;
+            Csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;
+            Csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;
+            Csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4;
+
+            /*************************************************************************
+        CSD v1/v2 decoding  
+      *************************************************************************/
+
+            if(flag_SDHC == 0) {
+                Csd->version.v1.Reserved1 = ((CSD_Tab[6] & 0x0C) >> 2);
+
+                Csd->version.v1.DeviceSize = ((CSD_Tab[6] & 0x03) << 10) | (CSD_Tab[7] << 2) |
+                                             ((CSD_Tab[8] & 0xC0) >> 6);
+                Csd->version.v1.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;
+                Csd->version.v1.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);
+                Csd->version.v1.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;
+                Csd->version.v1.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;
+                Csd->version.v1.DeviceSizeMul = ((CSD_Tab[9] & 0x03) << 1) |
+                                                ((CSD_Tab[10] & 0x80) >> 7);
+            } else {
+                Csd->version.v2.Reserved1 = ((CSD_Tab[6] & 0x0F) << 2) |
+                                            ((CSD_Tab[7] & 0xC0) >> 6);
+                Csd->version.v2.DeviceSize = ((CSD_Tab[7] & 0x3F) << 16) | (CSD_Tab[8] << 8) |
+                                             CSD_Tab[9];
+                Csd->version.v2.Reserved2 = ((CSD_Tab[10] & 0x80) >> 8);
+            }
+
+            Csd->EraseSingleBlockEnable = (CSD_Tab[10] & 0x40) >> 6;
+            Csd->EraseSectorSize = ((CSD_Tab[10] & 0x3F) << 1) | ((CSD_Tab[11] & 0x80) >> 7);
+            Csd->WrProtectGrSize = (CSD_Tab[11] & 0x7F);
+            Csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7;
+            Csd->Reserved2 = (CSD_Tab[12] & 0x60) >> 5;
+            Csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;
+            Csd->MaxWrBlockLen = ((CSD_Tab[12] & 0x03) << 2) | ((CSD_Tab[13] & 0xC0) >> 6);
+            Csd->WriteBlockPartial = (CSD_Tab[13] & 0x20) >> 5;
+            Csd->Reserved3 = (CSD_Tab[13] & 0x1F);
+            Csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7;
+            Csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6;
+            Csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;
+            Csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;
+            Csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2;
+            Csd->Reserved4 = (CSD_Tab[14] & 0x03);
+            Csd->crc = (CSD_Tab[15] & 0xFE) >> 1;
+            Csd->Reserved5 = (CSD_Tab[15] & 0x01);
+
+            retr = BSP_SD_OK;
+        }
+    }
+
+    /* Send dummy byte: 8 Clock pulses of delay */
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+    /* Return the reponse */
+    return retr;
+}
+
+/**
+  * @brief  Reads the SD card CID register.
+  *         Reading the contents of the CID register in SPI mode is a simple 
+  *         read-block transaction.
+  * @param  Cid: pointer on an CID register structure
+  * @retval SD status
+  */
+uint8_t SD_GetCIDRegister(SD_CID* Cid) {
+    uint32_t counter = 0;
+    uint8_t retr = BSP_SD_ERROR;
+    uint8_t CID_Tab[16];
+    SD_CmdAnswer_typedef response;
+
+    /* Send CMD10 (CID register) and Wait for response in the R1 format (0x00 is no errors) */
+    response = SD_SendCmd(SD_CMD_SEND_CID, 0, 0xFF, SD_ANSWER_R1_EXPECTED);
+    if(response.r1 == SD_R1_NO_ERROR) {
+        if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) {
+            /* Store CID register value on CID_Tab */
+            for(counter = 0; counter < 16; counter++) {
+                CID_Tab[counter] = SD_IO_WriteByte(SD_DUMMY_BYTE);
+            }
+
+            /* Get CRC bytes (not really needed by us, but required by SD) */
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+            /* Byte 0 */
+            Cid->ManufacturerID = CID_Tab[0];
+
+            /* Byte 1 */
+            Cid->OEM_AppliID = CID_Tab[1] << 8;
+
+            /* Byte 2 */
+            Cid->OEM_AppliID |= CID_Tab[2];
+
+            /* Byte 3 */
+            Cid->ProdName1 = CID_Tab[3] << 24;
+
+            /* Byte 4 */
+            Cid->ProdName1 |= CID_Tab[4] << 16;
+
+            /* Byte 5 */
+            Cid->ProdName1 |= CID_Tab[5] << 8;
+
+            /* Byte 6 */
+            Cid->ProdName1 |= CID_Tab[6];
+
+            /* Byte 7 */
+            Cid->ProdName2 = CID_Tab[7];
+
+            /* Byte 8 */
+            Cid->ProdRev = CID_Tab[8];
+
+            /* Byte 9 */
+            Cid->ProdSN = CID_Tab[9] << 24;
+
+            /* Byte 10 */
+            Cid->ProdSN |= CID_Tab[10] << 16;
+
+            /* Byte 11 */
+            Cid->ProdSN |= CID_Tab[11] << 8;
+
+            /* Byte 12 */
+            Cid->ProdSN |= CID_Tab[12];
+
+            /* Byte 13 */
+            Cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4;
+            Cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8;
+
+            /* Byte 14 */
+            Cid->ManufactDate |= CID_Tab[14];
+
+            /* Byte 15 */
+            Cid->CID_CRC = (CID_Tab[15] & 0xFE) >> 1;
+            Cid->Reserved2 = 1;
+
+            retr = BSP_SD_OK;
+        }
+    }
+
+    /* Send dummy byte: 8 Clock pulses of delay */
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+    /* Return the reponse */
+    return retr;
+}
+
+/**
+  * @brief  Sends 5 bytes command to the SD card and get response
+  * @param  Cmd: The user expected command to send to SD card.
+  * @param  Arg: The command argument.
+  * @param  Crc: The CRC.
+  * @param  Answer: SD_ANSWER_NOT_EXPECTED or SD_ANSWER_EXPECTED
+  * @retval SD status
+  */
+SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t Answer) {
+    uint8_t frame[SD_CMD_LENGTH], frameout[SD_CMD_LENGTH];
+    SD_CmdAnswer_typedef retr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+    /* R1 Lenght = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 1 Bytes answer + NEC(0) = 15bytes */
+    /* R1b identical to R1 + Busy information                                                   */
+    /* R2 Lenght = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 2 Bytes answer + NEC(0) = 16bytes */
+
+    /* Prepare Frame to send */
+    frame[0] = (Cmd | 0x40); /* Construct byte 1 */
+    frame[1] = (uint8_t)(Arg >> 24); /* Construct byte 2 */
+    frame[2] = (uint8_t)(Arg >> 16); /* Construct byte 3 */
+    frame[3] = (uint8_t)(Arg >> 8); /* Construct byte 4 */
+    frame[4] = (uint8_t)(Arg); /* Construct byte 5 */
+    frame[5] = (Crc | 0x01); /* Construct byte 6 */
+
+    /* Send the command */
+    SD_IO_CSState(0);
+    SD_IO_WriteReadData(frame, frameout, SD_CMD_LENGTH); /* Send the Cmd bytes */
+
+    switch(Answer) {
+    case SD_ANSWER_R1_EXPECTED:
+        retr.r1 = SD_ReadData();
+        break;
+    case SD_ANSWER_R1B_EXPECTED:
+        retr.r1 = SD_ReadData();
+        retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE);
+        /* Set CS High */
+        SD_IO_CSState(1);
+        HAL_Delay(1);
+        /* Set CS Low */
+        SD_IO_CSState(0);
+
+        /* Wait IO line return 0xFF */
+        while(SD_IO_WriteByte(SD_DUMMY_BYTE) != 0xFF)
+            ;
+        break;
+    case SD_ANSWER_R2_EXPECTED:
+        retr.r1 = SD_ReadData();
+        retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE);
+        break;
+    case SD_ANSWER_R3_EXPECTED:
+    case SD_ANSWER_R7_EXPECTED:
+        retr.r1 = SD_ReadData();
+        retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE);
+        retr.r3 = SD_IO_WriteByte(SD_DUMMY_BYTE);
+        retr.r4 = SD_IO_WriteByte(SD_DUMMY_BYTE);
+        retr.r5 = SD_IO_WriteByte(SD_DUMMY_BYTE);
+        break;
+    default:
+        break;
+    }
+    return retr;
+}
+
+/**
+  * @brief  Gets the SD card data response and check the busy flag.
+  * @param  None
+  * @retval The SD status: Read data response xxx0<status>1
+  *         - status 010: Data accecpted
+  *         - status 101: Data rejected due to a crc error
+  *         - status 110: Data rejected due to a Write error.
+  *         - status 111: Data rejected due to other error.
+  */
+uint8_t SD_GetDataResponse(void) {
+    uint8_t dataresponse;
+    uint8_t rvalue = SD_DATA_OTHER_ERROR;
+
+    dataresponse = SD_IO_WriteByte(SD_DUMMY_BYTE);
+    SD_IO_WriteByte(SD_DUMMY_BYTE); /* read the busy response byte*/
+
+    /* Mask unused bits */
+    switch(dataresponse & 0x1F) {
+    case SD_DATA_OK:
+        rvalue = SD_DATA_OK;
+
+        /* Set CS High */
+        SD_IO_CSState(1);
+        /* Set CS Low */
+        SD_IO_CSState(0);
+
+        /* Wait IO line return 0xFF */
+        while(SD_IO_WriteByte(SD_DUMMY_BYTE) != 0xFF)
+            ;
+        break;
+    case SD_DATA_CRC_ERROR:
+        rvalue = SD_DATA_CRC_ERROR;
+        break;
+    case SD_DATA_WRITE_ERROR:
+        rvalue = SD_DATA_WRITE_ERROR;
+        break;
+    default:
+        break;
+    }
+
+    /* Return response */
+    return rvalue;
+}
+
+/**
+  * @brief  Put the SD in Idle state.
+  * @param  None
+  * @retval SD status
+  */
+uint8_t SD_GoIdleState(void) {
+    SD_CmdAnswer_typedef response;
+    __IO uint8_t counter;
+    /* Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode and 
+     wait for In Idle State Response (R1 Format) equal to 0x01 */
+    counter = 0;
+    do {
+        counter++;
+        response = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95, SD_ANSWER_R1_EXPECTED);
+        SD_IO_CSState(1);
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+        if(counter >= SD_MAX_TRY) {
+            return BSP_SD_ERROR;
+        }
+    } while(response.r1 != SD_R1_IN_IDLE_STATE);
+
+    /* Send CMD8 (SD_CMD_SEND_IF_COND) to check the power supply status 
+     and wait until response (R7 Format) equal to 0xAA and */
+    response = SD_SendCmd(SD_CMD_SEND_IF_COND, 0x1AA, 0x87, SD_ANSWER_R7_EXPECTED);
+    SD_IO_CSState(1);
+    SD_IO_WriteByte(SD_DUMMY_BYTE);
+    if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) {
+        /* initialise card V1 */
+        counter = 0;
+        do {
+            counter++;
+            /* initialise card V1 */
+            /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */
+            response = SD_SendCmd(SD_CMD_APP_CMD, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED);
+            SD_IO_CSState(1);
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+            /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */
+            response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED);
+            SD_IO_CSState(1);
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+            if(counter >= SD_MAX_TRY) {
+                return BSP_SD_ERROR;
+            }
+        } while(response.r1 == SD_R1_IN_IDLE_STATE);
+        flag_SDHC = 0;
+    } else if(response.r1 == SD_R1_IN_IDLE_STATE) {
+        /* initialise card V2 */
+        counter = 0;
+        do {
+            counter++;
+            /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */
+            response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED);
+            SD_IO_CSState(1);
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+
+            /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */
+            response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x40000000, 0xFF, SD_ANSWER_R1_EXPECTED);
+            SD_IO_CSState(1);
+            SD_IO_WriteByte(SD_DUMMY_BYTE);
+            if(counter >= SD_MAX_TRY) {
+                return BSP_SD_ERROR;
+            }
+        } while(response.r1 == SD_R1_IN_IDLE_STATE);
+
+        if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) {
+            counter = 0;
+            do {
+                counter++;
+                /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */
+                response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED);
+                SD_IO_CSState(1);
+                SD_IO_WriteByte(SD_DUMMY_BYTE);
+                if(response.r1 != SD_R1_IN_IDLE_STATE) {
+                    return BSP_SD_ERROR;
+                }
+                /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */
+                response =
+                    SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED);
+                SD_IO_CSState(1);
+                SD_IO_WriteByte(SD_DUMMY_BYTE);
+                if(counter >= SD_MAX_TRY) {
+                    return BSP_SD_ERROR;
+                }
+            } while(response.r1 == SD_R1_IN_IDLE_STATE);
+        }
+
+        /* Send CMD58 (SD_CMD_READ_OCR) to initialize SDHC or SDXC cards: R3 response (0x00: no errors) */
+        response = SD_SendCmd(SD_CMD_READ_OCR, 0x00000000, 0xFF, SD_ANSWER_R3_EXPECTED);
+        SD_IO_CSState(1);
+        SD_IO_WriteByte(SD_DUMMY_BYTE);
+        if(response.r1 != SD_R1_NO_ERROR) {
+            return BSP_SD_ERROR;
+        }
+        flag_SDHC = (response.r2 & 0x40) >> 6;
+    } else {
+        return BSP_SD_ERROR;
+    }
+
+    return BSP_SD_OK;
+}
+
+/**
+  * @brief  Waits a data until a value different from SD_DUMMY_BITE
+  * @param  None
+  * @retval the value read
+  */
+uint8_t SD_ReadData(void) {
+    uint8_t timeout = 0x08;
+    uint8_t readvalue;
+
+    /* Check if response is got or a timeout is happen */
+    do {
+        readvalue = SD_IO_WriteByte(SD_DUMMY_BYTE);
+        timeout--;
+
+    } while((readvalue == SD_DUMMY_BYTE) && timeout);
+
+    /* Right response got */
+    return readvalue;
+}
+
+/**
+  * @brief  Waits a data from the SD card
+  * @param  data : Expected data from the SD card
+  * @retval BSP_SD_OK or BSP_SD_TIMEOUT
+  */
+uint8_t SD_WaitData(uint8_t data) {
+    uint16_t timeout = 0xFFFF;
+    uint8_t readvalue;
+
+    /* Check if response is got or a timeout is happen */
+
+    do {
+        readvalue = SD_IO_WriteByte(SD_DUMMY_BYTE);
+        timeout--;
+    } while((readvalue != data) && timeout);
+
+    if(timeout == 0) {
+        /* After time out */
+        return BSP_SD_TIMEOUT;
+    }
+
+    /* Right response got */
+    return BSP_SD_OK;
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 252 - 0
firmware/targets/f7/Src/fatfs/stm32_adafruit_sd.h

@@ -0,0 +1,252 @@
+/**
+  ******************************************************************************
+  * @file    stm32_adafruit_sd.h
+  * @author  MCD Application Team
+  * @version V3.0.0
+  * @date    23-December-2016
+  * @brief   This file contains the common defines and functions prototypes for
+  *          the stm32_adafruit_sd.c driver.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */ 
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32_ADAFRUIT_SD_H
+#define __STM32_ADAFRUIT_SD_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif 
+
+/* Includes ------------------------------------------------------------------*/
+#include <stdint.h>
+#include <stdbool.h>
+
+/** @addtogroup BSP
+  * @{
+  */ 
+#define __IO    volatile   
+   
+/** @addtogroup STM32_ADAFRUIT
+  * @{
+  */
+    
+/** @defgroup STM32_ADAFRUIT_SD
+  * @{
+  */    
+
+/** @defgroup STM32_ADAFRUIT_SD_Exported_Types
+  * @{
+  */
+   
+/** 
+  * @brief  SD status structure definition  
+  */     
+enum {    
+      BSP_SD_OK = 0x00,      
+      MSD_OK = 0x00,
+      BSP_SD_ERROR = 0x01,
+      BSP_SD_TIMEOUT
+};
+   
+typedef struct              
+{
+  uint8_t  Reserved1:2;               /* Reserved */
+  uint16_t DeviceSize:12;             /* Device Size */
+  uint8_t  MaxRdCurrentVDDMin:3;      /* Max. read current @ VDD min */
+  uint8_t  MaxRdCurrentVDDMax:3;      /* Max. read current @ VDD max */
+  uint8_t  MaxWrCurrentVDDMin:3;      /* Max. write current @ VDD min */
+  uint8_t  MaxWrCurrentVDDMax:3;      /* Max. write current @ VDD max */
+  uint8_t  DeviceSizeMul:3;           /* Device size multiplier */
+} struct_v1;
+
+
+typedef struct              
+{
+  uint8_t  Reserved1:6;               /* Reserved */
+  uint32_t DeviceSize:22;             /* Device Size */
+  uint8_t  Reserved2:1;               /* Reserved */
+} struct_v2;
+
+/** 
+  * @brief  Card Specific Data: CSD Register
+  */ 
+typedef struct
+{
+  /* Header part */
+  uint8_t  CSDStruct:2;            /* CSD structure */
+  uint8_t  Reserved1:6;            /* Reserved */
+  uint8_t  TAAC:8;                 /* Data read access-time 1 */
+  uint8_t  NSAC:8;                 /* Data read access-time 2 in CLK cycles */
+  uint8_t  MaxBusClkFrec:8;        /* Max. bus clock frequency */
+  uint16_t CardComdClasses:12;      /* Card command classes */
+  uint8_t  RdBlockLen:4;           /* Max. read data block length */
+  uint8_t  PartBlockRead:1;        /* Partial blocks for read allowed */
+  uint8_t  WrBlockMisalign:1;      /* Write block misalignment */
+  uint8_t  RdBlockMisalign:1;      /* Read block misalignment */
+  uint8_t  DSRImpl:1;              /* DSR implemented */
+  
+  /* v1 or v2 struct */
+  union csd_version {
+    struct_v1 v1;
+    struct_v2 v2;
+  } version;
+  
+  uint8_t  EraseSingleBlockEnable:1;  /* Erase single block enable */
+  uint8_t  EraseSectorSize:7;         /* Erase group size multiplier */
+  uint8_t  WrProtectGrSize:7;         /* Write protect group size */
+  uint8_t  WrProtectGrEnable:1;       /* Write protect group enable */
+  uint8_t  Reserved2:2;               /* Reserved */
+  uint8_t  WrSpeedFact:3;             /* Write speed factor */
+  uint8_t  MaxWrBlockLen:4;           /* Max. write data block length */
+  uint8_t  WriteBlockPartial:1;       /* Partial blocks for write allowed */
+  uint8_t  Reserved3:5;               /* Reserved */
+  uint8_t  FileFormatGrouop:1;        /* File format group */
+  uint8_t  CopyFlag:1;                /* Copy flag (OTP) */
+  uint8_t  PermWrProtect:1;           /* Permanent write protection */
+  uint8_t  TempWrProtect:1;           /* Temporary write protection */
+  uint8_t  FileFormat:2;              /* File Format */
+  uint8_t  Reserved4:2;               /* Reserved */
+  uint8_t  crc:7;                     /* Reserved */
+  uint8_t  Reserved5:1;               /* always 1*/
+  
+} SD_CSD;
+
+/** 
+  * @brief  Card Identification Data: CID Register   
+  */
+typedef struct
+{
+  __IO uint8_t  ManufacturerID;       /* ManufacturerID */
+  __IO uint16_t OEM_AppliID;          /* OEM/Application ID */
+  __IO uint32_t ProdName1;            /* Product Name part1 */
+  __IO uint8_t  ProdName2;            /* Product Name part2*/
+  __IO uint8_t  ProdRev;              /* Product Revision */
+  __IO uint32_t ProdSN;               /* Product Serial Number */
+  __IO uint8_t  Reserved1;            /* Reserved1 */
+  __IO uint16_t ManufactDate;         /* Manufacturing Date */
+  __IO uint8_t  CID_CRC;              /* CID CRC */
+  __IO uint8_t  Reserved2;            /* always 1 */
+} SD_CID;
+
+/** 
+  * @brief SD Card information 
+  */
+typedef struct
+{
+  SD_CSD Csd;
+  SD_CID Cid;
+  uint64_t CardCapacity;              /*!< Card Capacity */
+  uint32_t CardBlockSize;             /*!< Card Block Size */
+  uint32_t LogBlockNbr;               /*!< Specifies the Card logical Capacity in blocks   */
+  uint32_t LogBlockSize;              /*!< Specifies logical block size in bytes           */
+} SD_CardInfo;
+
+/**
+  * @}
+  */
+  
+/** @defgroup STM32_ADAFRUIT_SPI_SD_Exported_Constants
+  * @{
+  */ 
+  
+/**
+  * @brief  Block Size
+  */
+#define SD_BLOCK_SIZE    0x200
+
+/**
+  * @brief  SD detection on its memory slot
+  */
+#define SD_PRESENT               ((uint8_t)0x01)
+#define SD_NOT_PRESENT           ((uint8_t)0x00)
+
+#define SD_DATATIMEOUT           ((uint32_t)100000000)
+
+/** 
+  * @brief SD Card information structure 
+  */   
+#define BSP_SD_CardInfo SD_CardInfo
+
+/**
+  * @}
+  */
+  
+/** @defgroup STM32_ADAFRUIT_SD_Exported_Macro
+  * @{
+  */ 
+
+/**
+  * @}
+  */ 
+
+/** @defgroup STM32_ADAFRUIT_SD_Exported_Functions
+  * @{
+  */   
+uint8_t BSP_SD_Init(bool reset_card);
+uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout);
+uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout);
+uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr);
+uint8_t BSP_SD_GetCardState(void);
+uint8_t BSP_SD_GetCardInfo(SD_CardInfo *pCardInfo);
+   
+/* Link functions for SD Card peripheral*/
+void    SD_SPI_Slow_Init(void);
+void    SD_SPI_Fast_Init(void);
+void    SD_IO_Init(void);
+void    SD_IO_CSState(uint8_t state);
+void    SD_IO_WriteReadData(const uint8_t *DataIn, uint8_t *DataOut, uint16_t DataLength);
+uint8_t SD_IO_WriteByte(uint8_t Data);
+
+/* Link function for HAL delay */
+void HAL_Delay(__IO uint32_t Delay);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32_ADAFRUIT_SD_H */
+
+/**
+  * @}
+  */ 
+
+/**
+  * @}
+  */ 
+
+/**
+  * @}
+  */ 
+
+/**
+  * @}
+  */ 
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 138 - 0
firmware/targets/f7/Src/fatfs/syscall.c

@@ -0,0 +1,138 @@
+/*------------------------------------------------------------------------*/
+/* Sample code of OS dependent controls for FatFs                         */
+/* (C)ChaN, 2014                                                          */
+/*   Portions COPYRIGHT 2017 STMicroelectronics                           */
+/*   Portions Copyright (C) 2014, ChaN, all right reserved                */
+/*------------------------------------------------------------------------*/
+
+/**
+  ******************************************************************************
+  * @attention
+  *
+  * Copyright (c) 2017 STMicroelectronics. All rights reserved.
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the
+  * License. You may obtain a copy of the License at:
+  *                       opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+**/
+
+
+
+#include "fatfs/ff.h"
+
+
+#if _FS_REENTRANT
+/*------------------------------------------------------------------------*/
+/* Create a Synchronization Object                                        */
+/*------------------------------------------------------------------------*/
+/* This function is called in f_mount() function to create a new
+/  synchronization object, such as semaphore and mutex. When a 0 is returned,
+/  the f_mount() function fails with FR_INT_ERR.
+*/
+
+int ff_cre_syncobj (	/* 1:Function succeeded, 0:Could not create the sync object */
+	BYTE vol,			/* Corresponding volume (logical drive number) */
+	_SYNC_t *sobj		/* Pointer to return the created sync object */
+)
+{
+
+    int ret;
+
+    //osSemaphoreDef(SEM);
+    //*sobj = osSemaphoreCreate(osSemaphore(SEM), 1);
+    *sobj = osMutexNew(NULL);
+    ret = (*sobj != NULL);
+
+    return ret;
+}
+
+
+
+/*------------------------------------------------------------------------*/
+/* Delete a Synchronization Object                                        */
+/*------------------------------------------------------------------------*/
+/* This function is called in f_mount() function to delete a synchronization
+/  object that created with ff_cre_syncobj() function. When a 0 is returned,
+/  the f_mount() function fails with FR_INT_ERR.
+*/
+
+int ff_del_syncobj (	/* 1:Function succeeded, 0:Could not delete due to any error */
+	_SYNC_t sobj		/* Sync object tied to the logical drive to be deleted */
+)
+{
+    osMutexDelete(sobj);
+    return 1;
+}
+
+
+
+/*------------------------------------------------------------------------*/
+/* Request Grant to Access the Volume                                     */
+/*------------------------------------------------------------------------*/
+/* This function is called on entering file functions to lock the volume.
+/  When a 0 is returned, the file function fails with FR_TIMEOUT.
+*/
+
+int ff_req_grant (	/* 1:Got a grant to access the volume, 0:Could not get a grant */
+	_SYNC_t sobj	/* Sync object to wait */
+)
+{
+  int ret = 0;
+
+  if(osMutexAcquire(sobj, _FS_TIMEOUT) == osOK) {
+      ret = 1;
+  }
+
+  return ret;
+}
+
+
+
+/*------------------------------------------------------------------------*/
+/* Release Grant to Access the Volume                                     */
+/*------------------------------------------------------------------------*/
+/* This function is called on leaving file functions to unlock the volume.
+*/
+
+void ff_rel_grant (
+	_SYNC_t sobj	/* Sync object to be signaled */
+)
+{
+    osMutexRelease(sobj);
+}
+
+#endif
+
+
+
+
+#if _USE_LFN == 3	/* LFN with a working buffer on the heap */
+/*------------------------------------------------------------------------*/
+/* Allocate a memory block                                                */
+/*------------------------------------------------------------------------*/
+/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
+*/
+
+void* ff_memalloc (	/* Returns pointer to the allocated memory block */
+	UINT msize		/* Number of bytes to allocate */
+)
+{
+	return ff_malloc(msize);	/* Allocate a new memory block with POSIX API */
+}
+
+
+/*------------------------------------------------------------------------*/
+/* Free a memory block                                                    */
+/*------------------------------------------------------------------------*/
+
+void ff_memfree (
+	void* mblock	/* Pointer to the memory block to free */
+)
+{
+	ff_free(mblock);	/* Discard the memory block with POSIX API */
+}
+
+#endif

+ 223 - 0
firmware/targets/f7/Src/fatfs/user_diskio.c

@@ -0,0 +1,223 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file    user_diskio.c
+ * @brief   This file includes a diskio driver skeleton to be completed by the user.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+ * All rights reserved.</center></h2>
+ *
+ * This software component is licensed by ST under Ultimate Liberty license
+ * SLA0044, the "License"; You may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ *                             www.st.com/SLA0044
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+
+#ifdef USE_OBSOLETE_USER_CODE_SECTION_0
+/* 
+ * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0)
+ * To be suppressed in the future. 
+ * Kept to ensure backward compatibility with previous CubeMx versions when 
+ * migrating projects. 
+ * User code previously added there should be copied in the new user sections before 
+ * the section contents can be deleted.
+ */
+/* USER CODE BEGIN 0 */
+/* USER CODE END 0 */
+#endif
+
+/* USER CODE BEGIN DECL */
+
+/* Includes ------------------------------------------------------------------*/
+#include "user_diskio.h"
+#include "furi-hal-spi.h"
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+
+/* Private variables ---------------------------------------------------------*/
+/* Disk status */
+static volatile DSTATUS Stat = STA_NOINIT;
+
+static DSTATUS User_CheckStatus(BYTE lun) {
+    Stat = STA_NOINIT;
+    if(BSP_SD_GetCardState() == MSD_OK) {
+        Stat &= ~STA_NOINIT;
+    }
+
+    return Stat;
+}
+
+/* USER CODE END DECL */
+
+/* Private function prototypes -----------------------------------------------*/
+DSTATUS USER_initialize(BYTE pdrv);
+DSTATUS USER_status(BYTE pdrv);
+DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
+#if _USE_WRITE == 1
+DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
+#endif /* _USE_WRITE == 1 */
+#if _USE_IOCTL == 1
+DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff);
+#endif /* _USE_IOCTL == 1 */
+
+Diskio_drvTypeDef USER_Driver = {
+    USER_initialize,
+    USER_status,
+    USER_read,
+#if _USE_WRITE
+    USER_write,
+#endif /* _USE_WRITE == 1 */
+#if _USE_IOCTL == 1
+    USER_ioctl,
+#endif /* _USE_IOCTL == 1 */
+};
+
+/* Private functions ---------------------------------------------------------*/
+
+/**
+  * @brief  Initializes a Drive
+  * @param  pdrv: Physical drive number (0..)
+  * @retval DSTATUS: Operation status
+  */
+DSTATUS USER_initialize(BYTE pdrv) {
+    /* USER CODE BEGIN INIT */
+
+    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+
+    DSTATUS status = User_CheckStatus(pdrv);
+
+    furi_hal_spi_device_return(sd_spi_fast_dev);
+
+    return status;
+    /* USER CODE END INIT */
+}
+
+/**
+  * @brief  Gets Disk Status 
+  * @param  pdrv: Physical drive number (0..)
+  * @retval DSTATUS: Operation status
+  */
+DSTATUS USER_status(BYTE pdrv) {
+    /* USER CODE BEGIN STATUS */
+    return Stat;
+    /* USER CODE END STATUS */
+}
+
+/**
+  * @brief  Reads Sector(s) 
+  * @param  pdrv: Physical drive number (0..)
+  * @param  *buff: Data buffer to store read data
+  * @param  sector: Sector address (LBA)
+  * @param  count: Number of sectors to read (1..128)
+  * @retval DRESULT: Operation result
+  */
+DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
+    /* USER CODE BEGIN READ */
+    DRESULT res = RES_ERROR;
+
+    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+
+    if(BSP_SD_ReadBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
+        /* wait until the read operation is finished */
+        while(BSP_SD_GetCardState() != MSD_OK) {
+        }
+        res = RES_OK;
+    }
+
+    furi_hal_spi_device_return(sd_spi_fast_dev);
+
+    return res;
+    /* USER CODE END READ */
+}
+
+/**
+  * @brief  Writes Sector(s)  
+  * @param  pdrv: Physical drive number (0..)
+  * @param  *buff: Data to be written
+  * @param  sector: Sector address (LBA)
+  * @param  count: Number of sectors to write (1..128)
+  * @retval DRESULT: Operation result
+  */
+#if _USE_WRITE == 1
+DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
+    /* USER CODE BEGIN WRITE */
+    /* USER CODE HERE */
+    DRESULT res = RES_ERROR;
+
+    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+
+    if(BSP_SD_WriteBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) {
+        /* wait until the Write operation is finished */
+        while(BSP_SD_GetCardState() != MSD_OK) {
+        }
+        res = RES_OK;
+    }
+
+    furi_hal_spi_device_return(sd_spi_fast_dev);
+
+    return res;
+    /* USER CODE END WRITE */
+}
+#endif /* _USE_WRITE == 1 */
+
+/**
+  * @brief  I/O control operation  
+  * @param  pdrv: Physical drive number (0..)
+  * @param  cmd: Control code
+  * @param  *buff: Buffer to send/receive control data
+  * @retval DRESULT: Operation result
+  */
+#if _USE_IOCTL == 1
+DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
+    /* USER CODE BEGIN IOCTL */
+    DRESULT res = RES_ERROR;
+    BSP_SD_CardInfo CardInfo;
+
+    if(Stat & STA_NOINIT) return RES_NOTRDY;
+
+    const FuriHalSpiDevice* sd_spi_fast_dev = furi_hal_spi_device_get(FuriHalSpiDeviceIdSdCardFast);
+
+    switch(cmd) {
+    /* Make sure that no pending write process */
+    case CTRL_SYNC:
+        res = RES_OK;
+        break;
+
+    /* Get number of sectors on the disk (DWORD) */
+    case GET_SECTOR_COUNT:
+        BSP_SD_GetCardInfo(&CardInfo);
+        *(DWORD*)buff = CardInfo.LogBlockNbr;
+        res = RES_OK;
+        break;
+
+    /* Get R/W sector size (WORD) */
+    case GET_SECTOR_SIZE:
+        BSP_SD_GetCardInfo(&CardInfo);
+        *(WORD*)buff = CardInfo.LogBlockSize;
+        res = RES_OK;
+        break;
+
+    /* Get erase block size in unit of sector (DWORD) */
+    case GET_BLOCK_SIZE:
+        BSP_SD_GetCardInfo(&CardInfo);
+        *(DWORD*)buff = CardInfo.LogBlockSize;
+        res = RES_OK;
+        break;
+
+    default:
+        res = RES_PARERR;
+    }
+
+    furi_hal_spi_device_return(sd_spi_fast_dev);
+
+    return res;
+    /* USER CODE END IOCTL */
+}
+#endif /* _USE_IOCTL == 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 48 - 0
firmware/targets/f7/Src/fatfs/user_diskio.h

@@ -0,0 +1,48 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+  * @file    user_diskio.h
+  * @brief   This file contains the common defines and functions prototypes for  
+  *          the user_diskio driver.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USER_DISKIO_H
+#define __USER_DISKIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* USER CODE BEGIN 0 */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32_adafruit_sd.h"
+#include "fatfs/ff_gen_drv.h"
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+extern Diskio_drvTypeDef USER_Driver;
+
+/* USER CODE END 0 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USER_DISKIO_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 21 - 0
firmware/targets/f7/Src/freertos-openocd.c

@@ -0,0 +1,21 @@
+
+/*
+ * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer
+ * present in the kernel, so it has to be supplied by other means for
+ * OpenOCD's threads awareness.
+ *
+ * Add this file to your project, and, if you're using --gc-sections,
+ * ``--undefined=uxTopUsedPriority'' (or
+ * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final
+ * linking) to your LDFLAGS; same with all the other symbols you need.
+ */
+
+#include "FreeRTOS.h"
+
+#ifdef __GNUC__
+#define USED __attribute__((used))
+#else
+#define USED
+#endif
+
+const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1;

+ 139 - 0
firmware/targets/f7/Src/gpio.c

@@ -0,0 +1,139 @@
+#include "gpio.h"
+
+void MX_GPIO_Init(void) {
+    GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+    /* GPIO Ports Clock Enable */
+    __HAL_RCC_GPIOA_CLK_ENABLE();
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    __HAL_RCC_GPIOC_CLK_ENABLE();
+    __HAL_RCC_GPIOD_CLK_ENABLE();
+    __HAL_RCC_GPIOE_CLK_ENABLE();
+    __HAL_RCC_GPIOH_CLK_ENABLE();
+
+    /*Configure GPIO pin : PtPin */
+    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+    GPIO_InitStruct.Pull = GPIO_PULLUP;
+    GPIO_InitStruct.Pin = BUTTON_BACK_Pin;
+    HAL_GPIO_Init(BUTTON_BACK_GPIO_Port, &GPIO_InitStruct);
+
+    /*Configure GPIO pin : PtPin */
+    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Pin = BUTTON_OK_Pin;
+    HAL_GPIO_Init(BUTTON_OK_GPIO_Port, &GPIO_InitStruct);
+
+    /*Configure GPIO pins : PCPin PCPin PCPin PCPin */
+    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Pin = PC0_Pin;
+    HAL_GPIO_Init(PC0_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = PC1_Pin;
+    HAL_GPIO_Init(PC1_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = PC3_Pin;
+    HAL_GPIO_Init(PC3_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = VIBRO_Pin;
+    HAL_GPIO_Init(VIBRO_GPIO_Port, &GPIO_InitStruct);
+
+    /* RF_SW_0 */
+    HAL_GPIO_WritePin(RF_SW_0_GPIO_Port, RF_SW_0_Pin, GPIO_PIN_RESET);
+    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Pin = RF_SW_0_Pin;
+    HAL_GPIO_Init(RF_SW_0_GPIO_Port, &GPIO_InitStruct);
+
+    /* PERIPH_POWER */
+    HAL_GPIO_WritePin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin, GPIO_PIN_SET);
+    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Pin = PERIPH_POWER_Pin;
+    HAL_GPIO_Init(PERIPH_POWER_GPIO_Port, &GPIO_InitStruct);
+
+    /*Configure GPIO pins : PAPin PAPin PAPin */
+    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Pin = PA4_Pin;
+    HAL_GPIO_Init(PA4_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = PA6_Pin;
+    HAL_GPIO_Init(PA6_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = PA7_Pin;
+    HAL_GPIO_Init(PA7_GPIO_Port, &GPIO_InitStruct);
+
+    /*Configure GPIO pin : PtPin */
+    GPIO_InitStruct.Pin = RFID_PULL_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    HAL_GPIO_Init(RFID_PULL_GPIO_Port, &GPIO_InitStruct);
+
+    /*Configure GPIO pins : PBPin PBPin PBPin */
+    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Pin = PB2_Pin;
+    HAL_GPIO_Init(PB2_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = iBTN_Pin;
+    HAL_GPIO_Init(iBTN_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = PB3_Pin;
+    HAL_GPIO_Init(PB3_GPIO_Port, &GPIO_InitStruct);
+
+    /*Configure GPIO pins : PBPin PBPin PBPin PBPin */
+    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+    GPIO_InitStruct.Pull = GPIO_PULLUP;
+    GPIO_InitStruct.Pin = BUTTON_UP_Pin;
+    HAL_GPIO_Init(BUTTON_UP_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = BUTTON_LEFT_Pin;
+    HAL_GPIO_Init(BUTTON_LEFT_GPIO_Port, &GPIO_InitStruct);
+    GPIO_InitStruct.Pin = BUTTON_RIGHT_Pin;
+    HAL_GPIO_Init(BUTTON_RIGHT_GPIO_Port, &GPIO_InitStruct);
+
+    /*Configure GPIO pins : PBPin PBPin PBPin PBPin */
+    GPIO_InitStruct.Pin = BUTTON_DOWN_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+    GPIO_InitStruct.Pull = GPIO_PULLUP;
+    HAL_GPIO_Init(BUTTON_DOWN_GPIO_Port, &GPIO_InitStruct);
+
+    /* DISPLAY_RST */
+    HAL_GPIO_WritePin(DISPLAY_RST_GPIO_Port, DISPLAY_RST_Pin, GPIO_PIN_RESET);
+    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Pin = DISPLAY_RST_Pin;
+    HAL_GPIO_Init(DISPLAY_RST_GPIO_Port, &GPIO_InitStruct);
+
+    /* DISPLAY_DI */
+    HAL_GPIO_WritePin(DISPLAY_DI_GPIO_Port, DISPLAY_DI_Pin, GPIO_PIN_RESET);
+    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Pin = DISPLAY_DI_Pin;
+    HAL_GPIO_Init(DISPLAY_DI_GPIO_Port, &GPIO_InitStruct);
+
+    /* SD_CD */
+    GPIO_InitStruct.Pin = SD_CD_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    HAL_GPIO_Init(SD_CD_GPIO_Port, &GPIO_InitStruct);
+
+    /* Enable all NVIC lines related to gpio */
+    HAL_NVIC_SetPriority(EXTI0_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
+
+    HAL_NVIC_SetPriority(EXTI1_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(EXTI1_IRQn);
+
+    HAL_NVIC_SetPriority(EXTI2_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(EXTI2_IRQn);
+
+    HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(EXTI3_IRQn);
+
+    HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(EXTI4_IRQn);
+
+    HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
+
+    HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
+}

+ 55 - 0
firmware/targets/f7/Src/main.c

@@ -0,0 +1,55 @@
+#include "main.h"
+
+#include "fatfs/fatfs.h"
+
+#include <furi.h>
+#include <furi-hal.h>
+#include <flipper.h>
+
+int main(void) {
+    // Initialize FURI layer
+    furi_init();
+
+    // Initialize ST HAL
+    HAL_Init();
+
+    // Flipper FURI HAL
+    furi_hal_init();
+
+    // 3rd party
+    MX_FATFS_Init();
+    FURI_LOG_I("HAL", "FATFS OK");
+
+    // CMSIS initialization
+    osKernelInitialize();
+    FURI_LOG_I("HAL", "KERNEL OK");
+
+    // Init flipper
+    flipper_init();
+
+    // Start kernel
+    osKernelStart();
+
+    while (1) {}
+}
+
+void Error_Handler(void) {
+    asm("bkpt 1");
+    while(1) {}
+}
+
+#ifdef  USE_FULL_ASSERT
+/**
+    * @brief  Reports the name of the source file and the source line number
+    *         where the assert_param error has occurred.
+    * @param  file: pointer to the source file name
+    * @param  line: assert_param error line source number
+    * @retval None
+    */
+void assert_failed(uint8_t *file, uint32_t line) {
+    /* USER CODE BEGIN 6 */
+    /* User can add his own implementation to report the file name and line number,
+         tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
+    /* USER CODE END 6 */
+}
+#endif /* USE_FULL_ASSERT */

+ 77 - 0
firmware/targets/f7/Src/pka.c

@@ -0,0 +1,77 @@
+/**
+  ******************************************************************************
+  * @file    pka.c
+  * @brief   This file provides code for the configuration
+  *          of the PKA instances.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "pka.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+PKA_HandleTypeDef hpka;
+
+/* PKA init function */
+void MX_PKA_Init(void)
+{
+
+  hpka.Instance = PKA;
+  if (HAL_PKA_Init(&hpka) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_PKA_MspInit(PKA_HandleTypeDef* pkaHandle)
+{
+
+  if(pkaHandle->Instance==PKA)
+  {
+  /* USER CODE BEGIN PKA_MspInit 0 */
+
+  /* USER CODE END PKA_MspInit 0 */
+    /* PKA clock enable */
+    __HAL_RCC_PKA_CLK_ENABLE();
+  /* USER CODE BEGIN PKA_MspInit 1 */
+
+  /* USER CODE END PKA_MspInit 1 */
+  }
+}
+
+void HAL_PKA_MspDeInit(PKA_HandleTypeDef* pkaHandle)
+{
+
+  if(pkaHandle->Instance==PKA)
+  {
+  /* USER CODE BEGIN PKA_MspDeInit 0 */
+
+  /* USER CODE END PKA_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_PKA_CLK_DISABLE();
+  /* USER CODE BEGIN PKA_MspDeInit 1 */
+
+  /* USER CODE END PKA_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 37 - 0
firmware/targets/f7/Src/rf.c

@@ -0,0 +1,37 @@
+/**
+  ******************************************************************************
+  * @file    rf.c
+  * @brief   This file provides code for the configuration
+  *          of the RF instances.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "rf.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/* RF init function */
+void MX_RF_Init(void)
+{
+
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 77 - 0
firmware/targets/f7/Src/rng.c

@@ -0,0 +1,77 @@
+/**
+  ******************************************************************************
+  * @file    rng.c
+  * @brief   This file provides code for the configuration
+  *          of the RNG instances.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "rng.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+RNG_HandleTypeDef hrng;
+
+/* RNG init function */
+void MX_RNG_Init(void)
+{
+
+  hrng.Instance = RNG;
+  if (HAL_RNG_Init(&hrng) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_RNG_MspInit(RNG_HandleTypeDef* rngHandle)
+{
+
+  if(rngHandle->Instance==RNG)
+  {
+  /* USER CODE BEGIN RNG_MspInit 0 */
+
+  /* USER CODE END RNG_MspInit 0 */
+    /* RNG clock enable */
+    __HAL_RCC_RNG_CLK_ENABLE();
+  /* USER CODE BEGIN RNG_MspInit 1 */
+
+  /* USER CODE END RNG_MspInit 1 */
+  }
+}
+
+void HAL_RNG_MspDeInit(RNG_HandleTypeDef* rngHandle)
+{
+
+  if(rngHandle->Instance==RNG)
+  {
+  /* USER CODE BEGIN RNG_MspDeInit 0 */
+
+  /* USER CODE END RNG_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_RNG_CLK_DISABLE();
+  /* USER CODE BEGIN RNG_MspDeInit 1 */
+
+  /* USER CODE END RNG_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 123 - 0
firmware/targets/f7/Src/rtc.c

@@ -0,0 +1,123 @@
+/**
+  ******************************************************************************
+  * @file    rtc.c
+  * @brief   This file provides code for the configuration
+  *          of the RTC instances.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "rtc.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+RTC_HandleTypeDef hrtc;
+
+/* RTC init function */
+void MX_RTC_Init(void)
+{
+  RTC_TimeTypeDef sTime = {0};
+  RTC_DateTypeDef sDate = {0};
+
+  /** Initialize RTC Only
+  */
+  hrtc.Instance = RTC;
+  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
+  hrtc.Init.AsynchPrediv = 127;
+  hrtc.Init.SynchPrediv = 255;
+  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
+  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
+  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
+  hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
+  if (HAL_RTC_Init(&hrtc) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+  /* USER CODE BEGIN Check_RTC_BKUP */
+  return;
+  /* USER CODE END Check_RTC_BKUP */
+
+  /** Initialize RTC and set the Time and Date
+  */
+  sTime.Hours = 0x0;
+  sTime.Minutes = 0x0;
+  sTime.Seconds = 0x0;
+  sTime.SubSeconds = 0x0;
+  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
+  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
+  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sDate.WeekDay = RTC_WEEKDAY_MONDAY;
+  sDate.Month = RTC_MONTH_JANUARY;
+  sDate.Date = 0x1;
+  sDate.Year = 0x0;
+
+  if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
+{
+
+  if(rtcHandle->Instance==RTC)
+  {
+  /* USER CODE BEGIN RTC_MspInit 0 */
+
+  /* USER CODE END RTC_MspInit 0 */
+    /* RTC clock enable */
+    __HAL_RCC_RTC_ENABLE();
+    __HAL_RCC_RTCAPB_CLK_ENABLE();
+
+    /* RTC interrupt Init */
+    HAL_NVIC_SetPriority(TAMP_STAMP_LSECSS_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(TAMP_STAMP_LSECSS_IRQn);
+  /* USER CODE BEGIN RTC_MspInit 1 */
+
+  /* USER CODE END RTC_MspInit 1 */
+  }
+}
+
+void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
+{
+
+  if(rtcHandle->Instance==RTC)
+  {
+  /* USER CODE BEGIN RTC_MspDeInit 0 */
+
+  /* USER CODE END RTC_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_RTC_DISABLE();
+    __HAL_RCC_RTCAPB_CLK_DISABLE();
+
+    /* RTC interrupt Deinit */
+    HAL_NVIC_DisableIRQ(TAMP_STAMP_LSECSS_IRQn);
+  /* USER CODE BEGIN RTC_MspDeInit 1 */
+
+  /* USER CODE END RTC_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 93 - 0
firmware/targets/f7/Src/stm32wbxx_hal_msp.c

@@ -0,0 +1,93 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * File Name          : stm32wbxx_hal_msp.c
+  * Description        : This file provides code for the MSP Initialization
+  *                      and de-Initialization codes.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* USER CODE BEGIN TD */
+
+/* USER CODE END TD */
+
+/* Private define ------------------------------------------------------------*/
+/* USER CODE BEGIN Define */
+
+/* USER CODE END Define */
+
+/* Private macro -------------------------------------------------------------*/
+/* USER CODE BEGIN Macro */
+
+/* USER CODE END Macro */
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+/* Private function prototypes -----------------------------------------------*/
+/* USER CODE BEGIN PFP */
+
+/* USER CODE END PFP */
+
+/* External functions --------------------------------------------------------*/
+/* USER CODE BEGIN ExternalFunctions */
+
+/* USER CODE END ExternalFunctions */
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+/**
+  * Initializes the Global MSP.
+  */
+void HAL_MspInit(void)
+{
+  /* USER CODE BEGIN MspInit 0 */
+
+  /* USER CODE END MspInit 0 */
+
+  __HAL_RCC_HSEM_CLK_ENABLE();
+
+  /* System interrupt init*/
+  /* PendSV_IRQn interrupt configuration */
+  HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0);
+
+  /* Peripheral interrupt init */
+  /* RCC_IRQn interrupt configuration */
+  HAL_NVIC_SetPriority(RCC_IRQn, 5, 0);
+  HAL_NVIC_EnableIRQ(RCC_IRQn);
+  /* HSEM_IRQn interrupt configuration */
+  HAL_NVIC_SetPriority(HSEM_IRQn, 5, 0);
+  HAL_NVIC_EnableIRQ(HSEM_IRQn);
+
+  /* USER CODE BEGIN MspInit 1 */
+
+  /* USER CODE END MspInit 1 */
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 52 - 0
firmware/targets/f7/Src/stm32wbxx_it.c

@@ -0,0 +1,52 @@
+#include "main.h"
+#include "stm32wbxx_it.h"
+#include "FreeRTOS.h"
+#include "task.h"
+
+extern PCD_HandleTypeDef hpcd_USB_FS;
+extern COMP_HandleTypeDef hcomp1;
+extern RTC_HandleTypeDef hrtc;
+extern TIM_HandleTypeDef htim1;
+extern TIM_HandleTypeDef htim2;
+extern TIM_HandleTypeDef htim16;
+extern TIM_HandleTypeDef htim17;
+
+extern void HW_TS_RTC_Wakeup_Handler();
+extern void HW_IPCC_Tx_Handler();
+extern void HW_IPCC_Rx_Handler();
+
+void SysTick_Handler(void) {
+    HAL_IncTick();
+}
+
+void USB_LP_IRQHandler(void) {
+    HAL_PCD_IRQHandler(&hpcd_USB_FS);
+}
+
+void COMP_IRQHandler(void) {
+    HAL_COMP_IRQHandler(&hcomp1);
+}
+
+void TIM1_TRG_COM_TIM17_IRQHandler(void) {
+    HAL_TIM_IRQHandler(&htim1);
+}
+
+void TIM1_CC_IRQHandler(void) {
+    HAL_TIM_IRQHandler(&htim1);
+}
+
+void HSEM_IRQHandler(void) {
+    HAL_HSEM_IRQHandler();
+}
+
+void RTC_WKUP_IRQHandler(void){
+    HW_TS_RTC_Wakeup_Handler();
+}
+
+void IPCC_C1_TX_IRQHandler(void){
+    HW_IPCC_Tx_Handler();
+}
+
+void IPCC_C1_RX_IRQHandler(void){
+    HW_IPCC_Rx_Handler();
+}

+ 357 - 0
firmware/targets/f7/Src/system_stm32wbxx.c

@@ -0,0 +1,357 @@
+/**
+  ******************************************************************************
+  * @file    system_stm32wbxx.c
+  * @author  MCD Application Team
+  * @brief   CMSIS Cortex Device Peripheral Access Layer System Source File
+  *
+  *   This file provides two functions and one global variable to be called from
+  *   user application:
+  *      - SystemInit(): This function is called at startup just after reset and
+  *                      before branch to main program. This call is made inside
+  *                      the "startup_stm32wbxx.s" file.
+  *
+  *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+  *                                  by the user application to setup the SysTick
+  *                                  timer or configure other parameters.
+  *
+  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+  *                                 be called whenever the core clock is changed
+  *                                 during program execution.
+  *
+  *   After each device reset the MSI (4 MHz) is used as system clock source.
+  *   Then SystemInit() function is called, in "startup_stm32wbxx.s" file, to
+  *   configure the system clock before to branch to main program.
+  *
+  *   This file configures the system clock as follows:
+  *=============================================================================
+  *-----------------------------------------------------------------------------
+  *        System Clock source                    | MSI
+  *-----------------------------------------------------------------------------
+  *        SYSCLK(Hz)                             | 4000000
+  *-----------------------------------------------------------------------------
+  *        HCLK(Hz)                               | 4000000
+  *-----------------------------------------------------------------------------
+  *        AHB Prescaler                          | 1
+  *-----------------------------------------------------------------------------
+  *        APB1 Prescaler                         | 1
+  *-----------------------------------------------------------------------------
+  *        APB2 Prescaler                         | 1
+  *-----------------------------------------------------------------------------
+  *        PLL_M                                  | 1
+  *-----------------------------------------------------------------------------
+  *        PLL_N                                  | 8
+  *-----------------------------------------------------------------------------
+  *        PLL_P                                  | 7
+  *-----------------------------------------------------------------------------
+  *        PLL_Q                                  | 2
+  *-----------------------------------------------------------------------------
+  *        PLL_R                                  | 2
+  *-----------------------------------------------------------------------------
+  *        PLLSAI1_P                              | NA
+  *-----------------------------------------------------------------------------
+  *        PLLSAI1_Q                              | NA
+  *-----------------------------------------------------------------------------
+  *        PLLSAI1_R                              | NA
+  *-----------------------------------------------------------------------------
+  *        Require 48MHz for USB OTG FS,          | Disabled
+  *        SDIO and RNG clock                     |
+  *-----------------------------------------------------------------------------
+  *=============================================================================
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics. 
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under BSD 3-Clause license,
+  * the "License"; You may not use this file except in compliance with the 
+  * License. You may obtain a copy of the License at:
+  *                        opensource.org/licenses/BSD-3-Clause
+  *
+  ******************************************************************************
+  */
+
+/** @addtogroup CMSIS
+  * @{
+  */
+
+/** @addtogroup stm32WBxx_system
+  * @{
+  */
+
+/** @addtogroup stm32WBxx_System_Private_Includes
+  * @{
+  */
+
+#include "stm32wbxx.h"
+
+#if !defined  (HSE_VALUE)
+  #define HSE_VALUE    (32000000UL) /*!< Value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined  (MSI_VALUE)
+   #define MSI_VALUE    (4000000UL) /*!< Value of the Internal oscillator in Hz*/
+#endif /* MSI_VALUE */
+
+#if !defined  (HSI_VALUE)
+  #define HSI_VALUE    (16000000UL) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+#if !defined  (LSI_VALUE) 
+ #define LSI_VALUE  (32000UL)       /*!< Value of LSI in Hz*/
+#endif /* LSI_VALUE */ 
+
+#if !defined  (LSE_VALUE)
+  #define LSE_VALUE    (32768UL)    /*!< Value of LSE in Hz*/
+#endif /* LSE_VALUE */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_TypesDefinitions
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_Defines
+  * @{
+  */
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+     Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET         OS_OFFSET            /*!< Vector Table base offset field.
+                                                     This value must be a multiple of 0x200. */
+
+#define VECT_TAB_BASE_ADDRESS   SRAM1_BASE       /*!< Vector Table base offset field.
+                                                     This value must be a multiple of 0x200. */
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_Macros
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_Variables
+  * @{
+  */
+  /* The SystemCoreClock variable is updated in three ways:
+      1) by calling CMSIS function SystemCoreClockUpdate()
+      2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+      3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
+         Note: If you use this function to configure the system clock; then there
+               is no need to call the 2 first functions listed above, since SystemCoreClock
+               variable is updated automatically.
+  */
+  uint32_t SystemCoreClock  = 4000000UL ; /*CPU1: M4 on MSI clock after startup (4MHz)*/
+
+  const uint32_t AHBPrescTable[16UL] = {1UL, 3UL, 5UL, 1UL, 1UL, 6UL, 10UL, 32UL, 2UL, 4UL, 8UL, 16UL, 64UL, 128UL, 256UL, 512UL};
+
+  const uint32_t APBPrescTable[8UL]  = {0UL, 0UL, 0UL, 0UL, 1UL, 2UL, 3UL, 4UL};
+
+  const uint32_t MSIRangeTable[16UL] = {100000UL, 200000UL, 400000UL, 800000UL, 1000000UL, 2000000UL, \
+                                      4000000UL, 8000000UL, 16000000UL, 24000000UL, 32000000UL, 48000000UL, 0UL, 0UL, 0UL, 0UL}; /* 0UL values are incorrect cases */
+
+#if defined(STM32WB55xx) || defined(STM32WB5Mxx) || defined(STM32WB35xx)
+  const uint32_t SmpsPrescalerTable[4UL][6UL]={{1UL,3UL,2UL,2UL,1UL,2UL}, \
+                                        {2UL,6UL,4UL,3UL,2UL,4UL}, \
+                                        {4UL,12UL,8UL,6UL,4UL,8UL}, \
+                                        {4UL,12UL,8UL,6UL,4UL,8UL}};
+#endif
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_FunctionPrototypes
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @addtogroup STM32WBxx_System_Private_Functions
+  * @{
+  */
+
+/**
+  * @brief  Setup the microcontroller system.
+  * @param  None
+  * @retval None
+  */
+void SystemInit(void)
+{
+  /* Configure the Vector Table location add offset address ------------------*/
+#if defined(VECT_TAB_SRAM) && defined(VECT_TAB_BASE_ADDRESS)  
+  /* program in SRAMx */
+  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET;  /* Vector Table Relocation in Internal SRAMx for CPU1 */
+#else    /* program in FLASH */
+  SCB->VTOR = VECT_TAB_OFFSET;              /* Vector Table Relocation in Internal FLASH */
+#endif
+
+  /* FPU settings ------------------------------------------------------------*/
+  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+    SCB->CPACR |= ((3UL << (10UL*2UL))|(3UL << (11UL*2UL)));  /* set CP10 and CP11 Full Access */
+  #endif
+  
+  /* Reset the RCC clock configuration to the default reset state ------------*/
+  /* Set MSION bit */
+  RCC->CR |= RCC_CR_MSION;
+
+  /* Reset CFGR register */
+  RCC->CFGR = 0x00070000U;
+
+  /* Reset PLLSAI1ON, PLLON, HSECSSON, HSEON, HSION, and MSIPLLON bits */
+  RCC->CR &= (uint32_t)0xFAF6FEFBU;
+
+  /*!< Reset LSI1 and LSI2 bits */
+  RCC->CSR &= (uint32_t)0xFFFFFFFAU;
+  
+  /*!< Reset HSI48ON  bit */
+  RCC->CRRCR &= (uint32_t)0xFFFFFFFEU;
+    
+  /* Reset PLLCFGR register */
+  RCC->PLLCFGR = 0x22041000U;
+
+#if defined(STM32WB55xx) || defined(STM32WB5Mxx)
+  /* Reset PLLSAI1CFGR register */
+  RCC->PLLSAI1CFGR = 0x22041000U;
+#endif
+  
+  /* Reset HSEBYP bit */
+  RCC->CR &= 0xFFFBFFFFU;
+
+  /* Disable all interrupts */
+  RCC->CIER = 0x00000000;
+}
+
+/**
+  * @brief  Update SystemCoreClock variable according to Clock Register Values.
+  *         The SystemCoreClock variable contains the core clock (HCLK), it can
+  *         be used by the user application to setup the SysTick timer or configure
+  *         other parameters.
+  *
+  * @note   Each time the core clock (HCLK) changes, this function must be called
+  *         to update SystemCoreClock variable value. Otherwise, any configuration
+  *         based on this variable will be incorrect.
+  *
+  * @note   - The system frequency computed by this function is not the real
+  *           frequency in the chip. It is calculated based on the predefined
+  *           constant and the selected clock source:
+  *
+  *           - If SYSCLK source is MSI, SystemCoreClock will contain the MSI_VALUE(*)
+  *
+  *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**)
+  *
+  *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***)
+  *
+  *           - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***)
+  *             or HSI_VALUE(*) or MSI_VALUE(*) multiplied/divided by the PLL factors.
+  *
+  *         (*) MSI_VALUE is a constant defined in stm32wbxx_hal.h file (default value
+  *             4 MHz) but the real value may vary depending on the variations
+  *             in voltage and temperature.
+  *
+  *         (**) HSI_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value
+  *              16 MHz) but the real value may vary depending on the variations
+  *              in voltage and temperature.
+  *
+  *         (***) HSE_VALUE is a constant defined in stm32wbxx_hal_conf.h file (default value
+  *              32 MHz), user has to ensure that HSE_VALUE is same as the real
+  *              frequency of the crystal used. Otherwise, this function may
+  *              have wrong result.
+  *
+  *         - The result of this function could be not correct when using fractional
+  *           value for HSE crystal.
+  *
+  * @param  None
+  * @retval None
+  */
+void SystemCoreClockUpdate(void)
+{
+  uint32_t tmp, msirange, pllvco, pllr, pllsource , pllm;
+
+  /* Get MSI Range frequency--------------------------------------------------*/
+
+  /*MSI frequency range in Hz*/
+  msirange = MSIRangeTable[(RCC->CR & RCC_CR_MSIRANGE) >> RCC_CR_MSIRANGE_Pos];
+
+  /* Get SYSCLK source -------------------------------------------------------*/
+  switch (RCC->CFGR & RCC_CFGR_SWS)
+  {
+    case 0x00:   /* MSI used as system clock source */
+      SystemCoreClock = msirange;
+      break;
+
+    case 0x04:  /* HSI used as system clock source */
+      /* HSI used as system clock source */
+        SystemCoreClock = HSI_VALUE;
+      break;
+
+    case 0x08:  /* HSE used as system clock source */
+      SystemCoreClock = HSE_VALUE;
+      break;
+
+    case 0x0C: /* PLL used as system clock  source */
+      /* PLL_VCO = (HSE_VALUE or HSI_VALUE or MSI_VALUE/ PLLM) * PLLN
+         SYSCLK = PLL_VCO / PLLR
+         */
+      pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC);
+      pllm = ((RCC->PLLCFGR & RCC_PLLCFGR_PLLM) >> RCC_PLLCFGR_PLLM_Pos) + 1UL ;
+
+      if(pllsource == 0x02UL) /* HSI used as PLL clock source */
+      {
+        pllvco = (HSI_VALUE / pllm);
+      }
+      else if(pllsource == 0x03UL) /* HSE used as PLL clock source */
+      {
+        pllvco = (HSE_VALUE / pllm);
+      }
+      else /* MSI used as PLL clock source */
+      {
+        pllvco = (msirange / pllm);
+      }
+      
+      pllvco = pllvco * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos);
+      pllr = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> RCC_PLLCFGR_PLLR_Pos) + 1UL);
+      
+      SystemCoreClock = pllvco/pllr;
+      break;
+
+    default:
+      SystemCoreClock = msirange;
+      break;
+  }
+  
+  /* Compute HCLK clock frequency --------------------------------------------*/
+  /* Get HCLK1 prescaler */
+  tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos)];
+  /* HCLK clock frequency */
+  SystemCoreClock = SystemCoreClock / tmp;
+
+}
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 361 - 0
firmware/targets/f7/Src/tim.c

@@ -0,0 +1,361 @@
+/**
+  ******************************************************************************
+  * @file    tim.c
+  * @brief   This file provides code for the configuration
+  *          of the TIM instances.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "tim.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+TIM_HandleTypeDef htim1;
+TIM_HandleTypeDef htim2;
+TIM_HandleTypeDef htim16;
+
+/* TIM1 init function */
+void MX_TIM1_Init(void)
+{
+  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
+  TIM_MasterConfigTypeDef sMasterConfig = {0};
+  TIM_OC_InitTypeDef sConfigOC = {0};
+  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
+
+  htim1.Instance = TIM1;
+  htim1.Init.Prescaler = 0;
+  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
+  htim1.Init.Period = 65535;
+  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+  htim1.Init.RepetitionCounter = 0;
+  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
+  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
+  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  if (HAL_TIM_OC_Init(&htim1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
+  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
+  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sConfigOC.OCMode = TIM_OCMODE_TIMING;
+  sConfigOC.Pulse = 0;
+  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
+  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
+  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
+  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
+  if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sConfigOC.OCMode = TIM_OCMODE_PWM1;
+  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
+  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
+  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
+  sBreakDeadTimeConfig.DeadTime = 0;
+  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
+  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
+  sBreakDeadTimeConfig.BreakFilter = 0;
+  sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
+  sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
+  sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
+  sBreakDeadTimeConfig.Break2Filter = 0;
+  sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
+  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
+  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  HAL_TIM_MspPostInit(&htim1);
+
+}
+/* TIM2 init function */
+void MX_TIM2_Init(void)
+{
+  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
+  TIM_MasterConfigTypeDef sMasterConfig = {0};
+  TIM_IC_InitTypeDef sConfigIC = {0};
+
+  htim2.Instance = TIM2;
+  htim2.Init.Prescaler = 64-1;
+  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
+  htim2.Init.Period = 4294967295;
+  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
+  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
+  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
+  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
+  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
+  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
+  sConfigIC.ICFilter = 0;
+  if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
+  sConfigIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
+  if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+/* TIM16 init function */
+void MX_TIM16_Init(void)
+{
+  TIM_OC_InitTypeDef sConfigOC = {0};
+  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
+
+  htim16.Instance = TIM16;
+  htim16.Init.Prescaler = 500 - 1;
+  htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
+  htim16.Init.Period = 291;
+  htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+  htim16.Init.RepetitionCounter = 0;
+  htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
+  if (HAL_TIM_Base_Init(&htim16) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  if (HAL_TIM_PWM_Init(&htim16) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sConfigOC.OCMode = TIM_OCMODE_PWM1;
+  sConfigOC.Pulse = 145;
+  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
+  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
+  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
+  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
+  if (HAL_TIM_PWM_ConfigChannel(&htim16, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
+  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
+  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
+  sBreakDeadTimeConfig.DeadTime = 0;
+  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
+  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
+  sBreakDeadTimeConfig.BreakFilter = 0;
+  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
+  if (HAL_TIMEx_ConfigBreakDeadTime(&htim16, &sBreakDeadTimeConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  HAL_TIM_MspPostInit(&htim16);
+
+}
+
+void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(tim_baseHandle->Instance==TIM1)
+  {
+  /* USER CODE BEGIN TIM1_MspInit 0 */
+
+  /* USER CODE END TIM1_MspInit 0 */
+    /* TIM1 clock enable */
+    __HAL_RCC_TIM1_CLK_ENABLE();
+
+    /* TIM1 interrupt Init */
+    HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM17_IRQn, 0, 0);
+    HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM17_IRQn);
+  /* USER CODE BEGIN TIM1_MspInit 1 */
+
+  /* USER CODE END TIM1_MspInit 1 */
+  }
+  else if(tim_baseHandle->Instance==TIM2)
+  {
+  /* USER CODE BEGIN TIM2_MspInit 0 */
+
+  /* USER CODE END TIM2_MspInit 0 */
+    /* TIM2 clock enable */
+    __HAL_RCC_TIM2_CLK_ENABLE();
+
+    __HAL_RCC_GPIOA_CLK_ENABLE();
+    /**TIM2 GPIO Configuration
+    PA0     ------> TIM2_CH1
+    */
+    GPIO_InitStruct.Pin = IR_RX_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
+    HAL_GPIO_Init(IR_RX_GPIO_Port, &GPIO_InitStruct);
+
+    /* TIM2 interrupt Init */
+    HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(TIM2_IRQn);
+  /* USER CODE BEGIN TIM2_MspInit 1 */
+
+  /* USER CODE END TIM2_MspInit 1 */
+  }
+  else if(tim_baseHandle->Instance==TIM16)
+  {
+  /* USER CODE BEGIN TIM16_MspInit 0 */
+
+  /* USER CODE END TIM16_MspInit 0 */
+    /* TIM16 clock enable */
+    __HAL_RCC_TIM16_CLK_ENABLE();
+  /* USER CODE BEGIN TIM16_MspInit 1 */
+
+  /* USER CODE END TIM16_MspInit 1 */
+  }
+}
+void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(timHandle->Instance==TIM1)
+  {
+  /* USER CODE BEGIN TIM1_MspPostInit 0 */
+
+  /* USER CODE END TIM1_MspPostInit 0 */
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    /**TIM1 GPIO Configuration
+    PB9     ------> TIM1_CH3N
+    PB13     ------> TIM1_CH1N
+    */
+    GPIO_InitStruct.Pin = IR_TX_Pin|RFID_OUT_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
+    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+  /* USER CODE BEGIN TIM1_MspPostInit 1 */
+
+  /* USER CODE END TIM1_MspPostInit 1 */
+  }
+  else if(timHandle->Instance==TIM16)
+  {
+  /* USER CODE BEGIN TIM16_MspPostInit 0 */
+
+  /* USER CODE END TIM16_MspPostInit 0 */
+
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    /**TIM16 GPIO Configuration
+    PB8     ------> TIM16_CH1
+    */
+    GPIO_InitStruct.Pin = SPEAKER_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF14_TIM16;
+    HAL_GPIO_Init(SPEAKER_GPIO_Port, &GPIO_InitStruct);
+
+  /* USER CODE BEGIN TIM16_MspPostInit 1 */
+
+  /* USER CODE END TIM16_MspPostInit 1 */
+  }
+
+}
+
+void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
+{
+
+  if(tim_baseHandle->Instance==TIM1)
+  {
+  /* USER CODE BEGIN TIM1_MspDeInit 0 */
+
+  /* USER CODE END TIM1_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_TIM1_CLK_DISABLE();
+
+    /* TIM1 interrupt Deinit */
+    HAL_NVIC_DisableIRQ(TIM1_TRG_COM_TIM17_IRQn);
+  /* USER CODE BEGIN TIM1_MspDeInit 1 */
+
+  /* USER CODE END TIM1_MspDeInit 1 */
+  }
+  else if(tim_baseHandle->Instance==TIM2)
+  {
+  /* USER CODE BEGIN TIM2_MspDeInit 0 */
+
+  /* USER CODE END TIM2_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_TIM2_CLK_DISABLE();
+
+    /**TIM2 GPIO Configuration
+    PA0     ------> TIM2_CH1
+    */
+    HAL_GPIO_DeInit(IR_RX_GPIO_Port, IR_RX_Pin);
+
+    /* TIM2 interrupt Deinit */
+    HAL_NVIC_DisableIRQ(TIM2_IRQn);
+  /* USER CODE BEGIN TIM2_MspDeInit 1 */
+
+  /* USER CODE END TIM2_MspDeInit 1 */
+  }
+  else if(tim_baseHandle->Instance==TIM16)
+  {
+  /* USER CODE BEGIN TIM16_MspDeInit 0 */
+
+  /* USER CODE END TIM16_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_TIM16_CLK_DISABLE();
+  /* USER CODE BEGIN TIM16_MspDeInit 1 */
+
+  /* USER CODE END TIM16_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 776 - 0
firmware/targets/f7/ble-glue/app_ble.c

@@ -0,0 +1,776 @@
+#include "main.h"
+
+#include "app_entry.h"
+#include "app_common.h"
+#include "dbg_trace.h"
+#include "ble.h"
+#include "tl.h"
+#include "app_ble.h"
+
+#include "cmsis_os.h"
+#include "shci.h"
+#include "otp.h"
+#include "dev_info_service.h"
+#include "battery_service.h"
+#include "serial_service.h"
+
+#include <furi-hal.h>
+
+typedef struct _tSecurityParams {
+  uint8_t ioCapability;
+  uint8_t mitm_mode;
+  uint8_t bonding_mode;
+  uint8_t Use_Fixed_Pin;
+  uint8_t encryptionKeySizeMin;
+  uint8_t encryptionKeySizeMax;
+  uint32_t Fixed_Pin;
+  uint8_t initiateSecurity;
+} tSecurityParams;
+
+typedef struct _tBLEProfileGlobalContext {
+  tSecurityParams bleSecurityParam;
+  uint16_t gapServiceHandle;
+  uint16_t devNameCharHandle;
+  uint16_t appearanceCharHandle;
+  uint16_t connectionHandle;
+  uint8_t advtServUUIDlen;
+  uint8_t advtServUUID[100];
+} BleGlobalContext_t;
+
+typedef struct {
+  BleGlobalContext_t BleApplicationContext_legacy;
+  APP_BLE_ConnStatus_t Device_Connection_Status;
+  uint8_t Advertising_mgr_timer_Id;
+} BleApplicationContext_t;
+
+
+#define FAST_ADV_TIMEOUT               (30*1000*1000/CFG_TS_TICK_VAL) /**< 30s */
+#define INITIAL_ADV_TIMEOUT            (60*1000*1000/CFG_TS_TICK_VAL) /**< 60s */
+
+#define BD_ADDR_SIZE_LOCAL    6
+
+#define LED_ON_TIMEOUT                 (0.005*1000*1000/CFG_TS_TICK_VAL) /**< 5ms */
+
+PLACE_IN_SECTION("MB_MEM1") ALIGN(4) static TL_CmdPacket_t BleCmdBuffer;
+
+static const uint8_t M_bd_addr[BD_ADDR_SIZE_LOCAL] =
+    {
+        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x0000000000FF)),
+        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x00000000FF00) >> 8),
+        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x000000FF0000) >> 16),
+        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x0000FF000000) >> 24),
+        (uint8_t)((CFG_ADV_BD_ADDRESS & 0x00FF00000000) >> 32),
+        (uint8_t)((CFG_ADV_BD_ADDRESS & 0xFF0000000000) >> 40)
+    };
+
+static uint8_t bd_addr_udn[BD_ADDR_SIZE_LOCAL];
+
+static const uint8_t BLE_CFG_IR_VALUE[16] = CFG_BLE_IRK;
+static const uint8_t BLE_CFG_ER_VALUE[16] = CFG_BLE_ERK;
+
+PLACE_IN_SECTION("TAG_OTA_END") const uint32_t MagicKeywordValue = 0x94448A29 ;
+PLACE_IN_SECTION("TAG_OTA_START") const uint32_t MagicKeywordAddress = (uint32_t)&MagicKeywordValue;
+
+PLACE_IN_SECTION("BLE_APP_CONTEXT") static BleApplicationContext_t BleApplicationContext;
+PLACE_IN_SECTION("BLE_APP_CONTEXT") static uint16_t AdvIntervalMin, AdvIntervalMax;
+
+uint8_t  manuf_data[14] = {
+    sizeof(manuf_data)-1, AD_TYPE_MANUFACTURER_SPECIFIC_DATA,
+    0x01/*SKD version */,
+    0x00 /* Generic*/,
+    0x00 /* GROUP A Feature  */,
+    0x00 /* GROUP A Feature */,
+    0x00 /* GROUP B Feature */,
+    0x00 /* GROUP B Feature */,
+    0x00, /* BLE MAC start -MSB */
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00, /* BLE MAC stop */
+
+};
+
+osMutexId_t MtxHciId;
+osSemaphoreId_t SemHciId;
+osThreadId_t AdvUpdateProcessId;
+osThreadId_t HciUserEvtProcessId;
+
+const osThreadAttr_t AdvUpdateProcess_attr = {
+    .name = CFG_ADV_UPDATE_PROCESS_NAME,
+    .attr_bits = CFG_ADV_UPDATE_PROCESS_ATTR_BITS,
+    .cb_mem = CFG_ADV_UPDATE_PROCESS_CB_MEM,
+    .cb_size = CFG_ADV_UPDATE_PROCESS_CB_SIZE,
+    .stack_mem = CFG_ADV_UPDATE_PROCESS_STACK_MEM,
+    .priority = CFG_ADV_UPDATE_PROCESS_PRIORITY,
+    .stack_size = CFG_ADV_UPDATE_PROCESS_STACK_SIZE
+};
+
+const osThreadAttr_t HciUserEvtProcess_attr = {
+    .name = CFG_HCI_USER_EVT_PROCESS_NAME,
+    .attr_bits = CFG_HCI_USER_EVT_PROCESS_ATTR_BITS,
+    .cb_mem = CFG_HCI_USER_EVT_PROCESS_CB_MEM,
+    .cb_size = CFG_HCI_USER_EVT_PROCESS_CB_SIZE,
+    .stack_mem = CFG_HCI_USER_EVT_PROCESS_STACK_MEM,
+    .priority = CFG_HCI_USER_EVT_PROCESS_PRIORITY,
+    .stack_size = CFG_HCI_USER_EVT_PROCESS_STACK_SIZE
+};
+
+/* Private function prototypes -----------------------------------------------*/
+static void HciUserEvtProcess(void *argument);
+static void BLE_UserEvtRx( void * pPayload );
+static void BLE_StatusNot( HCI_TL_CmdStatus_t status );
+static void Ble_Tl_Init( void );
+static void Ble_Hci_Gap_Gatt_Init();
+static const uint8_t* BleGetBdAddress( void );
+static void Adv_Request( APP_BLE_ConnStatus_t New_Status );
+static void Adv_Mgr( void );
+static void AdvUpdateProcess(void *argument);
+static void Adv_Update( void );
+
+
+bool APP_BLE_Init() {
+  SHCI_C2_Ble_Init_Cmd_Packet_t ble_init_cmd_packet = {
+    {{0,0,0}},                  /**< Header unused */
+    {0,                         /** pBleBufferAddress not used */
+    0,                          /** BleBufferSize not used */
+    CFG_BLE_NUM_GATT_ATTRIBUTES,
+    CFG_BLE_NUM_GATT_SERVICES,
+    CFG_BLE_ATT_VALUE_ARRAY_SIZE,
+    CFG_BLE_NUM_LINK,
+    CFG_BLE_DATA_LENGTH_EXTENSION,
+    CFG_BLE_PREPARE_WRITE_LIST_SIZE,
+    CFG_BLE_MBLOCK_COUNT,
+    CFG_BLE_MAX_ATT_MTU,
+    CFG_BLE_SLAVE_SCA,
+    CFG_BLE_MASTER_SCA,
+    CFG_BLE_LSE_SOURCE,
+    CFG_BLE_MAX_CONN_EVENT_LENGTH,
+    CFG_BLE_HSE_STARTUP_TIME,
+    CFG_BLE_VITERBI_MODE,
+    CFG_BLE_LL_ONLY,
+    0}
+  };
+
+  // Initialize Ble Transport Layer
+  Ble_Tl_Init( );
+  // Register the hci transport layer to handle BLE User Asynchronous Events
+  HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr);
+  // Starts the BLE Stack on CPU2
+  return (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) == SHCI_Success);
+}
+
+static void set_advertisment_service_uid(uint8_t* uid, uint8_t uin_len);
+
+bool APP_BLE_Start() {
+  if (APPE_Status() != BleGlueStatusStarted) {
+    return false;
+  }
+  // Initialization of HCI & GATT & GAP layer
+  Ble_Hci_Gap_Gatt_Init();
+  // Initialization of the BLE Services
+  SVCCTL_Init();
+  // Initialization of the BLE App Context
+  BleApplicationContext.Device_Connection_Status = APP_BLE_IDLE;
+  BleApplicationContext.BleApplicationContext_legacy.connectionHandle = 0xFFFF;
+  // From here, all initialization are BLE application specific
+  AdvUpdateProcessId = osThreadNew(AdvUpdateProcess, NULL, &AdvUpdateProcess_attr);
+
+  // Initialization of ADV - Ad Manufacturer Element - Support OTA Bit Masks
+#if(BLE_CFG_OTA_REBOOT_CHAR != 0)
+  manuf_data[sizeof(manuf_data)-8] = CFG_FEATURE_OTA_REBOOT;
+#endif
+
+  // Initialize DIS Application
+  dev_info_service_init();
+  // Initialize BAS Application
+  battery_svc_init();
+  // Initialize Serial application
+  serial_svc_init();
+  // Create timer to handle the connection state machine
+  HW_TS_Create(CFG_TIM_PROC_ID_ISR, &(BleApplicationContext.Advertising_mgr_timer_Id), hw_ts_SingleShot, Adv_Mgr);
+  uint8_t adv_service_uid[2];
+  adv_service_uid[0] = 0x80 | furi_hal_version_get_hw_color();
+  adv_service_uid[1] = 0x30;
+
+  set_advertisment_service_uid(adv_service_uid, sizeof(adv_service_uid));
+  /* Initialize intervals for reconnexion without intervals update */
+  AdvIntervalMin = CFG_FAST_CONN_ADV_INTERVAL_MIN;
+  AdvIntervalMax = CFG_FAST_CONN_ADV_INTERVAL_MAX;
+
+  Adv_Request(APP_BLE_FAST_ADV);
+  return true;
+}
+
+void SVCCTL_SvcInit() {
+    // Dummy function to prevent unused services initialization
+    // TODO refactore
+}
+
+SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification( void *pckt )
+{
+  hci_event_pckt *event_pckt;
+  evt_le_meta_event *meta_evt;
+  evt_blue_aci *blue_evt;
+  hci_le_phy_update_complete_event_rp0 *evt_le_phy_update_complete;
+  uint8_t TX_PHY, RX_PHY;
+  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
+
+  event_pckt = (hci_event_pckt*) ((hci_uart_pckt *) pckt)->data;
+
+  switch (event_pckt->evt) {
+    case EVT_DISCONN_COMPLETE:
+    {
+      hci_disconnection_complete_event_rp0 *disconnection_complete_event;
+      disconnection_complete_event = (hci_disconnection_complete_event_rp0 *) event_pckt->data;
+
+      if (disconnection_complete_event->Connection_Handle == BleApplicationContext.BleApplicationContext_legacy.connectionHandle) {
+        BleApplicationContext.BleApplicationContext_legacy.connectionHandle = 0;
+        BleApplicationContext.Device_Connection_Status = APP_BLE_IDLE;
+        APP_DBG_MSG("\r\n\r** DISCONNECTION EVENT WITH CLIENT \r\n");
+      }
+      /* restart advertising */
+      Adv_Request(APP_BLE_FAST_ADV);
+      furi_hal_power_insomnia_exit();
+    }
+    break; /* EVT_DISCONN_COMPLETE */
+
+    case EVT_LE_META_EVENT:
+    {
+      meta_evt = (evt_le_meta_event*) event_pckt->data;
+      switch (meta_evt->subevent)
+      {
+        case EVT_LE_CONN_UPDATE_COMPLETE:
+          APP_DBG_MSG("\r\n\r** CONNECTION UPDATE EVENT WITH CLIENT \r\n");
+
+          /* USER CODE BEGIN EVT_LE_CONN_UPDATE_COMPLETE */
+
+          /* USER CODE END EVT_LE_CONN_UPDATE_COMPLETE */
+          break;
+        case EVT_LE_PHY_UPDATE_COMPLETE:
+          APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE \r\n");
+          evt_le_phy_update_complete = (hci_le_phy_update_complete_event_rp0*)meta_evt->data;
+          if (evt_le_phy_update_complete->Status == 0)
+          {
+            APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE, status ok \r\n");
+          }
+          else
+          {
+            APP_DBG_MSG("EVT_UPDATE_PHY_COMPLETE, status nok \r\n");
+          }
+
+          ret = hci_le_read_phy(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,&TX_PHY,&RX_PHY);
+          if (ret == BLE_STATUS_SUCCESS)
+          {
+            APP_DBG_MSG("Read_PHY success \r\n");
+
+            if ((TX_PHY == TX_2M) && (RX_PHY == RX_2M))
+            {
+              APP_DBG_MSG("PHY Param  TX= %d, RX= %d \r\n", TX_PHY, RX_PHY);
+            }
+            else
+            {
+              APP_DBG_MSG("PHY Param  TX= %d, RX= %d \r\n", TX_PHY, RX_PHY);
+            }
+          }
+          else
+          {
+            APP_DBG_MSG("Read conf not succeess \r\n");
+          }
+          break;
+        case EVT_LE_CONN_COMPLETE:
+        {
+          furi_hal_power_insomnia_enter();
+          hci_le_connection_complete_event_rp0 *connection_complete_event;
+
+          /**
+           * The connection is done, there is no need anymore to schedule the LP ADV
+           */
+          connection_complete_event = (hci_le_connection_complete_event_rp0 *) meta_evt->data;
+
+          HW_TS_Stop(BleApplicationContext.Advertising_mgr_timer_Id);
+
+          APP_DBG_MSG("EVT_LE_CONN_COMPLETE for connection handle 0x%x\r\n", connection_complete_event->Connection_Handle);
+          if (BleApplicationContext.Device_Connection_Status == APP_BLE_LP_CONNECTING)
+          {
+            /* Connection as client */
+            BleApplicationContext.Device_Connection_Status = APP_BLE_CONNECTED_CLIENT;
+          }
+          else
+          {
+            /* Connection as server */
+            BleApplicationContext.Device_Connection_Status = APP_BLE_CONNECTED_SERVER;
+          }
+          BleApplicationContext.BleApplicationContext_legacy.connectionHandle = connection_complete_event->Connection_Handle;
+        }
+        break; /* HCI_EVT_LE_CONN_COMPLETE */
+        default:
+          break;
+      }
+    }
+    break; /* HCI_EVT_LE_META_EVENT */
+
+    case EVT_VENDOR:
+      blue_evt = (evt_blue_aci*) event_pckt->data;
+      switch (blue_evt->ecode) {
+        aci_gap_pairing_complete_event_rp0 *pairing_complete;
+
+      case EVT_BLUE_GAP_LIMITED_DISCOVERABLE: 
+        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_LIMITED_DISCOVERABLE \r\n");
+          break; /* EVT_BLUE_GAP_LIMITED_DISCOVERABLE */
+          
+      case EVT_BLUE_GAP_PASS_KEY_REQUEST:  
+        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_PASS_KEY_REQUEST \r\n");
+
+        aci_gap_pass_key_resp(BleApplicationContext.BleApplicationContext_legacy.connectionHandle,123456);
+
+        APP_DBG_MSG("\r\n\r** aci_gap_pass_key_resp \r\n");
+          break; /* EVT_BLUE_GAP_PASS_KEY_REQUEST */
+
+      case EVT_BLUE_GAP_AUTHORIZATION_REQUEST:    
+        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_AUTHORIZATION_REQUEST \r\n");
+          break; /* EVT_BLUE_GAP_AUTHORIZATION_REQUEST */
+
+      case EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED:   
+        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED \r\n");
+          break; /* EVT_BLUE_GAP_SLAVE_SECURITY_INITIATED */
+
+      case EVT_BLUE_GAP_BOND_LOST:    
+        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_BOND_LOST \r\n");
+          aci_gap_allow_rebond(BleApplicationContext.BleApplicationContext_legacy.connectionHandle);
+        APP_DBG_MSG("\r\n\r** Send allow rebond \r\n");
+          break; /* EVT_BLUE_GAP_BOND_LOST */
+
+      case EVT_BLUE_GAP_DEVICE_FOUND:  
+        APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_DEVICE_FOUND \r\n");
+          break; /* EVT_BLUE_GAP_DEVICE_FOUND */
+
+      case EVT_BLUE_GAP_ADDR_NOT_RESOLVED:
+         APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_DEVICE_FOUND \r\n");
+          break; /* EVT_BLUE_GAP_DEVICE_FOUND */
+      
+      case (EVT_BLUE_GAP_KEYPRESS_NOTIFICATION):
+         APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_KEYPRESS_NOTIFICATION \r\n");
+          break; /* EVT_BLUE_GAP_KEY_PRESS_NOTIFICATION */    
+
+       case (EVT_BLUE_GAP_NUMERIC_COMPARISON_VALUE):
+          APP_DBG_MSG("numeric_value = %ld\r\n",
+                      ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value);
+
+          APP_DBG_MSG("Hex_value = %lx\r\n",
+                      ((aci_gap_numeric_comparison_value_event_rp0 *)(blue_evt->data))->Numeric_Value);
+
+          aci_gap_numeric_comparison_value_confirm_yesno(BleApplicationContext.BleApplicationContext_legacy.connectionHandle, 1); /* CONFIRM_YES = 1 */
+
+          APP_DBG_MSG("\r\n\r** aci_gap_numeric_comparison_value_confirm_yesno-->YES \r\n");
+          break;
+
+        case (EVT_BLUE_GAP_PAIRING_CMPLT):
+          {
+            pairing_complete = (aci_gap_pairing_complete_event_rp0*)blue_evt->data;
+
+            APP_DBG_MSG("BLE_CTRL_App_Notification: EVT_BLUE_GAP_PAIRING_CMPLT, pairing_complete->Status = %d\r\n",pairing_complete->Status);
+            if (pairing_complete->Status == 0) {
+              APP_DBG_MSG("\r\n\r** Pairing OK \r\n");
+            } else {
+              APP_DBG_MSG("\r\n\r** Pairing KO \r\n");
+            }
+          }
+          break;
+
+      /* USER CODE END ecode */
+        case EVT_BLUE_GAP_PROCEDURE_COMPLETE:
+          APP_DBG_MSG("\r\n\r** EVT_BLUE_GAP_PROCEDURE_COMPLETE \r\n");
+          break;
+      }
+      break; /* EVT_VENDOR */
+      default:
+        break;
+  }
+
+  return (SVCCTL_UserEvtFlowEnable);
+}
+
+static void set_advertisment_service_uid(uint8_t* uid, uint8_t uid_len) {
+    BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen = 1;
+    if(uid_len == 2) {
+        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_16_BIT_SERV_UUID;
+    } else if (uid_len == 4) {
+        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_32_BIT_SERV_UUID;
+    } else if(uid_len == 16) {
+        BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = AD_TYPE_128_BIT_SERV_UUID_CMPLT_LIST;
+    }
+    memcpy(&BleApplicationContext.BleApplicationContext_legacy.advtServUUID[1], uid, uid_len);
+    BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen += uid_len;
+}
+
+APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status() {
+    return BleApplicationContext.Device_Connection_Status;
+}
+
+static void Ble_Tl_Init( void ) {
+  HCI_TL_HciInitConf_t Hci_Tl_Init_Conf;
+
+  MtxHciId = osMutexNew( NULL );
+  SemHciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */
+
+  Hci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&BleCmdBuffer;
+  Hci_Tl_Init_Conf.StatusNotCallBack = BLE_StatusNot;
+  hci_init(BLE_UserEvtRx, (void*) &Hci_Tl_Init_Conf);
+}
+
+static void Ble_Hci_Gap_Gatt_Init() {
+  uint8_t role;
+  uint16_t gap_service_handle, gap_dev_name_char_handle, gap_appearance_char_handle;
+  const uint8_t *bd_addr;
+  uint32_t srd_bd_addr[2];
+  uint16_t appearance[1] = { BLE_CFG_GAP_APPEARANCE };
+
+  /*HCI Reset to synchronise BLE Stack*/
+  hci_reset();
+
+  /**
+   * Write the BD Address
+   */
+  bd_addr = BleGetBdAddress();
+  aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET,
+                            CONFIG_DATA_PUBADDR_LEN,
+                            (uint8_t*) bd_addr);
+
+  /* BLE MAC in ADV Packet */
+  manuf_data[ sizeof(manuf_data)-6] = bd_addr[5];
+  manuf_data[ sizeof(manuf_data)-5] = bd_addr[4];
+  manuf_data[ sizeof(manuf_data)-4] = bd_addr[3];
+  manuf_data[ sizeof(manuf_data)-3] = bd_addr[2];
+  manuf_data[ sizeof(manuf_data)-2] = bd_addr[1];
+  manuf_data[ sizeof(manuf_data)-1] = bd_addr[0];
+
+  /**
+   * Write Identity root key used to derive LTK and CSRK
+   */
+    aci_hal_write_config_data(CONFIG_DATA_IR_OFFSET,
+    CONFIG_DATA_IR_LEN,
+                            (uint8_t*) BLE_CFG_IR_VALUE);
+
+   /**
+   * Write Encryption root key used to derive LTK and CSRK
+   */
+    aci_hal_write_config_data(CONFIG_DATA_ER_OFFSET,
+    CONFIG_DATA_ER_LEN,
+                            (uint8_t*) BLE_CFG_ER_VALUE);
+
+   /**
+   * Write random bd_address
+   */
+   /* random_bd_address = R_bd_address;
+    aci_hal_write_config_data(CONFIG_DATA_RANDOM_ADDRESS_WR,
+    CONFIG_DATA_RANDOM_ADDRESS_LEN,
+                            (uint8_t*) random_bd_address);
+  */
+
+  /**
+   * Static random Address
+   * The two upper bits shall be set to 1
+   * The lowest 32bits is read from the UDN to differentiate between devices
+   * The RNG may be used to provide a random number on each power on
+   */
+  srd_bd_addr[1] =  0x0000ED6E;
+  srd_bd_addr[0] =  LL_FLASH_GetUDN( );
+  aci_hal_write_config_data( CONFIG_DATA_RANDOM_ADDRESS_OFFSET, CONFIG_DATA_RANDOM_ADDRESS_LEN, (uint8_t*)srd_bd_addr );
+
+  /**
+   * Write Identity root key used to derive LTK and CSRK
+   */
+    aci_hal_write_config_data( CONFIG_DATA_IR_OFFSET, CONFIG_DATA_IR_LEN, (uint8_t*)BLE_CFG_IR_VALUE );
+
+   /**
+   * Write Encryption root key used to derive LTK and CSRK
+   */
+    aci_hal_write_config_data( CONFIG_DATA_ER_OFFSET, CONFIG_DATA_ER_LEN, (uint8_t*)BLE_CFG_ER_VALUE );
+
+  /**
+   * Set TX Power to 0dBm.
+   */
+  aci_hal_set_tx_power_level(1, CFG_TX_POWER);
+
+  /**
+   * Initialize GATT interface
+   */
+  aci_gatt_init();
+
+  /**
+   * Initialize GAP interface
+   */
+  role = 0;
+
+#if (BLE_CFG_PERIPHERAL == 1)
+  role |= GAP_PERIPHERAL_ROLE;
+#endif
+
+#if (BLE_CFG_CENTRAL == 1)
+  role |= GAP_CENTRAL_ROLE;
+#endif
+
+  if (role > 0)
+  {
+    const char *name = furi_hal_version_get_device_name_ptr();
+    aci_gap_init(role, 0,
+                 strlen(name),
+                 &gap_service_handle, &gap_dev_name_char_handle, &gap_appearance_char_handle);
+
+    if (aci_gatt_update_char_value(gap_service_handle, gap_dev_name_char_handle, 0, strlen(name), (uint8_t *) name))
+    {
+      BLE_DBG_SVCCTL_MSG("Device Name aci_gatt_update_char_value failed.\r\n");
+    }
+  }
+
+  if(aci_gatt_update_char_value(gap_service_handle,
+                                gap_appearance_char_handle,
+                                0,
+                                2,
+                                (uint8_t *)&appearance))
+  {
+    BLE_DBG_SVCCTL_MSG("Appearance aci_gatt_update_char_value failed.\r\n");
+  }
+  /**
+   * Initialize Default PHY
+   */
+  hci_le_set_default_phy(ALL_PHYS_PREFERENCE,TX_2M_PREFERRED,RX_2M_PREFERRED);
+
+  /**
+   * Initialize IO capability
+   */
+  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.ioCapability = CFG_IO_CAPABILITY;
+  aci_gap_set_io_capability(BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.ioCapability);
+
+  /**
+   * Initialize authentication
+   */
+  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.mitm_mode = CFG_MITM_PROTECTION;
+  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMin = CFG_ENCRYPTION_KEY_SIZE_MIN;
+  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMax = CFG_ENCRYPTION_KEY_SIZE_MAX;
+  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Use_Fixed_Pin = CFG_USED_FIXED_PIN;
+  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Fixed_Pin = CFG_FIXED_PIN;
+  BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode = CFG_BONDING_MODE;
+
+  aci_gap_set_authentication_requirement(BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode,
+                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.mitm_mode,
+                                         CFG_SC_SUPPORT,
+                                         CFG_KEYPRESS_NOTIFICATION_SUPPORT,
+                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMin,
+                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.encryptionKeySizeMax,
+                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Use_Fixed_Pin,
+                                         BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.Fixed_Pin,
+                                         PUBLIC_ADDR
+                                         );
+
+  /**
+   * Initialize whitelist
+   */
+   if (BleApplicationContext.BleApplicationContext_legacy.bleSecurityParam.bonding_mode)
+   {
+     aci_gap_configure_whitelist();
+   }
+}
+
+static void Adv_Request(APP_BLE_ConnStatus_t New_Status)
+{
+  tBleStatus ret = BLE_STATUS_INVALID_PARAMS;
+  uint16_t Min_Inter, Max_Inter;
+
+  if (New_Status == APP_BLE_FAST_ADV)
+  {
+    Min_Inter = AdvIntervalMin;
+    Max_Inter = AdvIntervalMax;
+  }
+  else
+  {
+    Min_Inter = CFG_LP_CONN_ADV_INTERVAL_MIN;
+    Max_Inter = CFG_LP_CONN_ADV_INTERVAL_MAX;
+  }
+
+    /**
+     * Stop the timer, it will be restarted for a new shot
+     * It does not hurt if the timer was not running
+     */
+    HW_TS_Stop(BleApplicationContext.Advertising_mgr_timer_Id);
+
+    APP_DBG_MSG("First index in %d state \r\n", BleApplicationContext.Device_Connection_Status);
+
+    if ((New_Status == APP_BLE_LP_ADV)
+        && ((BleApplicationContext.Device_Connection_Status == APP_BLE_FAST_ADV)
+            || (BleApplicationContext.Device_Connection_Status == APP_BLE_LP_ADV)))
+    {
+      /* Connection in ADVERTISE mode have to stop the current advertising */
+      ret = aci_gap_set_non_discoverable();
+      if (ret == BLE_STATUS_SUCCESS)
+      {
+        APP_DBG_MSG("Successfully Stopped Advertising \r\n");
+      }
+      else
+      {
+        APP_DBG_MSG("Stop Advertising Failed , result: %d \r\n", ret);
+      }
+    }
+
+    BleApplicationContext.Device_Connection_Status = New_Status;
+
+    const char* name = furi_hal_version_get_ble_local_device_name_ptr();
+
+    /* Start Fast or Low Power Advertising */
+    ret = aci_gap_set_discoverable(
+        ADV_IND,
+        Min_Inter,
+        Max_Inter,
+        PUBLIC_ADDR,
+        NO_WHITE_LIST_USE, /* use white list */
+        strlen(name),
+        (uint8_t*)name,
+        BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen,
+        BleApplicationContext.BleApplicationContext_legacy.advtServUUID,
+        0,
+        0);
+    if(ret) {
+      FURI_LOG_E("APP ble", "Set discoverable err: %d", ret);
+    }
+
+    /* Update Advertising data */
+    ret = aci_gap_update_adv_data(sizeof(manuf_data), (uint8_t*) manuf_data);
+    if (ret == BLE_STATUS_SUCCESS) {
+      if (New_Status == APP_BLE_FAST_ADV) {
+        APP_DBG_MSG("Successfully Start Fast Advertising \r\n" );
+        /* Start Timer to STOP ADV - TIMEOUT */
+        HW_TS_Start(BleApplicationContext.Advertising_mgr_timer_Id, INITIAL_ADV_TIMEOUT);
+      } else {
+        APP_DBG_MSG("Successfully Start Low Power Advertising \r\n");
+      }
+    } else {
+      if (New_Status == APP_BLE_FAST_ADV) {
+        APP_DBG_MSG("Start Fast Advertising Failed , result: %d \r\n", ret);
+      } else {
+        APP_DBG_MSG("Start Low Power Advertising Failed , result: %d \r\n", ret);
+      }
+    }
+}
+
+const uint8_t* BleGetBdAddress( void ) {
+  uint8_t *otp_addr;
+  const uint8_t *bd_addr;
+  uint32_t udn;
+  uint32_t company_id;
+  uint32_t device_id;
+
+  udn = LL_FLASH_GetUDN();
+
+  if(udn != 0xFFFFFFFF) {
+    company_id = LL_FLASH_GetSTCompanyID();
+    device_id = LL_FLASH_GetDeviceID();
+
+    bd_addr_udn[0] = (uint8_t)(udn & 0x000000FF);
+    bd_addr_udn[1] = (uint8_t)( (udn & 0x0000FF00) >> 8 );
+    bd_addr_udn[2] = (uint8_t)( (udn & 0x00FF0000) >> 16 );
+    bd_addr_udn[3] = (uint8_t)device_id;
+    bd_addr_udn[4] = (uint8_t)(company_id & 0x000000FF);;
+    bd_addr_udn[5] = (uint8_t)( (company_id & 0x0000FF00) >> 8 );
+
+    bd_addr = (const uint8_t *)bd_addr_udn;
+  } else {
+    otp_addr = OTP_Read(0);
+    if(otp_addr) {
+      bd_addr = ((OTP_ID0_t*)otp_addr)->bd_address;
+    } else {
+      bd_addr = M_bd_addr;
+    }
+  }
+
+  return bd_addr;
+}
+
+/*************************************************************
+ *
+ *SPECIFIC FUNCTIONS
+ *
+ *************************************************************/
+static void Adv_Mgr( void ) {
+  /**
+   * The code shall be executed in the background as an aci command may be sent
+   * The background is the only place where the application can make sure a new aci command
+   * is not sent if there is a pending one
+   */
+  osThreadFlagsSet( AdvUpdateProcessId, 1 );
+}
+
+static void AdvUpdateProcess(void *argument) {
+  UNUSED(argument);
+
+  for(;;) {
+    osThreadFlagsWait( 1, osFlagsWaitAny, osWaitForever);
+    Adv_Update( );
+  }
+}
+
+static void Adv_Update( void ) {
+  Adv_Request(APP_BLE_LP_ADV);
+
+}
+
+static void HciUserEvtProcess(void *argument) {
+  UNUSED(argument);
+
+  for(;;)
+  {
+    osThreadFlagsWait( 1, osFlagsWaitAny, osWaitForever);
+    hci_user_evt_proc( );
+  }
+}
+
+/*************************************************************
+ *
+ * WRAP FUNCTIONS
+ *
+ *************************************************************/
+void hci_notify_asynch_evt(void* pdata) {
+  UNUSED(pdata);
+  osThreadFlagsSet( HciUserEvtProcessId, 1 );
+}
+
+void hci_cmd_resp_release(uint32_t flag) {
+  UNUSED(flag);
+  osSemaphoreRelease( SemHciId );
+}
+
+void hci_cmd_resp_wait(uint32_t timeout) {
+  UNUSED(timeout);
+  osSemaphoreAcquire( SemHciId, osWaitForever );
+}
+
+static void BLE_UserEvtRx( void * pPayload ) {
+  SVCCTL_UserEvtFlowStatus_t svctl_return_status;
+  tHCI_UserEvtRxParam *pParam;
+
+  pParam = (tHCI_UserEvtRxParam *)pPayload;
+
+  svctl_return_status = SVCCTL_UserEvtRx((void *)&(pParam->pckt->evtserial));
+  if (svctl_return_status != SVCCTL_UserEvtFlowDisable) {
+    pParam->status = HCI_TL_UserEventFlow_Enable;
+  } else {
+    pParam->status = HCI_TL_UserEventFlow_Disable;
+  }
+}
+
+static void BLE_StatusNot( HCI_TL_CmdStatus_t status ) {
+  switch (status) {
+    case HCI_TL_CmdBusy:
+      osMutexAcquire( MtxHciId, osWaitForever );
+      break;
+    case HCI_TL_CmdAvailable:
+      osMutexRelease( MtxHciId );
+      break;
+    default:
+      break;
+  }
+}
+
+void SVCCTL_ResumeUserEventFlow( void ) {
+  hci_resume_flow();
+}

+ 27 - 0
firmware/targets/f7/ble-glue/app_ble.h

@@ -0,0 +1,27 @@
+#pragma once 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include "hci_tl.h"
+
+typedef enum {
+    APP_BLE_IDLE,
+    APP_BLE_FAST_ADV,
+    APP_BLE_LP_ADV,
+    APP_BLE_SCAN,
+    APP_BLE_LP_CONNECTING,
+    APP_BLE_CONNECTED_SERVER,
+    APP_BLE_CONNECTED_CLIENT
+} APP_BLE_ConnStatus_t;
+
+bool APP_BLE_Init();
+bool APP_BLE_Start();
+
+APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
+
+#ifdef __cplusplus
+}
+#endif

+ 43 - 0
firmware/targets/f7/ble-glue/app_common.h

@@ -0,0 +1,43 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+  * File Name          : app_common.h
+  * Description        : App Common application configuration file for STM32WPAN Middleware.
+  *
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef APP_COMMON_H
+#define APP_COMMON_H
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <furi/common_defines.h>
+
+#include "app_conf.h"
+
+#define DIVC( x, y )         (((x)+(y)-1)/(y))
+
+#define DIVR( x, y )         (((x)+((y)/2))/(y))
+
+#endif

+ 474 - 0
firmware/targets/f7/ble-glue/app_conf.h

@@ -0,0 +1,474 @@
+#pragma once
+
+#include "hw.h"
+#include "hw_conf.h"
+#include "hw_if.h"
+#include "ble_bufsize.h"
+
+#define CFG_TX_POWER                      (0x19) /* +0dBm */
+
+/**
+ * Define Advertising parameters
+ */
+#define CFG_ADV_BD_ADDRESS                (0x7257acd87a6c)
+#define CFG_FAST_CONN_ADV_INTERVAL_MIN    (0x80)   /**< 80ms */
+#define CFG_FAST_CONN_ADV_INTERVAL_MAX    (0xa0)  /**< 100ms */
+#define CFG_LP_CONN_ADV_INTERVAL_MIN      (0x640) /**< 1s */
+#define CFG_LP_CONN_ADV_INTERVAL_MAX      (0xfa0) /**< 2.5s */
+
+/**
+ * Define IO Authentication
+ */
+#define CFG_BONDING_MODE                 (1)
+#define CFG_FIXED_PIN                    (111111)
+#define CFG_USED_FIXED_PIN               (1)
+#define CFG_ENCRYPTION_KEY_SIZE_MAX      (16)
+#define CFG_ENCRYPTION_KEY_SIZE_MIN      (8)
+
+/**
+ * Define IO capabilities
+ */
+#define CFG_IO_CAPABILITY_DISPLAY_ONLY       (0x00)
+#define CFG_IO_CAPABILITY_DISPLAY_YES_NO     (0x01)
+#define CFG_IO_CAPABILITY_KEYBOARD_ONLY      (0x02)
+#define CFG_IO_CAPABILITY_NO_INPUT_NO_OUTPUT (0x03)
+#define CFG_IO_CAPABILITY_KEYBOARD_DISPLAY   (0x04)
+
+#define CFG_IO_CAPABILITY              CFG_IO_CAPABILITY_DISPLAY_YES_NO
+
+/**
+ * Define MITM modes
+ */
+#define CFG_MITM_PROTECTION_NOT_REQUIRED      (0x00)
+#define CFG_MITM_PROTECTION_REQUIRED          (0x01)
+
+#define CFG_MITM_PROTECTION             CFG_MITM_PROTECTION_REQUIRED
+
+/**
+ * Define Secure Connections Support
+ */
+#define CFG_SECURE_NOT_SUPPORTED       (0x00)
+#define CFG_SECURE_OPTIONAL            (0x01)
+#define CFG_SECURE_MANDATORY           (0x02)
+
+#define CFG_SC_SUPPORT                 CFG_SECURE_OPTIONAL
+
+/**
+ * Define Keypress Notification Support
+ */
+#define CFG_KEYPRESS_NOT_SUPPORTED      (0x00)
+#define CFG_KEYPRESS_SUPPORTED          (0x01)
+
+#define CFG_KEYPRESS_NOTIFICATION_SUPPORT             CFG_KEYPRESS_NOT_SUPPORTED
+
+/**
+ * Numeric Comparison Answers
+ */
+#define YES (0x01)
+#define NO  (0x00)
+
+/**
+ * Device name configuration for Generic Access Service
+ */
+#define CFG_GAP_DEVICE_NAME             "TEMPLATE"
+#define CFG_GAP_DEVICE_NAME_LENGTH      (8)
+
+/**
+ * Define PHY
+ */
+#define ALL_PHYS_PREFERENCE                             0x00
+#define RX_2M_PREFERRED                                 0x02
+#define TX_2M_PREFERRED                                 0x02
+#define TX_1M                                           0x01
+#define TX_2M                                           0x02
+#define RX_1M                                           0x01
+#define RX_2M                                           0x02
+
+/**
+*   Identity root key used to derive LTK and CSRK
+*/
+#define CFG_BLE_IRK     {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0}
+
+/**
+* Encryption root key used to derive LTK and CSRK
+*/
+#define CFG_BLE_ERK     {0xfe,0xdc,0xba,0x09,0x87,0x65,0x43,0x21,0xfe,0xdc,0xba,0x09,0x87,0x65,0x43,0x21}
+
+/* USER CODE BEGIN Generic_Parameters */
+/**
+ * SMPS supply
+ * SMPS not used when Set to 0
+ * SMPS used when Set to 1
+ */
+#define CFG_USE_SMPS    1
+/* USER CODE END Generic_Parameters */
+
+/**< specific parameters */
+/*****************************************************/
+
+/**
+* AD Element - Group B Feature
+*/
+/* LSB - Second Byte */
+#define CFG_FEATURE_OTA_REBOOT                  (0x20)
+
+/******************************************************************************
+ * BLE Stack
+ ******************************************************************************/
+/**
+ * Maximum number of simultaneous connections that the device will support.
+ * Valid values are from 1 to 8
+ */
+#define CFG_BLE_NUM_LINK            2
+
+/**
+ * Maximum number of Services that can be stored in the GATT database.
+ * Note that the GAP and GATT services are automatically added so this parameter should be 2 plus the number of user services
+ */
+#define CFG_BLE_NUM_GATT_SERVICES   8
+
+/**
+ * Maximum number of Attributes
+ * (i.e. the number of characteristic + the number of characteristic values + the number of descriptors, excluding the services)
+ * that can be stored in the GATT database.
+ * Note that certain characteristics and relative descriptors are added automatically during device initialization
+ * so this parameters should be 9 plus the number of user Attributes
+ */
+#define CFG_BLE_NUM_GATT_ATTRIBUTES 68
+
+/**
+ * Maximum supported ATT_MTU size
+ */
+#define CFG_BLE_MAX_ATT_MTU             (156)
+
+/**
+ * Size of the storage area for Attribute values
+ *  This value depends on the number of attributes used by application. In particular the sum of the following quantities (in octets) should be made for each attribute:
+ *  - attribute value length
+ *  - 5, if UUID is 16 bit; 19, if UUID is 128 bit
+ *  - 2, if server configuration descriptor is used
+ *  - 2*DTM_NUM_LINK, if client configuration descriptor is used
+ *  - 2, if extended properties is used
+ *  The total amount of memory needed is the sum of the above quantities for each attribute.
+ */
+#define CFG_BLE_ATT_VALUE_ARRAY_SIZE    (1344)
+
+/**
+ * Prepare Write List size in terms of number of packet
+ */
+#define CFG_BLE_PREPARE_WRITE_LIST_SIZE         BLE_PREP_WRITE_X_ATT(CFG_BLE_MAX_ATT_MTU)
+
+/**
+ * Number of allocated memory blocks
+ */
+#define CFG_BLE_MBLOCK_COUNT            (BLE_MBLOCKS_CALC(CFG_BLE_PREPARE_WRITE_LIST_SIZE, CFG_BLE_MAX_ATT_MTU, CFG_BLE_NUM_LINK))
+
+/**
+ * Enable or disable the Extended Packet length feature. Valid values are 0 or 1.
+ */
+#define CFG_BLE_DATA_LENGTH_EXTENSION   1
+
+/**
+ * Sleep clock accuracy in Slave mode (ppm value)
+ */
+#define CFG_BLE_SLAVE_SCA   500
+
+/**
+ * Sleep clock accuracy in Master mode
+ * 0 : 251 ppm to 500 ppm
+ * 1 : 151 ppm to 250 ppm
+ * 2 : 101 ppm to 150 ppm
+ * 3 : 76 ppm to 100 ppm
+ * 4 : 51 ppm to 75 ppm
+ * 5 : 31 ppm to 50 ppm
+ * 6 : 21 ppm to 30 ppm
+ * 7 : 0 ppm to 20 ppm
+ */
+#define CFG_BLE_MASTER_SCA   0
+
+/**
+ *  Source for the low speed clock for RF wake-up
+ *  1 : external high speed crystal HSE/32/32
+ *  0 : external low speed crystal ( no calibration )
+ */
+#define CFG_BLE_LSE_SOURCE  0
+
+/**
+ * Start up time of the high speed (16 or 32 MHz) crystal oscillator in units of 625/256 us (~2.44 us)
+ */
+#define CFG_BLE_HSE_STARTUP_TIME  0x148
+
+/**
+ * Maximum duration of the connection event when the device is in Slave mode in units of 625/256 us (~2.44 us)
+ */
+#define CFG_BLE_MAX_CONN_EVENT_LENGTH  ( 0xFFFFFFFF )
+
+/**
+ * Viterbi Mode
+ * 1 : enabled
+ * 0 : disabled
+ */
+#define CFG_BLE_VITERBI_MODE  1
+
+/**
+ *  LL Only Mode
+ *  1 : LL Only
+ *  0 : LL + Host
+ */
+#define CFG_BLE_LL_ONLY  0
+/******************************************************************************
+ * Transport Layer
+ ******************************************************************************/
+/**
+ * Queue length of BLE Event
+ * This parameter defines the number of asynchronous events that can be stored in the HCI layer before
+ * being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer
+ * is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large
+ * enough to store all asynchronous events received in between.
+ * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events
+ * between the HCI command and its event.
+ * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small,
+ * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting
+ * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate
+ * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout).
+ */
+#define CFG_TLBLE_EVT_QUEUE_LENGTH 5
+/**
+ * This parameter should be set to fit most events received by the HCI layer. It defines the buffer size of each element
+ * allocated in the queue of received events and can be used to optimize the amount of RAM allocated by the Memory Manager.
+ * It should not exceed 255 which is the maximum HCI packet payload size (a greater value is a lost of memory as it will
+ * never be used)
+ * With the current wireless firmware implementation, this parameter shall be kept to 255
+ *
+ */
+#define CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE 255   /**< Set to 255 with the memory manager and the mailbox */
+
+#define TL_BLE_EVENT_FRAME_SIZE ( TL_EVT_HDR_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE )
+/******************************************************************************
+ * UART interfaces
+ ******************************************************************************/
+
+/**
+ * Select UART interfaces
+ */
+#define CFG_DEBUG_TRACE_UART    hw_uart1
+#define CFG_CONSOLE_MENU      0
+
+/******************************************************************************
+ * Low Power
+ ******************************************************************************/
+/**
+ *  When set to 1, the low power mode is enable
+ *  When set to 0, the device stays in RUN mode
+ */
+#define CFG_LPM_SUPPORTED    1
+
+/******************************************************************************
+ * Timer Server
+ ******************************************************************************/
+/**
+ *  CFG_RTC_WUCKSEL_DIVIDER:  This sets the RTCCLK divider to the wakeup timer.
+ *  The lower is the value, the better is the power consumption and the accuracy of the timerserver
+ *  The higher is the value, the finest is the granularity
+ *
+ *  CFG_RTC_ASYNCH_PRESCALER: This sets the asynchronous prescaler of the RTC. It should as high as possible ( to ouput
+ *  clock as low as possible) but the output clock should be equal or higher frequency compare to the clock feeding
+ *  the wakeup timer. A lower clock speed would impact the accuracy of the timer server.
+ *
+ *  CFG_RTC_SYNCH_PRESCALER: This sets the synchronous prescaler of the RTC.
+ *  When the 1Hz calendar clock is required, it shall be sets according to other settings
+ *  When the 1Hz calendar clock is not needed, CFG_RTC_SYNCH_PRESCALER should be set to 0x7FFF (MAX VALUE)
+ *
+ *  CFG_RTCCLK_DIVIDER_CONF:
+ *  Shall be set to either 0,2,4,8,16
+ *  When set to either 2,4,8,16, the 1Hhz calendar is supported
+ *  When set to 0, the user sets its own configuration
+ *
+ *  The following settings are computed with LSI as input to the RTC
+ */
+#define CFG_RTCCLK_DIVIDER_CONF 0
+
+#if (CFG_RTCCLK_DIVIDER_CONF == 0)
+/**
+ * Custom configuration
+ * It does not support 1Hz calendar
+ * It divides the RTC CLK by 16
+ */
+#define CFG_RTCCLK_DIV  (16)
+#define CFG_RTC_WUCKSEL_DIVIDER (0)
+#define CFG_RTC_ASYNCH_PRESCALER (CFG_RTCCLK_DIV - 1)
+#define CFG_RTC_SYNCH_PRESCALER (0x7FFF)
+
+#else
+
+#if (CFG_RTCCLK_DIVIDER_CONF == 2)
+/**
+ * It divides the RTC CLK by 2
+ */
+#define CFG_RTC_WUCKSEL_DIVIDER (3)
+#endif
+
+#if (CFG_RTCCLK_DIVIDER_CONF == 4)
+/**
+ * It divides the RTC CLK by 4
+ */
+#define CFG_RTC_WUCKSEL_DIVIDER (2)
+#endif
+
+#if (CFG_RTCCLK_DIVIDER_CONF == 8)
+/**
+ * It divides the RTC CLK by 8
+ */
+#define CFG_RTC_WUCKSEL_DIVIDER (1)
+#endif
+
+#if (CFG_RTCCLK_DIVIDER_CONF == 16)
+/**
+ * It divides the RTC CLK by 16
+ */
+#define CFG_RTC_WUCKSEL_DIVIDER (0)
+#endif
+
+#define CFG_RTCCLK_DIV              CFG_RTCCLK_DIVIDER_CONF
+#define CFG_RTC_ASYNCH_PRESCALER    (CFG_RTCCLK_DIV - 1)
+#define CFG_RTC_SYNCH_PRESCALER     (DIVR( LSE_VALUE, (CFG_RTC_ASYNCH_PRESCALER+1) ) - 1 )
+
+#endif
+
+/** tick timer value in us */
+#define CFG_TS_TICK_VAL           DIVR( (CFG_RTCCLK_DIV * 1000000), LSE_VALUE )
+
+typedef enum
+{
+  CFG_TIM_PROC_ID_ISR,
+  /* USER CODE BEGIN CFG_TimProcID_t */
+
+  /* USER CODE END CFG_TimProcID_t */
+} CFG_TimProcID_t;
+
+/******************************************************************************
+ * Debug
+ ******************************************************************************/
+/**
+ * When set, this resets some hw resources to set the device in the same state than the power up
+ * The FW resets only register that may prevent the FW to run properly
+ *
+ * This shall be set to 0 in a final product
+ *
+ */
+#define CFG_HW_RESET_BY_FW         0
+
+/**
+ * keep debugger enabled while in any low power mode when set to 1
+ * should be set to 0 in production
+ */
+#define CFG_DEBUGGER_SUPPORTED    0
+
+/**
+ * When set to 1, the traces are enabled in the BLE services
+ */
+#define CFG_DEBUG_BLE_TRACE     1
+
+/**
+ * Enable or Disable traces in application
+ */
+#define CFG_DEBUG_APP_TRACE     1
+
+#if (CFG_DEBUG_APP_TRACE != 0)
+#define APP_DBG_MSG                 PRINT_MESG_DBG
+#else
+#define APP_DBG_MSG                 PRINT_NO_MESG
+#endif
+
+#if ( (CFG_DEBUG_BLE_TRACE != 0) || (CFG_DEBUG_APP_TRACE != 0) )
+#define CFG_DEBUG_TRACE             1
+#endif
+
+#if (CFG_DEBUG_TRACE != 0)
+#undef CFG_LPM_SUPPORTED
+#undef CFG_DEBUGGER_SUPPORTED
+#define CFG_LPM_SUPPORTED         0
+#define CFG_DEBUGGER_SUPPORTED      1
+#endif
+
+/**
+ * When CFG_DEBUG_TRACE_FULL is set to 1, the trace are output with the API name, the file name and the line number
+ * When CFG_DEBUG_TRACE_LIGHT is set to 1, only the debug message is output
+ *
+ * When both are set to 0, no trace are output
+ * When both are set to 1,  CFG_DEBUG_TRACE_FULL is selected
+ */
+#define CFG_DEBUG_TRACE_LIGHT     0
+#define CFG_DEBUG_TRACE_FULL      0
+
+#if (( CFG_DEBUG_TRACE != 0 ) && ( CFG_DEBUG_TRACE_LIGHT == 0 ) && (CFG_DEBUG_TRACE_FULL == 0))
+#undef CFG_DEBUG_TRACE_FULL
+#undef CFG_DEBUG_TRACE_LIGHT
+#define CFG_DEBUG_TRACE_FULL      0
+#define CFG_DEBUG_TRACE_LIGHT     1
+#endif
+
+#if ( CFG_DEBUG_TRACE == 0 )
+#undef CFG_DEBUG_TRACE_FULL
+#undef CFG_DEBUG_TRACE_LIGHT
+#define CFG_DEBUG_TRACE_FULL      0
+#define CFG_DEBUG_TRACE_LIGHT     0
+#endif
+
+/**
+ * When not set, the traces is looping on sending the trace over UART
+ */
+#define DBG_TRACE_USE_CIRCULAR_QUEUE 0
+
+/**
+ * max buffer Size to queue data traces and max data trace allowed.
+ * Only Used if DBG_TRACE_USE_CIRCULAR_QUEUE is defined
+ */
+#define DBG_TRACE_MSG_QUEUE_SIZE 4096
+#define MAX_DBG_TRACE_MSG_SIZE 1024
+
+#define CFG_LED_SUPPORTED         0
+#define CFG_BUTTON_SUPPORTED      0
+
+/******************************************************************************
+ * FreeRTOS
+ ******************************************************************************/
+#define CFG_SHCI_USER_EVT_PROCESS_NAME        "ble_shci_evt"
+#define CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS   (0)
+#define CFG_SHCI_USER_EVT_PROCESS_CB_MEM      (0)
+#define CFG_SHCI_USER_EVT_PROCESS_CB_SIZE     (0)
+#define CFG_SHCI_USER_EVT_PROCESS_STACK_MEM   (0)
+#define CFG_SHCI_USER_EVT_PROCESS_PRIORITY    osPriorityNone
+#define CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE  (128 * 7)
+
+#define CFG_HCI_USER_EVT_PROCESS_NAME         "ble_hci_evt"
+#define CFG_HCI_USER_EVT_PROCESS_ATTR_BITS    (0)
+#define CFG_HCI_USER_EVT_PROCESS_CB_MEM       (0)
+#define CFG_HCI_USER_EVT_PROCESS_CB_SIZE      (0)
+#define CFG_HCI_USER_EVT_PROCESS_STACK_MEM    (0)
+#define CFG_HCI_USER_EVT_PROCESS_PRIORITY     osPriorityNone
+#define CFG_HCI_USER_EVT_PROCESS_STACK_SIZE   (128 * 8)
+
+#define CFG_ADV_UPDATE_PROCESS_NAME           "ble_adv_upd"
+#define CFG_ADV_UPDATE_PROCESS_ATTR_BITS      (0)
+#define CFG_ADV_UPDATE_PROCESS_CB_MEM         (0)
+#define CFG_ADV_UPDATE_PROCESS_CB_SIZE        (0)
+#define CFG_ADV_UPDATE_PROCESS_STACK_MEM      (0)
+#define CFG_ADV_UPDATE_PROCESS_PRIORITY       osPriorityNone
+#define CFG_ADV_UPDATE_PROCESS_STACK_SIZE     (128 * 6)
+
+#define CFG_HRS_PROCESS_NAME                  "hrs"
+#define CFG_HRS_PROCESS_ATTR_BITS             (0)
+#define CFG_HRS_PROCESS_CB_MEM                (0)
+#define CFG_HRS_PROCESS_CB_SIZE               (0)
+#define CFG_HRS_PROCESS_STACK_MEM             (0)
+#define CFG_HRS_PROCESS_PRIORITY              osPriorityNone
+#define CFG_HRS_PROCESS_STACK_SIZE            (128 * 8)
+
+typedef enum {
+    CFG_LPM_APP,
+    CFG_LPM_APP_BLE,
+} CFG_LPM_Id_t;
+
+#define CFG_OTP_BASE_ADDRESS    OTP_AREA_BASE
+#define CFG_OTP_END_ADRESS      OTP_AREA_END_ADDR

+ 192 - 0
firmware/targets/f7/ble-glue/app_entry.c

@@ -0,0 +1,192 @@
+#include "app_common.h"
+#include "main.h"
+#include "app_entry.h"
+#include "app_ble.h"
+#include "ble.h"
+#include "tl.h"
+#include "cmsis_os.h"
+#include "shci_tl.h"
+#include <furi-hal.h>
+
+extern RTC_HandleTypeDef hrtc;
+
+#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC(( sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE ), 4U))
+
+PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t EvtPool[POOL_SIZE];
+PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t SystemCmdBuffer;
+PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t SystemSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U];
+PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t BleSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255];
+
+osMutexId_t MtxShciId;
+osSemaphoreId_t SemShciId;
+osThreadId_t ShciUserEvtProcessId;
+
+volatile static BleGlueStatus ble_glue_status = BleGlueStatusUninitialized;
+
+const osThreadAttr_t ShciUserEvtProcess_attr = {
+    .name = CFG_SHCI_USER_EVT_PROCESS_NAME,
+    .attr_bits = CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS,
+    .cb_mem = CFG_SHCI_USER_EVT_PROCESS_CB_MEM,
+    .cb_size = CFG_SHCI_USER_EVT_PROCESS_CB_SIZE,
+    .stack_mem = CFG_SHCI_USER_EVT_PROCESS_STACK_MEM,
+    .priority = CFG_SHCI_USER_EVT_PROCESS_PRIORITY,
+    .stack_size = CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE
+};
+
+static void ShciUserEvtProcess(void *argument);
+static void SystemPower_Config( void );
+static void appe_Tl_Init( void );
+static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status );
+static void APPE_SysUserEvtRx( void * pPayload );
+
+BleGlueStatus APPE_Status() {
+  return ble_glue_status;
+}
+
+void APPE_Init() {
+  ble_glue_status = BleGlueStatusStartup;
+  SystemPower_Config(); /**< Configure the system Power Mode */
+
+  HW_TS_Init(hw_ts_InitMode_Full, &hrtc); /**< Initialize the TimerServer */
+
+  // APPD_Init();
+  furi_hal_power_insomnia_enter();
+
+  appe_Tl_Init();	/* Initialize all transport layers */
+
+  /**
+   * From now, the application is waiting for the ready event ( VS_HCI_C2_Ready )
+   * received on the system channel before starting the Stack
+   * This system event is received with APPE_SysUserEvtRx()
+   */
+}
+
+/*************************************************************
+ *
+ * LOCAL FUNCTIONS
+ *
+ *************************************************************/
+
+/**
+ * @brief  Configure the system for power optimization
+ *
+ * @note  This API configures the system to be ready for low power mode
+ *
+ * @param  None
+ * @retval None
+ */
+static void SystemPower_Config(void) {
+  // Select HSI as system clock source after Wake Up from Stop mode
+  LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
+
+  /* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */
+  LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
+}
+
+static void appe_Tl_Init( void ) {
+  TL_MM_Config_t tl_mm_config;
+  SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf;
+  /**< Reference table initialization */
+  TL_Init();
+
+  MtxShciId = osMutexNew( NULL );
+  SemShciId = osSemaphoreNew( 1, 0, NULL ); /*< Create the semaphore and make it busy at initialization */
+
+  /** FreeRTOS system task creation */
+  ShciUserEvtProcessId = osThreadNew(ShciUserEvtProcess, NULL, &ShciUserEvtProcess_attr);
+
+  /**< System channel initialization */
+  SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&SystemCmdBuffer;
+  SHci_Tl_Init_Conf.StatusNotCallBack = APPE_SysStatusNot;
+  shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf);
+
+  /**< Memory Manager channel initialization */
+  tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer;
+  tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer;
+  tl_mm_config.p_AsynchEvtPool = EvtPool;
+  tl_mm_config.AsynchEvtPoolSize = POOL_SIZE;
+  TL_MM_Init( &tl_mm_config );
+
+  TL_Enable();
+}
+
+static void APPE_SysStatusNot( SHCI_TL_CmdStatus_t status ) {
+  switch (status) {
+    case SHCI_TL_CmdBusy:
+      osMutexAcquire( MtxShciId, osWaitForever );
+      break;
+    case SHCI_TL_CmdAvailable:
+      osMutexRelease( MtxShciId );
+      break;
+    default:
+      break;
+  }
+}
+
+/**
+ * The type of the payload for a system user event is tSHCI_UserEvtRxParam
+ * When the system event is both :
+ *    - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY)
+ *    - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING)
+ * The buffer shall not be released
+ * ( eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable )
+ * When the status is not filled, the buffer is released by default
+ */
+static void APPE_SysUserEvtRx( void * pPayload ) {
+  UNUSED(pPayload);
+  /* Traces channel initialization */
+  // APPD_EnableCPU2( );
+  
+  if (APP_BLE_Init()) {
+    ble_glue_status = BleGlueStatusStarted;
+  } else {
+    ble_glue_status = BleGlueStatusBroken;
+  }
+  furi_hal_power_insomnia_exit();
+}
+
+/*************************************************************
+ *
+ * FREERTOS WRAPPER FUNCTIONS
+ *
+*************************************************************/
+static void ShciUserEvtProcess(void *argument) {
+  UNUSED(argument);
+  for(;;) {
+    osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever);
+    shci_user_evt_proc();
+  }
+}
+
+/*************************************************************
+ *
+ * WRAP FUNCTIONS
+ *
+ *************************************************************/
+void shci_notify_asynch_evt(void* pdata) {
+  UNUSED(pdata);
+  osThreadFlagsSet( ShciUserEvtProcessId, 1 );
+}
+
+void shci_cmd_resp_release(uint32_t flag) {
+  UNUSED(flag);
+  osSemaphoreRelease( SemShciId );
+}
+
+void shci_cmd_resp_wait(uint32_t timeout) {
+  UNUSED(timeout);
+  osSemaphoreAcquire( SemShciId, osWaitForever );
+}
+
+#if(CFG_DEBUG_TRACE != 0)
+void DbgOutputInit( void )
+{
+}
+
+void DbgOutputTraces(  uint8_t *p_data, uint16_t size, void (*cb)(void) )
+{
+  furi_hal_console_tx(p_data, size);
+  cb();
+}
+#endif
+

+ 20 - 0
firmware/targets/f7/ble-glue/app_entry.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    BleGlueStatusUninitialized,
+    BleGlueStatusStartup,
+    BleGlueStatusBroken,
+    BleGlueStatusStarted
+} BleGlueStatus;
+
+void APPE_Init();
+
+BleGlueStatus APPE_Status();
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif

+ 55 - 0
firmware/targets/f7/ble-glue/battery_service.c

@@ -0,0 +1,55 @@
+#include "battery_service.h"
+#include "app_common.h"
+#include "ble.h"
+
+#include <furi.h>
+
+#define BATTERY_SERVICE_TAG "battery service"
+
+typedef struct {
+    uint16_t svc_handle;
+    uint16_t char_level_handle;
+} BatterySvc;
+
+static BatterySvc battery_svc;
+
+bool battery_svc_init() {
+    tBleStatus status;
+    const uint16_t service_uuid = BATTERY_SERVICE_UUID;
+    const uint16_t char_battery_level_uuid = BATTERY_LEVEL_CHAR_UUID;
+
+    // Add Battery service
+    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&service_uuid, PRIMARY_SERVICE, 4, &battery_svc.svc_handle);
+    if(status) {
+        FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery service: %d", status);
+    }
+
+    // Add Battery level characteristic
+    status = aci_gatt_add_char(battery_svc.svc_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t *) &char_battery_level_uuid,
+                                1,
+                                CHAR_PROP_READ | CHAR_PROP_NOTIFY,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &battery_svc.char_level_handle);
+    if(status) {
+        FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed to add Battery level characteristic: %d", status);
+    }
+    return status != BLE_STATUS_SUCCESS;
+}
+
+bool battery_svc_update_level(uint8_t battery_charge) {
+    FURI_LOG_I(BATTERY_SERVICE_TAG, "Updating battery level characteristic");
+    tBleStatus result = aci_gatt_update_char_value(battery_svc.svc_handle,
+                                          battery_svc.char_level_handle,
+                                          0,
+                                          1,
+                                          &battery_charge);
+    if(result) {
+        FURI_LOG_E(BATTERY_SERVICE_TAG, "Failed updating RX characteristic: %d", result);
+    }
+    return result != BLE_STATUS_SUCCESS;
+}

+ 16 - 0
firmware/targets/f7/ble-glue/battery_service.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool battery_svc_init();
+
+bool battery_svc_update_level(uint8_t battery_level);
+
+#ifdef __cplusplus
+}
+#endif

+ 69 - 0
firmware/targets/f7/ble-glue/ble_conf.h

@@ -0,0 +1,69 @@
+/**
+ ******************************************************************************
+  * File Name          : App/ble_conf.h
+  * Description        : Configuration file for BLE Middleware.
+  *
+ ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef BLE_CONF_H
+#define BLE_CONF_H
+
+#include "app_conf.h"
+
+/******************************************************************************
+ *
+ * BLE SERVICES CONFIGURATION
+ * blesvc
+ *
+ ******************************************************************************/
+
+ /**
+ * This setting shall be set to '1' if the device needs to support the Peripheral Role
+ * In the MS configuration, both BLE_CFG_PERIPHERAL and BLE_CFG_CENTRAL shall be set to '1'
+ */
+#define BLE_CFG_PERIPHERAL                                                     1
+
+/**
+ * This setting shall be set to '1' if the device needs to support the Central Role
+ * In the MS configuration, both BLE_CFG_PERIPHERAL and BLE_CFG_CENTRAL shall be set to '1'
+ */
+#define BLE_CFG_CENTRAL                                                        0
+
+/**
+ * There is one handler per service enabled
+ * Note: There is no handler for the Device Information Service
+ *
+ * This shall take into account all registered handlers
+ * (from either the provided services or the custom services)
+ */
+#define BLE_CFG_SVC_MAX_NBR_CB                                                 7
+
+#define BLE_CFG_CLT_MAX_NBR_CB                                                 0
+
+/******************************************************************************
+ * GAP Service - Apprearance
+ ******************************************************************************/
+
+#define BLE_CFG_UNKNOWN_APPEARANCE                  (0)
+#define BLE_CFG_GAP_APPEARANCE                      (0x0086)
+
+/******************************************************************************
+ * Over The Air Feature (OTA) - STM Proprietary
+ ******************************************************************************/
+#define BLE_CFG_OTA_REBOOT_CHAR         0/**< REBOOT OTA MODE CHARACTERISTIC */
+
+#endif /*BLE_CONF_H */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 199 - 0
firmware/targets/f7/ble-glue/ble_dbg_conf.h

@@ -0,0 +1,199 @@
+/**
+ ******************************************************************************
+  * File Name          : App/ble_dbg_conf.h
+  * Description        : Debug configuration file for BLE Middleware.
+  *
+ ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __BLE_DBG_CONF_H
+#define __BLE_DBG_CONF_H
+
+/**
+ * Enable or Disable traces from BLE
+ */
+
+#define BLE_DBG_APP_EN             0
+#define BLE_DBG_DIS_EN             0
+#define BLE_DBG_HRS_EN             0
+#define BLE_DBG_SVCCTL_EN          0
+#define BLE_DBG_BLS_EN             0
+#define BLE_DBG_HTS_EN             0
+#define BLE_DBG_P2P_STM_EN         0
+
+/**
+ * Macro definition
+ */
+#if ( BLE_DBG_APP_EN != 0 )
+#define BLE_DBG_APP_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_APP_MSG             PRINT_NO_MESG
+#endif
+
+#if ( BLE_DBG_DIS_EN != 0 )
+#define BLE_DBG_DIS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_DIS_MSG             PRINT_NO_MESG
+#endif
+
+#if ( BLE_DBG_HRS_EN != 0 )
+#define BLE_DBG_HRS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_HRS_MSG             PRINT_NO_MESG
+#endif
+
+#if ( BLE_DBG_P2P_STM_EN != 0 )
+#define BLE_DBG_P2P_STM_MSG         PRINT_MESG_DBG
+#else
+#define BLE_DBG_P2P_STM_MSG         PRINT_NO_MESG
+#endif
+
+#if ( BLE_DBG_TEMPLATE_STM_EN != 0 )
+#define BLE_DBG_TEMPLATE_STM_MSG         PRINT_MESG_DBG
+#else
+#define BLE_DBG_TEMPLATE_STM_MSG         PRINT_NO_MESG
+#endif
+
+#if ( BLE_DBG_EDS_STM_EN != 0 )
+#define BLE_DBG_EDS_STM_MSG         PRINT_MESG_DBG
+#else
+#define BLE_DBG_EDS_STM_MSG         PRINT_NO_MESG
+#endif
+
+#if ( BLE_DBG_LBS_STM_EN != 0 )
+#define BLE_DBG_LBS_STM_MSG         PRINT_MESG_DBG
+#else
+#define BLE_DBG_LBS_STM_MSG         PRINT_NO_MESG
+#endif
+
+#if ( BLE_DBG_SVCCTL_EN != 0 )
+#define BLE_DBG_SVCCTL_MSG          PRINT_MESG_DBG
+#else
+#define BLE_DBG_SVCCTL_MSG          PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_CTS_EN != 0)
+#define BLE_DBG_CTS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_CTS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_HIDS_EN != 0)
+#define BLE_DBG_HIDS_MSG            PRINT_MESG_DBG
+#else
+#define BLE_DBG_HIDS_MSG            PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_PASS_EN != 0)
+#define BLE_DBG_PASS_MSG            PRINT_MESG_DBG
+#else
+#define BLE_DBG_PASS_MSG            PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_BLS_EN != 0)
+#define BLE_DBG_BLS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_BLS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_HTS_EN != 0)
+#define BLE_DBG_HTS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_HTS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_ANS_EN != 0)
+#define BLE_DBG_ANS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_ANS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_ESS_EN != 0)
+#define BLE_DBG_ESS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_ESS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_GLS_EN != 0)
+#define BLE_DBG_GLS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_GLS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_BAS_EN != 0)
+#define BLE_DBG_BAS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_BAS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_RTUS_EN != 0)
+#define BLE_DBG_RTUS_MSG            PRINT_MESG_DBG
+#else
+#define BLE_DBG_RTUS_MSG            PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_HPS_EN != 0)
+#define BLE_DBG_HPS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_HPS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_TPS_EN != 0)
+#define BLE_DBG_TPS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_TPS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_LLS_EN != 0)
+#define BLE_DBG_LLS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_LLS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_IAS_EN != 0)
+#define BLE_DBG_IAS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_IAS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_WSS_EN != 0)
+#define BLE_DBG_WSS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_WSS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_LNS_EN != 0)
+#define BLE_DBG_LNS_MSG             PRINT_MESG_DBG
+#else
+#define BLE_DBG_LNS_MSG             PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_SCPS_EN != 0)
+#define BLE_DBG_SCPS_MSG            PRINT_MESG_DBG
+#else
+#define BLE_DBG_SCPS_MSG            PRINT_NO_MESG
+#endif
+
+#if (BLE_DBG_DTS_EN != 0)
+#define BLE_DBG_DTS_MSG             PRINT_MESG_DBG
+#define BLE_DBG_DTS_BUF             PRINT_LOG_BUFF_DBG
+#else
+#define BLE_DBG_DTS_MSG             PRINT_NO_MESG
+#define BLE_DBG_DTS_BUF             PRINT_NO_MESG
+#endif
+
+#endif /*__BLE_DBG_CONF_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 121 - 0
firmware/targets/f7/ble-glue/dev_info_service.c

@@ -0,0 +1,121 @@
+#include "dev_info_service.h"
+#include "app_common.h"
+#include "ble.h"
+
+#include <furi.h>
+
+#define DEV_INFO_SERVICE_TAG "dev info service"
+
+typedef struct {
+    uint16_t service_handle;
+    uint16_t man_name_char_handle;
+    uint16_t serial_num_char_handle;
+    uint16_t firmware_rev_char_handle;
+    uint16_t software_rev_char_handle;
+} DevInfoSvc;
+
+bool dev_info_service_init() {
+    tBleStatus status;
+    DevInfoSvc dev_info_svc;
+
+    // Add Device Information Service
+    uint16_t uuid = DEVICE_INFORMATION_SERVICE_UUID;
+    status = aci_gatt_add_service(UUID_TYPE_16, (Service_UUID_t*)&uuid, PRIMARY_SERVICE, 9, &dev_info_svc.service_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add Device Information Service: %d", status);
+    }
+
+    // Add characteristics
+    uuid = MANUFACTURER_NAME_UUID;
+    status = aci_gatt_add_char(dev_info_svc.service_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t*)&uuid,
+                                strlen(DEV_INFO_MANUFACTURER_NAME),
+                                CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &dev_info_svc.man_name_char_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add manufacturer name char: %d", status);
+
+    }
+    uuid = SERIAL_NUMBER_UUID;
+    status = aci_gatt_add_char(dev_info_svc.service_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t*)&uuid,
+                                strlen(DEV_INFO_SERIAL_NUMBER),
+                                CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &dev_info_svc.serial_num_char_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add serial number char: %d", status);
+    }
+    uuid = FIRMWARE_REVISION_UUID;
+    status = aci_gatt_add_char(dev_info_svc.service_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t*)&uuid,
+                                strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER),
+                                CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &dev_info_svc.firmware_rev_char_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add firmware revision char: %d", status);
+    }
+    uuid = SOFTWARE_REVISION_UUID;
+    status = aci_gatt_add_char(dev_info_svc.service_handle,
+                                UUID_TYPE_16,
+                                (Char_UUID_t*)&uuid,
+                                strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER),
+                                CHAR_PROP_READ,
+                                ATTR_PERMISSION_NONE,
+                                GATT_DONT_NOTIFY_EVENTS,
+                                10,
+                                CHAR_VALUE_LEN_CONSTANT,
+                                &dev_info_svc.software_rev_char_handle);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to add software revision char: %d", status);
+    }
+
+    // Update characteristics
+    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
+                                        dev_info_svc.man_name_char_handle,
+                                        0,
+                                        strlen(DEV_INFO_MANUFACTURER_NAME),
+                                        (uint8_t*)DEV_INFO_MANUFACTURER_NAME);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update manufacturer name char: %d", status);
+    }
+    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
+                                        dev_info_svc.serial_num_char_handle,
+                                        0,
+                                        strlen(DEV_INFO_SERIAL_NUMBER),
+                                        (uint8_t*)DEV_INFO_SERIAL_NUMBER);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update serial number char: %d", status);
+    }
+    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
+                                        dev_info_svc.firmware_rev_char_handle,
+                                        0,
+                                        strlen(DEV_INFO_FIRMWARE_REVISION_NUMBER),
+                                        (uint8_t*)DEV_INFO_FIRMWARE_REVISION_NUMBER);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update firmware revision char: %d", status);
+    }
+    status = aci_gatt_update_char_value(dev_info_svc.service_handle,
+                                        dev_info_svc.software_rev_char_handle,
+                                        0,
+                                        strlen(DEV_INFO_SOFTWARE_REVISION_NUMBER),
+                                        (uint8_t*)DEV_INFO_SOFTWARE_REVISION_NUMBER);
+    if(status) {
+        FURI_LOG_E(DEV_INFO_SERVICE_TAG, "Failed to update software revision char: %d", status);
+    }
+    return status != BLE_STATUS_SUCCESS;
+}

+ 20 - 0
firmware/targets/f7/ble-glue/dev_info_service.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DEV_INFO_MANUFACTURER_NAME              "Flipper Devices Inc."
+#define DEV_INFO_SERIAL_NUMBER                  "1.0"
+#define DEV_INFO_FIRMWARE_REVISION_NUMBER       TARGET
+#define DEV_INFO_SOFTWARE_REVISION_NUMBER       GIT_COMMIT " " GIT_BRANCH " " GIT_BRANCH_NUM " " BUILD_DATE
+
+
+bool dev_info_service_init();
+
+#ifdef __cplusplus
+}
+#endif

+ 199 - 0
firmware/targets/f7/ble-glue/hw_conf.h

@@ -0,0 +1,199 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * @file    hw_conf.h
+ * @author  MCD Application Team
+ * @brief   Configuration of hardware interface
+  ******************************************************************************
+  * @attention
+  *
+ * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license 
+  * SLA0044, the "License"; You may not use this file except in compliance with 
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef HW_CONF_H
+#define HW_CONF_H
+
+#include "FreeRTOSConfig.h"
+
+/******************************************************************************
+ * Semaphores
+ * THIS SHALL NO BE CHANGED AS THESE SEMAPHORES ARE USED AS WELL ON THE CM0+
+ *****************************************************************************/
+/**
+*  Index of the semaphore used by CPU2 to prevent the CPU1 to either write or erase data in flash
+*  The CPU1 shall not either write or erase in flash when this semaphore is taken by the CPU2
+*  When the CPU1 needs to either write or erase in flash, it shall first get the semaphore and release it just
+*  after writing a raw (64bits data) or erasing one sector.
+*  Once the Semaphore has been released, there shall be at least 1us before it can be taken again. This is required
+*  to give the opportunity to CPU2 to take it.
+*  On v1.4.0 and older CPU2 wireless firmware, this semaphore is unused and CPU2 is using PES bit.
+*  By default, CPU2 is using the PES bit to protect its timing. The CPU1 may request the CPU2 to use the semaphore
+*  instead of the PES bit by sending the system command SHCI_C2_SetFlashActivityControl()
+*/
+#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID                    7
+
+/**
+*  Index of the semaphore used by CPU1 to prevent the CPU2 to either write or erase data in flash
+*  In order to protect its timing, the CPU1 may get this semaphore to prevent the  CPU2 to either
+*  write or erase in flash (as this will stall both CPUs)
+*  The PES bit shall not be used as this may stall the CPU2 in some cases.
+*/
+#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID                    6
+
+/**
+*  Index of the semaphore used to manage the CLK48 clock configuration
+*  When the USB is required, this semaphore shall be taken before configuring te CLK48 for USB
+*  and should be released after the application switch OFF the clock when the USB is not used anymore
+*  When using the RNG, it is good enough to use CFG_HW_RNG_SEMID to control CLK48.
+*  More details in AN5289
+*/
+#define CFG_HW_CLK48_CONFIG_SEMID                               5
+
+/* Index of the semaphore used to manage the entry Stop Mode procedure */
+#define CFG_HW_ENTRY_STOP_MODE_SEMID                            4
+
+/* Index of the semaphore used to access the RCC */
+#define CFG_HW_RCC_SEMID                                        3
+
+/* Index of the semaphore used to access the FLASH */
+#define CFG_HW_FLASH_SEMID                                      2
+
+/* Index of the semaphore used to access the PKA */
+#define CFG_HW_PKA_SEMID                                        1
+
+/* Index of the semaphore used to access the RNG */
+#define CFG_HW_RNG_SEMID                                        0
+
+/******************************************************************************
+ * HW TIMER SERVER
+ *****************************************************************************/
+/**
+ * The user may define the maximum number of virtual timers supported.
+ * It shall not exceed 255
+ */
+#define CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER  6
+
+/**
+ * The user may define the priority in the NVIC of the RTC_WKUP interrupt handler that is used to manage the
+ * wakeup timer.
+ * This setting is the preemptpriority part of the NVIC.
+ */
+#define CFG_HW_TS_NVIC_RTC_WAKEUP_IT_PREEMPTPRIO    (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1) /* FreeRTOS requirement */
+
+/**
+ * The user may define the priority in the NVIC of the RTC_WKUP interrupt handler that is used to manage the
+ * wakeup timer.
+ * This setting is the subpriority part of the NVIC. It does not exist on all processors. When it is not supported
+ * on the CPU, the setting is ignored
+ */
+#define CFG_HW_TS_NVIC_RTC_WAKEUP_IT_SUBPRIO  0
+
+/**
+ *  Define a critical section in the Timer server
+ *  The Timer server does not support the API to be nested
+ *  The  Application shall either:
+ *    a) Ensure this will never happen
+ *    b) Define the critical section
+ *  The default implementations is masking all interrupts using the PRIMASK bit
+ *  The TimerServer driver uses critical sections to avoid context corruption. This is achieved with the macro
+ *  TIMER_ENTER_CRITICAL_SECTION and TIMER_EXIT_CRITICAL_SECTION. When CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION is set
+ *  to 1, all STM32 interrupts are masked with the PRIMASK bit of the CortexM CPU. It is possible to use the BASEPRI
+ *  register of the CortexM CPU to keep allowed some interrupts with high priority. In that case, the user shall
+ *  re-implement TIMER_ENTER_CRITICAL_SECTION and TIMER_EXIT_CRITICAL_SECTION and shall make sure that no TimerServer
+ *  API are called when the TIMER critical section is entered
+ */
+#define CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION  1
+
+/**
+   * This value shall reflect the maximum delay there could be in the application between the time the RTC interrupt
+   * is generated by the Hardware and the time when the  RTC interrupt handler is called. This time is measured in
+   * number of RTCCLK ticks.
+   * A relaxed timing would be 10ms
+   * When the value is too short, the timerserver will not be able to count properly and all timeout may be random.
+   * When the value is too long, the device may wake up more often than the most optimal configuration. However, the
+   * impact on power consumption would be marginal (unless the value selected is extremely too long). It is strongly
+   * recommended to select a value large enough to make sure it is not too short to ensure reliability of the system
+   * as this will have marginal impact on low power mode
+   */
+#define CFG_HW_TS_RTC_HANDLER_MAX_DELAY  ( 10 * (LSI_VALUE/1000) )
+
+  /**
+   * Interrupt ID in the NVIC of the RTC Wakeup interrupt handler
+   * It shall be type of IRQn_Type
+   */
+#define CFG_HW_TS_RTC_WAKEUP_HANDLER_ID  RTC_WKUP_IRQn
+
+/******************************************************************************
+ * HW UART
+ *****************************************************************************/
+#define CFG_HW_LPUART1_ENABLED           0
+#define CFG_HW_LPUART1_DMA_TX_SUPPORTED  0
+
+#define CFG_HW_USART1_ENABLED           1
+#define CFG_HW_USART1_DMA_TX_SUPPORTED  1
+
+/**
+ * UART1
+ */
+#define CFG_HW_USART1_PREEMPTPRIORITY         0x0F
+#define CFG_HW_USART1_SUBPRIORITY             0
+
+/** < The application shall check the selected source clock is enable */
+#define CFG_HW_USART1_SOURCE_CLOCK              RCC_USART1CLKSOURCE_SYSCLK
+
+#define CFG_HW_USART1_BAUDRATE                115200
+#define CFG_HW_USART1_WORDLENGTH              UART_WORDLENGTH_8B
+#define CFG_HW_USART1_STOPBITS                UART_STOPBITS_1
+#define CFG_HW_USART1_PARITY                  UART_PARITY_NONE
+#define CFG_HW_USART1_HWFLOWCTL               UART_HWCONTROL_NONE
+#define CFG_HW_USART1_MODE                    UART_MODE_TX_RX
+#define CFG_HW_USART1_ADVFEATUREINIT          UART_ADVFEATURE_NO_INIT
+#define CFG_HW_USART1_OVERSAMPLING            UART_OVERSAMPLING_8
+
+#define CFG_HW_USART1_TX_PORT_CLK_ENABLE      __HAL_RCC_GPIOB_CLK_ENABLE
+#define CFG_HW_USART1_TX_PORT                 GPIOB
+#define CFG_HW_USART1_TX_PIN                  GPIO_PIN_6
+#define CFG_HW_USART1_TX_MODE                 GPIO_MODE_AF_PP
+#define CFG_HW_USART1_TX_PULL                 GPIO_NOPULL
+#define CFG_HW_USART1_TX_SPEED                GPIO_SPEED_FREQ_VERY_HIGH
+#define CFG_HW_USART1_TX_ALTERNATE            GPIO_AF7_USART1
+
+#define CFG_HW_USART1_RX_PORT_CLK_ENABLE      __HAL_RCC_GPIOB_CLK_ENABLE
+#define CFG_HW_USART1_RX_PORT                 GPIOB
+#define CFG_HW_USART1_RX_PIN                  GPIO_PIN_7
+#define CFG_HW_USART1_RX_MODE                 GPIO_MODE_AF_PP
+#define CFG_HW_USART1_RX_PULL                 GPIO_NOPULL
+#define CFG_HW_USART1_RX_SPEED                GPIO_SPEED_FREQ_VERY_HIGH
+#define CFG_HW_USART1_RX_ALTERNATE            GPIO_AF7_USART1
+
+#define CFG_HW_USART1_CTS_PORT_CLK_ENABLE     __HAL_RCC_GPIOA_CLK_ENABLE
+#define CFG_HW_USART1_CTS_PORT                GPIOA
+#define CFG_HW_USART1_CTS_PIN                 GPIO_PIN_11
+#define CFG_HW_USART1_CTS_MODE                GPIO_MODE_AF_PP
+#define CFG_HW_USART1_CTS_PULL                GPIO_PULLDOWN
+#define CFG_HW_USART1_CTS_SPEED               GPIO_SPEED_FREQ_VERY_HIGH
+#define CFG_HW_USART1_CTS_ALTERNATE           GPIO_AF7_USART1
+
+#define CFG_HW_USART1_DMA_TX_PREEMPTPRIORITY  0x0F
+#define CFG_HW_USART1_DMA_TX_SUBPRIORITY      0
+
+#define CFG_HW_USART1_DMAMUX_CLK_ENABLE       __HAL_RCC_DMAMUX1_CLK_ENABLE
+#define CFG_HW_USART1_DMA_CLK_ENABLE          __HAL_RCC_DMA2_CLK_ENABLE
+#define CFG_HW_USART1_TX_DMA_REQ			  DMA_REQUEST_USART1_TX
+#define CFG_HW_USART1_TX_DMA_CHANNEL          DMA2_Channel4
+#define CFG_HW_USART1_TX_DMA_IRQn             DMA2_Channel4_IRQn
+#define CFG_HW_USART1_DMA_TX_IRQHandler       DMA2_Channel4_IRQHandler
+
+#endif /*HW_CONF_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 250 - 0
firmware/targets/f7/ble-glue/hw_if.h

@@ -0,0 +1,250 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file    hw_if.h
+  * @author  MCD Application Team
+  * @brief   Hardware Interface
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+/* USER CODE END Header */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef HW_IF_H
+#define HW_IF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  /* Includes ------------------------------------------------------------------*/
+#include "stm32wbxx.h"
+#include "stm32wbxx_ll_exti.h"
+#include "stm32wbxx_ll_system.h"
+#include "stm32wbxx_ll_rcc.h"
+#include "stm32wbxx_ll_ipcc.h"
+#include "stm32wbxx_ll_bus.h"
+#include "stm32wbxx_ll_pwr.h"
+#include "stm32wbxx_ll_cortex.h"
+#include "stm32wbxx_ll_utils.h"
+#include "stm32wbxx_ll_hsem.h"
+#include "stm32wbxx_ll_gpio.h"
+#include "stm32wbxx_ll_rtc.h"
+
+#ifdef  USE_STM32WBXX_USB_DONGLE
+#include "stm32wbxx_usb_dongle.h"
+#endif
+#ifdef  USE_STM32WBXX_NUCLEO
+#include "stm32wbxx_nucleo.h"
+#endif
+#ifdef  USE_X_NUCLEO_EPD
+#include "x_nucleo_epd.h"
+#endif
+
+/* Private includes ----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+  /******************************************************************************
+   * HW UART
+   ******************************************************************************/
+  typedef enum
+  {
+    hw_uart1,
+    hw_uart2,
+    hw_lpuart1,
+  } hw_uart_id_t;
+
+  typedef enum
+  {
+    hw_uart_ok,
+    hw_uart_error,
+    hw_uart_busy,
+    hw_uart_to,
+  } hw_status_t;
+
+  void HW_UART_Init(hw_uart_id_t hw_uart_id);
+  void HW_UART_Receive_IT(hw_uart_id_t hw_uart_id, uint8_t *pData, uint16_t Size, void (*Callback)(void));
+  void HW_UART_Transmit_IT(hw_uart_id_t hw_uart_id, uint8_t *pData, uint16_t Size,  void (*Callback)(void));
+  hw_status_t HW_UART_Transmit(hw_uart_id_t hw_uart_id, uint8_t *p_data, uint16_t size,  uint32_t timeout);
+  hw_status_t HW_UART_Transmit_DMA(hw_uart_id_t hw_uart_id, uint8_t *p_data, uint16_t size, void (*Callback)(void));
+  void HW_UART_Interrupt_Handler(hw_uart_id_t hw_uart_id);
+  void HW_UART_DMA_Interrupt_Handler(hw_uart_id_t hw_uart_id);
+
+  /******************************************************************************
+   * HW TimerServer
+   ******************************************************************************/
+  /* Exported types ------------------------------------------------------------*/
+  /**
+   * This setting is used when standby mode is supported.
+   * hw_ts_InitMode_Limited should be used when the device restarts from Standby Mode. In that case, the Timer Server does
+   * not re-initialized its context. Only the Hardware register which content has been lost is reconfigured
+   * Otherwise, hw_ts_InitMode_Full should be requested (Start from Power ON) and everything is re-initialized.
+   */
+  typedef enum
+  {
+    hw_ts_InitMode_Full,
+    hw_ts_InitMode_Limited,
+  } HW_TS_InitMode_t;
+
+  /**
+   * When a Timer is created as a SingleShot timer, it is not automatically restarted when the timeout occurs. However,
+   * the timer is kept reserved in the list and could be restarted at anytime with HW_TS_Start()
+   *
+   * When a Timer is created as a Repeated timer, it is automatically restarted when the timeout occurs.
+   */
+  typedef enum
+  {
+    hw_ts_SingleShot,
+    hw_ts_Repeated
+  } HW_TS_Mode_t;
+
+  /**
+   * hw_ts_Successful is returned when a Timer has been successfully created with HW_TS_Create(). Otherwise, hw_ts_Failed
+   * is returned. When hw_ts_Failed is returned, that means there are not enough free slots in the list to create a
+   * Timer. In that case, CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER should be increased
+   */
+  typedef enum
+  {
+    hw_ts_Successful,
+    hw_ts_Failed,
+  }HW_TS_ReturnStatus_t;
+
+  typedef void (*HW_TS_pTimerCb_t)(void);
+
+  /**
+   * @brief  Initialize the timer server
+   *         This API shall be called by the application before any timer is requested to the timer server. It
+   *         configures the RTC module to be connected to the LSI input clock.
+   *
+   * @param  TimerInitMode: When the device restarts from Standby, it should request hw_ts_InitMode_Limited so that the
+   *         Timer context is not re-initialized. Otherwise, hw_ts_InitMode_Full should be requested
+   * @param  hrtc: RTC Handle
+   * @retval None
+   */
+  void HW_TS_Init(HW_TS_InitMode_t TimerInitMode, RTC_HandleTypeDef *hrtc);
+
+  /**
+   * @brief  Interface to create a virtual timer
+   *         The user shall call this API to create a timer. Once created, the timer is reserved to the module until it
+   *         has been deleted. When creating a timer, the user shall specify the mode (single shot or repeated), the
+   *         callback to be notified when the timer expires and a module ID to identify in the timer interrupt handler
+   *         which module is concerned. In return, the user gets a timer ID to handle it.
+   *
+   * @param  TimerProcessID:  This is an identifier provided by the user and returned in the callback to allow
+   *                          identification of the requester
+   * @param  pTimerId: Timer Id returned to the user to request operation (start, stop, delete)
+   * @param  TimerMode: Mode of the virtual timer (Single shot or repeated)
+   * @param  pTimerCallBack: Callback when the virtual timer expires
+   * @retval HW_TS_ReturnStatus_t: Return whether the creation is sucessfull or not
+   */
+  HW_TS_ReturnStatus_t HW_TS_Create(uint32_t TimerProcessID, uint8_t *pTimerId, HW_TS_Mode_t TimerMode, HW_TS_pTimerCb_t pTimerCallBack);
+
+  /**
+   * @brief  Stop a virtual timer
+   *         This API may be used to stop a running timer. A timer which is stopped is move to the pending state.
+   *         A pending timer may be restarted at any time with a different timeout value but the mode cannot be changed.
+   *         Nothing is done when it is called to stop a timer which has been already stopped
+   *
+   * @param  TimerID:  Id of the timer to stop
+   * @retval None
+   */
+  void HW_TS_Stop(uint8_t TimerID);
+
+  /**
+   * @brief  Start a virtual timer
+   *         This API shall be used to start a timer. The timeout value is specified and may be different each time.
+   *         When the timer is in the single shot mode, it will move to the pending state when it expires. The user may
+   *         restart it at any time with a different timeout value. When the timer is in the repeated mode, it always
+   *         stay in the running state. When the timer expires, it will be restarted with the same timeout value.
+   *         This API shall not be called on a running timer.
+   *
+   * @param  TimerID:  The ID Id of the timer to start
+   * @param  timeout_ticks: Number of ticks of the virtual timer (Maximum value is (0xFFFFFFFF-0xFFFF = 0xFFFF0000)
+   * @retval None
+   */
+  void HW_TS_Start(uint8_t TimerID, uint32_t timeout_ticks);
+
+  /**
+   * @brief  Delete a virtual timer from the list
+   *         This API should be used when a timer is not needed anymore by the user. A deleted timer is removed from
+   *         the timer list managed by the timer server. It cannot be restarted again. The user has to go with the
+   *         creation of a new timer if required and may get a different timer id
+   *
+   * @param  TimerID:  The ID of the timer to remove from the list
+   * @retval None
+   */
+  void HW_TS_Delete(uint8_t TimerID);
+
+  /**
+   * @brief  Schedule the timer list on the timer interrupt handler
+   *         This interrupt handler shall be called by the application in the RTC interrupt handler. This handler takes
+   *         care of clearing all status flag required in the RTC and EXTI peripherals
+   *
+   * @param  None
+   * @retval None
+   */
+  void HW_TS_RTC_Wakeup_Handler(void);
+
+  /**
+   * @brief  Return the number of ticks to count before the interrupt
+   *         This API returns the number of ticks left to be counted before an interrupt is generated by the
+   *         Timer Server. This API may be used by the application for power management optimization. When the system
+   *         enters low power mode, the mode selection is a tradeoff between the wakeup time where the CPU is running
+   *         and the time while the CPU will be kept in low power mode before next wakeup. The deeper is the
+   *         low power mode used, the longer is the wakeup time. The low power mode management considering wakeup time
+   *         versus time in low power mode is implementation specific
+   *         When the timer is disabled (No timer in the list), it returns 0xFFFF
+   *
+   * @param  None
+   * @retval The number of ticks left to count
+   */
+  uint16_t HW_TS_RTC_ReadLeftTicksToCount(void);
+
+  /**
+   * @brief  Notify the application that a registered timer has expired
+   *         This API shall be implemented by the user application.
+   *         This API notifies the application that a timer expires. This API is running in the RTC Wakeup interrupt
+   *         context. The application may implement an Operating System to change the context priority where the timer
+   *         callback may be handled. This API provides the module ID to identify which module is concerned and to allow
+   *         sending the information to the correct task
+   *
+   * @param  TimerProcessID: The TimerProcessId associated with the timer when it has been created
+   * @param  TimerID: The TimerID of the expired timer
+   * @param  pTimerCallBack: The Callback associated with the timer when it has been created
+   * @retval None
+   */
+  void HW_TS_RTC_Int_AppNot(uint32_t TimerProcessID, uint8_t TimerID, HW_TS_pTimerCb_t pTimerCallBack);
+
+  /**
+   * @brief  Notify the application that the wakeupcounter has been updated
+   *         This API should be implemented by the user application
+   *         This API notifies the application that the counter has been updated. This is expected to be used along
+   *         with the HW_TS_RTC_ReadLeftTicksToCount () API. It could be that the counter has been updated since the
+   *         last call of HW_TS_RTC_ReadLeftTicksToCount () and before entering low power mode. This notification
+   *         provides a way to the application to solve that race condition to reevaluate the counter value before
+   *         entering low power mode
+   *
+   * @param  None
+   * @retval None
+   */
+  void HW_TS_RTC_CountUpdated_AppNot(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*HW_IF_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 675 - 0
firmware/targets/f7/ble-glue/hw_ipcc.c

@@ -0,0 +1,675 @@
+/**
+ ******************************************************************************
+  * File Name          : Target/hw_ipcc.c
+  * Description        : Hardware IPCC source file for STM32WPAN Middleware.
+  *
+ ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
+  * All rights reserved.</center></h2>
+  *
+  * This software component is licensed by ST under Ultimate Liberty license
+  * SLA0044, the "License"; You may not use this file except in compliance with
+  * the License. You may obtain a copy of the License at:
+  *                             www.st.com/SLA0044
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "app_common.h"
+#include "mbox_def.h"
+
+/* Global variables ---------------------------------------------------------*/
+/* Private defines -----------------------------------------------------------*/
+#define HW_IPCC_TX_PENDING( channel ) ( !(LL_C1_IPCC_IsActiveFlag_CHx( IPCC, channel )) ) &&  (((~(IPCC->C1MR)) & (channel << 16U)))
+#define HW_IPCC_RX_PENDING( channel )  (LL_C2_IPCC_IsActiveFlag_CHx( IPCC, channel )) && (((~(IPCC->C1MR)) & (channel << 0U)))
+
+/* Private macros ------------------------------------------------------------*/
+/* Private typedef -----------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+static void (*FreeBufCb)( void );
+
+/* Private function prototypes -----------------------------------------------*/
+static void HW_IPCC_BLE_EvtHandler( void );
+static void HW_IPCC_BLE_AclDataEvtHandler( void );
+static void HW_IPCC_MM_FreeBufHandler( void );
+static void HW_IPCC_SYS_CmdEvtHandler( void );
+static void HW_IPCC_SYS_EvtHandler( void );
+static void HW_IPCC_TRACES_EvtHandler( void );
+
+#ifdef THREAD_WB
+static void HW_IPCC_OT_CmdEvtHandler( void );
+static void HW_IPCC_THREAD_NotEvtHandler( void );
+static void HW_IPCC_THREAD_CliNotEvtHandler( void );
+#endif
+
+#ifdef LLD_TESTS_WB
+static void HW_IPCC_LLDTESTS_ReceiveCliRspHandler( void );
+static void HW_IPCC_LLDTESTS_ReceiveM0CmdHandler( void );
+#endif
+#ifdef LLD_BLE_WB
+/*static void HW_IPCC_LLD_BLE_ReceiveCliRspHandler( void );*/
+static void HW_IPCC_LLD_BLE_ReceiveRspHandler( void );
+static void HW_IPCC_LLD_BLE_ReceiveM0CmdHandler( void );
+#endif
+
+#ifdef MAC_802_15_4_WB
+static void HW_IPCC_MAC_802_15_4_CmdEvtHandler( void );
+static void HW_IPCC_MAC_802_15_4_NotEvtHandler( void );
+#endif
+
+#ifdef ZIGBEE_WB
+static void HW_IPCC_ZIGBEE_CmdEvtHandler( void );
+static void HW_IPCC_ZIGBEE_StackNotifEvtHandler( void );
+static void HW_IPCC_ZIGBEE_StackM0RequestHandler( void );
+#endif
+
+/* Public function definition -----------------------------------------------*/
+
+/******************************************************************************
+ * INTERRUPT HANDLER
+ ******************************************************************************/
+void HW_IPCC_Rx_Handler( void )
+{
+  if (HW_IPCC_RX_PENDING( HW_IPCC_SYSTEM_EVENT_CHANNEL ))
+  {
+      HW_IPCC_SYS_EvtHandler();
+  }
+#ifdef MAC_802_15_4_WB
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL ))
+  {
+    HW_IPCC_MAC_802_15_4_NotEvtHandler();
+  }
+#endif /* MAC_802_15_4_WB */
+#ifdef THREAD_WB
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL ))
+  {
+    HW_IPCC_THREAD_NotEvtHandler();
+  }
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL ))
+  {
+    HW_IPCC_THREAD_CliNotEvtHandler();
+  }
+#endif /* THREAD_WB */
+#ifdef LLD_TESTS_WB
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL ))
+  {
+    HW_IPCC_LLDTESTS_ReceiveCliRspHandler();
+  }
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_LLDTESTS_M0_CMD_CHANNEL ))
+  {
+    HW_IPCC_LLDTESTS_ReceiveM0CmdHandler();
+  }
+#endif /* LLD_TESTS_WB */
+#ifdef LLD_BLE_WB
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_LLD_BLE_RSP_CHANNEL ))
+  {
+    HW_IPCC_LLD_BLE_ReceiveRspHandler();
+  }
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_LLD_BLE_M0_CMD_CHANNEL ))
+  {
+    HW_IPCC_LLD_BLE_ReceiveM0CmdHandler();
+  }
+#endif /* LLD_TESTS_WB */
+#ifdef ZIGBEE_WB
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL ))
+  {
+    HW_IPCC_ZIGBEE_StackNotifEvtHandler();
+  }
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL ))
+  {
+    HW_IPCC_ZIGBEE_StackM0RequestHandler();
+  }
+#endif /* ZIGBEE_WB */
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_BLE_EVENT_CHANNEL ))
+  {
+    HW_IPCC_BLE_EvtHandler();
+  }
+  else if (HW_IPCC_RX_PENDING( HW_IPCC_TRACES_CHANNEL ))
+  {
+    HW_IPCC_TRACES_EvtHandler();
+  }
+
+  return;
+}
+
+void HW_IPCC_Tx_Handler( void )
+{
+  if (HW_IPCC_TX_PENDING( HW_IPCC_SYSTEM_CMD_RSP_CHANNEL ))
+  {
+    HW_IPCC_SYS_CmdEvtHandler();
+  }
+#ifdef MAC_802_15_4_WB
+  else if (HW_IPCC_TX_PENDING( HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL ))
+  {
+    HW_IPCC_MAC_802_15_4_CmdEvtHandler();
+  }
+#endif /* MAC_802_15_4_WB */
+#ifdef THREAD_WB
+  else if (HW_IPCC_TX_PENDING( HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL ))
+  {
+    HW_IPCC_OT_CmdEvtHandler();
+  }
+#endif /* THREAD_WB */
+#ifdef LLD_TESTS_WB
+// No TX handler for LLD tests
+#endif /* LLD_TESTS_WB */
+#ifdef ZIGBEE_WB
+  if (HW_IPCC_TX_PENDING( HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL ))
+  {
+      HW_IPCC_ZIGBEE_CmdEvtHandler();
+  }
+#endif /* ZIGBEE_WB */
+  else if (HW_IPCC_TX_PENDING( HW_IPCC_SYSTEM_CMD_RSP_CHANNEL ))
+  {
+    HW_IPCC_SYS_CmdEvtHandler();
+  }
+  else if (HW_IPCC_TX_PENDING( HW_IPCC_MM_RELEASE_BUFFER_CHANNEL ))
+  {
+    HW_IPCC_MM_FreeBufHandler();
+  }
+  else if (HW_IPCC_TX_PENDING( HW_IPCC_HCI_ACL_DATA_CHANNEL ))
+  {
+    HW_IPCC_BLE_AclDataEvtHandler();
+  }
+
+  return;
+}
+/******************************************************************************
+ * GENERAL
+ ******************************************************************************/
+void HW_IPCC_Enable( void )
+{
+  /**
+  * Such as IPCC IP available to the CPU2, it is required to keep the IPCC clock running
+    when FUS is running on CPU2 and CPU1 enters deep sleep mode
+  */
+  LL_C2_AHB3_GRP1_EnableClock(LL_C2_AHB3_GRP1_PERIPH_IPCC);
+
+   /**
+   * When the device is out of standby, it is required to use the EXTI mechanism to wakeup CPU2
+   */
+  LL_C2_EXTI_EnableEvent_32_63( LL_EXTI_LINE_41 );
+  LL_EXTI_EnableRisingTrig_32_63( LL_EXTI_LINE_41 );
+
+  /**
+   * In case the SBSFU is implemented, it may have already set the C2BOOT bit to startup the CPU2.
+   * In that case, to keep the mechanism transparent to the user application, it shall call the system command
+   * SHCI_C2_Reinit( ) before jumping to the application.
+   * When the CPU2 receives that command, it waits for its event input to be set to restart the CPU2 firmware.
+   * This is required because once C2BOOT has been set once, a clear/set on C2BOOT has no effect.
+   * When SHCI_C2_Reinit( ) is not called, generating an event to the CPU2 does not have any effect
+   * So, by default, the application shall both set the event flag and set the C2BOOT bit.
+   */
+  __SEV( );       /* Set the internal event flag and send an event to the CPU2 */
+  __WFE( );       /* Clear the internal event flag */
+  LL_PWR_EnableBootC2( );
+
+  return;
+}
+
+void HW_IPCC_Init( void )
+{
+  LL_AHB3_GRP1_EnableClock( LL_AHB3_GRP1_PERIPH_IPCC );
+
+  LL_C1_IPCC_EnableIT_RXO( IPCC );
+  LL_C1_IPCC_EnableIT_TXF( IPCC );
+
+  HAL_NVIC_SetPriority(IPCC_C1_RX_IRQn, 6, 0);
+  HAL_NVIC_EnableIRQ(IPCC_C1_RX_IRQn);
+  HAL_NVIC_SetPriority(IPCC_C1_TX_IRQn, 6, 0);
+  HAL_NVIC_EnableIRQ(IPCC_C1_TX_IRQn);
+
+  return;
+}
+
+/******************************************************************************
+ * BLE
+ ******************************************************************************/
+void HW_IPCC_BLE_Init( void )
+{
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_BLE_EVENT_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_BLE_SendCmd( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_BLE_CMD_CHANNEL );
+
+  return;
+}
+
+static void HW_IPCC_BLE_EvtHandler( void )
+{
+  HW_IPCC_BLE_RxEvtNot();
+
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_BLE_EVENT_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_BLE_SendAclData( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL );
+  LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL );
+
+  return;
+}
+
+static void HW_IPCC_BLE_AclDataEvtHandler( void )
+{
+  LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_HCI_ACL_DATA_CHANNEL );
+
+  HW_IPCC_BLE_AclDataAckNot();
+
+  return;
+}
+
+__weak void HW_IPCC_BLE_AclDataAckNot( void ){};
+__weak void HW_IPCC_BLE_RxEvtNot( void ){};
+
+/******************************************************************************
+ * SYSTEM
+ ******************************************************************************/
+void HW_IPCC_SYS_Init( void )
+{
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_SYSTEM_EVENT_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_SYS_SendCmd( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL );
+  LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL );
+
+  return;
+}
+
+static void HW_IPCC_SYS_CmdEvtHandler( void )
+{
+  LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_SYSTEM_CMD_RSP_CHANNEL );
+
+  HW_IPCC_SYS_CmdEvtNot();
+
+  return;
+}
+
+static void HW_IPCC_SYS_EvtHandler( void )
+{
+  HW_IPCC_SYS_EvtNot();
+
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_SYSTEM_EVENT_CHANNEL );
+
+  return;
+}
+
+__weak void HW_IPCC_SYS_CmdEvtNot( void ){};
+__weak void HW_IPCC_SYS_EvtNot( void ){};
+
+/******************************************************************************
+ * MAC 802.15.4
+ ******************************************************************************/
+#ifdef MAC_802_15_4_WB
+void HW_IPCC_MAC_802_15_4_Init( void )
+{
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_MAC_802_15_4_SendCmd( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL );
+  LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_MAC_802_15_4_SendAck( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL );
+
+  return;
+}
+
+static void HW_IPCC_MAC_802_15_4_CmdEvtHandler( void )
+{
+  LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL );
+
+  HW_IPCC_MAC_802_15_4_CmdEvtNot();
+
+  return;
+}
+
+static void HW_IPCC_MAC_802_15_4_NotEvtHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL );
+
+  HW_IPCC_MAC_802_15_4_EvtNot();
+
+  return;
+}
+__weak void HW_IPCC_MAC_802_15_4_CmdEvtNot( void ){};
+__weak void HW_IPCC_MAC_802_15_4_EvtNot( void ){};
+#endif
+
+/******************************************************************************
+ * THREAD
+ ******************************************************************************/
+#ifdef THREAD_WB
+void HW_IPCC_THREAD_Init( void )
+{
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_OT_SendCmd( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL );
+  LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_CLI_SendCmd( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_THREAD_CLI_CMD_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_THREAD_SendAck( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_THREAD_CliSendAck( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL );
+
+  return;
+}
+
+static void HW_IPCC_OT_CmdEvtHandler( void )
+{
+  LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL );
+
+  HW_IPCC_OT_CmdEvtNot();
+
+  return;
+}
+
+static void HW_IPCC_THREAD_NotEvtHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL );
+
+  HW_IPCC_THREAD_EvtNot();
+
+  return;
+}
+
+static void HW_IPCC_THREAD_CliNotEvtHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL );
+
+  HW_IPCC_THREAD_CliEvtNot();
+
+  return;
+}
+
+__weak void HW_IPCC_OT_CmdEvtNot( void ){};
+__weak void HW_IPCC_CLI_CmdEvtNot( void ){};
+__weak void HW_IPCC_THREAD_EvtNot( void ){};
+
+#endif /* THREAD_WB */
+
+/******************************************************************************
+ * LLD TESTS
+ ******************************************************************************/
+#ifdef LLD_TESTS_WB
+void HW_IPCC_LLDTESTS_Init( void )
+{
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL );
+  return;
+}
+
+void HW_IPCC_LLDTESTS_SendCliCmd( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_LLDTESTS_CLI_CMD_CHANNEL );
+  return;
+}
+
+static void HW_IPCC_LLDTESTS_ReceiveCliRspHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL );
+  HW_IPCC_LLDTESTS_ReceiveCliRsp();
+  return;
+}
+
+void HW_IPCC_LLDTESTS_SendCliRspAck( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_CLI_RSP_CHANNEL );
+  return;
+}
+
+static void HW_IPCC_LLDTESTS_ReceiveM0CmdHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL );
+  HW_IPCC_LLDTESTS_ReceiveM0Cmd();
+  return;
+}
+
+void HW_IPCC_LLDTESTS_SendM0CmdAck( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLDTESTS_M0_CMD_CHANNEL );
+  return;
+}
+__weak void HW_IPCC_LLDTESTS_ReceiveCliRsp( void ){};
+__weak void HW_IPCC_LLDTESTS_ReceiveM0Cmd( void ){};
+#endif /* LLD_TESTS_WB */
+
+/******************************************************************************
+ * LLD BLE
+ ******************************************************************************/
+#ifdef LLD_BLE_WB
+void HW_IPCC_LLD_BLE_Init( void )
+{
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL );
+  return;
+}
+
+void HW_IPCC_LLD_BLE_SendCliCmd( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_LLD_BLE_CLI_CMD_CHANNEL );
+  return;
+}
+
+/*static void HW_IPCC_LLD_BLE_ReceiveCliRspHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL );
+  HW_IPCC_LLD_BLE_ReceiveCliRsp();
+  return;
+}*/
+
+void HW_IPCC_LLD_BLE_SendCliRspAck( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_CLI_RSP_CHANNEL );
+  return;
+}
+
+static void HW_IPCC_LLD_BLE_ReceiveM0CmdHandler( void )
+{
+  //LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL );
+  HW_IPCC_LLD_BLE_ReceiveM0Cmd();
+  return;
+}
+
+void HW_IPCC_LLD_BLE_SendM0CmdAck( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL );
+  //LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_M0_CMD_CHANNEL );
+  return;
+}
+__weak void HW_IPCC_LLD_BLE_ReceiveCliRsp( void ){};
+__weak void HW_IPCC_LLD_BLE_ReceiveM0Cmd( void ){};
+
+/* Transparent Mode */
+void HW_IPCC_LLD_BLE_SendCmd( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_LLD_BLE_CMD_CHANNEL );
+  return;
+}
+
+static void HW_IPCC_LLD_BLE_ReceiveRspHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL );
+  HW_IPCC_LLD_BLE_ReceiveRsp();
+  return;
+}
+
+void HW_IPCC_LLD_BLE_SendRspAck( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_LLD_BLE_RSP_CHANNEL );
+  return;
+}
+
+#endif /* LLD_BLE_WB */
+
+/******************************************************************************
+ * ZIGBEE
+ ******************************************************************************/
+#ifdef ZIGBEE_WB
+void HW_IPCC_ZIGBEE_Init( void )
+{
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_ZIGBEE_SendM4RequestToM0( void )
+{
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL );
+  LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL );
+
+  return;
+}
+
+void HW_IPCC_ZIGBEE_SendM4AckToM0Notify( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL );
+
+  return;
+}
+
+static void HW_IPCC_ZIGBEE_CmdEvtHandler( void )
+{
+  LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL );
+
+  HW_IPCC_ZIGBEE_RecvAppliAckFromM0();
+
+  return;
+}
+
+static void HW_IPCC_ZIGBEE_StackNotifEvtHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL );
+
+  HW_IPCC_ZIGBEE_RecvM0NotifyToM4();
+
+  return;
+}
+
+static void HW_IPCC_ZIGBEE_StackM0RequestHandler( void )
+{
+  LL_C1_IPCC_DisableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL );
+
+  HW_IPCC_ZIGBEE_RecvM0RequestToM4();
+
+  return;
+}
+
+void HW_IPCC_ZIGBEE_SendM4AckToM0Request( void )
+{
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL );
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_ZIGBEE_M0_REQUEST_CHANNEL );
+
+  return;
+}
+
+__weak void HW_IPCC_ZIGBEE_RecvAppliAckFromM0( void ){};
+__weak void HW_IPCC_ZIGBEE_RecvM0NotifyToM4( void ){};
+__weak void HW_IPCC_ZIGBEE_RecvM0RequestToM4( void ){};
+#endif /* ZIGBEE_WB */
+
+/******************************************************************************
+ * MEMORY MANAGER
+ ******************************************************************************/
+void HW_IPCC_MM_SendFreeBuf( void (*cb)( void ) )
+{
+  if ( LL_C1_IPCC_IsActiveFlag_CHx( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL ) )
+  {
+    FreeBufCb = cb;
+    LL_C1_IPCC_EnableTransmitChannel( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL );
+  }
+  else
+  {
+    cb();
+
+    LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL );
+  }
+
+  return;
+}
+
+static void HW_IPCC_MM_FreeBufHandler( void )
+{
+  LL_C1_IPCC_DisableTransmitChannel( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL );
+
+  FreeBufCb();
+
+  LL_C1_IPCC_SetFlag_CHx( IPCC, HW_IPCC_MM_RELEASE_BUFFER_CHANNEL );
+
+  return;
+}
+
+/******************************************************************************
+ * TRACES
+ ******************************************************************************/
+void HW_IPCC_TRACES_Init( void )
+{
+  LL_C1_IPCC_EnableReceiveChannel( IPCC, HW_IPCC_TRACES_CHANNEL );
+
+  return;
+}
+
+static void HW_IPCC_TRACES_EvtHandler( void )
+{
+  HW_IPCC_TRACES_EvtNot();
+
+  LL_C1_IPCC_ClearFlag_CHx( IPCC, HW_IPCC_TRACES_CHANNEL );
+
+  return;
+}
+
+__weak void HW_IPCC_TRACES_EvtNot( void ){};
+
+/******************* (C) COPYRIGHT 2019 STMicroelectronics *****END OF FILE****/

Некоторые файлы не были показаны из-за большого количества измененных файлов