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

[FL-873] Add F5 target, lp5562 driver and api-hal-light (#347)

* Add F5 target, lp5562 driver and api-hal-light. Update api-usage, switch to F5 by default.
* API HAL: add i2c and hardware version api. Dolphin: show hardware version.
* OTP version generator and flashing utility.
* Assets script: fix code formatting
* Backport F5 changes to F4
* F4: disable insomnia, prevent damage to BLE RX path
* F5 HAL API Light: remove magic delay to fix magic BLE
* Dolphin: HW target validation on start
* invert RSSI indication in sub-1
* API HAL: rename board to body in version api
* Gpio tester: detach and release viewport on exit

Co-authored-by: aanper <mail@s3f.ru>
あく 4 лет назад
Родитель
Сommit
68a3f6b4b7
100 измененных файлов с 9632 добавлено и 145 удалено
  1. 6 10
      applications/backlight-control/backlight-control.c
  2. 1 0
      applications/bt/bt_i.h
  3. 2 7
      applications/cc1101-workaround/cc1101-workaround.cpp
  4. 2 0
      applications/cc1101-workaround/cc1101.cpp
  5. 1 0
      applications/cli/cli_i.h
  6. 2 0
      applications/coreglitch_demo_0/coreglitch_demo_0.c
  7. 27 17
      applications/dolphin/dolphin.c
  8. 4 3
      applications/dolphin/dolphin_i.h
  9. 1 0
      applications/dolphin/dolphin_state.c
  10. 30 5
      applications/dolphin/dolphin_views.c
  11. 10 6
      applications/dolphin/dolphin_views.h
  12. 13 28
      applications/examples/blink.c
  13. 1 0
      applications/examples/input_dump.c
  14. 1 0
      applications/examples/uart_write.c
  15. 5 6
      applications/examples/vibro.c
  16. 10 5
      applications/gpio-tester/gpio-tester.c
  17. 2 0
      applications/gui/u8g2_periphery.c
  18. 1 0
      applications/ibutton/blanks_writer.cpp
  19. 4 12
      applications/ibutton/ibutton.cpp
  20. 4 12
      applications/irda/irda.c
  21. 2 0
      applications/irda/irda_nec.c
  22. 2 0
      applications/irda/irda_samsung.c
  23. 1 0
      applications/lf-rfid/em4100.c
  24. 3 5
      applications/lf-rfid/lf-rfid.c
  25. 2 0
      applications/music-player/music-player.c
  26. 1 0
      applications/power/power.c
  27. 5 19
      applications/sd-card-test/sd-card-test.cpp
  28. 1 0
      applications/sd-filesystem/sd-filesystem.h
  29. 29 0
      assets/assets.py
  30. 1 1
      bootloader/Makefile
  31. 187 0
      bootloader/targets/f5/stm32wb55xx_flash_cm4.ld
  32. 166 0
      bootloader/targets/f5/target.c
  33. 29 0
      bootloader/targets/f5/target.mk
  34. 0 1
      core/furi.h
  35. 1 1
      firmware/Makefile
  36. 26 0
      firmware/targets/api-hal-include/api-hal-i2c.h
  37. 17 0
      firmware/targets/api-hal-include/api-hal-light.h
  38. 25 0
      firmware/targets/api-hal-include/api-hal-version.h
  39. 3 0
      firmware/targets/api-hal-include/api-hal.h
  40. 4 3
      firmware/targets/f4/api-hal/api-hal-gpio.c
  41. 17 0
      firmware/targets/f4/api-hal/api-hal-i2c.c
  42. 55 0
      firmware/targets/f4/api-hal/api-hal-light.c
  43. 1 1
      firmware/targets/f4/api-hal/api-hal-power.c
  44. 17 2
      firmware/targets/f4/api-hal/api-hal-resources.h
  45. 34 0
      firmware/targets/f4/api-hal/api-hal-version.c
  46. 3 1
      firmware/targets/f4/api-hal/api-hal.c
  47. 166 0
      firmware/targets/f5/Inc/FreeRTOSConfig.h
  48. 52 0
      firmware/targets/f5/Inc/adc.h
  49. 54 0
      firmware/targets/f5/Inc/aes.h
  50. 52 0
      firmware/targets/f5/Inc/comp.h
  51. 52 0
      firmware/targets/f5/Inc/crc.h
  52. 49 0
      firmware/targets/f5/Inc/gpio.h
  53. 54 0
      firmware/targets/f5/Inc/i2c.h
  54. 198 0
      firmware/targets/f5/Inc/main.h
  55. 52 0
      firmware/targets/f5/Inc/pka.h
  56. 50 0
      firmware/targets/f5/Inc/rf.h
  57. 52 0
      firmware/targets/f5/Inc/rng.h
  58. 52 0
      firmware/targets/f5/Inc/rtc.h
  59. 57 0
      firmware/targets/f5/Inc/spi.h
  60. 353 0
      firmware/targets/f5/Inc/stm32wbxx_hal_conf.h
  61. 81 0
      firmware/targets/f5/Inc/stm32wbxx_it.h
  62. 58 0
      firmware/targets/f5/Inc/tim.h
  63. 52 0
      firmware/targets/f5/Inc/usart.h
  64. 105 0
      firmware/targets/f5/Inc/usb_device.h
  65. 134 0
      firmware/targets/f5/Inc/usbd_cdc_if.h
  66. 176 0
      firmware/targets/f5/Inc/usbd_conf.h
  67. 145 0
      firmware/targets/f5/Inc/usbd_desc.h
  68. 128 0
      firmware/targets/f5/Src/adc.c
  69. 127 0
      firmware/targets/f5/Src/aes.c
  70. 103 0
      firmware/targets/f5/Src/comp.c
  71. 82 0
      firmware/targets/f5/Src/crc.c
  72. 56 0
      firmware/targets/f5/Src/fatfs/fatfs.c
  73. 49 0
      firmware/targets/f5/Src/fatfs/fatfs.h
  74. 270 0
      firmware/targets/f5/Src/fatfs/ffconf.h
  75. 124 0
      firmware/targets/f5/Src/fatfs/spi_sd_hal.c
  76. 1015 0
      firmware/targets/f5/Src/fatfs/stm32_adafruit_sd.c
  77. 251 0
      firmware/targets/f5/Src/fatfs/stm32_adafruit_sd.h
  78. 138 0
      firmware/targets/f5/Src/fatfs/syscall.c
  79. 230 0
      firmware/targets/f5/Src/fatfs/user_diskio.c
  80. 48 0
      firmware/targets/f5/Src/fatfs/user_diskio.h
  81. 21 0
      firmware/targets/f5/Src/freertos-openocd.c
  82. 197 0
      firmware/targets/f5/Src/gpio.c
  83. 120 0
      firmware/targets/f5/Src/i2c.c
  84. 155 0
      firmware/targets/f5/Src/main.c
  85. 77 0
      firmware/targets/f5/Src/pka.c
  86. 37 0
      firmware/targets/f5/Src/rf.c
  87. 77 0
      firmware/targets/f5/Src/rng.c
  88. 123 0
      firmware/targets/f5/Src/rtc.c
  89. 344 0
      firmware/targets/f5/Src/spi.c
  90. 93 0
      firmware/targets/f5/Src/stm32wbxx_hal_msp.c
  91. 418 0
      firmware/targets/f5/Src/stm32wbxx_it.c
  92. 357 0
      firmware/targets/f5/Src/system_stm32wbxx.c
  93. 361 0
      firmware/targets/f5/Src/tim.c
  94. 121 0
      firmware/targets/f5/Src/usart.c
  95. 99 0
      firmware/targets/f5/Src/usb_device.c
  96. 311 0
      firmware/targets/f5/Src/usbd_cdc_if.c
  97. 810 0
      firmware/targets/f5/Src/usbd_conf.c
  98. 396 0
      firmware/targets/f5/Src/usbd_desc.c
  99. 13 0
      firmware/targets/f5/api-hal/api-hal-boot.c
  100. 78 0
      firmware/targets/f5/api-hal/api-hal-bt.c

+ 6 - 10
applications/backlight-control/backlight-control.c

@@ -1,6 +1,7 @@
 #include <furi.h>
+#include <api-hal.h>
 
-#define BACKLIGHT_TIME 10000
+#define BACKLIGHT_TIME 30000
 #define BACKLIGHT_FLAG_ACTIVITY 0x00000001U
 
 static void event_cb(const void* value, void* ctx) {
@@ -8,24 +9,19 @@ static void event_cb(const void* value, void* ctx) {
 }
 
 int32_t backlight_control(void* p) {
-    // TODO open record
-    const GpioPin* backlight_record = &backlight_gpio;
-
-    // configure pin
-    gpio_init(backlight_record, GpioModeOutputPushPull);
-    gpio_write(backlight_record, true);
-
     // open record
     PubSub* event_record = furi_record_open("input_events");
     subscribe_pubsub(event_record, event_cb, (void*)osThreadGetId());
 
+    api_hal_light_set(LightBacklight, 0xFF);
+
     while(1) {
         // wait for event
         if(osThreadFlagsWait(BACKLIGHT_FLAG_ACTIVITY, osFlagsWaitAny, BACKLIGHT_TIME) ==
            BACKLIGHT_FLAG_ACTIVITY) {
-            gpio_write(backlight_record, true);
+            api_hal_light_set(LightBacklight, 0xFF);
         } else {
-            gpio_write(backlight_record, false);
+            api_hal_light_set(LightBacklight, 0x00);
         }
     }
 

+ 1 - 0
applications/bt/bt_i.h

@@ -3,6 +3,7 @@
 #include "bt.h"
 
 #include <furi.h>
+#include <api-hal.h>
 
 #include <cli/cli.h>
 

+ 2 - 7
applications/cc1101-workaround/cc1101-workaround.cpp

@@ -1,5 +1,6 @@
 #include "cc1101.h"
 #include <furi.h>
+#include <api-hal.h>
 #include <gui/gui.h>
 #include <input/input.h>
 
@@ -409,12 +410,6 @@ extern "C" int32_t cc1101_workaround(void* p) {
 
     printf("init ok\r\n");
 
-    // TODO open record
-    GpioPin* led_record = (GpioPin*)&led_gpio[1];
-
-    // configure pin
-    gpio_init(led_record, GpioModeOutputOpenDrain);
-
     const int16_t RSSI_THRESHOLD = -60;
 
     // setup_freq(&cc1101, &FREQ_LIST[1]);
@@ -530,7 +525,7 @@ extern "C" int32_t cc1101_workaround(void* p) {
             // TOOD what about rssi offset
             state->last_rssi = rx_rssi(&cc1101, &FREQ_LIST[state->active_freq_idx]);
 
-            gpio_write(led_record, state->last_rssi < RSSI_THRESHOLD);
+            api_hal_light_set(LightGreen, state->last_rssi > RSSI_THRESHOLD ? 0xFF : 0x00);
         } else if(!state->need_cc1101_conf && state->mode == ModeTx) {
             /*
             const uint8_t data = 0xA5;

+ 2 - 0
applications/cc1101-workaround/cc1101.cpp

@@ -1,4 +1,6 @@
 #include <furi.h>
+#include <api-hal.h>
+
 #include "cc1101-workaround/cc1101.h"
 #include "spi.h"
 #include <math.h>

+ 1 - 0
applications/cli/cli_i.h

@@ -3,6 +3,7 @@
 #include "cli.h"
 
 #include <furi.h>
+#include <api-hal.h>
 
 #include <m-dict.h>
 

+ 2 - 0
applications/coreglitch_demo_0/coreglitch_demo_0.c

@@ -1,4 +1,6 @@
 #include <furi.h>
+#include <api-hal.h>
+
 #include "u8g2/u8g2.h"
 
 extern TIM_HandleTypeDef SPEAKER_TIM;

+ 27 - 17
applications/dolphin/dolphin.c

@@ -38,16 +38,16 @@ bool dolphin_view_idle_main_input(InputEvent* event, void* context) {
             with_value_mutex(
                 dolphin->menu_vm, (Menu * menu) { menu_ok(menu); });
         } else if(event->key == InputKeyUp) {
-            view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleStats);
+            view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleUp);
         } else if(event->key == InputKeyDown) {
-            view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleDebug);
+            view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleDown);
         }
     }
     // All events consumed
     return true;
 }
 
-bool dolphin_view_idle_stats_input(InputEvent* event, void* context) {
+bool dolphin_view_idle_up_input(InputEvent* event, void* context) {
     furi_assert(event);
     furi_assert(context);
     Dolphin* dolphin = context;
@@ -95,21 +95,27 @@ Dolphin* dolphin_alloc() {
     view_dispatcher_add_view(
         dolphin->idle_view_dispatcher, DolphinViewIdleMain, dolphin->idle_view_main);
     // Stats Idle View
-    dolphin->idle_view_stats = view_alloc();
-    view_set_context(dolphin->idle_view_stats, dolphin);
+    dolphin->idle_view_up = view_alloc();
+    view_set_context(dolphin->idle_view_up, dolphin);
     view_allocate_model(
-        dolphin->idle_view_stats, ViewModelTypeLockFree, sizeof(DolphinViewIdleStatsModel));
-    view_set_draw_callback(dolphin->idle_view_stats, dolphin_view_idle_stats_draw);
-    view_set_input_callback(dolphin->idle_view_stats, dolphin_view_idle_stats_input);
-    view_set_previous_callback(dolphin->idle_view_stats, dolphin_view_idle_back);
+        dolphin->idle_view_up, ViewModelTypeLockFree, sizeof(DolphinViewIdleUpModel));
+    view_set_draw_callback(dolphin->idle_view_up, dolphin_view_idle_up_draw);
+    view_set_input_callback(dolphin->idle_view_up, dolphin_view_idle_up_input);
+    view_set_previous_callback(dolphin->idle_view_up, dolphin_view_idle_back);
     view_dispatcher_add_view(
-        dolphin->idle_view_dispatcher, DolphinViewIdleStats, dolphin->idle_view_stats);
-    // Debug Idle View
-    dolphin->idle_view_debug = view_alloc();
-    view_set_draw_callback(dolphin->idle_view_debug, dolphin_view_idle_debug_draw);
-    view_set_previous_callback(dolphin->idle_view_debug, dolphin_view_idle_back);
+        dolphin->idle_view_dispatcher, DolphinViewIdleUp, dolphin->idle_view_up);
+    // Down Idle View
+    dolphin->idle_view_down = view_alloc();
+    view_set_draw_callback(dolphin->idle_view_down, dolphin_view_idle_down_draw);
+    view_set_previous_callback(dolphin->idle_view_down, dolphin_view_idle_back);
     view_dispatcher_add_view(
-        dolphin->idle_view_dispatcher, DolphinViewIdleDebug, dolphin->idle_view_debug);
+        dolphin->idle_view_dispatcher, DolphinViewIdleDown, dolphin->idle_view_down);
+    // HW Mismatch
+    dolphin->view_hw_mismatch = view_alloc();
+    view_set_draw_callback(dolphin->view_hw_mismatch, dolphin_view_hw_mismatch_draw);
+    view_set_previous_callback(dolphin->view_hw_mismatch, dolphin_view_idle_back);
+    view_dispatcher_add_view(
+        dolphin->idle_view_dispatcher, DolphinViewHwMismatch, dolphin->view_hw_mismatch);
 
     return dolphin;
 }
@@ -140,7 +146,7 @@ int32_t dolphin_task() {
         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewFirstStart);
     }
     with_view_model(
-        dolphin->idle_view_stats, (DolphinViewIdleStatsModel * model) {
+        dolphin->idle_view_up, (DolphinViewIdleUpModel * model) {
             model->icounter = dolphin_state_get_icounter(dolphin->state);
             model->butthurt = dolphin_state_get_butthurt(dolphin->state);
             return true;
@@ -148,13 +154,17 @@ int32_t dolphin_task() {
 
     furi_record_create("dolphin", dolphin);
 
+    if(!api_hal_version_do_i_belong_here()) {
+        view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewHwMismatch);
+    }
+
     DolphinEvent event;
     while(1) {
         furi_check(osMessageQueueGet(dolphin->event_queue, &event, NULL, osWaitForever) == osOK);
         if(event.type == DolphinEventTypeDeed) {
             dolphin_state_on_deed(dolphin->state, event.deed);
             with_view_model(
-                dolphin->idle_view_stats, (DolphinViewIdleStatsModel * model) {
+                dolphin->idle_view_up, (DolphinViewIdleUpModel * model) {
                     model->icounter = dolphin_state_get_icounter(dolphin->state);
                     model->butthurt = dolphin_state_get_butthurt(dolphin->state);
                     return true;

+ 4 - 3
applications/dolphin/dolphin_i.h

@@ -5,7 +5,7 @@
 #include "dolphin_views.h"
 
 #include <furi.h>
-
+#include <api-hal.h>
 #include <gui/gui.h>
 #include <gui/view_dispatcher.h>
 #include <gui/canvas.h>
@@ -37,8 +37,9 @@ struct Dolphin {
     ViewDispatcher* idle_view_dispatcher;
     View* idle_view_first_start;
     View* idle_view_main;
-    View* idle_view_stats;
-    View* idle_view_debug;
+    View* idle_view_up;
+    View* idle_view_down;
+    View* view_hw_mismatch;
 };
 
 Dolphin* dolphin_alloc();

+ 1 - 0
applications/dolphin/dolphin_state.c

@@ -1,5 +1,6 @@
 #include "dolphin_state.h"
 #include <furi.h>
+#include <api-hal.h>
 
 typedef struct {
     uint8_t magic;

+ 30 - 5
applications/dolphin/dolphin_views.c

@@ -3,6 +3,8 @@
 #include <gui/gui.h>
 #include <gui/elements.h>
 
+#include <api-hal.h>
+
 void dolphin_view_first_start_draw(Canvas* canvas, void* model) {
     DolphinViewFirstStartModel* m = model;
     canvas_clear(canvas);
@@ -64,8 +66,8 @@ void dolphin_view_idle_main_draw(Canvas* canvas, void* model) {
     canvas_draw_str(canvas, 2, 52, "\\/: Version");
 }
 
-void dolphin_view_idle_stats_draw(Canvas* canvas, void* model) {
-    DolphinViewIdleStatsModel* m = model;
+void dolphin_view_idle_up_draw(Canvas* canvas, void* model) {
+    DolphinViewIdleUpModel* m = model;
     canvas_clear(canvas);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontPrimary);
@@ -80,7 +82,7 @@ void dolphin_view_idle_stats_draw(Canvas* canvas, void* model) {
     canvas_draw_str(canvas, 5, 40, "< > change icounter");
 }
 
-void dolphin_view_idle_debug_draw(Canvas* canvas, void* model) {
+void dolphin_view_idle_down_draw(Canvas* canvas, void* model) {
     canvas_clear(canvas);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontPrimary);
@@ -88,8 +90,31 @@ void dolphin_view_idle_debug_draw(Canvas* canvas, void* model) {
     canvas_set_font(canvas, FontSecondary);
     canvas_draw_str(canvas, 5, 22, TARGET " " BUILD_DATE);
     canvas_draw_str(canvas, 5, 32, GIT_BRANCH);
-    canvas_draw_str(canvas, 5, 42, GIT_BRANCH_NUM);
-    canvas_draw_str(canvas, 5, 52, GIT_COMMIT);
+    canvas_draw_str(canvas, 5, 42, GIT_BRANCH_NUM " " GIT_COMMIT);
+
+    char buffer[64];
+    snprintf(
+        buffer,
+        64,
+        "HW: %d.F%dB%dC%d",
+        api_hal_version_get_hw_version(),
+        api_hal_version_get_hw_target(),
+        api_hal_version_get_hw_body(),
+        api_hal_version_get_hw_connect());
+    canvas_draw_str(canvas, 5, 52, buffer);
+}
+
+void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model) {
+    canvas_clear(canvas);
+    canvas_set_color(canvas, ColorBlack);
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str(canvas, 2, 10, "!!!! HW Mismatch !!!!");
+
+    char buffer[64];
+    canvas_set_font(canvas, FontSecondary);
+    snprintf(buffer, 64, "HW target: F%d", api_hal_version_get_hw_target());
+    canvas_draw_str(canvas, 5, 22, buffer);
+    canvas_draw_str(canvas, 5, 32, "FW target: " TARGET);
 }
 
 uint32_t dolphin_view_idle_back(void* context) {

+ 10 - 6
applications/dolphin/dolphin_views.h

@@ -10,8 +10,9 @@
 typedef enum {
     DolphinViewFirstStart,
     DolphinViewIdleMain,
-    DolphinViewIdleStats,
-    DolphinViewIdleDebug,
+    DolphinViewIdleUp,
+    DolphinViewIdleDown,
+    DolphinViewHwMismatch,
 } DolphinViewIdle;
 
 typedef struct {
@@ -24,11 +25,14 @@ bool dolphin_view_first_start_input(InputEvent* event, void* context);
 typedef struct {
     uint32_t icounter;
     uint32_t butthurt;
-} DolphinViewIdleStatsModel;
+} DolphinViewIdleUpModel;
 
 void dolphin_view_idle_main_draw(Canvas* canvas, void* model);
 bool dolphin_view_idle_main_input(InputEvent* event, void* context);
-void dolphin_view_idle_stats_draw(Canvas* canvas, void* model);
-bool dolphin_view_idle_stats_input(InputEvent* event, void* context);
-void dolphin_view_idle_debug_draw(Canvas* canvas, void* model);
+
+void dolphin_view_idle_up_draw(Canvas* canvas, void* model);
+void dolphin_view_idle_down_draw(Canvas* canvas, void* model);
+
+void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model);
+
 uint32_t dolphin_view_idle_back(void* context);

+ 13 - 28
applications/examples/blink.c

@@ -1,44 +1,29 @@
 #include <furi.h>
+#include <api-hal.h>
 
-void rgb_set(
-    bool r,
-    bool g,
-    bool b,
-    const GpioPin* led_r,
-    const GpioPin* led_g,
-    const GpioPin* led_b) {
-    gpio_write(led_r, !r);
-    gpio_write(led_g, !g);
-    gpio_write(led_b, !b);
+void rgb_set(bool r, bool g, bool b) {
+    api_hal_light_set(LightRed, r ? 0xFF : 0x00);
+    api_hal_light_set(LightGreen, g ? 0xFF : 0x00);
+    api_hal_light_set(LightBlue, b ? 0xFF : 0x00);
 }
 
 int32_t application_blink(void* p) {
-    // TODO open record
-    const GpioPin* led_r_record = &led_gpio[0];
-    const GpioPin* led_g_record = &led_gpio[1];
-    const GpioPin* led_b_record = &led_gpio[2];
-
-    // configure pin
-    gpio_init(led_r_record, GpioModeOutputOpenDrain);
-    gpio_init(led_g_record, GpioModeOutputOpenDrain);
-    gpio_init(led_b_record, GpioModeOutputOpenDrain);
-
     while(1) {
-        rgb_set(1, 0, 0, led_r_record, led_g_record, led_b_record);
+        rgb_set(1, 0, 0);
         delay(500);
-        rgb_set(0, 1, 0, led_r_record, led_g_record, led_b_record);
+        rgb_set(0, 1, 0);
         delay(500);
-        rgb_set(1, 1, 0, led_r_record, led_g_record, led_b_record);
+        rgb_set(0, 0, 1);
         delay(500);
-        rgb_set(0, 0, 1, led_r_record, led_g_record, led_b_record);
+        rgb_set(1, 1, 0);
         delay(500);
-        rgb_set(1, 0, 1, led_r_record, led_g_record, led_b_record);
+        rgb_set(0, 1, 1);
         delay(500);
-        rgb_set(0, 1, 1, led_r_record, led_g_record, led_b_record);
+        rgb_set(1, 0, 1);
         delay(500);
-        rgb_set(1, 1, 1, led_r_record, led_g_record, led_b_record);
+        rgb_set(1, 1, 1);
         delay(500);
-        rgb_set(0, 0, 0, led_r_record, led_g_record, led_b_record);
+        rgb_set(0, 0, 0);
         delay(500);
     }
 

+ 1 - 0
applications/examples/input_dump.c

@@ -1,4 +1,5 @@
 #include <furi.h>
+#include <api-hal.h>
 #include <stdio.h>
 #include <input/input.h>
 

+ 1 - 0
applications/examples/uart_write.c

@@ -1,4 +1,5 @@
 #include <furi.h>
+#include <api-hal.h>
 #include <string.h>
 
 int32_t application_uart_write(void* p) {

+ 5 - 6
applications/examples/vibro.c

@@ -1,8 +1,9 @@
 #include <furi.h>
+#include <api-hal.h>
+
 #include <input/input.h>
 
 typedef struct {
-    GpioPin* led;
     GpioPin* vibro;
 } Ctx;
 
@@ -13,20 +14,18 @@ static void button_handler(const void* value, void* _ctx) {
     if(event->key != InputKeyOk) return;
 
     if(event->type == InputTypePress) {
-        gpio_write(ctx->led, false);
+        api_hal_light_set(LightGreen, 0xFF);
         gpio_write(ctx->vibro, true);
     } else if(event->type == InputTypeRelease) {
-        gpio_write(ctx->led, true);
+        api_hal_light_set(LightGreen, 0x00);
         gpio_write(ctx->vibro, false);
     }
 }
 
 int32_t application_vibro(void* p) {
-    Ctx ctx = {.led = (GpioPin*)&led_gpio[1], .vibro = (GpioPin*)&vibro_gpio};
+    Ctx ctx = {.vibro = (GpioPin*)&vibro_gpio};
 
-    gpio_init(ctx.led, GpioModeOutputOpenDrain);
     gpio_init(ctx.vibro, GpioModeOutputPushPull);
-    gpio_write(ctx.led, true);
     gpio_write(ctx.vibro, false);
 
     // subscribe on buttons

+ 10 - 5
applications/gpio-tester/gpio-tester.c

@@ -1,4 +1,6 @@
 #include <furi.h>
+#include <api-hal.h>
+
 #include <gui/gui.h>
 #include <input/input.h>
 
@@ -84,8 +86,6 @@ int32_t app_gpio_test(void* p) {
         gpio_init((GpioPin*)&GPIO_PINS[i].pin, GpioModeOutputPushPull);
     }
 
-    gpio_init((GpioPin*)&led_gpio[1], GpioModeOutputOpenDrain);
-
     AppEvent event;
     while(1) {
         osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
@@ -96,8 +96,13 @@ int32_t app_gpio_test(void* p) {
                 if(event.value.input.type == InputTypeShort &&
                    event.value.input.key == InputKeyBack) {
                     printf("[gpio-tester] bye!\r\n");
-                    // TODO remove all view_ports create by app
+
+                    api_hal_light_set(LightGreen, 0x00);
+
                     view_port_enabled_set(view_port, false);
+                    gui_remove_view_port(gui, view_port);
+                    view_port_free(view_port);
+
                     return 0;
                 }
 
@@ -118,10 +123,10 @@ int32_t app_gpio_test(void* p) {
                 if(event.value.input.key == InputKeyOk) {
                     if(event.value.input.type == InputTypePress) {
                         gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, true);
-                        gpio_write((GpioPin*)&led_gpio[1], false);
+                        api_hal_light_set(LightGreen, 0xFF);
                     } else if(event.value.input.type == InputTypeRelease) {
                         gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, false);
-                        gpio_write((GpioPin*)&led_gpio[1], true);
+                        api_hal_light_set(LightGreen, 0x00);
                     }
                 }
             }

+ 2 - 0
applications/gui/u8g2_periphery.c

@@ -1,5 +1,7 @@
 #include "u8g2/u8g2.h"
 #include <furi.h>
+#include <api-hal.h>
+
 #include <main.h>
 
 extern SPI_HandleTypeDef SPI_D;

+ 1 - 0
applications/ibutton/blanks_writer.cpp

@@ -40,6 +40,7 @@ public:
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
+#include <api-hal.h>
 
 void BlanksWriter::onewire_release(void) {
     gpio_write(gpio, true);

+ 4 - 12
applications/ibutton/ibutton.cpp

@@ -15,14 +15,6 @@ void AppiButton::run() {
 
     switch_to_mode(0);
 
-    // TODO open record
-    red_led_record = &led_gpio[0];
-    green_led_record = &led_gpio[1];
-
-    // configure pin
-    gpio_init(red_led_record, GpioModeOutputOpenDrain);
-    gpio_init(green_led_record, GpioModeOutputOpenDrain);
-
     api_hal_power_insomnia_enter();
     app_ready();
 
@@ -112,15 +104,15 @@ void AppiButton::render_cyfral_list(Canvas* canvas, AppiButtonState* state) {
 }
 
 void AppiButton::blink_red() {
-    gpio_write(red_led_record, 0);
+    api_hal_light_set(LightRed, 0xFF);
     delay(10);
-    gpio_write(red_led_record, 1);
+    api_hal_light_set(LightRed, 0x00);
 }
 
 void AppiButton::blink_green() {
-    gpio_write(green_led_record, 0);
+    api_hal_light_set(LightGreen, 0xFF);
     delay(10);
-    gpio_write(green_led_record, 1);
+    api_hal_light_set(LightGreen, 0x00);
 }
 
 void AppiButton::increase_mode() {

+ 4 - 12
applications/irda/irda.c

@@ -1,4 +1,5 @@
 #include <furi.h>
+#include <api-hal.h>
 #include <gui/gui.h>
 #include <input/input.h>
 
@@ -274,15 +275,6 @@ int32_t irda(void* p) {
     Gui* gui = furi_record_open("gui");
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
-    // Red LED
-    // TODO open record
-    const GpioPin* red_led_record = &led_gpio[0];
-    const GpioPin* green_led_record = &led_gpio[1];
-
-    // configure pin
-    gpio_init(red_led_record, GpioModeOutputOpenDrain);
-    gpio_init(green_led_record, GpioModeOutputOpenDrain);
-
     // setup irda rx timer
     tim_irda_rx_init();
 
@@ -346,7 +338,7 @@ int32_t irda(void* p) {
                 out.data_length = out_data_length;
                 out.data = out_data;
 
-                gpio_write(red_led_record, event.value.rx.edge);
+                api_hal_light_set(LightRed, event.value.rx.edge ? 0x00 : 0xFF);
 
                 bool decoded =
                     process_decoder(decoder, event.value.rx.edge, &event.value.rx.lasted, 1, &out);
@@ -378,8 +370,8 @@ int32_t irda(void* p) {
                     view_port_update(view_port);
 
                     // blink anyway
-                    gpio_write(green_led_record, false);
-                    gpio_write(green_led_record, true);
+                    api_hal_light_set(LightGreen, 0xFF);
+                    api_hal_light_set(LightGreen, 0x00);
                 }
             }
 

+ 2 - 0
applications/irda/irda_nec.c

@@ -1,4 +1,6 @@
 #include <furi.h>
+#include <api-hal.h>
+
 #include "irda_nec.h"
 #include "irda_protocols.h"
 

+ 2 - 0
applications/irda/irda_samsung.c

@@ -1,4 +1,6 @@
 #include <furi.h>
+#include <api-hal.h>
+
 #include "irda_samsung.h"
 #include "irda_protocols.h"
 

+ 1 - 0
applications/lf-rfid/em4100.c

@@ -1,4 +1,5 @@
 #include <furi.h>
+#include <api-hal.h>
 
 void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data) {
     uint8_t value[10];

+ 3 - 5
applications/lf-rfid/lf-rfid.c

@@ -1,4 +1,5 @@
 #include <furi.h>
+#include <api-hal.h>
 #include <gui/gui.h>
 
 typedef enum { EventTypeTick, EventTypeKey, EventTypeRx } EventType;
@@ -213,9 +214,6 @@ int32_t lf_rfid_workaround(void* p) {
     bool center = false;
     size_t symbol_cnt = 0;
 
-    GpioPin* led_record = (GpioPin*)&led_gpio[1];
-    gpio_init(led_record, GpioModeOutputOpenDrain);
-
     uint8_t buf[64];
     for(size_t i = 0; i < 64; i++) {
         buf[i] = 0;
@@ -272,9 +270,9 @@ int32_t lf_rfid_workaround(void* p) {
                     extract_data(&buf[9], &state->customer_id, &state->em_data);
                     printf("customer: %02d, data: %010lu\n", state->customer_id, state->em_data);
                     release_mutex(&state_mutex, state);
-                    gpio_write(led_record, false);
+                    api_hal_light_set(LightGreen, 0xFF);
                     osDelay(100);
-                    gpio_write(led_record, true);
+                    api_hal_light_set(LightGreen, 0x00);
                 }
 
                 symbol_cnt = 0;

+ 2 - 0
applications/music-player/music-player.c

@@ -1,4 +1,6 @@
 #include <furi.h>
+#include <api-hal.h>
+
 #include <gui/gui.h>
 #include <input/input.h>
 

+ 1 - 0
applications/power/power.c

@@ -2,6 +2,7 @@
 #include "power_views.h"
 
 #include <furi.h>
+#include <api-hal.h>
 
 #include <menu/menu.h>
 #include <menu/menu_item.h>

+ 5 - 19
applications/sd-card-test/sd-card-test.cpp

@@ -43,8 +43,6 @@ public:
 class SdTest : public AppTemplate<SdTestState, SdTestEvent> {
 public:
     // vars
-    GpioPin* red_led_record;
-    GpioPin* green_led_record;
     const uint32_t benchmark_data_size = 4096;
     uint8_t* benchmark_data;
     FS_Api* fs_api;
@@ -90,18 +88,6 @@ public:
 
 // start app
 void SdTest::run() {
-    // create pin
-    GpioPin red_led = led_gpio[0];
-    GpioPin green_led = led_gpio[1];
-
-    // TODO open record
-    red_led_record = &red_led;
-    green_led_record = &green_led;
-
-    // configure pin
-    gpio_init(red_led_record, GpioModeOutputOpenDrain);
-    gpio_init(green_led_record, GpioModeOutputOpenDrain);
-
     app_ready();
 
     fs_api = static_cast<FS_Api*>(furi_record_open("sdcard"));
@@ -844,21 +830,21 @@ bool SdTest::ask(InputKey input_button_cancel, InputKey input_button_ok) {
 
 // blink red led
 void SdTest::blink_red() {
-    gpio_write(red_led_record, 0);
+    api_hal_light_set(LightRed, 0xFF);
     delay(50);
-    gpio_write(red_led_record, 1);
+    api_hal_light_set(LightRed, 0x00);
 }
 
 // light up red led
 void SdTest::set_red() {
-    gpio_write(red_led_record, 0);
+    api_hal_light_set(LightRed, 0x00);
 }
 
 // blink green led
 void SdTest::blink_green() {
-    gpio_write(green_led_record, 0);
+    api_hal_light_set(LightGreen, 0xFF);
     delay(50);
-    gpio_write(green_led_record, 1);
+    api_hal_light_set(LightGreen, 0x00);
 }
 
 // set text, but with infinite loop

+ 1 - 0
applications/sd-filesystem/sd-filesystem.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <furi.h>
+#include <api-hal.h>
 #include <gui/gui.h>
 #include <input/input.h>
 

+ 29 - 0
assets/assets.py

@@ -6,6 +6,8 @@ import subprocess
 import io
 import os
 import sys
+import struct
+import datetime
 
 ICONS_SUPPORTED_FORMATS = ["png"]
 
@@ -64,6 +66,21 @@ class Assets:
             "-o", "--output-directory", help="Output directory"
         )
         self.parser_icons.set_defaults(func=self.icons)
+        self.parser_otp = self.subparsers.add_parser(
+            "otp", help="OTP HW version generator"
+        )
+        self.parser_otp.add_argument(
+            "--version", type=int, help="Version", required=True
+        )
+        self.parser_otp.add_argument(
+            "--firmware", type=int, help="Firmware", required=True
+        )
+        self.parser_otp.add_argument("--body", type=int, help="Body", required=True)
+        self.parser_otp.add_argument(
+            "--connect", type=int, help="Connect", required=True
+        )
+        self.parser_otp.add_argument("file", help="Output file")
+        self.parser_otp.set_defaults(func=self.otp)
         # logging
         self.logger = logging.getLogger()
 
@@ -82,6 +99,18 @@ class Assets:
         # execute requested function
         self.args.func()
 
+    def otp(self):
+        self.logger.debug(f"Generating OTP")
+        data = struct.pack(
+            "<BBBBL",
+            self.args.version,
+            self.args.firmware,
+            self.args.body,
+            self.args.connect,
+            int(datetime.datetime.now().timestamp()),
+        )
+        open(self.args.file, "wb").write(data)
+
     def icons(self):
         self.logger.debug(f"Converting icons")
         icons_c = open(os.path.join(self.args.output_directory, "assets_icons.c"), "w")

+ 1 - 1
bootloader/Makefile

@@ -9,7 +9,7 @@ ASM_SOURCES		+= $(wildcard src/*.s)
 C_SOURCES		+= $(wildcard src/*.c)
 CPP_SOURCES		+= $(wildcard src/*.cpp)
 
-TARGET			?= f4
+TARGET			?= f5
 TARGET_DIR		= targets/$(TARGET)
 include			$(TARGET_DIR)/target.mk
 

+ 187 - 0
bootloader/targets/f5/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 = 512K
+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
+}
+
+

+ 166 - 0
bootloader/targets/f5/target.c

@@ -0,0 +1,166 @@
+#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>
+
+// Boot request enum
+#define BOOT_REQUEST_NONE 0x00000000
+#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)
+
+void target_led_set_red(uint8_t value) {
+}
+
+void target_led_set_green(uint8_t value) {
+}
+
+void target_led_set_blue(uint8_t value) {
+}
+
+void target_led_set_backlight(uint8_t value) {
+}
+
+void target_led_control(char* c) {
+    target_led_set_red(0x00);
+    target_led_set_green(0x00);
+    target_led_set_blue(0x00);
+    do {
+        if(*c == 'R') {
+            target_led_set_red(0xFF);
+        } else if(*c == 'G') {
+            target_led_set_green(0xFF);
+        } else if(*c == 'B') {
+            target_led_set_blue(0xFF);
+        } else if(*c == '.') {
+            LL_mDelay(125);
+            target_led_set_red(0x00);
+            target_led_set_green(0x00);
+            target_led_set_blue(0x00);
+            LL_mDelay(125);
+        } else if(*c == '-') {
+            LL_mDelay(250);
+            target_led_set_red(0x00);
+            target_led_set_green(0x00);
+            target_led_set_blue(0x00);
+            LL_mDelay(250);
+        } else if(*c == '|') {
+            target_led_set_red(0x00);
+            target_led_set_green(0x00);
+            target_led_set_blue(0x00);
+        }
+        c++;
+    } while(*c != 0);
+}
+
+void clock_init() {
+    LL_Init1msTick(4000000);
+    LL_SetSystemCoreClock(4000000);
+}
+
+void gpio_init() {
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
+    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
+    // 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 rtc_init() {
+    // LSE and RTC
+    LL_PWR_EnableBkUpAccess();
+    if(!LL_RCC_LSE_IsReady()) {
+        // Try to start LSE normal way
+        LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_MEDIUMLOW);
+        LL_RCC_LSE_Enable();
+        uint32_t c = 0;
+        while(!LL_RCC_LSE_IsReady() && c < 200) {
+            LL_mDelay(10);
+            c++;
+        }
+        // Plan B: reset backup domain
+        if(!LL_RCC_LSE_IsReady()) {
+            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 clocking
+    LL_RCC_EnableRTC();
+    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB);
+}
+
+void usb_wire_reset() {
+    LL_GPIO_ResetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN);
+    LL_mDelay(10);
+    LL_GPIO_SetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN);
+}
+
+void target_init() {
+    clock_init();
+    gpio_init();
+    rtc_init();
+    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_DFU) {
+        LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_NONE);
+        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");
+    // Remap memory to system bootloader
+    LL_SYSCFG_SetRemapMemory(LL_SYSCFG_REMAP_SYSTEMFLASH);
+    target_switch(0x0);
+}
+
+void target_switch2os() {
+    target_led_control("G");
+    SCB->VTOR = BOOT_ADDRESS + OS_OFFSET;
+    target_switch((void*)(BOOT_ADDRESS + OS_OFFSET));
+}

+ 29 - 0
bootloader/targets/f5/target.mk

@@ -0,0 +1,29 @@
+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 "stm32wbx.cpu configure -rtos auto" -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		= ../lib/STM32CubeWB
+
+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
+
+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
+
+ASM_SOURCES		+= $(wildcard $(TARGET_DIR)/*.s)
+C_SOURCES		+= $(wildcard $(TARGET_DIR)/*.c)
+CPP_SOURCES		+= $(wildcard $(TARGET_DIR)/*.cpp)

+ 0 - 1
core/furi.h

@@ -13,7 +13,6 @@
 #include <api-hal/api-gpio.h>
 #include <api-hal/api-interrupt-mgr.h>
 
-#include <api-hal.h>
 #include <stdlib.h>
 
 #ifdef __cplusplus

+ 1 - 1
firmware/Makefile

@@ -11,7 +11,7 @@ include			$(PROJECT_ROOT)/lib/lib.mk
 CFLAGS += -Werror -Wno-address-of-packed-member
 CPPFLAGS += -Werror
 
-TARGET			?= f4
+TARGET			?= f5
 
 TARGET_DIR		= targets/$(TARGET)
 

+ 26 - 0
firmware/targets/api-hal-include/api-hal-i2c.h

@@ -0,0 +1,26 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <i2c.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void api_hal_i2c_init();
+
+void api_hal_i2c_lock();
+
+void api_hal_i2c_unlock();
+
+#define with_api_hal_i2c(type, pointer, function_body)          \
+    {                                                           \
+        api_hal_i2c_lock();                                     \
+        *pointer = ({ type __fn__ function_body __fn__; })();   \
+        api_hal_i2c_unlock();                                   \
+    }
+
+#ifdef __cplusplus
+}
+#endif

+ 17 - 0
firmware/targets/api-hal-include/api-hal-light.h

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

+ 25 - 0
firmware/targets/api-hal-include/api-hal-version.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool api_hal_version_do_i_belong_here();
+
+const uint8_t api_hal_version_get_hw_version();
+
+const uint8_t api_hal_version_get_hw_target();
+
+const uint8_t api_hal_version_get_hw_body();
+
+const uint8_t api_hal_version_get_hw_connect();
+
+const uint32_t api_hal_version_get_hw_timestamp();
+
+#ifdef __cplusplus
+}
+#endif

+ 3 - 0
firmware/targets/api-hal-include/api-hal.h

@@ -6,14 +6,17 @@ template <unsigned int N> struct STOP_EXTERNING_ME {};
 
 #include "api-hal-boot.h"
 #include "api-hal-os.h"
+#include "api-hal-i2c.h"
 #include "api-hal-resources.h"
 #include "api-hal-gpio.h"
+#include "api-hal-light.h"
 #include "api-hal-delay.h"
 #include "api-hal-pwm.h"
 #include "api-hal-task.h"
 #include "api-hal-tim.h"
 #include "api-hal-power.h"
 #include "api-hal-vcp.h"
+#include "api-hal-version.h"
 #include "api-hal-uid.h"
 #include "api-hal-bt.h"
 #include "api-hal-spi.h"

+ 4 - 3
firmware/targets/f4/api-hal/api-hal-gpio.c

@@ -1,6 +1,7 @@
-#include "api-hal-gpio.h"
-#include "api-hal-resources.h"
-#include "spi.h"
+#include <api-hal-gpio.h>
+#include <api-hal-spi.h>
+#include <api-hal-resources.h>
+#include <api-hal-delay.h>
 
 // init GPIO
 void hal_gpio_init(

+ 17 - 0
firmware/targets/f4/api-hal/api-hal-i2c.c

@@ -0,0 +1,17 @@
+#include <api-hal-i2c.h>
+#include <furi.h>
+
+osMutexId_t api_hal_i2c_mutex = NULL;
+
+void api_hal_i2c_init() {
+    api_hal_i2c_mutex = osMutexNew(NULL);
+    furi_check(api_hal_i2c_mutex);
+}
+
+void api_hal_i2c_lock() {
+    furi_check(osMutexAcquire(api_hal_i2c_mutex, osWaitForever) == osOK);
+}
+
+void api_hal_i2c_unlock() {
+    furi_check(osMutexRelease(api_hal_i2c_mutex) == osOK);
+}

+ 55 - 0
firmware/targets/f4/api-hal/api-hal-light.c

@@ -0,0 +1,55 @@
+#include <api-hal-light.h>
+#include <stm32wbxx_ll_gpio.h>
+
+// LCD backlight
+#define BOOT_LCD_BL_PORT GPIOA
+#define BOOT_LCD_BL_PIN LL_GPIO_PIN_15
+// LEDs
+#define LED_RED_PORT GPIOA
+#define LED_RED_PIN LL_GPIO_PIN_1
+#define LED_GREEN_PORT GPIOA
+#define LED_GREEN_PIN LL_GPIO_PIN_2
+#define LED_BLUE_PORT GPIOA
+#define LED_BLUE_PIN LL_GPIO_PIN_3
+
+static void api_hal_light_gpio_set(GPIO_TypeDef* port, uint32_t pin, uint8_t value) {
+    if (value) {
+        LL_GPIO_ResetOutputPin(port, pin);
+    } else {
+        LL_GPIO_SetOutputPin(port, pin);
+    }
+}
+
+void api_hal_light_init() {
+    LL_GPIO_SetPinMode(BOOT_LCD_BL_PORT, BOOT_LCD_BL_PIN, LL_GPIO_MODE_OUTPUT);
+    LL_GPIO_SetPinSpeed(BOOT_LCD_BL_PORT, BOOT_LCD_BL_PIN, LL_GPIO_SPEED_FREQ_LOW);
+    LL_GPIO_SetPinOutputType(BOOT_LCD_BL_PORT, BOOT_LCD_BL_PIN, LL_GPIO_OUTPUT_PUSHPULL);
+
+    LL_GPIO_SetPinMode(LED_RED_PORT, LED_RED_PIN, LL_GPIO_MODE_OUTPUT);
+    LL_GPIO_SetPinOutputType(LED_RED_PORT, LED_RED_PIN, LL_GPIO_OUTPUT_OPENDRAIN);
+
+    LL_GPIO_SetPinMode(LED_GREEN_PORT, LED_GREEN_PIN, LL_GPIO_MODE_OUTPUT);
+    LL_GPIO_SetPinOutputType(LED_GREEN_PORT, LED_GREEN_PIN, LL_GPIO_OUTPUT_OPENDRAIN);
+
+    LL_GPIO_SetPinMode(LED_BLUE_PORT, LED_BLUE_PIN, LL_GPIO_MODE_OUTPUT);
+    LL_GPIO_SetPinOutputType(LED_BLUE_PORT, LED_BLUE_PIN, LL_GPIO_OUTPUT_OPENDRAIN);
+}
+
+void api_hal_light_set(Light light, uint8_t value) {
+    switch(light) {
+        case LightRed:
+            api_hal_light_gpio_set(LED_RED_PORT, LED_RED_PIN, value);
+        break;
+        case LightGreen:
+            api_hal_light_gpio_set(LED_GREEN_PORT, LED_GREEN_PIN, value);
+        break;
+        case LightBlue:
+            api_hal_light_gpio_set(LED_BLUE_PORT, LED_BLUE_PIN, value);
+        break;
+        case LightBacklight:
+            api_hal_light_gpio_set(BOOT_LCD_BL_PORT, BOOT_LCD_BL_PIN, !value);
+        break;
+        default:
+        break;
+    }
+}

+ 1 - 1
firmware/targets/f4/api-hal/api-hal-power.c

@@ -12,7 +12,7 @@
 #include <bq27220.h>
 #include <bq25896.h>
 
-volatile uint32_t api_hal_power_insomnia = 0;
+volatile uint32_t api_hal_power_insomnia = 1;
 
 void HAL_RCC_CSSCallback(void) {
     LL_RCC_ForceBackupDomainReset();

+ 17 - 2
firmware/targets/f4/api-hal/api-hal-resources.h

@@ -1,7 +1,12 @@
 #pragma once
+
 #include "main.h"
 #include <furi.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Input Related Constants */
 #define INPUT_DEBOUNCE_TICKS 20
 
@@ -15,6 +20,14 @@ typedef enum {
     InputKeyBack,
 } InputKey;
 
+/* Light */
+typedef enum {
+    LightRed,
+    LightGreen,
+    LightBlue,
+    LightBacklight,
+} Light;
+
 typedef struct {
     const GPIO_TypeDef* port;
     const uint16_t pin;
@@ -25,9 +38,11 @@ typedef struct {
 extern const InputPin input_pins[];
 extern const size_t input_pins_count;
 
-extern const GpioPin led_gpio[3];
-extern const GpioPin backlight_gpio;
 extern const GpioPin sd_cs_gpio;
 extern const GpioPin vibro_gpio;
 extern const GpioPin ibutton_gpio;
 extern const GpioPin cc1101_g0_gpio;
+
+#ifdef __cplusplus
+}
+#endif

+ 34 - 0
firmware/targets/f4/api-hal/api-hal-version.c

@@ -0,0 +1,34 @@
+#include <api-hal-version.h>
+#include <stm32wbxx.h>
+
+typedef struct {
+    uint8_t version;
+    uint8_t target;
+    uint8_t body;
+    uint8_t connect;
+    uint32_t timestamp;
+} ApiHalVersionOTP;
+
+bool api_hal_version_do_i_belong_here() {
+    return api_hal_version_get_hw_target() == 4;
+}
+
+const uint8_t api_hal_version_get_hw_version() {
+    return ((ApiHalVersionOTP*)OTP_AREA_BASE)->version;
+}
+
+const uint8_t api_hal_version_get_hw_target() {
+    return ((ApiHalVersionOTP*)OTP_AREA_BASE)->target;
+}
+
+const uint8_t api_hal_version_get_hw_body() {
+    return ((ApiHalVersionOTP*)OTP_AREA_BASE)->body;
+}
+
+const uint8_t api_hal_version_get_hw_connect() {
+    return ((ApiHalVersionOTP*)OTP_AREA_BASE)->connect;
+}
+
+const uint32_t api_hal_version_get_hw_timestamp() {
+    return ((ApiHalVersionOTP*)OTP_AREA_BASE)->timestamp;
+}

+ 3 - 1
firmware/targets/f4/api-hal/api-hal.c

@@ -4,4 +4,6 @@ void api_hal_init() {
     api_hal_os_init();
     api_hal_vcp_init();
     api_hal_spi_init();
-}
+    api_hal_i2c_init();
+    api_hal_light_init();
+}

+ 166 - 0
firmware/targets/f5/Inc/FreeRTOSConfig.h

@@ -0,0 +1,166 @@
+/* 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;
+  void xPortSysTickHandler(void);
+/* USER CODE BEGIN 0 */
+  extern void configureTimerForRunTimeStats(void);
+  extern unsigned long getRunTimeCounterValue(void);
+/* USER CODE END 0 */
+#endif
+#define configENABLE_FPU                         1
+#define configENABLE_MPU                         1
+
+#define configUSE_PREEMPTION                     1
+#define configSUPPORT_STATIC_ALLOCATION          1
+#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)
+#define configTOTAL_HEAP_SIZE                    ((size_t)131072)
+#define configMAX_TASK_NAME_LEN                  ( 16 )
+#define configGENERATE_RUN_TIME_STATS            0
+#define configUSE_TRACE_FACILITY                 0
+#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                 10
+#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_vTaskPrioritySet             1
+#define INCLUDE_uxTaskPriorityGet            1
+#define INCLUDE_vTaskDelete                  1
+#define INCLUDE_vTaskSuspend                 1
+#define INCLUDE_vTaskDelayUntil              1
+#define INCLUDE_vTaskDelay                   1
+#define INCLUDE_xTaskGetSchedulerState       1
+#define INCLUDE_xTimerPendFunctionCall       1
+#define INCLUDE_xQueueGetMutexHolder         1
+#define INCLUDE_uxTaskGetStackHighWaterMark  1
+#define INCLUDE_eTaskGetState                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: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick,
+              to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
+
+/* #define xPortSysTickHandler SysTick_Handler */
+
+#endif /* FREERTOS_CONFIG_H */

+ 52 - 0
firmware/targets/f5/Inc/adc.h

@@ -0,0 +1,52 @@
+/**
+  ******************************************************************************
+  * @file    adc.h
+  * @brief   This file contains all the function prototypes for
+  *          the adc.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 __ADC_H__
+#define __ADC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern ADC_HandleTypeDef hadc1;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_ADC1_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ADC_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 54 - 0
firmware/targets/f5/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/f5/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****/

+ 52 - 0
firmware/targets/f5/Inc/crc.h

@@ -0,0 +1,52 @@
+/**
+  ******************************************************************************
+  * @file    crc.h
+  * @brief   This file contains all the function prototypes for
+  *          the crc.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 __CRC_H__
+#define __CRC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern CRC_HandleTypeDef hcrc;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_CRC_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CRC_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 49 - 0
firmware/targets/f5/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****/

+ 54 - 0
firmware/targets/f5/Inc/i2c.h

@@ -0,0 +1,54 @@
+/**
+  ******************************************************************************
+  * @file    i2c.h
+  * @brief   This file contains all the function prototypes for
+  *          the i2c.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 __I2C_H__
+#define __I2C_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern I2C_HandleTypeDef hi2c1;
+
+/* USER CODE BEGIN Private defines */
+
+#define POWER_I2C hi2c1
+
+/* USER CODE END Private defines */
+
+void MX_I2C1_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __I2C_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 198 - 0
firmware/targets/f5/Inc/main.h

@@ -0,0 +1,198 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : main.h
+  * @brief          : Header for main.c file.
+  *                   This file contains the common defines of the application.
+  ******************************************************************************
+  * @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 __MAIN_H
+#define __MAIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32wbxx_hal.h"
+
+/* 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 Error_Handler(void);
+
+/* USER CODE BEGIN EFP */
+
+/* USER CODE END EFP */
+
+/* Private defines -----------------------------------------------------------*/
+#define BUTTON_BACK_Pin GPIO_PIN_13
+#define BUTTON_BACK_GPIO_Port GPIOC
+#define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn
+#define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14
+#define QUARTZ_32MHZ_IN_GPIO_Port GPIOC
+#define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15
+#define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC
+#define BUTTON_OK_Pin GPIO_PIN_3
+#define BUTTON_OK_GPIO_Port GPIOH
+#define BUTTON_OK_EXTI_IRQn EXTI3_IRQn
+#define SPEAKER_Pin GPIO_PIN_8
+#define SPEAKER_GPIO_Port GPIOB
+#define IR_TX_Pin GPIO_PIN_9
+#define IR_TX_GPIO_Port GPIOB
+#define PC0_Pin GPIO_PIN_0
+#define PC0_GPIO_Port GPIOC
+#define PC1_Pin GPIO_PIN_1
+#define PC1_GPIO_Port GPIOC
+#define PC3_Pin GPIO_PIN_3
+#define PC3_GPIO_Port GPIOC
+#define IR_RX_Pin GPIO_PIN_0
+#define IR_RX_GPIO_Port GPIOA
+#define PA_SW_0_Pin GPIO_PIN_1
+#define PA_SW_0_GPIO_Port GPIOA
+#define PA_SW_1_Pin GPIO_PIN_2
+#define PA_SW_1_GPIO_Port GPIOA
+#define PERIPH_POWER_Pin GPIO_PIN_3
+#define PERIPH_POWER_GPIO_Port GPIOA
+#define PA4_Pin GPIO_PIN_4
+#define PA4_GPIO_Port GPIOA
+#define SPI_R_SCK_Pin GPIO_PIN_5
+#define SPI_R_SCK_GPIO_Port GPIOA
+#define PA6_Pin GPIO_PIN_6
+#define PA6_GPIO_Port GPIOA
+#define PA7_Pin GPIO_PIN_7
+#define PA7_GPIO_Port GPIOA
+#define RFID_PULL_Pin GPIO_PIN_8
+#define RFID_PULL_GPIO_Port GPIOA
+#define RFID_PULL_EXTI_IRQn EXTI9_5_IRQn
+#define I2C_SCL_Pin GPIO_PIN_9
+#define I2C_SCL_GPIO_Port GPIOA
+#define CC1101_G0_Pin GPIO_PIN_4
+#define CC1101_G0_GPIO_Port GPIOC
+#define RFID_RF_IN_Pin GPIO_PIN_5
+#define RFID_RF_IN_GPIO_Port GPIOC
+#define PB2_Pin GPIO_PIN_2
+#define PB2_GPIO_Port GPIOB
+#define BUTTON_UP_Pin GPIO_PIN_10
+#define BUTTON_UP_GPIO_Port GPIOB
+#define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn
+#define BUTTON_LEFT_Pin GPIO_PIN_11
+#define BUTTON_LEFT_GPIO_Port GPIOB
+#define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn
+#define DISPLAY_RST_Pin GPIO_PIN_0
+#define DISPLAY_RST_GPIO_Port GPIOB
+#define BUTTON_DOWN_Pin GPIO_PIN_1
+#define BUTTON_DOWN_GPIO_Port GPIOB
+#define BUTTON_DOWN_EXTI_IRQn EXTI1_IRQn
+#define NFC_CS_Pin GPIO_PIN_4
+#define NFC_CS_GPIO_Port GPIOE
+#define BUTTON_RIGHT_Pin GPIO_PIN_12
+#define BUTTON_RIGHT_GPIO_Port GPIOB
+#define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn
+#define RFID_OUT_Pin GPIO_PIN_13
+#define RFID_OUT_GPIO_Port GPIOB
+#define iBTN_Pin GPIO_PIN_14
+#define iBTN_GPIO_Port GPIOB
+#define SPI_D_MOSI_Pin GPIO_PIN_15
+#define SPI_D_MOSI_GPIO_Port GPIOB
+#define DISPLAY_DI_Pin GPIO_PIN_6
+#define DISPLAY_DI_GPIO_Port GPIOC
+#define I2C_SDA_Pin GPIO_PIN_10
+#define I2C_SDA_GPIO_Port GPIOA
+#define SD_CD_Pin GPIO_PIN_15
+#define SD_CD_GPIO_Port GPIOA
+#define PC10_Pin GPIO_PIN_10
+#define PC10_GPIO_Port GPIOC
+#define DISPLAY_CS_Pin GPIO_PIN_11
+#define DISPLAY_CS_GPIO_Port GPIOC
+#define SD_CS_Pin GPIO_PIN_12
+#define SD_CS_GPIO_Port GPIOC
+#define CC1101_CS_Pin GPIO_PIN_0
+#define CC1101_CS_GPIO_Port GPIOD
+#define SPI_D_SCK_Pin GPIO_PIN_1
+#define SPI_D_SCK_GPIO_Port GPIOD
+#define PB3_Pin GPIO_PIN_3
+#define PB3_GPIO_Port GPIOB
+#define SPI_R_MISO_Pin GPIO_PIN_4
+#define SPI_R_MISO_GPIO_Port GPIOB
+#define SPI_R_MOSI_Pin GPIO_PIN_5
+#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
+}
+#endif
+
+#endif /* __MAIN_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 52 - 0
firmware/targets/f5/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/f5/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/f5/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/f5/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****/

+ 57 - 0
firmware/targets/f5/Inc/spi.h

@@ -0,0 +1,57 @@
+/**
+  ******************************************************************************
+  * @file    spi.h
+  * @brief   This file contains all the function prototypes for
+  *          the spi.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 __SPI_H__
+#define __SPI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern SPI_HandleTypeDef hspi1;
+extern SPI_HandleTypeDef hspi2;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_SPI1_Init(void);
+void MX_SPI2_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+void NFC_SPI_Reconfigure();
+void SD_SPI_Reconfigure_Slow();
+void SD_SPI_Reconfigure_Fast();
+void CC1101_SPI_Reconfigure();
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SPI_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 353 - 0
firmware/targets/f5/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****/

+ 81 - 0
firmware/targets/f5/Inc/stm32wbxx_it.h

@@ -0,0 +1,81 @@
+/* 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 NMI_Handler(void);
+void HardFault_Handler(void);
+void MemManage_Handler(void);
+void BusFault_Handler(void);
+void UsageFault_Handler(void);
+void DebugMon_Handler(void);
+void SysTick_Handler(void);
+void TAMP_STAMP_LSECSS_IRQHandler(void);
+void RCC_IRQHandler(void);
+void EXTI1_IRQHandler(void);
+void EXTI3_IRQHandler(void);
+void ADC1_IRQHandler(void);
+void USB_LP_IRQHandler(void);
+void COMP_IRQHandler(void);
+void EXTI9_5_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 EXTI15_10_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/f5/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****/

+ 52 - 0
firmware/targets/f5/Inc/usart.h

@@ -0,0 +1,52 @@
+/**
+  ******************************************************************************
+  * @file    usart.h
+  * @brief   This file contains all the function prototypes for
+  *          the usart.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 __USART_H__
+#define __USART_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "main.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+extern UART_HandleTypeDef huart1;
+
+/* USER CODE BEGIN Private defines */
+
+/* USER CODE END Private defines */
+
+void MX_USART1_UART_Init(void);
+
+/* USER CODE BEGIN Prototypes */
+
+/* USER CODE END Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USART_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 105 - 0
firmware/targets/f5/Inc/usb_device.h

@@ -0,0 +1,105 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : usb_device.h
+  * @version        : v3.0_Cube
+  * @brief          : Header for usb_device.c file.
+  ******************************************************************************
+  * @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 __USB_DEVICE__H__
+#define __USB_DEVICE__H__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32wbxx.h"
+#include "stm32wbxx_hal.h"
+#include "usbd_def.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/** @addtogroup USBD_OTG_DRIVER
+  * @{
+  */
+
+/** @defgroup USBD_DEVICE USBD_DEVICE
+  * @brief Device file for Usb otg low level driver.
+  * @{
+  */
+
+/** @defgroup USBD_DEVICE_Exported_Variables USBD_DEVICE_Exported_Variables
+  * @brief Public variables.
+  * @{
+  */
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+/* Private function prototypes -----------------------------------------------*/
+/* USER CODE BEGIN PFP */
+
+/* USER CODE END PFP */
+
+/*
+ * -- Insert your variables declaration here --
+ */
+/* USER CODE BEGIN VARIABLES */
+
+/* USER CODE END VARIABLES */
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DEVICE_Exported_FunctionsPrototype USBD_DEVICE_Exported_FunctionsPrototype
+  * @brief Declaration of public functions for Usb device.
+  * @{
+  */
+
+/** USB Device initialization function. */
+void MX_USB_Device_Init(void);
+
+/*
+ * -- Insert functions declaration here --
+ */
+/* USER CODE BEGIN FD */
+
+/* USER CODE END FD */
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USB_DEVICE__H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 134 - 0
firmware/targets/f5/Inc/usbd_cdc_if.h

@@ -0,0 +1,134 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : usbd_cdc_if.h
+  * @version        : v3.0_Cube
+  * @brief          : Header for usbd_cdc_if.c file.
+  ******************************************************************************
+  * @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 __USBD_CDC_IF_H__
+#define __USBD_CDC_IF_H__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_cdc.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+  * @brief For Usb device.
+  * @{
+  */
+
+/** @defgroup USBD_CDC_IF USBD_CDC_IF
+  * @brief Usb VCP device module
+  * @{
+  */
+
+/** @defgroup USBD_CDC_IF_Exported_Defines USBD_CDC_IF_Exported_Defines
+  * @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  CDC_DATA_HS_MAX_PACKET_SIZE
+#define APP_TX_DATA_SIZE  CDC_DATA_HS_MAX_PACKET_SIZE
+
+/* USER CODE END EXPORTED_DEFINES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Exported_Types USBD_CDC_IF_Exported_Types
+  * @brief Types.
+  * @{
+  */
+
+/* USER CODE BEGIN EXPORTED_TYPES */
+
+/* USER CODE END EXPORTED_TYPES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Exported_Macros USBD_CDC_IF_Exported_Macros
+  * @brief Aliases.
+  * @{
+  */
+
+/* USER CODE BEGIN EXPORTED_MACRO */
+
+/* USER CODE END EXPORTED_MACRO */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
+  * @brief Public variables.
+  * @{
+  */
+
+/** CDC Interface callback. */
+extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
+
+/* USER CODE BEGIN EXPORTED_VARIABLES */
+
+/* USER CODE END EXPORTED_VARIABLES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Exported_FunctionsPrototype USBD_CDC_IF_Exported_FunctionsPrototype
+  * @brief Public functions declaration.
+  * @{
+  */
+
+uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
+
+/* USER CODE BEGIN EXPORTED_FUNCTIONS */
+
+/* USER CODE END EXPORTED_FUNCTIONS */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_CDC_IF_H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 176 - 0
firmware/targets/f5/Inc/usbd_conf.h

@@ -0,0 +1,176 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : usbd_conf.h
+  * @version        : v3.0_Cube
+  * @brief          : Header for usbd_conf.c file.
+  ******************************************************************************
+  * @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 __USBD_CONF__H__
+#define __USBD_CONF__H__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "stm32wbxx.h"
+#include "stm32wbxx_hal.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/** @addtogroup USBD_OTG_DRIVER
+  * @brief Driver for Usb device.
+  * @{
+  */
+
+/** @defgroup USBD_CONF USBD_CONF
+  * @brief Configuration file for Usb otg low level driver.
+  * @{
+  */
+
+/** @defgroup USBD_CONF_Exported_Variables USBD_CONF_Exported_Variables
+  * @brief Public variables.
+  * @{
+  */
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+/* USER CODE END PV */
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines
+  * @brief Defines for configuration of the Usb device.
+  * @{
+  */
+
+/*---------- -----------*/
+#define USBD_MAX_NUM_INTERFACES     1U
+/*---------- -----------*/
+#define USBD_MAX_NUM_CONFIGURATION     1U
+/*---------- -----------*/
+#define USBD_MAX_STR_DESC_SIZ     512U
+/*---------- -----------*/
+#define USBD_DEBUG_LEVEL     0U
+/*---------- -----------*/
+#define USBD_LPM_ENABLED     1U
+/*---------- -----------*/
+#define USBD_SELF_POWERED     1U
+
+/****************************************/
+/* #define for FS and HS identification */
+#define DEVICE_FS 		0
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CONF_Exported_Macros USBD_CONF_Exported_Macros
+  * @brief Aliases.
+  * @{
+  */
+
+/* Memory management macros */
+
+/** Alias for memory allocation. */
+#define USBD_malloc         (void *)USBD_static_malloc
+
+/** Alias for memory release. */
+#define USBD_free           USBD_static_free
+
+/** Alias for memory set. */
+#define USBD_memset         memset
+
+/** Alias for memory copy. */
+#define USBD_memcpy         memcpy
+
+/** Alias for delay. */
+#define USBD_Delay          HAL_Delay
+/* DEBUG macros */
+
+#if (USBD_DEBUG_LEVEL > 0)
+#define USBD_UsrLog(...)    printf(__VA_ARGS__);\
+                            printf("\n");
+#else
+#define USBD_UsrLog(...)
+#endif
+
+#if (USBD_DEBUG_LEVEL > 1)
+
+#define USBD_ErrLog(...)    printf("ERROR: ") ;\
+                            printf(__VA_ARGS__);\
+                            printf("\n");
+#else
+#define USBD_ErrLog(...)
+#endif
+
+#if (USBD_DEBUG_LEVEL > 2)
+#define USBD_DbgLog(...)    printf("DEBUG : ") ;\
+                            printf(__VA_ARGS__);\
+                            printf("\n");
+#else
+#define USBD_DbgLog(...)
+#endif
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CONF_Exported_Types USBD_CONF_Exported_Types
+  * @brief Types.
+  * @{
+  */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CONF_Exported_FunctionsPrototype USBD_CONF_Exported_FunctionsPrototype
+  * @brief Declaration of public functions for Usb device.
+  * @{
+  */
+
+/* Exported functions -------------------------------------------------------*/
+void *USBD_static_malloc(uint32_t size);
+void USBD_static_free(void *p);
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_CONF__H__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 145 - 0
firmware/targets/f5/Inc/usbd_desc.h

@@ -0,0 +1,145 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : usbd_desc.c
+  * @version        : v3.0_Cube
+  * @brief          : Header for usbd_conf.c file.
+  ******************************************************************************
+  * @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 __USBD_DESC__C__
+#define __USBD_DESC__C__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_def.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+  * @{
+  */
+
+/** @defgroup USBD_DESC USBD_DESC
+  * @brief Usb device descriptors module.
+  * @{
+  */
+
+/** @defgroup USBD_DESC_Exported_Constants USBD_DESC_Exported_Constants
+  * @brief Constants.
+  * @{
+  */
+#define         DEVICE_ID1          (UID_BASE)
+#define         DEVICE_ID2          (UID_BASE + 0x4)
+#define         DEVICE_ID3          (UID_BASE + 0x8)
+
+#define         USB_SIZ_STRING_SERIAL       0x1A
+
+/* USER CODE BEGIN EXPORTED_CONSTANTS */
+
+/* USER CODE END EXPORTED_CONSTANTS */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Exported_Defines USBD_DESC_Exported_Defines
+  * @brief Defines.
+  * @{
+  */
+
+/* USER CODE BEGIN EXPORTED_DEFINES */
+
+/* USER CODE END EXPORTED_DEFINES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Exported_TypesDefinitions USBD_DESC_Exported_TypesDefinitions
+  * @brief Types.
+  * @{
+  */
+
+/* USER CODE BEGIN EXPORTED_TYPES */
+
+/* USER CODE END EXPORTED_TYPES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Exported_Macros USBD_DESC_Exported_Macros
+  * @brief Aliases.
+  * @{
+  */
+
+/* USER CODE BEGIN EXPORTED_MACRO */
+
+/* USER CODE END EXPORTED_MACRO */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Exported_Variables USBD_DESC_Exported_Variables
+  * @brief Public variables.
+  * @{
+  */
+
+extern USBD_DescriptorsTypeDef     CDC_Desc;
+
+/* USER CODE BEGIN EXPORTED_VARIABLES */
+
+/* USER CODE END EXPORTED_VARIABLES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Exported_FunctionsPrototype USBD_DESC_Exported_FunctionsPrototype
+  * @brief Public functions declaration.
+  * @{
+  */
+
+/* USER CODE BEGIN EXPORTED_FUNCTIONS */
+
+/* USER CODE END EXPORTED_FUNCTIONS */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBD_DESC__C__ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 128 - 0
firmware/targets/f5/Src/adc.c

@@ -0,0 +1,128 @@
+/**
+  ******************************************************************************
+  * @file    adc.c
+  * @brief   This file provides code for the configuration
+  *          of the ADC 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 "adc.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+ADC_HandleTypeDef hadc1;
+
+/* ADC1 init function */
+void MX_ADC1_Init(void)
+{
+  ADC_ChannelConfTypeDef sConfig = {0};
+
+  /** Common config
+  */
+  hadc1.Instance = ADC1;
+  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
+  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
+  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
+  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
+  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
+  hadc1.Init.LowPowerAutoWait = DISABLE;
+  hadc1.Init.ContinuousConvMode = DISABLE;
+  hadc1.Init.NbrOfConversion = 1;
+  hadc1.Init.DiscontinuousConvMode = DISABLE;
+  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
+  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
+  hadc1.Init.DMAContinuousRequests = DISABLE;
+  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
+  hadc1.Init.OversamplingMode = DISABLE;
+  if (HAL_ADC_Init(&hadc1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /** Configure Regular Channel
+  */
+  sConfig.Channel = ADC_CHANNEL_14;
+  sConfig.Rank = ADC_REGULAR_RANK_1;
+  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
+  sConfig.SingleDiff = ADC_SINGLE_ENDED;
+  sConfig.OffsetNumber = ADC_OFFSET_NONE;
+  sConfig.Offset = 0;
+  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(adcHandle->Instance==ADC1)
+  {
+  /* USER CODE BEGIN ADC1_MspInit 0 */
+
+  /* USER CODE END ADC1_MspInit 0 */
+    /* ADC1 clock enable */
+    __HAL_RCC_ADC_CLK_ENABLE();
+
+    __HAL_RCC_GPIOC_CLK_ENABLE();
+    /**ADC1 GPIO Configuration
+    PC5     ------> ADC1_IN14
+    */
+    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);
+
+    /* ADC1 interrupt Init */
+    HAL_NVIC_SetPriority(ADC1_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(ADC1_IRQn);
+  /* USER CODE BEGIN ADC1_MspInit 1 */
+
+  /* USER CODE END ADC1_MspInit 1 */
+  }
+}
+
+void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
+{
+
+  if(adcHandle->Instance==ADC1)
+  {
+  /* USER CODE BEGIN ADC1_MspDeInit 0 */
+
+  /* USER CODE END ADC1_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_ADC_CLK_DISABLE();
+
+    /**ADC1 GPIO Configuration
+    PC5     ------> ADC1_IN14
+    */
+    HAL_GPIO_DeInit(RFID_RF_IN_GPIO_Port, RFID_RF_IN_Pin);
+
+    /* ADC1 interrupt Deinit */
+    HAL_NVIC_DisableIRQ(ADC1_IRQn);
+  /* USER CODE BEGIN ADC1_MspDeInit 1 */
+
+  /* USER CODE END ADC1_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 127 - 0
firmware/targets/f5/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/f5/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****/

+ 82 - 0
firmware/targets/f5/Src/crc.c

@@ -0,0 +1,82 @@
+/**
+  ******************************************************************************
+  * @file    crc.c
+  * @brief   This file provides code for the configuration
+  *          of the CRC 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 "crc.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+CRC_HandleTypeDef hcrc;
+
+/* CRC init function */
+void MX_CRC_Init(void)
+{
+
+  hcrc.Instance = CRC;
+  hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;
+  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
+  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
+  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
+  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
+  if (HAL_CRC_Init(&hcrc) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_CRC_MspInit(CRC_HandleTypeDef* crcHandle)
+{
+
+  if(crcHandle->Instance==CRC)
+  {
+  /* USER CODE BEGIN CRC_MspInit 0 */
+
+  /* USER CODE END CRC_MspInit 0 */
+    /* CRC clock enable */
+    __HAL_RCC_CRC_CLK_ENABLE();
+  /* USER CODE BEGIN CRC_MspInit 1 */
+
+  /* USER CODE END CRC_MspInit 1 */
+  }
+}
+
+void HAL_CRC_MspDeInit(CRC_HandleTypeDef* crcHandle)
+{
+
+  if(crcHandle->Instance==CRC)
+  {
+  /* USER CODE BEGIN CRC_MspDeInit 0 */
+
+  /* USER CODE END CRC_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_CRC_CLK_DISABLE();
+  /* USER CODE BEGIN CRC_MspDeInit 1 */
+
+  /* USER CODE END CRC_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 56 - 0
firmware/targets/f5/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/f5/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/f5/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		1
+/* 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    3
+/* 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    1      /* 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	0
+#define _NORTC_MON	6
+#define _NORTC_MDAY	4
+#define _NORTC_YEAR	2015
+/* 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    2     /* 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    1  /* 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 */

+ 124 - 0
firmware/targets/f5/Src/fatfs/spi_sd_hal.c

@@ -0,0 +1,124 @@
+#include "main.h"
+
+#define SD_DUMMY_BYTE 0xFF
+#define SD_CS_LOW() HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET)
+#define SD_CS_HIGH() HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET)
+
+const uint32_t SpiTimeout = 1000;
+extern SPI_HandleTypeDef SPI_SD_HANDLE;
+uint8_t SD_IO_WriteByte(uint8_t Data);
+
+/******************************************************************************
+                            BUS OPERATIONS
+ *******************************************************************************/
+
+/**
+ * @brief  SPI error treatment function
+ * @retval None
+ */
+static void SPIx_Error(void) {
+    /* De-initialize the SPI communication BUS */
+    HAL_SPI_DeInit(&SPI_SD_HANDLE);
+
+    /* Re-Initiaize the SPI communication BUS */
+    HAL_SPI_Init(&SPI_SD_HANDLE);
+}
+
+/**
+ * @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) {
+    HAL_StatusTypeDef status = HAL_OK;
+    status =
+        HAL_SPI_TransmitReceive(&SPI_SD_HANDLE, (uint8_t*)DataIn, DataOut, DataLength, SpiTimeout);
+
+    /* Check the communication status */
+    if(status != HAL_OK) {
+        /* Execute user timeout callback */
+        SPIx_Error();
+    }
+}
+
+/**
+ * @brief  SPI Write a byte to device
+ * @param  Value: value to be written
+ * @retval None
+ */
+__attribute__((unused)) static void SPIx_Write(uint8_t Value) {
+    HAL_StatusTypeDef status = HAL_OK;
+    uint8_t data;
+
+    status = HAL_SPI_TransmitReceive(&SPI_SD_HANDLE, (uint8_t*)&Value, &data, 1, SpiTimeout);
+
+    /* Check the communication status */
+    if(status != HAL_OK) {
+        /* Execute user timeout callback */
+        SPIx_Error();
+    }
+}
+
+/******************************************************************************
+                            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 */
+    SD_CS_HIGH();
+
+    /* 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) {
+    if(val == 1) {
+        SD_CS_HIGH();
+    } else {
+        SD_CS_LOW();
+    }
+}
+
+/**
+ * @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;
+}

+ 1015 - 0
firmware/targets/f5/Src/fatfs/stm32_adafruit_sd.c

@@ -0,0 +1,1015 @@
+/**
+  ******************************************************************************
+  * @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 "spi.h"
+#include "api-hal-spi.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 ---------------------------------------------------------*/
+
+/** @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(void) {
+    /* Init to maximum slow speed */
+    // TODO: SPI manager
+    api_hal_spi_lock_device(&sd_slow_spi);
+
+    /* 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 = SD_GoIdleState();
+
+    // TODO: SPI manager
+    api_hal_spi_unlock_device(&sd_slow_spi);
+
+    /* 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;
+    uint8_t retr = BSP_SD_ERROR;
+    SD_CmdAnswer_typedef response;
+    uint16_t BlockSize = 512;
+
+    uint8_t* ptr = NULL;
+    //  uint8_t ptr[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);
+
+    /* 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,
+            (ReadAddr + offset) * (flag_SDHC == 1 ? 1 : BlockSize),
+            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;
+            /* 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;
+    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;
+    }
+
+    /* 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,
+            (WriteAddr + offset) * (flag_SDHC == 1 ? 1 : BlockSize),
+            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;
+
+        /* 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 = 0;
+    /* 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 */
+    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 */
+        do {
+            /* 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);
+        } while(response.r1 == SD_R1_IN_IDLE_STATE);
+        flag_SDHC = 0;
+    } else if(response.r1 == SD_R1_IN_IDLE_STATE) {
+        /* initialise card V2 */
+        do {
+            /* 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);
+        } while(response.r1 == SD_R1_IN_IDLE_STATE);
+
+        if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) {
+            do {
+                /* 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);
+            } 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****/

+ 251 - 0
firmware/targets/f5/Src/fatfs/stm32_adafruit_sd.h

@@ -0,0 +1,251 @@
+/**
+  ******************************************************************************
+  * @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>
+
+/** @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(void);
+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/f5/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

+ 230 - 0
firmware/targets/f5/Src/fatfs/user_diskio.c

@@ -0,0 +1,230 @@
+/* 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 "spi.h"
+#include "api-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 */
+    // TODO: SPI manager
+    api_hal_spi_lock_device(&sd_fast_spi);
+
+    DSTATUS status = User_CheckStatus(pdrv);
+
+    // TODO: SPI manager
+    api_hal_spi_unlock_device(&sd_fast_spi);
+
+    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;
+
+    // TODO: SPI manager
+    api_hal_spi_lock_device(&sd_fast_spi);
+
+    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;
+    }
+
+    // TODO: SPI manager
+    api_hal_spi_unlock_device(&sd_fast_spi);
+
+    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;
+
+    // TODO: SPI manager
+    api_hal_spi_lock_device(&sd_fast_spi);
+
+    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;
+    }
+
+    // TODO: SPI manager
+    api_hal_spi_unlock_device(&sd_fast_spi);
+
+    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;
+
+    // TODO: SPI manager
+    api_hal_spi_lock_device(&sd_fast_spi);
+
+    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;
+    }
+
+    // TODO: SPI manager
+    api_hal_spi_unlock_device(&sd_fast_spi);
+
+    return res;
+    /* USER CODE END IOCTL */
+}
+#endif /* _USE_IOCTL == 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 48 - 0
firmware/targets/f5/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/f5/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;

+ 197 - 0
firmware/targets/f5/Src/gpio.c

@@ -0,0 +1,197 @@
+/**
+  ******************************************************************************
+  * @file    gpio.c
+  * @brief   This file provides code for the configuration
+  *          of all used GPIO pins.
+  ******************************************************************************
+  * @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 "gpio.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/*----------------------------------------------------------------------------*/
+/* Configure GPIO                                                             */
+/*----------------------------------------------------------------------------*/
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/** Configure pins as
+        * Analog
+        * Input
+        * Output
+        * EVENT_OUT
+        * EXTI
+*/
+void MX_GPIO_Init(void)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+  /* GPIO Ports Clock Enable */
+  __HAL_RCC_GPIOC_CLK_ENABLE();
+  __HAL_RCC_GPIOH_CLK_ENABLE();
+  __HAL_RCC_GPIOB_CLK_ENABLE();
+  __HAL_RCC_GPIOA_CLK_ENABLE();
+  __HAL_RCC_GPIOE_CLK_ENABLE();
+  __HAL_RCC_GPIOD_CLK_ENABLE();
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(GPIOA, PA_SW_0_Pin|PA_SW_1_Pin, GPIO_PIN_RESET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin, GPIO_PIN_SET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(DISPLAY_RST_GPIO_Port, DISPLAY_RST_Pin, GPIO_PIN_RESET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(NFC_CS_GPIO_Port, NFC_CS_Pin, GPIO_PIN_SET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(DISPLAY_DI_GPIO_Port, DISPLAY_DI_Pin, GPIO_PIN_RESET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(GPIOC, DISPLAY_CS_Pin|SD_CS_Pin, GPIO_PIN_SET);
+
+  /*Configure GPIO pin Output Level */
+  HAL_GPIO_WritePin(CC1101_CS_GPIO_Port, CC1101_CS_Pin, GPIO_PIN_SET);
+
+  /*Configure GPIO pin : PtPin */
+  GPIO_InitStruct.Pin = BUTTON_BACK_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+  GPIO_InitStruct.Pull = GPIO_PULLUP;
+  HAL_GPIO_Init(BUTTON_BACK_GPIO_Port, &GPIO_InitStruct);
+
+  /*Configure GPIO pin : PtPin */
+  GPIO_InitStruct.Pin = BUTTON_OK_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  HAL_GPIO_Init(BUTTON_OK_GPIO_Port, &GPIO_InitStruct);
+
+  /*Configure GPIO pins : PCPin PCPin PCPin PCPin */
+  GPIO_InitStruct.Pin = PC0_Pin|PC1_Pin|PC3_Pin|PC10_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+  /*Configure GPIO pins : PAPin PAPin */
+  GPIO_InitStruct.Pin = PA_SW_0_Pin|PA_SW_1_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+  /*Configure GPIO pin : PtPin */
+  GPIO_InitStruct.Pin = PERIPH_POWER_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(PERIPH_POWER_GPIO_Port, &GPIO_InitStruct);
+
+  /*Configure GPIO pins : PAPin PAPin PAPin */
+  GPIO_InitStruct.Pin = PA4_Pin|PA6_Pin|PA7_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  HAL_GPIO_Init(GPIOA, &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 pin : PtPin */
+  GPIO_InitStruct.Pin = CC1101_G0_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+  HAL_GPIO_Init(CC1101_G0_GPIO_Port, &GPIO_InitStruct);
+
+  /*Configure GPIO pins : PBPin PBPin PBPin */
+  GPIO_InitStruct.Pin = PB2_Pin|iBTN_Pin|PB3_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+  /*Configure GPIO pins : PBPin PBPin PBPin PBPin */
+  GPIO_InitStruct.Pin = BUTTON_UP_Pin|BUTTON_LEFT_Pin|BUTTON_DOWN_Pin|BUTTON_RIGHT_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
+  GPIO_InitStruct.Pull = GPIO_PULLUP;
+  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+  /*Configure GPIO pin : PtPin */
+  GPIO_InitStruct.Pin = DISPLAY_RST_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(DISPLAY_RST_GPIO_Port, &GPIO_InitStruct);
+
+  /*Configure GPIO pin : PtPin */
+  GPIO_InitStruct.Pin = NFC_CS_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+  HAL_GPIO_Init(NFC_CS_GPIO_Port, &GPIO_InitStruct);
+
+  /*Configure GPIO pins : PCPin PCPin */
+  GPIO_InitStruct.Pin = DISPLAY_DI_Pin|DISPLAY_CS_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+  /*Configure GPIO pin : PtPin */
+  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);
+
+  /*Configure GPIO pin : PtPin */
+  GPIO_InitStruct.Pin = SD_CS_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+  HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct);
+
+  /*Configure GPIO pin : PtPin */
+  GPIO_InitStruct.Pin = CC1101_CS_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+  GPIO_InitStruct.Pull = GPIO_NOPULL;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+  HAL_GPIO_Init(CC1101_CS_GPIO_Port, &GPIO_InitStruct);
+
+  /* EXTI interrupt init*/
+  HAL_NVIC_SetPriority(EXTI1_IRQn, 5, 0);
+  HAL_NVIC_EnableIRQ(EXTI1_IRQn);
+
+  HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0);
+  HAL_NVIC_EnableIRQ(EXTI3_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);
+
+}
+
+/* USER CODE BEGIN 2 */
+
+/* USER CODE END 2 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 120 - 0
firmware/targets/f5/Src/i2c.c

@@ -0,0 +1,120 @@
+/**
+  ******************************************************************************
+  * @file    i2c.c
+  * @brief   This file provides code for the configuration
+  *          of the I2C 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 "i2c.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+I2C_HandleTypeDef hi2c1;
+
+/* I2C1 init function */
+void MX_I2C1_Init(void)
+{
+
+  hi2c1.Instance = I2C1;
+  hi2c1.Init.Timing = 0x10707DBC;
+  hi2c1.Init.OwnAddress1 = 0;
+  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
+  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
+  hi2c1.Init.OwnAddress2 = 0;
+  hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
+  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
+  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
+  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /** Configure Analogue filter
+  */
+  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  /** Configure Digital filter
+  */
+  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(i2cHandle->Instance==I2C1)
+  {
+  /* USER CODE BEGIN I2C1_MspInit 0 */
+
+  /* USER CODE END I2C1_MspInit 0 */
+
+    __HAL_RCC_GPIOA_CLK_ENABLE();
+    /**I2C1 GPIO Configuration
+    PA9     ------> I2C1_SCL
+    PA10     ------> I2C1_SDA
+    */
+    GPIO_InitStruct.Pin = I2C_SCL_Pin|I2C_SDA_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
+    GPIO_InitStruct.Pull = GPIO_PULLUP;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
+    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+    /* I2C1 clock enable */
+    __HAL_RCC_I2C1_CLK_ENABLE();
+  /* USER CODE BEGIN I2C1_MspInit 1 */
+
+  /* USER CODE END I2C1_MspInit 1 */
+  }
+}
+
+void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
+{
+
+  if(i2cHandle->Instance==I2C1)
+  {
+  /* USER CODE BEGIN I2C1_MspDeInit 0 */
+
+  /* USER CODE END I2C1_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_I2C1_CLK_DISABLE();
+
+    /**I2C1 GPIO Configuration
+    PA9     ------> I2C1_SCL
+    PA10     ------> I2C1_SDA
+    */
+    HAL_GPIO_DeInit(I2C_SCL_GPIO_Port, I2C_SCL_Pin);
+
+    HAL_GPIO_DeInit(I2C_SDA_GPIO_Port, I2C_SDA_Pin);
+
+  /* USER CODE BEGIN I2C1_MspDeInit 1 */
+
+  /* USER CODE END I2C1_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 155 - 0
firmware/targets/f5/Src/main.c

@@ -0,0 +1,155 @@
+#include "main.h"
+
+#include "cmsis_os2.h"
+#include "adc.h"
+#include "aes.h"
+#include "comp.h"
+#include "crc.h"
+#include "i2c.h"
+#include "pka.h"
+#include "rf.h"
+#include "rng.h"
+#include "rtc.h"
+#include "spi.h"
+#include "tim.h"
+#include "usart.h"
+#include "usb_device.h"
+#include "gpio.h"
+#include "fatfs/fatfs.h"
+
+#include <furi.h>
+#include <api-hal.h>
+#include <flipper.h>
+
+void SystemClock_Config(void);
+void MX_FREERTOS_Init(void);
+
+int main(void)
+{
+    HAL_Init();
+    SystemClock_Config();
+
+    MX_GPIO_Init();
+    MX_ADC1_Init();
+    MX_I2C1_Init();
+    MX_RTC_Init();
+    MX_SPI1_Init();
+    MX_SPI2_Init();
+    MX_USART1_UART_Init();
+    MX_USB_Device_Init();
+    MX_TIM1_Init();
+    MX_TIM2_Init();
+    MX_TIM16_Init();
+    MX_COMP1_Init();
+    MX_RF_Init();
+    MX_PKA_Init();
+    MX_RNG_Init();
+    MX_AES1_Init();
+    MX_AES2_Init();
+    MX_CRC_Init();
+
+    api_hal_init();
+    MX_FATFS_Init();
+    delay_us_init_DWT();
+
+    furi_init();
+    // CMSIS initialization
+    osKernelInitialize();
+    // Init flipper
+    flipper_init();
+    // Start kernel
+    osKernelStart();
+
+    while (1) {}
+}
+
+void SystemClock_Config(void)
+{
+    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
+
+    HAL_PWR_EnableBkUpAccess();
+
+    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_MEDIUMLOW);
+    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+
+    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE
+                                                            |RCC_OSCILLATORTYPE_LSE;
+    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
+    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
+    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+    RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
+    RCC_OscInitStruct.PLL.PLLN = 8;
+    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
+    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
+    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
+    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+        Error_Handler();
+    }
+    
+    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK4|RCC_CLOCKTYPE_HCLK2
+                                                            |RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
+                                                            |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
+    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
+    RCC_ClkInitStruct.AHBCLK2Divider = RCC_SYSCLK_DIV2;
+    RCC_ClkInitStruct.AHBCLK4Divider = RCC_SYSCLK_DIV1;
+
+    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) {
+        Error_Handler();
+    }
+
+    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SMPS|RCC_PERIPHCLK_RFWAKEUP
+                                                            |RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USART1
+                                                            |RCC_PERIPHCLK_I2C1|RCC_PERIPHCLK_CLK48SEL
+                                                            |RCC_PERIPHCLK_USB|RCC_PERIPHCLK_RNG
+                                                            |RCC_PERIPHCLK_ADC;
+    PeriphClkInitStruct.PLLSAI1.PLLN = 6;
+    PeriphClkInitStruct.PLLSAI1.PLLP = RCC_PLLP_DIV2;
+    PeriphClkInitStruct.PLLSAI1.PLLQ = RCC_PLLQ_DIV2;
+    PeriphClkInitStruct.PLLSAI1.PLLR = RCC_PLLR_DIV2;
+    PeriphClkInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_USBCLK|RCC_PLLSAI1_ADCCLK;
+    PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
+    PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
+    PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLLSAI1;
+    PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_CLK48;
+    PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
+    PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
+    PeriphClkInitStruct.RFWakeUpClockSelection = RCC_RFWKPCLKSOURCE_LSE;
+    PeriphClkInitStruct.SmpsClockSelection = RCC_SMPSCLKSOURCE_HSE;
+    PeriphClkInitStruct.SmpsDivSelection = RCC_SMPSCLKDIV_RANGE1;
+    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
+        Error_Handler();
+    }
+
+    // Enable CSS for both clocks
+    HAL_RCC_EnableCSS();
+    HAL_RCCEx_EnableLSECSS();
+}
+
+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/f5/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/f5/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/f5/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/f5/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****/

+ 344 - 0
firmware/targets/f5/Src/spi.c

@@ -0,0 +1,344 @@
+/**
+  ******************************************************************************
+  * @file    spi.c
+  * @brief   This file provides code for the configuration
+  *          of the SPI 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 "spi.h"
+#include <cmsis_os2.h>
+
+/* USER CODE BEGIN 0 */
+void Enable_SPI(SPI_HandleTypeDef* spi);
+/* USER CODE END 0 */
+
+SPI_HandleTypeDef hspi1;
+SPI_HandleTypeDef hspi2;
+
+/* SPI1 init function */
+void MX_SPI1_Init(void)
+{
+
+  hspi1.Instance = SPI1;
+  hspi1.Init.Mode = SPI_MODE_MASTER;
+  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
+  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
+  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
+  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
+  hspi1.Init.NSS = SPI_NSS_SOFT;
+  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
+  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
+  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
+  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+  hspi1.Init.CRCPolynomial = 7;
+  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
+  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
+  if (HAL_SPI_Init(&hspi1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+/* SPI2 init function */
+void MX_SPI2_Init(void)
+{
+
+  hspi2.Instance = SPI2;
+  hspi2.Init.Mode = SPI_MODE_MASTER;
+  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
+  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
+  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
+  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
+  hspi2.Init.NSS = SPI_NSS_SOFT;
+  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
+  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
+  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
+  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+  hspi2.Init.CRCPolynomial = 7;
+  hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
+  hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
+  if (HAL_SPI_Init(&hspi2) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(spiHandle->Instance==SPI1)
+  {
+  /* USER CODE BEGIN SPI1_MspInit 0 */
+
+  /* USER CODE END SPI1_MspInit 0 */
+    /* SPI1 clock enable */
+    __HAL_RCC_SPI1_CLK_ENABLE();
+
+    __HAL_RCC_GPIOA_CLK_ENABLE();
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    /**SPI1 GPIO Configuration
+    PA5     ------> SPI1_SCK
+    PB4     ------> SPI1_MISO
+    PB5     ------> SPI1_MOSI
+    */
+    GPIO_InitStruct.Pin = SPI_R_SCK_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
+    HAL_GPIO_Init(SPI_R_SCK_GPIO_Port, &GPIO_InitStruct);
+
+    GPIO_InitStruct.Pin = SPI_R_MISO_Pin|SPI_R_MOSI_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
+    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+  /* USER CODE BEGIN SPI1_MspInit 1 */
+
+  /* USER CODE END SPI1_MspInit 1 */
+  }
+  else if(spiHandle->Instance==SPI2)
+  {
+  /* USER CODE BEGIN SPI2_MspInit 0 */
+
+  /* USER CODE END SPI2_MspInit 0 */
+    /* SPI2 clock enable */
+    __HAL_RCC_SPI2_CLK_ENABLE();
+
+    __HAL_RCC_GPIOC_CLK_ENABLE();
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    __HAL_RCC_GPIOD_CLK_ENABLE();
+    /**SPI2 GPIO Configuration
+    PC2     ------> SPI2_MISO
+    PB15     ------> SPI2_MOSI
+    PD1     ------> SPI2_SCK
+    */
+    GPIO_InitStruct.Pin = GPIO_PIN_2;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
+    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+    GPIO_InitStruct.Pin = SPI_D_MOSI_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
+    HAL_GPIO_Init(SPI_D_MOSI_GPIO_Port, &GPIO_InitStruct);
+
+    GPIO_InitStruct.Pin = SPI_D_SCK_Pin;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
+    HAL_GPIO_Init(SPI_D_SCK_GPIO_Port, &GPIO_InitStruct);
+
+  /* USER CODE BEGIN SPI2_MspInit 1 */
+  
+  // SD Card need faster spi gpio
+  GPIO_InitStruct.Pin = GPIO_PIN_2;
+  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+  GPIO_InitStruct.Pull = GPIO_PULLUP;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+  GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
+  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+  GPIO_InitStruct.Pin = SPI_D_MOSI_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+  GPIO_InitStruct.Pull = GPIO_PULLUP;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+  GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
+  HAL_GPIO_Init(SPI_D_MOSI_GPIO_Port, &GPIO_InitStruct);
+
+  GPIO_InitStruct.Pin = SPI_D_SCK_Pin;
+  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+  GPIO_InitStruct.Pull = GPIO_PULLUP;
+  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+  GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
+  HAL_GPIO_Init(SPI_D_SCK_GPIO_Port, &GPIO_InitStruct);
+
+  /* USER CODE END SPI2_MspInit 1 */
+  }
+}
+
+void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
+{
+
+  if(spiHandle->Instance==SPI1)
+  {
+  /* USER CODE BEGIN SPI1_MspDeInit 0 */
+
+  /* USER CODE END SPI1_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_SPI1_CLK_DISABLE();
+
+    /**SPI1 GPIO Configuration
+    PA5     ------> SPI1_SCK
+    PB4     ------> SPI1_MISO
+    PB5     ------> SPI1_MOSI
+    */
+    HAL_GPIO_DeInit(SPI_R_SCK_GPIO_Port, SPI_R_SCK_Pin);
+
+    HAL_GPIO_DeInit(GPIOB, SPI_R_MISO_Pin|SPI_R_MOSI_Pin);
+
+  /* USER CODE BEGIN SPI1_MspDeInit 1 */
+
+  /* USER CODE END SPI1_MspDeInit 1 */
+  }
+  else if(spiHandle->Instance==SPI2)
+  {
+  /* USER CODE BEGIN SPI2_MspDeInit 0 */
+
+  /* USER CODE END SPI2_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_SPI2_CLK_DISABLE();
+
+    /**SPI2 GPIO Configuration
+    PC2     ------> SPI2_MISO
+    PB15     ------> SPI2_MOSI
+    PD1     ------> SPI2_SCK
+    */
+    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2);
+
+    HAL_GPIO_DeInit(SPI_D_MOSI_GPIO_Port, SPI_D_MOSI_Pin);
+
+    HAL_GPIO_DeInit(SPI_D_SCK_GPIO_Port, SPI_D_SCK_Pin);
+
+  /* USER CODE BEGIN SPI2_MspDeInit 1 */
+
+  /* USER CODE END SPI2_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+void NFC_SPI_Reconfigure() {
+  osKernelLock();
+
+  SPI_R.Init.Mode = SPI_MODE_MASTER;
+  SPI_R.Init.Direction = SPI_DIRECTION_2LINES;
+  SPI_R.Init.DataSize = SPI_DATASIZE_8BIT;
+  SPI_R.Init.CLKPolarity = SPI_POLARITY_LOW;
+  SPI_R.Init.CLKPhase = SPI_PHASE_2EDGE;
+  SPI_R.Init.NSS = SPI_NSS_SOFT;
+  SPI_R.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 8mhz, 10mhz is max
+  SPI_R.Init.FirstBit = SPI_FIRSTBIT_MSB;
+  SPI_R.Init.TIMode = SPI_TIMODE_DISABLE;
+  SPI_R.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+  SPI_R.Init.CRCPolynomial = 7;
+  SPI_R.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
+  SPI_R.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
+
+  if (HAL_SPI_Init(&SPI_R) != HAL_OK) {
+      Error_Handler();
+  }
+
+  Enable_SPI(&SPI_R);
+
+  osKernelUnlock();
+}
+
+void SD_SPI_Reconfigure_Slow(void) {
+  osKernelLock();
+
+  SPI_SD_HANDLE.Init.Mode = SPI_MODE_MASTER;
+  SPI_SD_HANDLE.Init.Direction = SPI_DIRECTION_2LINES;
+  SPI_SD_HANDLE.Init.DataSize = SPI_DATASIZE_8BIT;
+  SPI_SD_HANDLE.Init.CLKPolarity = SPI_POLARITY_LOW;
+  SPI_SD_HANDLE.Init.CLKPhase = SPI_PHASE_1EDGE;
+  SPI_SD_HANDLE.Init.NSS = SPI_NSS_SOFT;
+  SPI_SD_HANDLE.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
+  SPI_SD_HANDLE.Init.FirstBit = SPI_FIRSTBIT_MSB;
+  SPI_SD_HANDLE.Init.TIMode = SPI_TIMODE_DISABLE;
+  SPI_SD_HANDLE.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+  SPI_SD_HANDLE.Init.CRCPolynomial = 7;
+  SPI_SD_HANDLE.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
+  SPI_SD_HANDLE.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
+
+  if(HAL_SPI_Init(&SPI_SD_HANDLE) != HAL_OK) {
+      Error_Handler();
+  }
+
+  Enable_SPI(&SPI_SD_HANDLE);
+
+  osKernelUnlock();
+}
+
+void SD_SPI_Reconfigure_Fast(void) {
+  osKernelLock();
+
+  SPI_SD_HANDLE.Init.Mode = SPI_MODE_MASTER;
+  SPI_SD_HANDLE.Init.Direction = SPI_DIRECTION_2LINES;
+  SPI_SD_HANDLE.Init.DataSize = SPI_DATASIZE_8BIT;
+  SPI_SD_HANDLE.Init.CLKPolarity = SPI_POLARITY_LOW;
+  SPI_SD_HANDLE.Init.CLKPhase = SPI_PHASE_1EDGE;
+  SPI_SD_HANDLE.Init.NSS = SPI_NSS_SOFT;
+  SPI_SD_HANDLE.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
+  SPI_SD_HANDLE.Init.FirstBit = SPI_FIRSTBIT_MSB;
+  SPI_SD_HANDLE.Init.TIMode = SPI_TIMODE_DISABLE;
+  SPI_SD_HANDLE.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+  SPI_SD_HANDLE.Init.CRCPolynomial = 7;
+  SPI_SD_HANDLE.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
+  SPI_SD_HANDLE.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
+
+  if(HAL_SPI_Init(&SPI_SD_HANDLE) != HAL_OK) {
+      Error_Handler();
+  }
+
+  Enable_SPI(&SPI_SD_HANDLE);
+
+  osKernelUnlock();
+}
+
+void CC1101_SPI_Reconfigure(void) {
+  osKernelLock();
+
+  SPI_R.Init.Mode = SPI_MODE_MASTER;
+  SPI_R.Init.Direction = SPI_DIRECTION_2LINES;
+  SPI_R.Init.DataSize = SPI_DATASIZE_8BIT;
+  SPI_R.Init.CLKPolarity = SPI_POLARITY_LOW;
+  SPI_R.Init.CLKPhase = SPI_PHASE_1EDGE;
+  SPI_R.Init.NSS = SPI_NSS_SOFT;
+  SPI_R.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
+  SPI_R.Init.FirstBit = SPI_FIRSTBIT_MSB;
+  SPI_R.Init.TIMode = SPI_TIMODE_DISABLE;
+  SPI_R.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+  SPI_R.Init.CRCPolynomial = 7;
+  SPI_R.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
+  SPI_R.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
+
+  if(HAL_SPI_Init(&SPI_R) != HAL_OK) {
+      Error_Handler();
+  }
+
+  Enable_SPI(&SPI_R);
+
+  osKernelUnlock();
+}
+
+void Enable_SPI(SPI_HandleTypeDef* spi_instance){
+  if((spi_instance->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) {
+    __HAL_SPI_ENABLE(spi_instance);
+  }
+}
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 93 - 0
firmware/targets/f5/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****/

+ 418 - 0
firmware/targets/f5/Src/stm32wbxx_it.c

@@ -0,0 +1,418 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file    stm32wbxx_it.c
+  * @brief   Interrupt Service Routines.
+  ******************************************************************************
+  * @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"
+#include "stm32wbxx_it.h"
+#include "FreeRTOS.h"
+#include "task.h"
+/* Private includes ----------------------------------------------------------*/
+/* USER CODE BEGIN Includes */
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* USER CODE BEGIN TD */
+
+/* USER CODE END TD */
+
+/* Private define ------------------------------------------------------------*/
+/* USER CODE BEGIN PD */
+
+/* USER CODE END PD */
+
+/* Private macro -------------------------------------------------------------*/
+/* USER CODE BEGIN PM */
+
+/* USER CODE END PM */
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+/* Private function prototypes -----------------------------------------------*/
+/* USER CODE BEGIN PFP */
+
+/* USER CODE END PFP */
+
+/* Private user code ---------------------------------------------------------*/
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/* External variables --------------------------------------------------------*/
+extern PCD_HandleTypeDef hpcd_USB_FS;
+extern ADC_HandleTypeDef hadc1;
+extern COMP_HandleTypeDef hcomp1;
+extern RTC_HandleTypeDef hrtc;
+extern TIM_HandleTypeDef htim1;
+extern TIM_HandleTypeDef htim2;
+extern TIM_HandleTypeDef htim16;
+extern TIM_HandleTypeDef htim17;
+
+/* USER CODE BEGIN EV */
+
+/* USER CODE END EV */
+
+/******************************************************************************/
+/*           Cortex Processor Interruption and Exception Handlers          */
+/******************************************************************************/
+/**
+  * @brief This function handles Non maskable interrupt.
+  */
+void NMI_Handler(void)
+{
+  /* USER CODE BEGIN NonMaskableInt_IRQn 0 */
+
+  /* USER CODE END NonMaskableInt_IRQn 0 */
+  HAL_RCC_NMI_IRQHandler();
+  /* USER CODE BEGIN NonMaskableInt_IRQn 1 */
+
+  /* USER CODE END NonMaskableInt_IRQn 1 */
+}
+
+/**
+  * @brief This function handles Hard fault interrupt.
+  */
+void HardFault_Handler(void)
+{
+  /* USER CODE BEGIN HardFault_IRQn 0 */
+  if ((*(volatile uint32_t *)CoreDebug_BASE) & (1 << 0)) {
+    __asm("bkpt 1");
+  }
+  /* USER CODE END HardFault_IRQn 0 */
+  while (1)
+  {
+    /* USER CODE BEGIN W1_HardFault_IRQn 0 */
+    /* USER CODE END W1_HardFault_IRQn 0 */
+  }
+}
+
+/**
+  * @brief This function handles Memory management fault.
+  */
+void MemManage_Handler(void)
+{
+  /* USER CODE BEGIN MemoryManagement_IRQn 0 */
+  __asm("bkpt 1");
+  /* USER CODE END MemoryManagement_IRQn 0 */
+  while (1)
+  {
+    /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
+    /* USER CODE END W1_MemoryManagement_IRQn 0 */
+  }
+}
+
+/**
+  * @brief This function handles Prefetch fault, memory access fault.
+  */
+void BusFault_Handler(void)
+{
+  /* USER CODE BEGIN BusFault_IRQn 0 */
+  __asm("bkpt 1");
+  /* USER CODE END BusFault_IRQn 0 */
+  while (1)
+  {
+    /* USER CODE BEGIN W1_BusFault_IRQn 0 */
+    /* USER CODE END W1_BusFault_IRQn 0 */
+  }
+}
+
+/**
+  * @brief This function handles Undefined instruction or illegal state.
+  */
+void UsageFault_Handler(void)
+{
+  /* USER CODE BEGIN UsageFault_IRQn 0 */
+  __asm("bkpt 1");
+  /* USER CODE END UsageFault_IRQn 0 */
+  while (1)
+  {
+    /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
+    /* USER CODE END W1_UsageFault_IRQn 0 */
+  }
+}
+
+/**
+  * @brief This function handles Debug monitor.
+  */
+void DebugMon_Handler(void)
+{
+  /* USER CODE BEGIN DebugMonitor_IRQn 0 */
+
+  /* USER CODE END DebugMonitor_IRQn 0 */
+  /* USER CODE BEGIN DebugMonitor_IRQn 1 */
+
+  /* USER CODE END DebugMonitor_IRQn 1 */
+}
+
+/**
+  * @brief This function handles System tick timer.
+  */
+void SysTick_Handler(void)
+{
+  /* USER CODE BEGIN SysTick_IRQn 0 */
+
+  /* USER CODE END SysTick_IRQn 0 */
+  /* USER CODE BEGIN SysTick_IRQn 1 */
+  HAL_IncTick();
+  /* USER CODE END SysTick_IRQn 1 */
+}
+
+/******************************************************************************/
+/* STM32WBxx Peripheral Interrupt Handlers                                    */
+/* Add here the Interrupt Handlers for the used peripherals.                  */
+/* For the available peripheral interrupt handler names,                      */
+/* please refer to the startup file (startup_stm32wbxx.s).                    */
+/******************************************************************************/
+
+/**
+  * @brief This function handles RTC tamper and time stamp, CSS on LSE interrupts through EXTI line 18.
+  */
+void TAMP_STAMP_LSECSS_IRQHandler(void)
+{
+  /* USER CODE BEGIN TAMP_STAMP_LSECSS_IRQn 0 */
+  HAL_RCC_CSSCallback();
+  /* USER CODE END TAMP_STAMP_LSECSS_IRQn 0 */
+  /* USER CODE BEGIN TAMP_STAMP_LSECSS_IRQn 1 */
+
+  /* USER CODE END TAMP_STAMP_LSECSS_IRQn 1 */
+}
+
+/**
+  * @brief This function handles RCC global interrupt.
+  */
+void RCC_IRQHandler(void)
+{
+  /* USER CODE BEGIN RCC_IRQn 0 */
+  if (!LL_RCC_LSE_IsReady()) {
+    HAL_RCC_CSSCallback();
+  }
+  /* USER CODE END RCC_IRQn 0 */
+  /* USER CODE BEGIN RCC_IRQn 1 */
+
+  /* USER CODE END RCC_IRQn 1 */
+}
+
+/**
+  * @brief This function handles EXTI line1 interrupt.
+  */
+void EXTI1_IRQHandler(void)
+{
+  /* USER CODE BEGIN EXTI1_IRQn 0 */
+
+  /* USER CODE END EXTI1_IRQn 0 */
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
+  /* USER CODE BEGIN EXTI1_IRQn 1 */
+
+  /* USER CODE END EXTI1_IRQn 1 */
+}
+
+/**
+  * @brief This function handles EXTI line3 interrupt.
+  */
+void EXTI3_IRQHandler(void)
+{
+  /* USER CODE BEGIN EXTI3_IRQn 0 */
+
+  /* USER CODE END EXTI3_IRQn 0 */
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
+  /* USER CODE BEGIN EXTI3_IRQn 1 */
+
+  /* USER CODE END EXTI3_IRQn 1 */
+}
+
+/**
+  * @brief This function handles ADC1 global interrupt.
+  */
+void ADC1_IRQHandler(void)
+{
+  /* USER CODE BEGIN ADC1_IRQn 0 */
+
+  /* USER CODE END ADC1_IRQn 0 */
+  HAL_ADC_IRQHandler(&hadc1);
+  /* USER CODE BEGIN ADC1_IRQn 1 */
+
+  /* USER CODE END ADC1_IRQn 1 */
+}
+
+/**
+  * @brief This function handles USB low priority interrupt, USB wake-up interrupt through EXTI line 28.
+  */
+void USB_LP_IRQHandler(void)
+{
+  /* USER CODE BEGIN USB_LP_IRQn 0 */
+
+  /* USER CODE END USB_LP_IRQn 0 */
+  HAL_PCD_IRQHandler(&hpcd_USB_FS);
+  /* USER CODE BEGIN USB_LP_IRQn 1 */
+
+  /* USER CODE END USB_LP_IRQn 1 */
+}
+
+/**
+  * @brief This function handles COMP1 and COMP2 interrupts through EXTI lines 20 and 21.
+  */
+void COMP_IRQHandler(void)
+{
+  /* USER CODE BEGIN COMP_IRQn 0 */
+
+  /* USER CODE END COMP_IRQn 0 */
+  HAL_COMP_IRQHandler(&hcomp1);
+  /* USER CODE BEGIN COMP_IRQn 1 */
+
+  /* USER CODE END COMP_IRQn 1 */
+}
+
+/**
+  * @brief This function handles EXTI line[9:5] interrupts.
+  */
+void EXTI9_5_IRQHandler(void)
+{
+  /* USER CODE BEGIN EXTI9_5_IRQn 0 */
+
+  /* USER CODE END EXTI9_5_IRQn 0 */
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8);
+  /* USER CODE BEGIN EXTI9_5_IRQn 1 */
+
+  /* USER CODE END EXTI9_5_IRQn 1 */
+}
+
+/**
+  * @brief This function handles TIM1 update interrupt and TIM16 global interrupt.
+  */
+void TIM1_UP_TIM16_IRQHandler(void)
+{
+  /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 0 */
+
+  /* USER CODE END TIM1_UP_TIM16_IRQn 0 */
+  HAL_TIM_IRQHandler(&htim1);
+  HAL_TIM_IRQHandler(&htim16);
+  /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 1 */
+
+  /* USER CODE END TIM1_UP_TIM16_IRQn 1 */
+}
+
+/**
+  * @brief This function handles TIM1 trigger and commutation interrupts and TIM17 global interrupt.
+  */
+void TIM1_TRG_COM_TIM17_IRQHandler(void)
+{
+  /* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 0 */
+
+  /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 0 */
+  HAL_TIM_IRQHandler(&htim1);
+  /* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 1 */
+
+  /* USER CODE END TIM1_TRG_COM_TIM17_IRQn 1 */
+}
+
+/**
+  * @brief This function handles TIM1 capture compare interrupt.
+  */
+void TIM1_CC_IRQHandler(void)
+{
+  /* USER CODE BEGIN TIM1_CC_IRQn 0 */
+
+  /* USER CODE END TIM1_CC_IRQn 0 */
+  HAL_TIM_IRQHandler(&htim1);
+  /* USER CODE BEGIN TIM1_CC_IRQn 1 */
+
+  /* USER CODE END TIM1_CC_IRQn 1 */
+}
+
+/**
+  * @brief This function handles TIM2 global interrupt.
+  */
+void TIM2_IRQHandler(void)
+{
+  /* USER CODE BEGIN TIM2_IRQn 0 */
+
+  /* USER CODE END TIM2_IRQn 0 */
+  HAL_TIM_IRQHandler(&htim2);
+  /* USER CODE BEGIN TIM2_IRQn 1 */
+
+  /* USER CODE END TIM2_IRQn 1 */
+}
+
+/**
+  * @brief This function handles EXTI line[15:10] interrupts.
+  */
+void EXTI15_10_IRQHandler(void)
+{
+  /* USER CODE BEGIN EXTI15_10_IRQn 0 */
+
+  /* USER CODE END EXTI15_10_IRQn 0 */
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
+  /* USER CODE BEGIN EXTI15_10_IRQn 1 */
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
+  /* USER CODE END EXTI15_10_IRQn 1 */
+}
+
+/**
+  * @brief This function handles HSEM global interrupt.
+  */
+void HSEM_IRQHandler(void)
+{
+  /* USER CODE BEGIN HSEM_IRQn 0 */
+
+  /* USER CODE END HSEM_IRQn 0 */
+  HAL_HSEM_IRQHandler();
+  /* USER CODE BEGIN HSEM_IRQn 1 */
+
+  /* USER CODE END HSEM_IRQn 1 */
+}
+
+/* USER CODE BEGIN 1 */
+void EXTI4_IRQHandler(void)
+{
+  /* USER CODE BEGIN EXTI4_IRQn 0 */
+
+  /* USER CODE END EXTI4_IRQn 0 */
+  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
+  /* USER CODE BEGIN EXTI4_IRQn 1 */
+
+  /* USER CODE END EXTI4_IRQn 1 */
+}
+
+extern void HW_TS_RTC_Wakeup_Handler();
+extern void HW_IPCC_Tx_Handler();
+extern void HW_IPCC_Rx_Handler();
+
+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();
+}
+
+/* USER CODE END 1 */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 357 - 0
firmware/targets/f5/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/f5/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****/

+ 121 - 0
firmware/targets/f5/Src/usart.c

@@ -0,0 +1,121 @@
+/**
+  ******************************************************************************
+  * @file    usart.c
+  * @brief   This file provides code for the configuration
+  *          of the USART 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 "usart.h"
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+UART_HandleTypeDef huart1;
+
+/* USART1 init function */
+
+void MX_USART1_UART_Init(void)
+{
+
+  huart1.Instance = USART1;
+  huart1.Init.BaudRate = 115200;
+  huart1.Init.WordLength = UART_WORDLENGTH_8B;
+  huart1.Init.StopBits = UART_STOPBITS_1;
+  huart1.Init.Parity = UART_PARITY_NONE;
+  huart1.Init.Mode = UART_MODE_TX_RX;
+  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
+  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
+  huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
+  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
+  if (HAL_UART_Init(&huart1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
+  {
+    Error_Handler();
+  }
+  if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
+  {
+    Error_Handler();
+  }
+
+}
+
+void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
+{
+
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(uartHandle->Instance==USART1)
+  {
+  /* USER CODE BEGIN USART1_MspInit 0 */
+
+  /* USER CODE END USART1_MspInit 0 */
+    /* USART1 clock enable */
+    __HAL_RCC_USART1_CLK_ENABLE();
+
+    __HAL_RCC_GPIOB_CLK_ENABLE();
+    /**USART1 GPIO Configuration
+    PB6     ------> USART1_TX
+    PB7     ------> USART1_RX
+    */
+    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
+    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+  /* USER CODE BEGIN USART1_MspInit 1 */
+
+  /* USER CODE END USART1_MspInit 1 */
+  }
+}
+
+void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
+{
+
+  if(uartHandle->Instance==USART1)
+  {
+  /* USER CODE BEGIN USART1_MspDeInit 0 */
+
+  /* USER CODE END USART1_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_USART1_CLK_DISABLE();
+
+    /**USART1 GPIO Configuration
+    PB6     ------> USART1_TX
+    PB7     ------> USART1_RX
+    */
+    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);
+
+  /* USER CODE BEGIN USART1_MspDeInit 1 */
+
+  /* USER CODE END USART1_MspDeInit 1 */
+  }
+}
+
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 99 - 0
firmware/targets/f5/Src/usb_device.c

@@ -0,0 +1,99 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : usb_device.c
+  * @version        : v3.0_Cube
+  * @brief          : This file implements the USB Device
+  ******************************************************************************
+  * @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 "usb_device.h"
+#include "usbd_core.h"
+#include "usbd_desc.h"
+#include "usbd_cdc.h"
+#include "usbd_cdc_if.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* USER CODE BEGIN PV */
+/* Private variables ---------------------------------------------------------*/
+
+/* USER CODE END PV */
+
+/* USER CODE BEGIN PFP */
+/* Private function prototypes -----------------------------------------------*/
+
+/* USER CODE END PFP */
+
+extern void Error_Handler(void);
+/* USB Device Core handle declaration. */
+USBD_HandleTypeDef hUsbDeviceFS;
+extern USBD_DescriptorsTypeDef CDC_Desc;
+
+/*
+ * -- Insert your variables declaration here --
+ */
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/*
+ * -- Insert your external function declaration here --
+ */
+/* USER CODE BEGIN 1 */
+
+/* USER CODE END 1 */
+
+/**
+  * Init USB device Library, add supported class and start the library
+  * @retval None
+  */
+void MX_USB_Device_Init(void)
+{
+  /* USER CODE BEGIN USB_Device_Init_PreTreatment */
+
+  /* USER CODE END USB_Device_Init_PreTreatment */
+
+  /* Init Device Library, add supported class and start the library. */
+  if (USBD_Init(&hUsbDeviceFS, &CDC_Desc, DEVICE_FS) != USBD_OK) {
+    Error_Handler();
+  }
+  if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK) {
+    Error_Handler();
+  }
+  if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK) {
+    Error_Handler();
+  }
+  if (USBD_Start(&hUsbDeviceFS) != USBD_OK) {
+    Error_Handler();
+  }
+  /* USER CODE BEGIN USB_Device_Init_PostTreatment */
+
+  /* USER CODE END USB_Device_Init_PostTreatment */
+}
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 311 - 0
firmware/targets/f5/Src/usbd_cdc_if.c

@@ -0,0 +1,311 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : usbd_cdc_if.c
+  * @version        : v3.0_Cube
+  * @brief          : Usb device for Virtual Com Port.
+  ******************************************************************************
+  * @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 "usbd_cdc_if.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+
+/* USER CODE BEGIN PV */
+/* Private variables ---------------------------------------------------------*/
+
+/* USER CODE END PV */
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+  * @brief Usb device library.
+  * @{
+  */
+
+/** @addtogroup USBD_CDC_IF
+  * @{
+  */
+
+/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions
+  * @brief Private types.
+  * @{
+  */
+
+/* USER CODE BEGIN PRIVATE_TYPES */
+
+extern void _api_hal_vcp_init();
+extern void _api_hal_vcp_deinit();
+extern void _api_hal_vcp_control_line(uint8_t state);
+extern void _api_hal_vcp_rx_callback(char* buffer, size_t size);
+extern void _api_hal_vcp_tx_complete(size_t size);
+
+/* USER CODE END PRIVATE_TYPES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines
+  * @brief Private defines.
+  * @{
+  */
+
+/* USER CODE BEGIN PRIVATE_DEFINES */
+/* USER CODE END PRIVATE_DEFINES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros
+  * @brief Private macros.
+  * @{
+  */
+
+/* USER CODE BEGIN PRIVATE_MACRO */
+
+/* USER CODE END PRIVATE_MACRO */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables
+  * @brief Private variables.
+  * @{
+  */
+/* Create buffer for reception and transmission           */
+/* It's up to user to redefine and/or remove those define */
+/** Received data over USB are stored in this buffer      */
+uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
+
+/** Data to send over USB CDC are stored in this buffer   */
+uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
+
+/* USER CODE BEGIN PRIVATE_VARIABLES */
+
+/* USER CODE END PRIVATE_VARIABLES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
+  * @brief Public variables.
+  * @{
+  */
+
+extern USBD_HandleTypeDef hUsbDeviceFS;
+
+/* USER CODE BEGIN EXPORTED_VARIABLES */
+
+/* USER CODE END EXPORTED_VARIABLES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes
+  * @brief Private functions declaration.
+  * @{
+  */
+
+static int8_t CDC_Init_FS(void);
+static int8_t CDC_DeInit_FS(void);
+static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
+static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
+static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum);
+
+/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
+
+/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
+
+/**
+  * @}
+  */
+
+USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
+{
+  CDC_Init_FS,
+  CDC_DeInit_FS,
+  CDC_Control_FS,
+  CDC_Receive_FS,
+  CDC_TransmitCplt_FS
+};
+
+/* Private functions ---------------------------------------------------------*/
+/**
+  * @brief  Initializes the CDC media low layer over the FS USB IP
+  * @retval USBD_OK if all operations are OK else USBD_FAIL
+  */
+static int8_t CDC_Init_FS(void)
+{
+  /* USER CODE BEGIN 3 */
+  /* Set Application Buffers */
+  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
+  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
+  _api_hal_vcp_init();
+  return (USBD_OK);
+  /* USER CODE END 3 */
+}
+
+/**
+  * @brief  DeInitializes the CDC media low layer
+  * @retval USBD_OK if all operations are OK else USBD_FAIL
+  */
+static int8_t CDC_DeInit_FS(void)
+{
+  /* USER CODE BEGIN 4 */
+  _api_hal_vcp_deinit();
+  return (USBD_OK);
+  /* USER CODE END 4 */
+}
+
+/**
+  * @brief  Manage the CDC class requests
+  * @param  cmd: Command code
+  * @param  pbuf: Buffer containing command data (request parameters)
+  * @param  length: Number of data to be sent (in bytes)
+  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
+  */
+static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
+{
+  /* USER CODE BEGIN 5 */
+  if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) {
+  } else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) {
+  } else if (cmd == CDC_SET_COMM_FEATURE) {
+  } else if (cmd == CDC_GET_COMM_FEATURE) {
+  } else if (cmd == CDC_CLEAR_COMM_FEATURE) {
+  } else if (cmd == CDC_SET_LINE_CODING) {
+      /*******************************************************************************/
+      /* Line Coding Structure                                                       */
+      /*-----------------------------------------------------------------------------*/
+      /* Offset | Field       | Size | Value  | Description                          */
+      /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/
+      /* 4      | bCharFormat |   1  | Number | Stop bits                            */
+      /*                                        0 - 1 Stop bit                       */
+      /*                                        1 - 1.5 Stop bits                    */
+      /*                                        2 - 2 Stop bits                      */
+      /* 5      | bParityType |  1   | Number | Parity                               */
+      /*                                        0 - None                             */
+      /*                                        1 - Odd                              */
+      /*                                        2 - Even                             */
+      /*                                        3 - Mark                             */
+      /*                                        4 - Space                            */
+      /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */
+      /*******************************************************************************/
+  } else if (cmd == CDC_GET_LINE_CODING) {
+  } else if (cmd == CDC_SET_CONTROL_LINE_STATE) {
+    _api_hal_vcp_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue);
+  } else if (cmd == CDC_SEND_BREAK) {
+  } else {
+  }
+
+  return (USBD_OK);
+  /* USER CODE END 5 */
+}
+
+/**
+  * @brief  Data received over USB OUT endpoint are sent over CDC interface
+  *         through this function.
+  *
+  *         @note
+  *         This function will issue a NAK packet on any OUT packet received on
+  *         USB endpoint until exiting this function. If you exit this function
+  *         before transfer is complete on CDC interface (ie. using DMA controller)
+  *         it will result in receiving more data while previous ones are still
+  *         not sent.
+  *
+  * @param  Buf: Buffer of data to be received
+  * @param  Len: Number of data received (in bytes)
+  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
+  */
+static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
+{
+  /* USER CODE BEGIN 6 */
+  _api_hal_vcp_rx_callback((char*)Buf, *Len);
+  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
+  return (USBD_OK);
+  /* USER CODE END 6 */
+}
+
+/**
+  * @brief  CDC_Transmit_FS
+  *         Data to send over USB IN endpoint are sent over CDC interface
+  *         through this function.
+  *         @note
+  *
+  *
+  * @param  Buf: Buffer of data to be sent
+  * @param  Len: Number of data to be sent (in bytes)
+  * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
+  */
+uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
+{
+  uint8_t result = USBD_OK;
+  /* USER CODE BEGIN 7 */
+  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
+  if (hcdc->TxState != 0){
+    return USBD_BUSY;
+  }
+  memcpy(UserTxBufferFS, Buf, Len);
+  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len);
+  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
+  /* USER CODE END 7 */
+  return result;
+}
+
+/**
+  * @brief  CDC_TransmitCplt_FS
+  *         Data transmited callback
+  *
+  *         @note
+  *         This function is IN transfer complete callback used to inform user that
+  *         the submitted Data is successfully sent over USB.
+  *
+  * @param  Buf: Buffer of data to be received
+  * @param  Len: Number of data received (in bytes)
+  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
+  */
+static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum)
+{
+  uint8_t result = USBD_OK;
+  /* USER CODE BEGIN 13 */
+  UNUSED(Buf);
+  UNUSED(epnum);
+  _api_hal_vcp_tx_complete(*Len);
+  /* USER CODE END 13 */
+  return result;
+}
+
+/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
+
+/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 810 - 0
firmware/targets/f5/Src/usbd_conf.c

@@ -0,0 +1,810 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : usbd_conf.c
+  * @version        : v3.0_Cube
+  * @brief          : This file implements the board support package for the USB device library
+  ******************************************************************************
+  * @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 "stm32wbxx.h"
+#include "stm32wbxx_hal.h"
+#include "usbd_def.h"
+#include "usbd_core.h"
+
+#include "usbd_cdc.h"
+
+/* USER CODE BEGIN Includes */
+
+/* USER CODE END Includes */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+
+/* Private variables ---------------------------------------------------------*/
+/* USER CODE BEGIN PV */
+
+/* USER CODE END PV */
+
+PCD_HandleTypeDef hpcd_USB_FS;
+void Error_Handler(void);
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/* Exported function prototypes ----------------------------------------------*/
+
+/* USER CODE BEGIN PFP */
+/* Private function prototypes -----------------------------------------------*/
+
+/* USER CODE END PFP */
+
+/* Private functions ---------------------------------------------------------*/
+static USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status);
+/* USER CODE BEGIN 1 */
+static void SystemClockConfig_Resume(void);
+
+/* USER CODE END 1 */
+extern void SystemClock_Config(void);
+
+/*******************************************************************************
+                       LL Driver Callbacks (PCD -> USB Device Library)
+*******************************************************************************/
+/* MSP Init */
+
+#if (USE_HAL_PCD_REGISTER_CALLBACK == 1U)
+static void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
+#else
+void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACK */
+{
+  GPIO_InitTypeDef GPIO_InitStruct = {0};
+  if(pcdHandle->Instance==USB)
+  {
+  /* USER CODE BEGIN USB_MspInit 0 */
+
+  /* USER CODE END USB_MspInit 0 */
+
+    __HAL_RCC_GPIOA_CLK_ENABLE();
+    /**USB GPIO Configuration
+    PA11     ------> USB_DM
+    PA12     ------> USB_DP
+    */
+    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
+    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+    GPIO_InitStruct.Alternate = GPIO_AF10_USB;
+    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+    /* Peripheral clock enable */
+    __HAL_RCC_USB_CLK_ENABLE();
+
+    /* Peripheral interrupt init */
+    HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0);
+    HAL_NVIC_EnableIRQ(USB_LP_IRQn);
+  /* USER CODE BEGIN USB_MspInit 1 */
+
+  /* USER CODE END USB_MspInit 1 */
+  }
+}
+
+#if (USE_HAL_PCD_REGISTER_CALLBACK == 1U)
+static void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
+#else
+void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACK */
+{
+  if(pcdHandle->Instance==USB)
+  {
+  /* USER CODE BEGIN USB_MspDeInit 0 */
+
+  /* USER CODE END USB_MspDeInit 0 */
+    /* Peripheral clock disable */
+    __HAL_RCC_USB_CLK_DISABLE();
+
+    /**USB GPIO Configuration
+    PA11     ------> USB_DM
+    PA12     ------> USB_DP
+    */
+    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
+
+    /* Peripheral interrupt Deinit*/
+    HAL_NVIC_DisableIRQ(USB_LP_IRQn);
+
+  /* USER CODE BEGIN USB_MspDeInit 1 */
+
+  /* USER CODE END USB_MspDeInit 1 */
+  }
+}
+
+/**
+  * @brief  Setup stage callback
+  * @param  hpcd: PCD handle
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_SetupStageCallback_PreTreatment */
+
+  /* USER CODE END  HAL_PCD_SetupStageCallback_PreTreatment */
+  USBD_LL_SetupStage((USBD_HandleTypeDef*)hpcd->pData, (uint8_t *)hpcd->Setup);
+  /* USER CODE BEGIN HAL_PCD_SetupStageCallback_PostTreatment */
+
+  /* USER CODE END  HAL_PCD_SetupStageCallback_PostTreatment */
+}
+
+/**
+  * @brief  Data Out stage callback.
+  * @param  hpcd: PCD handle
+  * @param  epnum: Endpoint number
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#else
+void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_DataOutStageCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_DataOutStageCallback_PreTreatment */
+  USBD_LL_DataOutStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
+  /* USER CODE BEGIN HAL_PCD_DataOutStageCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_DataOutStageCallback_PostTreatment */
+}
+
+/**
+  * @brief  Data In stage callback.
+  * @param  hpcd: PCD handle
+  * @param  epnum: Endpoint number
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#else
+void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_DataInStageCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_DataInStageCallback_PreTreatment */
+  USBD_LL_DataInStage((USBD_HandleTypeDef*)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
+  /* USER CODE BEGIN HAL_PCD_DataInStageCallback_PostTreatment  */
+
+  /* USER CODE END HAL_PCD_DataInStageCallback_PostTreatment */
+}
+
+/**
+  * @brief  SOF callback.
+  * @param  hpcd: PCD handle
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_SOFCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_SOFCallback_PreTreatment */
+  USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData);
+  /* USER CODE BEGIN HAL_PCD_SOFCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_SOFCallback_PostTreatment */
+}
+
+/**
+  * @brief  Reset callback.
+  * @param  hpcd: PCD handle
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_ResetCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_ResetCallback_PreTreatment */
+  USBD_SpeedTypeDef speed = USBD_SPEED_FULL;
+
+  if ( hpcd->Init.speed != PCD_SPEED_FULL)
+  {
+    Error_Handler();
+  }
+    /* Set Speed. */
+  USBD_LL_SetSpeed((USBD_HandleTypeDef*)hpcd->pData, speed);
+
+  /* Reset Device. */
+  USBD_LL_Reset((USBD_HandleTypeDef*)hpcd->pData);
+  /* USER CODE BEGIN HAL_PCD_ResetCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_ResetCallback_PostTreatment */
+}
+
+/**
+  * @brief  Suspend callback.
+  * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
+  * @param  hpcd: PCD handle
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_SuspendCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_SuspendCallback_PreTreatment */
+  /* Inform USB library that core enters in suspend Mode. */
+  USBD_LL_Suspend((USBD_HandleTypeDef*)hpcd->pData);
+  /* Enter in STOP mode. */
+  /* USER CODE BEGIN 2 */
+  if (hpcd->Init.low_power_enable)
+  {
+    /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
+    SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
+  }
+  /* USER CODE END 2 */
+  /* USER CODE BEGIN HAL_PCD_SuspendCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_SuspendCallback_PostTreatment */
+}
+
+/**
+  * @brief  Resume callback.
+  * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
+  * @param  hpcd: PCD handle
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_ResumeCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_ResumeCallback_PreTreatment */
+
+  /* USER CODE BEGIN 3 */
+  if (hpcd->Init.low_power_enable)
+  {
+    /* Reset SLEEPDEEP bit of Cortex System Control Register. */
+    SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
+    SystemClockConfig_Resume();
+  }
+  /* USER CODE END 3 */
+
+  USBD_LL_Resume((USBD_HandleTypeDef*)hpcd->pData);
+  /* USER CODE BEGIN HAL_PCD_ResumeCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_ResumeCallback_PostTreatment */
+}
+
+/**
+  * @brief  ISOOUTIncomplete callback.
+  * @param  hpcd: PCD handle
+  * @param  epnum: Endpoint number
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#else
+void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_ISOOUTIncompleteCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_ISOOUTIncompleteCallback_PreTreatment */
+  USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
+  /* USER CODE BEGIN HAL_PCD_ISOOUTIncompleteCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_ISOOUTIncompleteCallback_PostTreatment */
+}
+
+/**
+  * @brief  ISOINIncomplete callback.
+  * @param  hpcd: PCD handle
+  * @param  epnum: Endpoint number
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#else
+void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_ISOINIncompleteCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_ISOINIncompleteCallback_PreTreatment */
+  USBD_LL_IsoINIncomplete((USBD_HandleTypeDef*)hpcd->pData, epnum);
+  /* USER CODE BEGIN HAL_PCD_ISOINIncompleteCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_ISOINIncompleteCallback_PostTreatment */
+}
+
+/**
+  * @brief  Connect callback.
+  * @param  hpcd: PCD handle
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_ConnectCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_ConnectCallback_PreTreatment */
+  USBD_LL_DevConnected((USBD_HandleTypeDef*)hpcd->pData);
+  /* USER CODE BEGIN HAL_PCD_ConnectCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_ConnectCallback_PostTreatment */
+}
+
+/**
+  * @brief  Disconnect callback.
+  * @param  hpcd: PCD handle
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
+#else
+void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN HAL_PCD_DisconnectCallback_PreTreatment */
+
+  /* USER CODE END HAL_PCD_DisconnectCallback_PreTreatment */
+  USBD_LL_DevDisconnected((USBD_HandleTypeDef*)hpcd->pData);
+  /* USER CODE BEGIN HAL_PCD_DisconnectCallback_PostTreatment */
+
+  /* USER CODE END HAL_PCD_DisconnectCallback_PostTreatment */
+}
+
+  /* USER CODE BEGIN LowLevelInterface */
+
+  /* USER CODE END LowLevelInterface */
+
+/*******************************************************************************
+                       LL Driver Interface (USB Device Library --> PCD)
+*******************************************************************************/
+
+/**
+  * @brief  Initializes the low level portion of the device driver.
+  * @param  pdev: Device handle
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
+{
+  /* Init USB Ip. */
+  hpcd_USB_FS.pData = pdev;
+  /* Link the driver to the stack. */
+  pdev->pData = &hpcd_USB_FS;
+/* Enable USB power on Pwrctrl CR2 register. */
+  HAL_PWREx_EnableVddUSB();
+
+  hpcd_USB_FS.Instance = USB;
+  hpcd_USB_FS.Init.dev_endpoints = 8;
+  hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
+  hpcd_USB_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
+  hpcd_USB_FS.Init.Sof_enable = DISABLE;
+  hpcd_USB_FS.Init.low_power_enable = DISABLE;
+  hpcd_USB_FS.Init.lpm_enable = DISABLE;
+  hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
+
+  #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+  /* register Msp Callbacks (before the Init) */
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_MSPINIT_CB_ID, PCD_MspInit);
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_MSPDEINIT_CB_ID, PCD_MspDeInit);
+  #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+
+  if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)
+  {
+    Error_Handler( );
+  }
+
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+  /* Register USB PCD CallBacks */
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SOF_CB_ID, PCD_SOFCallback);
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SETUPSTAGE_CB_ID, PCD_SetupStageCallback);
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_RESET_CB_ID, PCD_ResetCallback);
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SUSPEND_CB_ID, PCD_SuspendCallback);
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_RESUME_CB_ID, PCD_ResumeCallback);
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_CONNECT_CB_ID, PCD_ConnectCallback);
+  HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_DISCONNECT_CB_ID, PCD_DisconnectCallback);
+  /* USER CODE BEGIN RegisterCallBackFirstPart */
+
+  /* USER CODE END RegisterCallBackFirstPart */
+  HAL_PCD_RegisterLpmCallback(&hpcd_USB_FS, PCDEx_LPM_Callback);
+  HAL_PCD_RegisterDataOutStageCallback(&hpcd_USB_FS, PCD_DataOutStageCallback);
+  HAL_PCD_RegisterDataInStageCallback(&hpcd_USB_FS, PCD_DataInStageCallback);
+  HAL_PCD_RegisterIsoOutIncpltCallback(&hpcd_USB_FS, PCD_ISOOUTIncompleteCallback);
+  HAL_PCD_RegisterIsoInIncpltCallback(&hpcd_USB_FS, PCD_ISOINIncompleteCallback);
+  /* USER CODE BEGIN RegisterCallBackSecondPart */
+
+  /* USER CODE END RegisterCallBackSecondPart */
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+  /* USER CODE BEGIN EndPoint_Configuration */
+  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);
+  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
+  /* USER CODE END EndPoint_Configuration */
+  /* USER CODE BEGIN EndPoint_Configuration_CDC */
+  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x81 , PCD_SNG_BUF, 0xC0);
+  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x01 , PCD_SNG_BUF, 0x110);
+  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x82 , PCD_SNG_BUF, 0x100);
+  /* USER CODE END EndPoint_Configuration_CDC */
+  return USBD_OK;
+}
+
+/**
+  * @brief  De-Initializes the low level portion of the device driver.
+  * @param  pdev: Device handle
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_DeInit(pdev->pData);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Starts the low level portion of the device driver.
+  * @param  pdev: Device handle
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_Start(pdev->pData);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Stops the low level portion of the device driver.
+  * @param  pdev: Device handle
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_Stop(pdev->pData);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Opens an endpoint of the low level driver.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @param  ep_type: Endpoint type
+  * @param  ep_mps: Endpoint max packet size
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Closes an endpoint of the low level driver.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Flushes an endpoint of the Low Level Driver.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Sets a Stall condition on an endpoint of the Low Level Driver.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Clears a Stall condition on an endpoint of the Low Level Driver.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Returns Stall condition.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @retval Stall (1: Yes, 0: No)
+  */
+uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+  PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef*) pdev->pData;
+
+  if((ep_addr & 0x80) == 0x80)
+  {
+    return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
+  }
+  else
+  {
+    return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
+  }
+}
+
+/**
+  * @brief  Assigns a USB address to the device.
+  * @param  pdev: Device handle
+  * @param  dev_addr: Device address
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Transmits data over an endpoint.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @param  pbuf: Pointer to data to be sent
+  * @param  size: Data size
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Prepares an endpoint for reception.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @param  pbuf: Pointer to data to be received
+  * @param  size: Data size
+  * @retval USBD status
+  */
+USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
+{
+  HAL_StatusTypeDef hal_status = HAL_OK;
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);
+
+  usb_status =  USBD_Get_USB_Status(hal_status);
+
+  return usb_status;
+}
+
+/**
+  * @brief  Returns the last transfered packet size.
+  * @param  pdev: Device handle
+  * @param  ep_addr: Endpoint number
+  * @retval Recived Data Size
+  */
+uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
+{
+  return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef*) pdev->pData, ep_addr);
+}
+
+/**
+  * @brief  Send LPM message to user layer
+  * @param  hpcd: PCD handle
+  * @param  msg: LPM message
+  * @retval None
+  */
+#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+static void PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg)
+#else
+void HAL_PCDEx_LPM_Callback(PCD_HandleTypeDef *hpcd, PCD_LPM_MsgTypeDef msg)
+#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+{
+  /* USER CODE BEGIN LPM_Callback */
+  switch (msg)
+  {
+  case PCD_LPM_L0_ACTIVE:
+    if (hpcd->Init.low_power_enable)
+    {
+      SystemClockConfig_Resume();
+
+      /* Reset SLEEPDEEP bit of Cortex System Control Register. */
+      SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
+    }
+    USBD_LL_Resume(hpcd->pData);
+    break;
+
+  case PCD_LPM_L1_ACTIVE:
+    USBD_LL_Suspend(hpcd->pData);
+
+    /* Enter in STOP mode. */
+    if (hpcd->Init.low_power_enable)
+    {
+      /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
+      SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
+    }
+    break;
+  }
+  /* USER CODE END LPM_Callback */
+}
+
+/**
+  * @brief  Delays routine for the USB Device Library.
+  * @param  Delay: Delay in ms
+  * @retval None
+  */
+void USBD_LL_Delay(uint32_t Delay)
+{
+  HAL_Delay(Delay);
+}
+
+/**
+  * @brief  Static single allocation.
+  * @param  size: Size of allocated memory
+  * @retval None
+  */
+void *USBD_static_malloc(uint32_t size)
+{
+  static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4)+1];/* On 32-bit boundary */
+  return mem;
+}
+
+/**
+  * @brief  Dummy memory free
+  * @param  p: Pointer to allocated  memory address
+  * @retval None
+  */
+void USBD_static_free(void *p)
+{
+
+}
+
+/* USER CODE BEGIN 5 */
+/**
+  * @brief  Configures system clock after wake-up from USB resume callBack:
+  *         enable HSI, PLL and select PLL as system clock source.
+  * @retval None
+  */
+static void SystemClockConfig_Resume(void)
+{
+  SystemClock_Config();
+}
+/* USER CODE END 5 */
+
+/**
+  * @brief  Retuns the USB status depending on the HAL status:
+  * @param  hal_status: HAL status
+  * @retval USB status
+  */
+USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status)
+{
+  USBD_StatusTypeDef usb_status = USBD_OK;
+
+  switch (hal_status)
+  {
+    case HAL_OK :
+      usb_status = USBD_OK;
+    break;
+    case HAL_ERROR :
+      usb_status = USBD_FAIL;
+    break;
+    case HAL_BUSY :
+      usb_status = USBD_BUSY;
+    break;
+    case HAL_TIMEOUT :
+      usb_status = USBD_FAIL;
+    break;
+    default :
+      usb_status = USBD_FAIL;
+    break;
+  }
+  return usb_status;
+}
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 396 - 0
firmware/targets/f5/Src/usbd_desc.c

