[Silabs] Add deep sleep support for EM4 samples apps (#41487)
* PoC EM4
* Apply comments
diff --git a/examples/platform/silabs/FreeRTOSConfig.h b/examples/platform/silabs/FreeRTOSConfig.h
index 29f56a6..ca07807 100644
--- a/examples/platform/silabs/FreeRTOSConfig.h
+++ b/examples/platform/silabs/FreeRTOSConfig.h
@@ -128,6 +128,10 @@
#include "SEGGER_SYSVIEW_FreeRTOS.h"
#endif
+#if defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
+void sl_matter_em4_check(uint32_t expected_idle_time_ms);
+#endif // defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
+
/*-----------------------------------------------------------
* Application specific definitions.
*
@@ -143,6 +147,9 @@
/* Energy saving modes. */
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#define configUSE_TICKLESS_IDLE 1
+#if defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
+#define configPRE_SLEEP_PROCESSING(x) sl_matter_em4_check(x)
+#endif // defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
#elif (SLI_SI91X_MCU_INTERFACE && SL_ICD_ENABLED)
#define configUSE_TICKLESS_IDLE 1
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 70
diff --git a/examples/platform/silabs/MatterConfig.cpp b/examples/platform/silabs/MatterConfig.cpp
index 064d65f..9e16231 100644
--- a/examples/platform/silabs/MatterConfig.cpp
+++ b/examples/platform/silabs/MatterConfig.cpp
@@ -24,6 +24,17 @@
#include <mbedtls/platform.h>
+#if CHIP_CONFIG_ENABLE_ICD_SERVER
+#if defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
+#include "sl_sleeptimer.h"
+#include <app/icd/server/ICDConfigurationData.h> // nogncheck
+
+#include "em_burtc.h"
+#include "em_cmu.h"
+#include "em_emu.h"
+#endif // defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
+#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
+
#ifdef SL_WIFI
#include <platform/silabs/NetworkCommissioningWiFiDriver.h>
#include <platform/silabs/wifi/WifiInterface.h> // nogncheck
@@ -339,9 +350,35 @@
return CHIP_NO_ERROR;
}
+#if defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
+void OnEM4Trigger(uint32_t duration)
+{
+ CMU_ClockSelectSet(cmuClock_EM4GRPACLK, cmuSelect_ULFRCO);
+ CMU_ClockEnable(cmuClock_BURTC, true);
+ CMU_ClockEnable(cmuClock_BURAM, true);
+
+ BURTC_Init_TypeDef burtcInit = BURTC_INIT_DEFAULT;
+ burtcInit.compare0Top = true; // reset counter when counter reaches compare value
+ burtcInit.em4comp = true; // BURTC compare interrupt wakes from EM4 (causes reset)
+ BURTC_Init(&burtcInit);
+
+ BURTC_CounterReset();
+ BURTC_CompareSet(0, duration);
+
+ BURTC_IntEnable(BURTC_IEN_COMP); // compare match
+ NVIC_EnableIRQ(BURTC_IRQn);
+ BURTC_Enable(true);
+ EMU_EM4Init_TypeDef em4Init = EMU_EM4INIT_DEFAULT;
+ EMU_EM4Init(&em4Init);
+ BURTC_CounterReset();
+ EMU_EnterEM4();
+}
+
+#endif // defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
// ================================================================================
// FreeRTOS Callbacks
// ================================================================================
+
extern "C" void vApplicationIdleHook(void)
{
#if (SLI_SI91X_MCU_INTERFACE && CHIP_CONFIG_ENABLE_ICD_SERVER)
@@ -351,3 +388,30 @@
SiWxPlatformInterface::sl_si91x_uart_power_requirement_handler();
#endif
}
+
+#if CHIP_CONFIG_ENABLE_ICD_SERVER
+#if defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
+
+#ifndef SL_MATTER_EM4_THRESHOLD_PERCENTAGE
+#define SL_MATTER_EM4_THRESHOLD_PERCENTAGE 90
+#endif
+
+static_assert(SL_MATTER_EM4_THRESHOLD_PERCENTAGE > 0 && SL_MATTER_EM4_THRESHOLD_PERCENTAGE < 100,
+ "SL_MATTER_EM4_THRESHOLD_PERCENTAGE must be between 1 and 99");
+
+extern "C" void sl_matter_em4_check(uint32_t expected_idle_time_ms)
+{
+ if (chip::ICDConfigurationData::GetInstance().GetICDMode() == chip::ICDConfigurationData::ICDMode::LIT)
+ {
+ uint32_t idleDuration_seconds = chip::ICDConfigurationData::GetInstance().GetIdleModeDuration().count();
+ uint32_t threshold_ms = idleDuration_seconds * SL_EM4_THRESHOLD_PERCENTAGE * 10;
+ // Since the sleep timer will never match the actual idle time (hardware latency, etc), we set a threshold
+ // Multiply by 10 to converts seconds into milliseconds (e.g. 90% of 1000sec in ms is 1000*90*10 = 900000ms)
+ if (expected_idle_time_ms >= threshold_ms)
+ {
+ OnEM4Trigger(expected_idle_time_ms);
+ }
+ }
+}
+#endif // defined(SL_MATTER_EM4_SLEEP) && (SL_MATTER_EM4_SLEEP == 1)
+#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni
index 29158aa..1e2bfcc 100644
--- a/third_party/silabs/efr32_sdk.gni
+++ b/third_party/silabs/efr32_sdk.gni
@@ -91,6 +91,8 @@
sl_enable_test_event_trigger = false
sl_verbose_mode = false
+
+ sl_em4_sleep = false
}
examples_plat_dir = "${chip_root}/examples/platform/silabs/efr32"
@@ -490,6 +492,7 @@
"SL_CODE_COMPONENT_OPENTHREAD=openthread",
"SL_CODE_COMPONENT_INTERRUPT_MANAGER=interrupt_manager",
"SL_APP_PROPERTIES",
+ "SL_MATTER_EM4_SLEEP=${sl_em4_sleep}",
]
if (silabs_log_enabled && chip_logging) {
@@ -723,6 +726,7 @@
"${efr32_sdk_root}/platform/emdrv/nvm3/src/nvm3_object.c",
"${efr32_sdk_root}/platform/emdrv/nvm3/src/nvm3_page.c",
"${efr32_sdk_root}/platform/emdrv/nvm3/src/nvm3_utils.c",
+ "${efr32_sdk_root}/platform/emlib/src/em_burtc.c",
"${efr32_sdk_root}/platform/emlib/src/em_cmu.c",
"${efr32_sdk_root}/platform/emlib/src/em_crypto.c",
"${efr32_sdk_root}/platform/emlib/src/em_emu.c",