Bladeren bron

BleGlue: reorder initialization sequence, move core2 start to early stage. (#816)

あく 4 jaren geleden
bovenliggende
commit
b2356c7318

+ 74 - 19
firmware/targets/f6/ble-glue/ble_glue.c

@@ -19,6 +19,16 @@ PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ble_glue_system_cmd_b
 PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_system_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U];
 PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255];
 
+typedef enum {
+    // Stage 1: core2 startup and FUS
+    BleGlueStatusStartup,
+    BleGlueStatusBroken,
+    BleGlueStatusFusStarted,
+    // Stage 2: radio stack
+    BleGlueStatusRadioStackStarted,
+    BleGlueStatusRadioStackMissing
+} BleGlueStatus;
+
 typedef struct {
     osMutexId_t shci_mtx;
     osSemaphoreId_t shci_sem;
@@ -35,13 +45,6 @@ static void ble_glue_user_event_thread(void *argument);
 static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status);
 static void ble_glue_sys_user_event_callback(void* pPayload);
 
-BleGlueStatus ble_glue_get_status() {
-    if(!ble_glue) {
-        return BleGlueStatusUninitialized;
-    }
-    return ble_glue->status;
-}
-
 void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context) {
     furi_assert(ble_glue);
     furi_assert(callback);
@@ -96,6 +99,68 @@ void ble_glue_init() {
      */
 }
 
+static bool ble_glue_wait_status(BleGlueStatus status) {
+    bool ret = false;
+    size_t countdown = 1000;
+    while (countdown > 0) {
+        if (ble_glue->status == status) {
+            ret = true;
+            break;
+        }
+        countdown--;
+        osDelay(1);
+    }
+    return ret;
+}
+
+bool ble_glue_start() {
+    furi_assert(ble_glue);
+
+    if (!ble_glue_wait_status(BleGlueStatusFusStarted)) {
+        // shutdown core2 power
+        FURI_LOG_E(TAG, "Core2 catastrophic failure, cutting its power");
+        LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
+        ble_glue->status = BleGlueStatusBroken;
+        furi_hal_power_insomnia_exit();
+        return false;
+    }
+
+    bool ret = false;
+    furi_hal_power_insomnia_enter();
+    if(ble_app_init()) {
+        FURI_LOG_I(TAG, "Radio stack started");
+        ble_glue->status = BleGlueStatusRadioStackStarted;
+        ret = true;
+        if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) {
+            FURI_LOG_I(TAG, "Flash activity control switched to SEM7");
+        } else {
+            FURI_LOG_E(TAG, "Failed to switch flash activity control to SEM7");
+        }
+    } else {
+        FURI_LOG_E(TAG, "Radio stack startup failed");
+        ble_glue->status = BleGlueStatusRadioStackMissing;
+    }
+    furi_hal_power_insomnia_exit();
+
+    return ret;
+}
+
+bool ble_glue_is_alive() {
+    if(!ble_glue) {
+        return false;
+    }
+
+    return ble_glue->status >= BleGlueStatusFusStarted;
+}
+
+bool ble_glue_is_radio_stack_ready() {
+    if(!ble_glue) {
+        return false;
+    }
+
+    return ble_glue->status == BleGlueStatusRadioStackStarted;
+}
+
 static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) {
     switch (status) {
     case SHCI_TL_CmdBusy:
@@ -126,18 +191,8 @@ static void ble_glue_sys_user_event_callback( void * pPayload ) {
     TL_AsynchEvt_t *p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload);
     
     if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) {
-        if(ble_app_init()) {
-            FURI_LOG_I(TAG, "BLE stack started");
-            ble_glue->status = BleGlueStatusStarted;
-            if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) {
-                FURI_LOG_I(TAG, "Flash activity control switched to SEM7");
-            } else {
-                FURI_LOG_E(TAG, "Failed to switch flash activity control to SEM7");
-            }
-        } else {
-            FURI_LOG_E(TAG, "BLE stack startup failed");
-            ble_glue->status = BleGlueStatusBleStackMissing;
-        }
+        FURI_LOG_I(TAG, "Fus started");
+        ble_glue->status = BleGlueStatusFusStarted;
         furi_hal_power_insomnia_exit();
     } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_ERROR_NOTIF) {
         FURI_LOG_E(TAG, "Error during initialization");

+ 25 - 8
firmware/targets/f6/ble-glue/ble_glue.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <stdint.h>
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -8,17 +9,33 @@ extern "C" {
 
 typedef void(*BleGlueKeyStorageChangedCallback)(uint8_t* change_addr_start, uint16_t size, void* context);
 
-typedef enum {
-    BleGlueStatusUninitialized,
-    BleGlueStatusStartup,
-    BleGlueStatusBleStackMissing,
-    BleGlueStatusStarted
-} BleGlueStatus;
 
+/** Initialize start core2 and initialize transport */
 void ble_glue_init();
 
-BleGlueStatus ble_glue_get_status();
-
+/** Start Core2 Radio stack
+ *
+ * @return     true on success
+ */
+bool ble_glue_start();
+
+/** Is core2 alive and at least FUS is running
+ * 
+ * @return     true if core2 is alive
+ */
+bool ble_glue_is_alive();
+
+/** Is core2 radio stack present and ready
+ *
+ * @return     true if present and ready
+ */
+bool ble_glue_is_radio_stack_ready();
+
+/** Set callback for NVM in RAM changes
+ *
+ * @param[in]  callback  The callback to call on NVM change
+ * @param      context   The context for callback
+ */
 void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context);
 
 #ifdef __cplusplus

+ 1 - 1
firmware/targets/f6/ble-glue/gap.c

@@ -374,7 +374,7 @@ static void gap_advetise_timer_callback(void* context) {
 }
 
 bool gap_init(BleEventCallback on_event_cb, void* context) {
-    if (ble_glue_get_status() != BleGlueStatusStarted) {
+    if (!ble_glue_is_radio_stack_ready()) {
         return false;
     }
 

+ 15 - 28
firmware/targets/f6/furi-hal/furi-hal-bt.c

@@ -6,10 +6,19 @@
 
 #include <furi.h>
 
+#define TAG "FuriHalBt"
+
 osMutexId_t furi_hal_bt_core2_mtx = NULL;
 
 void furi_hal_bt_init() {
     furi_hal_bt_core2_mtx = osMutexNew(NULL);
+    furi_assert(furi_hal_bt_core2_mtx);
+
+    // Explicitly tell that we are in charge of CLK48 domain
+    HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID);
+
+    // Start Core2
+    ble_glue_init();
 }
 
 void furi_hal_bt_lock_core2() {
@@ -22,30 +31,16 @@ void furi_hal_bt_unlock_core2() {
     furi_check(osMutexRelease(furi_hal_bt_core2_mtx) == osOK);
 }
 
-static bool furi_hal_bt_wait_startup() {
-    uint16_t counter = 0;
-    while (!(ble_glue_get_status() == BleGlueStatusStarted || ble_glue_get_status() == BleGlueStatusBleStackMissing)) {
-        osDelay(10);
-        counter++;
-        if (counter > 1000) {
-            return false;
-        }
-    }
-    return true;
-}
-
 bool furi_hal_bt_start_core2() {
     furi_assert(furi_hal_bt_core2_mtx);
 
-    bool ret = false;
     osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever);
     // Explicitly tell that we are in charge of CLK48 domain
     HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID);
     // Start Core2
-    ble_glue_init();
-    // Wait for Core2 start
-    ret = furi_hal_bt_wait_startup();
+    bool ret = ble_glue_start();
     osMutexRelease(furi_hal_bt_core2_mtx);
+
     return ret;
 }
 
@@ -84,14 +79,8 @@ bool furi_hal_bt_tx(uint8_t* data, uint16_t size) {
     return serial_svc_update_tx(data, size);
 }
 
-bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) {
-    bool ret = false;
-    BleGlueStatus status = ble_glue_get_status();
-    if(status == BleGlueStatusUninitialized || BleGlueStatusStarted) {
-        ble_app_get_key_storage_buff(key_buff_addr, key_buff_size);
-        ret = true;
-    }
-    return ret;
+void furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) {
+    ble_app_get_key_storage_buff(key_buff_addr, key_buff_size);
 }
 
 void furi_hal_bt_set_key_storage_change_callback(BleGlueKeyStorageChangedCallback callback, void* context) {
@@ -110,8 +99,7 @@ void furi_hal_bt_nvm_sram_sem_release() {
 }
 
 void furi_hal_bt_dump_state(string_t buffer) {
-    BleGlueStatus status = ble_glue_get_status();
-    if (status == BleGlueStatusStarted) {
+    if (furi_hal_bt_is_alive()) {
         uint8_t HCI_Version;
         uint16_t HCI_Revision;
         uint8_t LMP_PAL_Version;
@@ -132,8 +120,7 @@ void furi_hal_bt_dump_state(string_t buffer) {
 }
 
 bool furi_hal_bt_is_alive() {
-    BleGlueStatus status = ble_glue_get_status();
-    return (status == BleGlueStatusBleStackMissing) || (status == BleGlueStatusStarted);
+    return ble_glue_is_alive();
 }
 
 bool furi_hal_bt_is_active() {

+ 2 - 4
firmware/targets/f6/furi-hal/furi-hal-flash.c

@@ -127,8 +127,7 @@ static void furi_hal_flash_begin(bool erase_flag) {
     furi_hal_bt_lock_core2();
 
     // If Core2 is running use IPC locking
-    BleGlueStatus status = ble_glue_get_status();
-    if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) {
+    if(furi_hal_bt_is_alive()) {
         furi_hal_flash_begin_with_core2(erase_flag);
     } else { 
         furi_hal_flash_unlock();
@@ -159,8 +158,7 @@ static void furi_hal_flash_end_with_core2(bool erase_flag) {
 
 static void furi_hal_flash_end(bool erase_flag) {
     // If Core2 is running use IPC locking
-    BleGlueStatus status = ble_glue_get_status();
-    if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) {
+    if(furi_hal_bt_is_alive()) {
         furi_hal_flash_end_with_core2(erase_flag);
     } else { 
         furi_hal_flash_lock();

+ 74 - 19
firmware/targets/f7/ble-glue/ble_glue.c

@@ -19,6 +19,16 @@ PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t ble_glue_system_cmd_b
 PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_system_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U];
 PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t ble_glue_ble_spare_event_buff[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255];
 
+typedef enum {
+    // Stage 1: core2 startup and FUS
+    BleGlueStatusStartup,
+    BleGlueStatusBroken,
+    BleGlueStatusFusStarted,
+    // Stage 2: radio stack
+    BleGlueStatusRadioStackStarted,
+    BleGlueStatusRadioStackMissing
+} BleGlueStatus;
+
 typedef struct {
     osMutexId_t shci_mtx;
     osSemaphoreId_t shci_sem;
@@ -35,13 +45,6 @@ static void ble_glue_user_event_thread(void *argument);
 static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status);
 static void ble_glue_sys_user_event_callback(void* pPayload);
 
-BleGlueStatus ble_glue_get_status() {
-    if(!ble_glue) {
-        return BleGlueStatusUninitialized;
-    }
-    return ble_glue->status;
-}
-
 void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context) {
     furi_assert(ble_glue);
     furi_assert(callback);
@@ -96,6 +99,68 @@ void ble_glue_init() {
      */
 }
 
+static bool ble_glue_wait_status(BleGlueStatus status) {
+    bool ret = false;
+    size_t countdown = 1000;
+    while (countdown > 0) {
+        if (ble_glue->status == status) {
+            ret = true;
+            break;
+        }
+        countdown--;
+        osDelay(1);
+    }
+    return ret;
+}
+
+bool ble_glue_start() {
+    furi_assert(ble_glue);
+
+    if (!ble_glue_wait_status(BleGlueStatusFusStarted)) {
+        // shutdown core2 power
+        FURI_LOG_E(TAG, "Core2 catastrophic failure, cutting its power");
+        LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
+        ble_glue->status = BleGlueStatusBroken;
+        furi_hal_power_insomnia_exit();
+        return false;
+    }
+
+    bool ret = false;
+    furi_hal_power_insomnia_enter();
+    if(ble_app_init()) {
+        FURI_LOG_I(TAG, "Radio stack started");
+        ble_glue->status = BleGlueStatusRadioStackStarted;
+        ret = true;
+        if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) {
+            FURI_LOG_I(TAG, "Flash activity control switched to SEM7");
+        } else {
+            FURI_LOG_E(TAG, "Failed to switch flash activity control to SEM7");
+        }
+    } else {
+        FURI_LOG_E(TAG, "Radio stack startup failed");
+        ble_glue->status = BleGlueStatusRadioStackMissing;
+    }
+    furi_hal_power_insomnia_exit();
+
+    return ret;
+}
+
+bool ble_glue_is_alive() {
+    if(!ble_glue) {
+        return false;
+    }
+
+    return ble_glue->status >= BleGlueStatusFusStarted;
+}
+
+bool ble_glue_is_radio_stack_ready() {
+    if(!ble_glue) {
+        return false;
+    }
+
+    return ble_glue->status == BleGlueStatusRadioStackStarted;
+}
+
 static void ble_glue_sys_status_not_callback(SHCI_TL_CmdStatus_t status) {
     switch (status) {
     case SHCI_TL_CmdBusy:
@@ -126,18 +191,8 @@ static void ble_glue_sys_user_event_callback( void * pPayload ) {
     TL_AsynchEvt_t *p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload);
     
     if(p_sys_event->subevtcode == SHCI_SUB_EVT_CODE_READY) {
-        if(ble_app_init()) {
-            FURI_LOG_I(TAG, "BLE stack started");
-            ble_glue->status = BleGlueStatusStarted;
-            if(SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7) == SHCI_Success) {
-                FURI_LOG_I(TAG, "Flash activity control switched to SEM7");
-            } else {
-                FURI_LOG_E(TAG, "Failed to switch flash activity control to SEM7");
-            }
-        } else {
-            FURI_LOG_E(TAG, "BLE stack startup failed");
-            ble_glue->status = BleGlueStatusBleStackMissing;
-        }
+        FURI_LOG_I(TAG, "Fus started");
+        ble_glue->status = BleGlueStatusFusStarted;
         furi_hal_power_insomnia_exit();
     } else if(p_sys_event->subevtcode == SHCI_SUB_EVT_ERROR_NOTIF) {
         FURI_LOG_E(TAG, "Error during initialization");

+ 25 - 8
firmware/targets/f7/ble-glue/ble_glue.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <stdint.h>
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -8,17 +9,33 @@ extern "C" {
 
 typedef void(*BleGlueKeyStorageChangedCallback)(uint8_t* change_addr_start, uint16_t size, void* context);
 
-typedef enum {
-    BleGlueStatusUninitialized,
-    BleGlueStatusStartup,
-    BleGlueStatusBleStackMissing,
-    BleGlueStatusStarted
-} BleGlueStatus;
 
+/** Initialize start core2 and initialize transport */
 void ble_glue_init();
 
-BleGlueStatus ble_glue_get_status();
-
+/** Start Core2 Radio stack
+ *
+ * @return     true on success
+ */
+bool ble_glue_start();
+
+/** Is core2 alive and at least FUS is running
+ * 
+ * @return     true if core2 is alive
+ */
+bool ble_glue_is_alive();
+
+/** Is core2 radio stack present and ready
+ *
+ * @return     true if present and ready
+ */
+bool ble_glue_is_radio_stack_ready();
+
+/** Set callback for NVM in RAM changes
+ *
+ * @param[in]  callback  The callback to call on NVM change
+ * @param      context   The context for callback
+ */
 void ble_glue_set_key_storage_changed_callback(BleGlueKeyStorageChangedCallback callback, void* context);
 
 #ifdef __cplusplus

+ 1 - 1
firmware/targets/f7/ble-glue/gap.c

@@ -374,7 +374,7 @@ static void gap_advetise_timer_callback(void* context) {
 }
 
 bool gap_init(BleEventCallback on_event_cb, void* context) {
-    if (ble_glue_get_status() != BleGlueStatusStarted) {
+    if (!ble_glue_is_radio_stack_ready()) {
         return false;
     }
 

+ 15 - 28
firmware/targets/f7/furi-hal/furi-hal-bt.c

@@ -6,10 +6,19 @@
 
 #include <furi.h>
 
+#define TAG "FuriHalBt"
+
 osMutexId_t furi_hal_bt_core2_mtx = NULL;
 
 void furi_hal_bt_init() {
     furi_hal_bt_core2_mtx = osMutexNew(NULL);
+    furi_assert(furi_hal_bt_core2_mtx);
+
+    // Explicitly tell that we are in charge of CLK48 domain
+    HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID);
+
+    // Start Core2
+    ble_glue_init();
 }
 
 void furi_hal_bt_lock_core2() {
@@ -22,30 +31,16 @@ void furi_hal_bt_unlock_core2() {
     furi_check(osMutexRelease(furi_hal_bt_core2_mtx) == osOK);
 }
 
-static bool furi_hal_bt_wait_startup() {
-    uint16_t counter = 0;
-    while (!(ble_glue_get_status() == BleGlueStatusStarted || ble_glue_get_status() == BleGlueStatusBleStackMissing)) {
-        osDelay(10);
-        counter++;
-        if (counter > 1000) {
-            return false;
-        }
-    }
-    return true;
-}
-
 bool furi_hal_bt_start_core2() {
     furi_assert(furi_hal_bt_core2_mtx);
 
-    bool ret = false;
     osMutexAcquire(furi_hal_bt_core2_mtx, osWaitForever);
     // Explicitly tell that we are in charge of CLK48 domain
     HAL_HSEM_FastTake(CFG_HW_CLK48_CONFIG_SEMID);
     // Start Core2
-    ble_glue_init();
-    // Wait for Core2 start
-    ret = furi_hal_bt_wait_startup();
+    bool ret = ble_glue_start();
     osMutexRelease(furi_hal_bt_core2_mtx);
+
     return ret;
 }
 
@@ -84,14 +79,8 @@ bool furi_hal_bt_tx(uint8_t* data, uint16_t size) {
     return serial_svc_update_tx(data, size);
 }
 
-bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) {
-    bool ret = false;
-    BleGlueStatus status = ble_glue_get_status();
-    if(status == BleGlueStatusUninitialized || BleGlueStatusStarted) {
-        ble_app_get_key_storage_buff(key_buff_addr, key_buff_size);
-        ret = true;
-    }
-    return ret;
+void furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size) {
+    ble_app_get_key_storage_buff(key_buff_addr, key_buff_size);
 }
 
 void furi_hal_bt_set_key_storage_change_callback(BleGlueKeyStorageChangedCallback callback, void* context) {
@@ -110,8 +99,7 @@ void furi_hal_bt_nvm_sram_sem_release() {
 }
 
 void furi_hal_bt_dump_state(string_t buffer) {
-    BleGlueStatus status = ble_glue_get_status();
-    if (status == BleGlueStatusStarted) {
+    if (furi_hal_bt_is_alive()) {
         uint8_t HCI_Version;
         uint16_t HCI_Revision;
         uint8_t LMP_PAL_Version;
@@ -132,8 +120,7 @@ void furi_hal_bt_dump_state(string_t buffer) {
 }
 
 bool furi_hal_bt_is_alive() {
-    BleGlueStatus status = ble_glue_get_status();
-    return (status == BleGlueStatusBleStackMissing) || (status == BleGlueStatusStarted);
+    return ble_glue_is_alive();
 }
 
 bool furi_hal_bt_is_active() {

+ 2 - 4
firmware/targets/f7/furi-hal/furi-hal-flash.c

@@ -127,8 +127,7 @@ static void furi_hal_flash_begin(bool erase_flag) {
     furi_hal_bt_lock_core2();
 
     // If Core2 is running use IPC locking
-    BleGlueStatus status = ble_glue_get_status();
-    if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) {
+    if(furi_hal_bt_is_alive()) {
         furi_hal_flash_begin_with_core2(erase_flag);
     } else { 
         furi_hal_flash_unlock();
@@ -159,8 +158,7 @@ static void furi_hal_flash_end_with_core2(bool erase_flag) {
 
 static void furi_hal_flash_end(bool erase_flag) {
     // If Core2 is running use IPC locking
-    BleGlueStatus status = ble_glue_get_status();
-    if(status == BleGlueStatusStarted || status == BleGlueStatusBleStackMissing) {
+    if(furi_hal_bt_is_alive()) {
         furi_hal_flash_end_with_core2(erase_flag);
     } else { 
         furi_hal_flash_lock();

+ 3 - 5
firmware/targets/furi-hal-include/furi-hal-bt.h

@@ -69,12 +69,10 @@ bool furi_hal_bt_is_alive();
 
 /** Get key storage buffer address and size
  *
- * @param       key_buff_addr   pointer to store buffer address
- * @param       key_buff_size   pointer to store buffer size
- *
- * @return      true on success
+ * @param      key_buff_addr  pointer to store buffer address
+ * @param      key_buff_size  pointer to store buffer size
  */
-bool furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size);
+void furi_hal_bt_get_key_storage_buff(uint8_t** key_buff_addr, uint16_t* key_buff_size);
 
 /** Get SRAM2 hardware semaphore
  * @note Must be called before SRAM2 read/write operations