@@ -0,0 +1,396 @@
+/* USER CODE BEGIN Header */
+/**
+  ******************************************************************************
+  * @file           : usbd_desc.c
+  * @version        : v3.0_Cube
+  * @brief          : This file implements the USB device descriptors.
+  ******************************************************************************
+  * @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 "usbd_core.h"
+#include "usbd_desc.h"
+#include "usbd_conf.h"
+
+/* USER CODE BEGIN INCLUDE */
+
+/* USER CODE END INCLUDE */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+
+/* USER CODE BEGIN PV */
+/* Private variables ---------------------------------------------------------*/
+
+/* USER CODE END PV */
+
+/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
+  * @{
+  */
+
+/** @addtogroup USBD_DESC
+  * @{
+  */
+
+/** @defgroup USBD_DESC_Private_TypesDefinitions USBD_DESC_Private_TypesDefinitions
+  * @brief Private types.
+  * @{
+  */
+
+/* USER CODE BEGIN PRIVATE_TYPES */
+
+/* USER CODE END PRIVATE_TYPES */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Private_Defines USBD_DESC_Private_Defines
+  * @brief Private defines.
+  * @{
+  */
+
+#define USBD_VID     1155
+#define USBD_LANGID_STRING     1033
+#define USBD_MANUFACTURER_STRING     "Flipper"
+#define USBD_PID     22336
+#define USBD_PRODUCT_STRING     "Flipper Control Virtual ComPort"
+#define USBD_CONFIGURATION_STRING     "CDC Config"
+#define USBD_INTERFACE_STRING     "CDC Interface"
+
+/* USER CODE BEGIN PRIVATE_DEFINES */
+
+/* USER CODE END PRIVATE_DEFINES */
+
+/**
+  * @}
+  */
+
+/* USER CODE BEGIN 0 */
+
+/* USER CODE END 0 */
+
+/** @defgroup USBD_DESC_Private_Macros USBD_DESC_Private_Macros
+  * @brief Private macros.
+  * @{
+  */
+
+/* USER CODE BEGIN PRIVATE_MACRO */
+
+/* USER CODE END PRIVATE_MACRO */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes
+  * @brief Private functions declaration.
+  * @{
+  */
+
+static void Get_SerialNum(void);
+static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len);
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Private_FunctionPrototypes USBD_DESC_Private_FunctionPrototypes
+  * @brief Private functions declaration.
+  * @{
+  */
+
+uint8_t * USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t * USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables
+  * @brief Private variables.
+  * @{
+  */
+
+USBD_DescriptorsTypeDef CDC_Desc =
+{
+  USBD_CDC_DeviceDescriptor,
+  USBD_CDC_LangIDStrDescriptor,
+  USBD_CDC_ManufacturerStrDescriptor,
+  USBD_CDC_ProductStrDescriptor,
+  USBD_CDC_SerialStrDescriptor,
+  USBD_CDC_ConfigStrDescriptor,
+  USBD_CDC_InterfaceStrDescriptor
+};
+
+#if defined ( __ICCARM__ ) /* IAR Compiler */
+  #pragma data_alignment=4
+#endif /* defined ( __ICCARM__ ) */
+/** USB standard device descriptor. */
+__ALIGN_BEGIN uint8_t USBD_CDC_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
+{
+  0x12,                       /*bLength */
+  USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/
+  0x00,                       /*bcdUSB */
+  0x02,
+  0x02,                       /*bDeviceClass*/
+  0x02,                       /*bDeviceSubClass*/
+  0x00,                       /*bDeviceProtocol*/
+  USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/
+  LOBYTE(USBD_VID),           /*idVendor*/
+  HIBYTE(USBD_VID),           /*idVendor*/
+  LOBYTE(USBD_PID),           /*idProduct*/
+  HIBYTE(USBD_PID),           /*idProduct*/
+  0x00,                       /*bcdDevice rel. 2.00*/
+  0x02,
+  USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
+  USBD_IDX_PRODUCT_STR,       /*Index of product string*/
+  USBD_IDX_SERIAL_STR,        /*Index of serial number string*/
+  USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/
+};
+
+/* USB_DeviceDescriptor */
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Private_Variables USBD_DESC_Private_Variables
+  * @brief Private variables.
+  * @{
+  */
+
+#if defined ( __ICCARM__ ) /* IAR Compiler */
+  #pragma data_alignment=4
+#endif /* defined ( __ICCARM__ ) */
+
+/** USB lang indentifier descriptor. */
+__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
+{
+     USB_LEN_LANGID_STR_DESC,
+     USB_DESC_TYPE_STRING,
+     LOBYTE(USBD_LANGID_STRING),
+     HIBYTE(USBD_LANGID_STRING)
+};
+
+#if defined ( __ICCARM__ ) /* IAR Compiler */
+  #pragma data_alignment=4
+#endif /* defined ( __ICCARM__ ) */
+/* Internal string descriptor. */
+__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
+
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4
+#endif
+__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = {
+  USB_SIZ_STRING_SERIAL,
+  USB_DESC_TYPE_STRING,
+};
+
+/**
+  * @}
+  */
+
+/** @defgroup USBD_DESC_Private_Functions USBD_DESC_Private_Functions
+  * @brief Private functions.
+  * @{
+  */
+
+/**
+  * @brief  Return the device descriptor
+  * @param  speed : Current device speed
+  * @param  length : Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t * USBD_CDC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  UNUSED(speed);
+  *length = sizeof(USBD_CDC_DeviceDesc);
+  return USBD_CDC_DeviceDesc;
+}
+
+/**
+  * @brief  Return the LangID string descriptor
+  * @param  speed : Current device speed
+  * @param  length : Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t * USBD_CDC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  UNUSED(speed);
+  *length = sizeof(USBD_LangIDDesc);
+  return USBD_LangIDDesc;
+}
+
+/**
+  * @brief  Return the product string descriptor
+  * @param  speed : Current device speed
+  * @param  length : Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t * USBD_CDC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == 0)
+  {
+    USBD_GetString((uint8_t *)USBD_PRODUCT_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)USBD_PRODUCT_STRING, USBD_StrDesc, length);
+  }
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Return the manufacturer string descriptor
+  * @param  speed : Current device speed
+  * @param  length : Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t * USBD_CDC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  UNUSED(speed);
+  USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Return the serial number string descriptor
+  * @param  speed : Current device speed
+  * @param  length : Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t * USBD_CDC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  UNUSED(speed);
+  *length = USB_SIZ_STRING_SERIAL;
+
+  /* Update the serial number string descriptor with the data from the unique
+   * ID */
+  Get_SerialNum();
+
+  /* USER CODE BEGIN USBD_CDC_SerialStrDescriptor */
+
+  /* USER CODE END USBD_CDC_SerialStrDescriptor */
+
+  return (uint8_t *) USBD_StringSerial;
+}
+
+/**
+  * @brief  Return the configuration string descriptor
+  * @param  speed : Current device speed
+  * @param  length : Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t * USBD_CDC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == USBD_SPEED_HIGH)
+  {
+    USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)USBD_CONFIGURATION_STRING, USBD_StrDesc, length);
+  }
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Return the interface string descriptor
+  * @param  speed : Current device speed
+  * @param  length : Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t * USBD_CDC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == 0)
+  {
+    USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)USBD_INTERFACE_STRING, USBD_StrDesc, length);
+  }
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Create the serial number string descriptor
+  * @param  None
+  * @retval None
+  */
+static void Get_SerialNum(void)
+{
+  uint32_t deviceserial0, deviceserial1, deviceserial2;
+
+  deviceserial0 = *(uint32_t *) DEVICE_ID1;
+  deviceserial1 = *(uint32_t *) DEVICE_ID2;
+  deviceserial2 = *(uint32_t *) DEVICE_ID3;
+
+  deviceserial0 += deviceserial2;
+
+  if (deviceserial0 != 0)
+  {
+    IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8);
+    IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4);
+  }
+}
+
+/**
+  * @brief  Convert Hex 32Bits value into char
+  * @param  value: value to convert
+  * @param  pbuf: pointer to the buffer
+  * @param  len: buffer length
+  * @retval None
+  */
+static void IntToUnicode(uint32_t value, uint8_t * pbuf, uint8_t len)
+{
+  uint8_t idx = 0;
+
+  for (idx = 0; idx < len; idx++)
+  {
+    if (((value >> 28)) < 0xA)
+    {
+      pbuf[2 * idx] = (value >> 28) + '0';
+    }
+    else
+    {
+      pbuf[2 * idx] = (value >> 28) + 'A' - 10;
+    }
+
+    value = value << 4;
+
+    pbuf[2 * idx + 1] = 0;
+  }
+}
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 13 - 0
firmware/targets/f5/api-hal/api-hal-boot.c

@@ -0,0 +1,13 @@
+#include <api-hal-boot.h>
+#include <stm32wbxx_ll_rtc.h>
+
+#define BOOT_REQUEST_NONE 0x00000000
+#define BOOT_REQUEST_DFU 0xDF00B000
+
+void api_hal_boot_set_mode(ApiHalBootMode mode) {
+    if (mode == ApiHalBootModeNormal) {
+        LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_NONE);
+    } else if (mode == ApiHalBootModeDFU) {
+        LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_DFU);
+    }
+}

