diff --git a/config/telink/chip-module/Kconfig.defaults b/config/telink/chip-module/Kconfig.defaults index dd51a307b3deac..98f28a87c921a7 100644 --- a/config/telink/chip-module/Kconfig.defaults +++ b/config/telink/chip-module/Kconfig.defaults @@ -296,6 +296,10 @@ config EXPOSE_CHIP_ID_VIA_BLE bool "Get CHIP ID via ble" default n +config STARTUP_OPTIMIZATE + bool "Control startup speed optimization" + default n + # Set multiplicator of Name Value Storage (NVS) as 1 to reach NVS sector size 4KB # nvs_sector_size = flash_page_size * mult = 4KB * 1 = 4KB config SETTINGS_NVS_SECTOR_SIZE_MULT diff --git a/examples/lighting-app/telink/src/ZclCallbacks.cpp b/examples/lighting-app/telink/src/ZclCallbacks.cpp index 09745e419e8b83..47048648ccda6d 100644 --- a/examples/lighting-app/telink/src/ZclCallbacks.cpp +++ b/examples/lighting-app/telink/src/ZclCallbacks.cpp @@ -30,6 +30,47 @@ LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); using namespace chip; using namespace chip::app::Clusters; +#if CONFIG_STARTUP_OPTIMIZATE +#include "AppTaskCommon.h" + +static uint8_t latest_level = 0; +#define CLUTER_SOTRE_TIMEOUT 500 +#define TRANSTION_TIMER_INIT_FLAG 0x55 +#define TRANSTION_TIMER_DEINIT_FLAG 0x00 + +struct k_timer LevelChangeTimer; +static int timer_period = CLUTER_SOTRE_TIMEOUT; +static uint8_t init_timer = TRANSTION_TIMER_INIT_FLAG; + +static void LevelTimeoutCallback(struct k_timer * timer) +{ + if (!timer) + { + return; + } + + cluster_startup_para cluster_para; + if (read_cluster_para(&cluster_para) != 0) + { + if (uart_init_flag) + { + printk("[LevelTimeoutCallback] Fail read startup cluster para\n"); + } + } + if (cluster_para.level != latest_level) + { + cluster_para.level = latest_level; + if (store_cluster_para(&cluster_para) != 0) + { + if (uart_init_flag) + { + printk("[LevelTimeoutCallback] Fail store startup cluster para\n"); + } + } + } +} +#endif // CONFIG_STARTUP_OPTIMIZATE + void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, uint8_t * value) { @@ -40,6 +81,43 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & ChipLogProgress(Zcl, "========MatterPostAttributeChangeCallback:clusterId=0x%x,AttributeId=0x%x,value=0x%x", clusterId, attributeId, *value); +#if CONFIG_STARTUP_OPTIMIZATE + if (init_timer == TRANSTION_TIMER_INIT_FLAG) + { + k_timer_init(&LevelChangeTimer, &LevelTimeoutCallback, nullptr); + init_timer = TRANSTION_TIMER_DEINIT_FLAG; + } + + if (clusterId == OnOff::Id && attributeId == OnOff::Attributes::OnOff::Id) + { + cluster_startup_para cluster_para; + if (read_cluster_para(&cluster_para) != 0) + { + if (uart_init_flag) + { + printk("[clusterId:OnOff] Fail read startup cluster para\n"); + } + } + if (cluster_para.onoff != *value) + { + cluster_para.onoff = *value; + if (store_cluster_para(&cluster_para) != 0) + { + if (uart_init_flag) + { + printk("[clusterId:OnOff] Fail store startup cluster para\n"); + } + } + } + } + else if (clusterId == LevelControl::Id && attributeId == LevelControl::Attributes::CurrentLevel::Id) + { + latest_level = *value; + k_timer_stop(&LevelChangeTimer); + k_timer_start(&LevelChangeTimer, K_MSEC(timer_period), K_NO_WAIT); + } +#endif // CONFIG_STARTUP_OPTIMIZATE + #else static HsvColor_t hsv; static XyColor_t xy; diff --git a/examples/platform/telink/common/include/AppTaskCommon.h b/examples/platform/telink/common/include/AppTaskCommon.h index 59772588460f14..dd504131d1f194 100644 --- a/examples/platform/telink/common/include/AppTaskCommon.h +++ b/examples/platform/telink/common/include/AppTaskCommon.h @@ -94,6 +94,28 @@ extern uint8_t para_lightness; extern uint8_t sBoot_zb; #endif +#if CONFIG_STARTUP_OPTIMIZATE +#define USER_CLUSTER_PARTITION user_cluster_partition +#define USER_CLUSTER_PARTITION_DEVICE FIXED_PARTITION_DEVICE(USER_CLUSTER_PARTITION) +#define USER_CLUSTER_PARTITION_OFFSET FIXED_PARTITION_OFFSET(USER_CLUSTER_PARTITION) +#define USER_CLUSTER_PARTITION_SIZE FIXED_PARTITION_SIZE(USER_CLUSTER_PARTITION) + +typedef struct +{ + uint8_t onoff; + uint8_t level; + uint8_t rfu[30]; +} cluster_startup_para; + +extern volatile bool uart_init_flag; + +void set_debug_flag(bool flag); +volatile bool read_debug_flag(void); +void init_cluster_partition(void); +int store_cluster_para(cluster_startup_para * data); +int read_cluster_para(cluster_startup_para * data); +#endif // CONFIG_STARTUP_OPTIMIZATE + #include using namespace ::chip; diff --git a/examples/platform/telink/common/src/AppTaskCommon.cpp b/examples/platform/telink/common/src/AppTaskCommon.cpp index c3eb105f5cd114..8f6a6e8e64968c 100644 --- a/examples/platform/telink/common/src/AppTaskCommon.cpp +++ b/examples/platform/telink/common/src/AppTaskCommon.cpp @@ -142,6 +142,130 @@ class AppCallbacks : public AppDelegate AppCallbacks sCallbacks; } // namespace +#if CONFIG_STARTUP_OPTIMIZATE +volatile bool uart_init_flag = false; +const struct device * cluster_para_dev = USER_CLUSTER_PARTITION_DEVICE; + +uint32_t cluster_para_addr = USER_CLUSTER_PARTITION_OFFSET; +#define CLUSTER_PARA_LEN (sizeof(cluster_startup_para)) +#define USER_CLUSTER_PARTITION_END (USER_CLUSTER_PARTITION_OFFSET + USER_CLUSTER_PARTITION_SIZE) + +void set_debug_flag(bool flag) +{ + uart_init_flag = flag; +} + +volatile bool read_debug_flag(void) +{ + return uart_init_flag; +} + +void clear_cluster_para(void) +{ + flash_erase(cluster_para_dev, USER_CLUSTER_PARTITION_OFFSET, USER_CLUSTER_PARTITION_SIZE); + cluster_para_addr = USER_CLUSTER_PARTITION_OFFSET; +} + +void init_cluster_partition(void) +{ + uint32_t i, cur_addr; + cluster_startup_para t_cmp; + cluster_startup_para t_cmp_back; + memset((void *) (&t_cmp_back), 0xff, CLUSTER_PARA_LEN); + + for (i = 0;; i++) + { + cur_addr = USER_CLUSTER_PARTITION_OFFSET + i * CLUSTER_PARA_LEN; + if (cur_addr >= USER_CLUSTER_PARTITION_END) + { + clear_cluster_para(); + if (uart_init_flag) + { + printk("Cluster partition is full, clear it and redirect address:0x%x\n", cluster_para_addr); + } + break; + } + + flash_read(cluster_para_dev, cur_addr, &t_cmp, CLUSTER_PARA_LEN); + if (memcmp(&t_cmp, &t_cmp_back, CLUSTER_PARA_LEN) == 0) // read t_cmp is 0xff + { + cluster_para_addr = cur_addr; + if (uart_init_flag) + { + printk("Init cluster partition:0x%x\n", cluster_para_addr); + } + return; + } + } +} + +int store_cluster_para(cluster_startup_para * data) +{ + if (data == NULL) + { + if (uart_init_flag) + { + printk("[ERROR] The data that needs to be stored is NULL\n"); + } + return -1; + } + if (cluster_para_addr >= (USER_CLUSTER_PARTITION_END - CLUSTER_PARA_LEN)) + { + clear_cluster_para(); + } + + flash_write(cluster_para_dev, cluster_para_addr, data, CLUSTER_PARA_LEN); + cluster_para_addr += CLUSTER_PARA_LEN; + return 0; +} + +int read_cluster_para(cluster_startup_para * data) +{ + if (data == NULL) + { + if (uart_init_flag) + { + printk("[ERROR] The data to be read is NULL\n"); + } + return -1; + } + if (cluster_para_addr >= USER_CLUSTER_PARTITION_END) + { + clear_cluster_para(); + if (uart_init_flag) + { + printk("[ERROR] The read address exceeds partition, clear it and redirect address:0x%x\n", cluster_para_addr); + } + return -1; + } + if ((cluster_para_addr - CLUSTER_PARA_LEN) < USER_CLUSTER_PARTITION_OFFSET) + { + if (uart_init_flag) + { + printk("[ERROR] The cluster parition all NULL\n"); + } + return -1; + } + + cluster_startup_para t_cmp; + cluster_startup_para t_cmp_back; + memset((void *) (&t_cmp_back), 0xff, CLUSTER_PARA_LEN); + + flash_read(cluster_para_dev, (cluster_para_addr - CLUSTER_PARA_LEN), &t_cmp, CLUSTER_PARA_LEN); + if (memcmp(&t_cmp, &t_cmp_back, CLUSTER_PARA_LEN) == 0) // read t_cmp is 0xff, error + { + clear_cluster_para(); + if (uart_init_flag) + { + printk("[ERROR] The previous data was not successfully written\n"); + } + return -1; + } + memcpy(data, &t_cmp, CLUSTER_PARA_LEN); + return 0; +} +#endif // CONFIG_STARTUP_OPTIMIZATE + #if CONFIG_DUAL_MODE_SWTICH void FactoryResetExtHandler(void) { @@ -149,6 +273,10 @@ void FactoryResetExtHandler(void) flash_erase(flash_para_dev, USER_PARTITION_OFFSET, USER_PARTITION_SIZE); // Need to erase zb nvs part in factory mode flash_erase(zb_para_dev, ZB_NVS_START_ADR, ZB_NVS_SEC_SIZE); +#if CONFIG_STARTUP_OPTIMIZATE + // Need to erase cluster para parition + flash_erase(cluster_para_dev, USER_CLUSTER_PARTITION_OFFSET, USER_CLUSTER_PARTITION_SIZE); +#endif // CONFIG_STARTUP_OPTIMIZATE } #endif @@ -940,6 +1068,18 @@ void AppTaskCommon::ChipEventHandler(const ChipDeviceEvent * event, intptr_t /* sBoot_zb = 0; flash_erase(flash_para_dev, USER_PARTITION_OFFSET, USER_PARTITION_SIZE); flash_write(flash_para_dev, USER_PARTITION_OFFSET, &val, 1); +#if CONFIG_STARTUP_OPTIMIZATE + cluster_startup_para cluster_para; + cluster_para.onoff = light_para.onoff; + cluster_para.level = light_para.level; + if (store_cluster_para(&cluster_para) != 0) + { + if (uart_init_flag) + { + printk("[Commissioning] Fail store startup cluster para\n"); + } + } +#endif // CONFIG_STARTUP_OPTIMIZATE printk("Commissioning complete, set Matter commissionined flag"); } break; diff --git a/examples/platform/telink/common/src/mainCommon.cpp b/examples/platform/telink/common/src/mainCommon.cpp index 3f68acab099528..72e470133fb1ea 100644 --- a/examples/platform/telink/common/src/mainCommon.cpp +++ b/examples/platform/telink/common/src/mainCommon.cpp @@ -142,8 +142,118 @@ void matter_nvs_raw_demo(void) #endif +#if CONFIG_STARTUP_OPTIMIZATE +#include "AppTaskCommon.h" +#include +#include +#include +#include +#include +#include + +struct k_timer PwmChangeTimer; +static PWM_POOL_DEFINE(pwm_pool); +struct pwm_pool_data * pwm_data = &pwm_pool; +static const struct device * flash_para_dev = USER_PARTITION_DEVICE; + +#define ENUM_BLUE (PwmManager::EAppPwm_Blue) +/* EAppPwm_Blue enum is 4, corresponds to channel 2 in dts */ +#define PWM_CHANNEL_BLUE ((uint32_t) ENUM_BLUE - 2) +/* pwm channel 0 is BIT(8) in driver */ +#define PWM_CHANNEL_TO_BIT(CHANNEL) ((CHANNEL == 0) ? FLD_PWM0_EN : BIT(CHANNEL)) +#define BIT_PWM_CHANNEL_BLUE PWM_CHANNEL_TO_BIT(PWM_CHANNEL_BLUE) + +#define PWM_CHANGE_TOTAL_TIME_MS 400 +#define PWM_CHANGE_PRE_STEP_MS 8 +#define PWM_STEP_CNT_MAX (PWM_CHANGE_TOTAL_TIME_MS / PWM_CHANGE_PRE_STEP_MS) +#define PWM_PULSE_CYCLE(period, level, cnt) ((period / (255 * PWM_STEP_CNT_MAX)) * (level) * (cnt)) + +static uint32_t cnt = 1; +static uint8_t cur_level = 0; +static uint32_t timer_period = PWM_CHANGE_PRE_STEP_MS; + +static void init_startup_para(void) +{ + cluster_startup_para light_cluster_para; + if (read_cluster_para(&light_cluster_para) != 0) + { + if (uart_init_flag) + { + printk("[init_startup_para] Fail read startup cluster para\n"); + } + } + + if (light_cluster_para.onoff == 1) + { + cur_level = light_cluster_para.level; + } + else + { // OFF || ERROR + cur_level = 0; + timer_period = 0; + } +} + +static void PwmSetTimeoutCallback(struct k_timer * timer) +{ + if (!timer) + { + return; + } + + pwm_set_dt(&pwm_data->out[ENUM_BLUE], pwm_data->out[ENUM_BLUE].period, + PWM_PULSE_CYCLE(pwm_data->out[ENUM_BLUE].period, cur_level, cnt)); + pwm_set_start((pwm_en_e) (BIT_PWM_CHANNEL_BLUE)); + + if (cnt >= PWM_STEP_CNT_MAX) + { + k_timer_stop(timer); + if (uart_init_flag) + { + printk("[PwmSetTimeoutCallback] The current pulse cycle after change: %d\n", + PWM_PULSE_CYCLE(pwm_data->out[ENUM_BLUE].period, cur_level, cnt)); + } + } + + cnt++; +} +#endif // CONFIG_STARTUP_OPTIMIZATE + +void early_proc_cluster(void) +{ +#if CONFIG_STARTUP_OPTIMIZATE + unsigned char val; + flash_read(flash_para_dev, USER_PARTITION_OFFSET, &val, 1); + if (val == USER_MATTER_PAIR_VAL) + { + init_cluster_partition(); + init_startup_para(); + if (timer_period != 0) + { + k_timer_init(&PwmChangeTimer, &PwmSetTimeoutCallback, nullptr); + k_timer_start(&PwmChangeTimer, K_MSEC(timer_period), K_MSEC(timer_period)); + } + } +#endif // CONFIG_STARTUP_OPTIMIZATE +} + +typedef void (*p_early_proc)(void); +p_early_proc early_proc_cluster_f = early_proc_cluster; + int main(void) { +#if CONFIG_STARTUP_OPTIMIZATE + /** + * @brief Control log output for startup optimizate module. + * + * @see It only takes effect when the startup optimizate + * module is opened. Note than the flag can only be set + * to true after the execution of the main function. + */ + set_debug_flag(true); + printk("cur_level:%d, timer_period:%d\n", cur_level, timer_period); +#endif // CONFIG_STARTUP_OPTIMIZATE + #if defined(CONFIG_USB_DEVICE_STACK) && !defined(CONFIG_CHIP_PW_RPC) usb_enable(NULL); #endif /* CONFIG_USB_DEVICE_STACK */ diff --git a/src/platform/telink/tl3218x.overlay b/src/platform/telink/tl3218x.overlay index 2e6a978de19ec6..fd056f3535dbed 100644 --- a/src/platform/telink/tl3218x.overlay +++ b/src/platform/telink/tl3218x.overlay @@ -49,8 +49,8 @@ &pwm0 { /* On board RGB LEDs */ pinctrl-ch0 = <&pwm_ch0_pb1_default>; - pinctrl-ch2 = <&pwm_ch1_pb2_default>; - pinctrl-ch1 = <&pwm_ch2_pb0_default>; + pinctrl-ch1 = <&pwm_ch1_pb2_default>; + pinctrl-ch2 = <&pwm_ch2_pb0_default>; }; &pinctrl { diff --git a/src/platform/telink/tlsr9528a.overlay b/src/platform/telink/tlsr9528a.overlay index 3eee50195133e6..8e9715d2d17b93 100644 --- a/src/platform/telink/tlsr9528a.overlay +++ b/src/platform/telink/tlsr9528a.overlay @@ -50,8 +50,8 @@ &pwm0 { /* On board RGB LEDs */ pinctrl-ch0 = <&pwm_ch0_pe7_default>; - pinctrl-ch2 = <&pwm_ch1_pd1_default>; - pinctrl-ch1 = <&pwm_ch2_pd0_default>; + pinctrl-ch1 = <&pwm_ch1_pd1_default>; + pinctrl-ch2 = <&pwm_ch2_pd0_default>; }; &pinctrl {