+ 78 - 0
firmware/targets/f5/api-hal/api-hal-bt.c

@@ -0,0 +1,78 @@
+#include <api-hal-bt.h>
+#include <app_entry.h>
+#include <ble.h>
+#include <stm32wbxx.h>
+#include <shci.h>
+#include <cmsis_os2.h>
+
+void api_hal_bt_init() {
+    // Explicitly tell that we are in charge of CLK48 domain
+    HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID);
+    // Start Core2, init HCI and start GAP/GATT
+    APPE_Init();
+}
+
+void api_hal_bt_dump_state(string_t buffer) {
+    BleGlueStatus status = APPE_Status();
+    if (status == BleGlueStatusStarted) {
+        uint8_t HCI_Version;
+        uint16_t HCI_Revision;
+        uint8_t LMP_PAL_Version;
+        uint16_t Manufacturer_Name;
+        uint16_t LMP_PAL_Subversion;
+
+        tBleStatus ret = hci_read_local_version_information(
+            &HCI_Version, &HCI_Revision, &LMP_PAL_Version, &Manufacturer_Name, &LMP_PAL_Subversion
+        );
+
+        string_cat_printf(buffer,
+            "Ret: %d, HCI_Version: %d, HCI_Revision: %d, LMP_PAL_Version: %d, Manufacturer_Name: %d, LMP_PAL_Subversion: %d",
+            ret, HCI_Version, HCI_Revision, LMP_PAL_Version, Manufacturer_Name, LMP_PAL_Subversion
+        );
+    } else {
+        string_cat_printf(buffer, "BLE not ready");
+    }
+}
+
+bool api_hal_bt_is_alive() {
+    return APPE_Status() == BleGlueStatusStarted;
+}
+
+bool api_hal_bt_wait_transition() {
+    uint8_t counter = 0;
+    while (APPE_Status() == BleGlueStatusStartup) {
+        osDelay(10);
+        counter++;
+        if (counter > 1000) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool api_hal_bt_lock_flash() {
+    if (!api_hal_bt_wait_transition()) {
+        return false;
+    }
+    if (APPE_Status() == BleGlueStatusUninitialized) {
+        HAL_FLASH_Unlock();
+    } else {
+        while (HAL_HSEM_FastTake(CFG_HW_FLASH_SEMID) != HAL_OK) {
+            osDelay(1);
+        }
+        SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON);
+        HAL_FLASH_Unlock();
+        while(LL_FLASH_IsOperationSuspended()) {};
+    }
+    return true;
+}
+
+void api_hal_bt_unlock_flash() {
+    if (APPE_Status() == BleGlueStatusUninitialized) {
+        HAL_FLASH_Lock();
+    } else {
+        SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_OFF);
+        HAL_FLASH_Lock();
+        HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID);
+    }
+}

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