572 lines
16 KiB
C
572 lines
16 KiB
C
/*
|
|
* Kneron Power Manager driver
|
|
*
|
|
* Copyright (C) 2019 Kneron, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "cmsis_os2.h"
|
|
#include "os_tick.h"
|
|
#include "RTX_Config.h"
|
|
#include "kmdw_power_manager.h"
|
|
#include "kdrv_scu.h"
|
|
#include "kdrv_power.h"
|
|
#include "kdrv_clock.h"
|
|
#include "kdrv_system.h"
|
|
#include "kmdw_system.h"
|
|
#include "rtc.h" // TODO: need to rewrite to kdrv_rtc.h
|
|
#include "kdrv_ddr.h"
|
|
#include "kmdw_console.h"
|
|
#include "kdrv_cmsis_core.h"
|
|
|
|
#define FLAG_SYSTEM_RESET BIT0
|
|
#define FLAG_SYSTEM_NAP BIT1
|
|
#define FLAG_SYSTEM_NAP2 BIT2
|
|
#define FLAG_SYSTEM_SLEEP BIT3
|
|
#define FLAG_SYSTEM_DEEP_SLEEP BIT4
|
|
#define FLAG_SYSTEM_TIMER BIT5
|
|
#define FLAG_SYSTEM_SHUTDOWN BIT6
|
|
#define FLAG_SYSTEM_ERROR BIT8
|
|
#define FLAG_SYSTEM_PWRBTN_FALL BIT16
|
|
#define FLAG_SYSTEM_PWRBTN_RISE BIT17
|
|
|
|
#define FLAGS_ALL (FLAG_SYSTEM_RESET | FLAG_SYSTEM_SHUTDOWN \
|
|
| FLAG_SYSTEM_NAP | FLAG_SYSTEM_NAP2 \
|
|
| FLAG_SYSTEM_SLEEP | FLAG_SYSTEM_DEEP_SLEEP \
|
|
| FLAG_SYSTEM_TIMER | FLAG_SYSTEM_ERROR \
|
|
| FLAG_SYSTEM_PWRBTN_FALL | FLAG_SYSTEM_PWRBTN_RISE)
|
|
|
|
#define PERIOD_PRINT (3 * OS_TICK_FREQ) // 3 secs
|
|
#define PERIOD_COUNT (PERIOD_PRINT + PERIOD_PRINT/100) // add 1% margin
|
|
|
|
/* SCU_REG_INT_EN & SCU_REG_INT_STS */
|
|
#define SCU_INT_RTC_PERIODIC BIT17
|
|
#define SCU_INT_RTC_ALARM BIT16
|
|
#define SCU_INT_PLL_UPDATE BIT8
|
|
#define SCU_INT_FCS BIT6
|
|
#define SCU_INT_BUSSPEED BIT5
|
|
#define SCU_INT_WAKEUP BIT3
|
|
#define SCU_INT_PWRBTN_RISE BIT1
|
|
#define SCU_INT_PWRBTN_FALL BIT0
|
|
|
|
/* Inactivity timers in seconds */
|
|
#define NAP_TIME_1 30
|
|
#define NAP_TIME_2 60
|
|
|
|
osThreadId_t power_tid;
|
|
uint32_t cpu_idle_counter = 0;
|
|
|
|
uint32_t idle_entry_time_in_secs;
|
|
uint32_t idle_exit_time_in_secs;
|
|
uint32_t sleep_state;
|
|
|
|
kmdw_power_manager_ptn_handler ptn_cb;
|
|
|
|
static struct pm_device_func_s {
|
|
enum kmdw_power_manager_device_id dev_id;
|
|
int inuse;
|
|
struct kmdw_power_manager_s pm;
|
|
} _pm_dev_fns[KMDW_POWER_MANAGER_DEVICE_MAX];
|
|
|
|
static void scu_system_isr(void)
|
|
{
|
|
static int pwr_button_wakeup = 1; // = 1 for cold boot by PWR button
|
|
uint32_t status;
|
|
|
|
status = inw(SCU_REG_INT_STS);
|
|
|
|
if (status & SCU_INT_RTC_ALARM)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_NAP);
|
|
if (status & SCU_INT_RTC_PERIODIC)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_TIMER);
|
|
if (status & SCU_INT_PWRBTN_FALL) {
|
|
if (pwr_button_wakeup) {
|
|
pwr_button_wakeup = 0;
|
|
} else {
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_PWRBTN_FALL);
|
|
}
|
|
}
|
|
if (status & SCU_INT_PWRBTN_RISE) {
|
|
if (sleep_state == 1) {
|
|
pwr_button_wakeup = 1;
|
|
} else {
|
|
pwr_button_wakeup = 0;
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_PWRBTN_RISE);
|
|
}
|
|
}
|
|
|
|
outw(SCU_REG_INT_STS, status);
|
|
NVIC_ClearPendingIRQ(SYS_SYSTEM_IRQ);
|
|
}
|
|
|
|
static void _scu_system_init(void)
|
|
{
|
|
NVIC_DisableIRQ(SYS_SYSTEM_IRQ);
|
|
|
|
rtc_init(NULL, NULL);
|
|
outw(SCU_REG_INT_STS, 0xffffffff); // Clear all old ones
|
|
|
|
/* Enable PWR button interrupt and wakeup */
|
|
outw(SCU_REG_INT_EN, SCU_INT_PWRBTN_FALL | SCU_INT_PWRBTN_RISE | SCU_INT_WAKEUP);
|
|
|
|
/* Enable nap alarm interrupt */
|
|
uint32_t nap_time = NAP_TIME_1;
|
|
rtc_alarm_enable(ALARM_IN_SECS, &nap_time, NULL);
|
|
masked_outw(SCU_REG_INT_EN, SCU_INT_RTC_ALARM, SCU_INT_RTC_ALARM);
|
|
|
|
NVIC_SetVector(SYS_SYSTEM_IRQ, (uint32_t)scu_system_isr);
|
|
NVIC_EnableIRQ(SYS_SYSTEM_IRQ);
|
|
}
|
|
|
|
#define MMFAR 0xE000ED34
|
|
#define FLAG_WAIT_FOREVER 0x40000000
|
|
static void _scpu_wait_reset(void)
|
|
{
|
|
osThreadId_t calling_tid = osThreadGetId();
|
|
if ((calling_tid == 0) || (calling_tid == power_tid)){ // no os or if power mgmnt thread is in trouble
|
|
#if 0
|
|
kdrv_power_sw_reset();
|
|
#else
|
|
for (;;);
|
|
#endif
|
|
}
|
|
else // let power mgmnt thread handles the reset
|
|
osThreadFlagsWait((u32)calling_tid , FLAG_WAIT_FOREVER, osWaitForever);
|
|
}
|
|
|
|
register unsigned int _msp __asm("msp");
|
|
register unsigned int _psp __asm("psp");
|
|
register unsigned int _lr __asm("lr");
|
|
static unsigned int stack, pc;
|
|
|
|
static void _scpu_hard_fault(void)
|
|
{
|
|
if (_lr & 4) {
|
|
stack = _psp;
|
|
pc = stack + 24;
|
|
}
|
|
else {
|
|
stack = _msp;
|
|
pc = stack + 40;
|
|
}
|
|
|
|
err_msg("scpu: hard fault @ %08X, PC = %08X, LR = %08X, SP = %08X\n", *(u32*)MMFAR,
|
|
*(u32*)pc, *(u32*)(pc-4), (u32)pc+8);
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_ERROR);
|
|
*(u32*)pc = (u32)&_scpu_wait_reset; // modify stack to go to the wait forever loop
|
|
}
|
|
|
|
static void _scpu_mem_mnmt(void)
|
|
{
|
|
if (_lr & 4) {
|
|
stack = _psp;
|
|
pc = stack + 24;
|
|
}
|
|
else {
|
|
stack = _msp;
|
|
pc = stack + 40;
|
|
}
|
|
|
|
err_msg("scpu: memory fault @ %08X, PC = %08X, LR = %08X, SP = %08X\n", *(u32*)MMFAR,
|
|
*(u32*)pc, *(u32*)(pc-4), (u32)pc+8);
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_ERROR);
|
|
*(u32*)pc = (u32)&_scpu_wait_reset; // modify stack to go to the wait forever loop
|
|
}
|
|
|
|
static void _scpu_bus_fault(void)
|
|
{
|
|
err_msg("scpu: _scpu_bus_fault !\n");
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_ERROR);
|
|
}
|
|
|
|
static void _scpu_usage_fault(void)
|
|
{
|
|
err_msg("scpu: _scpu_usage_fault !\n");
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_ERROR);
|
|
}
|
|
|
|
void kmdw_power_manager_error_notify(uint32_t code, void *object_id)
|
|
{
|
|
err_msg("scpu: exception: code=%d, object_id=0x%p\n", code, object_id);
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_ERROR);
|
|
}
|
|
|
|
void kmdw_power_manager_reset(void)
|
|
{
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_RESET);
|
|
}
|
|
|
|
void kmdw_power_manager_sleep(void)
|
|
{
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_SLEEP);
|
|
}
|
|
|
|
void kmdw_power_manager_deep_sleep(void)
|
|
{
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_DEEP_SLEEP);
|
|
}
|
|
|
|
void kmdw_power_manager_shutdown(void)
|
|
{
|
|
if (power_tid)
|
|
osThreadFlagsSet(power_tid, FLAG_SYSTEM_SHUTDOWN);
|
|
}
|
|
|
|
static void _power_mgr_cpu_usage(void)
|
|
{
|
|
static uint32_t last_record=0, print_count=0, diff;
|
|
|
|
diff = (cpu_idle_counter - last_record);
|
|
last_record = cpu_idle_counter;
|
|
|
|
if (diff > PERIOD_COUNT)
|
|
diff = PERIOD_COUNT;
|
|
|
|
info_msg("#%04d cpu loading %d %%\n", ++print_count,
|
|
(PERIOD_COUNT - diff) * 100 / PERIOD_COUNT);
|
|
}
|
|
|
|
__NO_RETURN void kmdw_power_manager_cpu_idle(void)
|
|
{
|
|
uint32_t tick_start, tick_end, tick_idle;
|
|
|
|
while(1) {
|
|
rtc_get_date_time_in_secs(&idle_entry_time_in_secs);
|
|
tick_start = osKernelGetTickCount();
|
|
__WFI();
|
|
tick_end = osKernelGetTickCount();
|
|
tick_idle = tick_end - tick_start;
|
|
cpu_idle_counter += tick_idle;
|
|
rtc_get_date_time_in_secs(&idle_exit_time_in_secs);
|
|
}
|
|
}
|
|
|
|
static void _power_manager_do_nap(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = KMDW_POWER_MANAGER_DEVICE_MAX - 1; i >= 0; i--) {
|
|
if (_pm_dev_fns[i].inuse && _pm_dev_fns[i].pm.nap)
|
|
{
|
|
if(_pm_dev_fns[i].pm.nap(_pm_dev_fns[i].dev_id) < 0)
|
|
{
|
|
info_msg("Can't take a nap\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
dbg_msg("Take a nap\n");
|
|
/* Disable npu/ncpu clocks */
|
|
kdrv_clock_disable(CLK_NPU);
|
|
kdrv_clock_disable(CLK_NCPU);
|
|
__WFI();
|
|
kdrv_clock_enable(CLK_NCPU);
|
|
kdrv_clock_enable(CLK_NPU);
|
|
|
|
for (i = 0; i < KMDW_POWER_MANAGER_DEVICE_MAX; i++) {
|
|
if (_pm_dev_fns[i].inuse && _pm_dev_fns[i].pm.wakeup_nap)
|
|
_pm_dev_fns[i].pm.wakeup_nap(_pm_dev_fns[i].dev_id);
|
|
}
|
|
}
|
|
|
|
static void _power_manager_do_deep_nap(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = KMDW_POWER_MANAGER_DEVICE_MAX - 1; i >= 0; i--) {
|
|
if (_pm_dev_fns[i].inuse && _pm_dev_fns[i].pm.deep_nap)
|
|
{
|
|
if(_pm_dev_fns[i].pm.deep_nap(_pm_dev_fns[i].dev_id) < 0)
|
|
{
|
|
info_msg("Can't take a deep nap\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
dbg_msg("Take a deep nap\n");
|
|
/* Disable npu/ncpu clocks + DDR self refresh */
|
|
kdrv_clock_disable(CLK_NPU);
|
|
kdrv_clock_disable(CLK_NCPU);
|
|
kdrv_ddr_self_refresh_enter();
|
|
__WFI();
|
|
kdrv_ddr_self_refresh_exit();
|
|
kdrv_clock_enable(CLK_NCPU);
|
|
kdrv_clock_enable(CLK_NPU);
|
|
|
|
for (i = 0; i < KMDW_POWER_MANAGER_DEVICE_MAX; i++) {
|
|
if (_pm_dev_fns[i].inuse && _pm_dev_fns[i].pm.wakeup_deep_nap)
|
|
_pm_dev_fns[i].pm.wakeup_deep_nap(_pm_dev_fns[i].dev_id);
|
|
}
|
|
}
|
|
|
|
static void _power_manager_do_sleep(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = KMDW_POWER_MANAGER_DEVICE_MAX - 1; i >= 0; i--) {
|
|
if (_pm_dev_fns[i].inuse && _pm_dev_fns[i].pm.sleep)
|
|
{
|
|
if(_pm_dev_fns[i].pm.sleep(_pm_dev_fns[i].dev_id) < 0)
|
|
{
|
|
info_msg("Can't sleep\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
dbg_msg("!!! sleep\n");
|
|
|
|
sleep_state = 1;
|
|
|
|
/* Retention: NPU power domain off */
|
|
kdrv_clock_disable(CLK_NPU);
|
|
kdrv_clock_disable(CLK_NCPU);
|
|
kdrv_ddr_self_refresh_enter();
|
|
__WFI();
|
|
kdrv_ddr_self_refresh_exit();
|
|
// kdrv_clock_enable(CLK_NCPU); // these are done in system_wakeup_ncpu();
|
|
// kdrv_clock_enable(CLK_NPU);
|
|
load_ncpu_fw(0); // reload ncpu fw but don't start it yet
|
|
system_wakeup_ncpu(0, 1);
|
|
// ddr doesn't seemed correct, reload default models for testing ???
|
|
|
|
sleep_state = 0;
|
|
dbg_msg("!!! sleep -> wakeup\n");
|
|
|
|
for (i = 0; i < KMDW_POWER_MANAGER_DEVICE_MAX; i++) {
|
|
if (_pm_dev_fns[i].inuse && _pm_dev_fns[i].pm.wakeup_sleep)
|
|
_pm_dev_fns[i].pm.wakeup_sleep(_pm_dev_fns[i].dev_id);
|
|
}
|
|
}
|
|
|
|
static void _power_manager_do_deep_sleep(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = KMDW_POWER_MANAGER_DEVICE_MAX - 1; i >= 0; i--) {
|
|
if (_pm_dev_fns[i].inuse && _pm_dev_fns[i].pm.deep_sleep)
|
|
{
|
|
if(_pm_dev_fns[i].pm.deep_sleep(_pm_dev_fns[i].dev_id) < 0)
|
|
{
|
|
info_msg("Can't deep sleep\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
dbg_msg("!!! deep sleep\n\n");
|
|
|
|
/* Deep Retention: NPU+Default domain off */
|
|
kdrv_power_softoff(POWER_MODE_DEEP_RETENTION);
|
|
__WFI();
|
|
|
|
err_msg("!!! deep sleep failed!\n");
|
|
|
|
/* TODO: resume here */
|
|
for (i = 0; i < KMDW_POWER_MANAGER_DEVICE_MAX; i++) {
|
|
if (_pm_dev_fns[i].inuse && _pm_dev_fns[i].pm.wakeup_deep_sleep)
|
|
_pm_dev_fns[i].pm.wakeup_deep_sleep(_pm_dev_fns[i].dev_id);
|
|
}
|
|
}
|
|
|
|
static void _power_manager_do_shutdown(void)
|
|
{
|
|
dbg_msg("!!! shutdown ...\n\n");
|
|
|
|
/* Disable alarm */
|
|
rtc_alarm_disable(ALARM_IN_SECS);
|
|
|
|
/* Power off everything except RTC */
|
|
kdrv_power_softoff(POWER_MODE_RTC);
|
|
__WFI();
|
|
|
|
err_msg("!!! shutdown failed!\n");
|
|
for (;;);
|
|
}
|
|
|
|
//#define PRINT_CPU_USAGE
|
|
|
|
void _kmdw_power_manager_thread(void *arg)
|
|
{
|
|
uint32_t status, timeout;
|
|
uint32_t current_time, elapsed_time, nap_time, pwrbtn_press_time, pwrbtn_release_time;
|
|
|
|
/* Init system/power/rtc control on SCU */
|
|
_scu_system_init();
|
|
|
|
#ifdef PRINT_CPU_USAGE
|
|
timeout = PERIOD_PRINT;
|
|
#else
|
|
timeout = osWaitForever;
|
|
#endif
|
|
|
|
while(1)
|
|
{
|
|
status = osThreadFlagsWait(FLAGS_ALL, osFlagsWaitAny, timeout);
|
|
|
|
if (status == osFlagsErrorTimeout) {
|
|
_power_mgr_cpu_usage();
|
|
continue;
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_SLEEP) {
|
|
_power_manager_do_sleep();
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_DEEP_SLEEP) {
|
|
_power_manager_do_deep_sleep();
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_RESET) {
|
|
info_msg("!!! reset\r\n");
|
|
// will not come back
|
|
kdrv_delay_us(50*1000);
|
|
kdrv_power_sw_reset();
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_SHUTDOWN) {
|
|
// will not come back
|
|
_power_manager_do_shutdown();
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_NAP) {
|
|
|
|
if (idle_exit_time_in_secs > idle_entry_time_in_secs)
|
|
elapsed_time = idle_exit_time_in_secs - idle_entry_time_in_secs;
|
|
else
|
|
elapsed_time = 0;
|
|
|
|
/* update */
|
|
rtc_get_date_time_in_secs(&idle_entry_time_in_secs);
|
|
|
|
/* set next alarm */
|
|
if (elapsed_time < NAP_TIME_1) {
|
|
nap_time = NAP_TIME_1;
|
|
rtc_alarm_enable(ALARM_IN_SECS, &nap_time, NULL);
|
|
} else if (elapsed_time < NAP_TIME_2) {
|
|
//rtc_current_time_info();
|
|
dbg_msg("Idle: %d seconds -> nap\n", elapsed_time);
|
|
/* Set longer nap time */
|
|
nap_time = NAP_TIME_2;
|
|
rtc_alarm_enable(ALARM_IN_SECS, &nap_time, NULL);
|
|
/* Take nap */
|
|
_power_manager_do_nap();
|
|
/* regular nap time upon wakeup */
|
|
nap_time = NAP_TIME_1;
|
|
rtc_alarm_enable(ALARM_IN_SECS, &nap_time, NULL);
|
|
} else {
|
|
//rtc_current_time_info();
|
|
dbg_msg("Idle: %d seconds -> deep nap\n", elapsed_time);
|
|
/* Set even longer nap time */
|
|
nap_time = NAP_TIME_2 * 10;
|
|
rtc_alarm_enable(ALARM_IN_SECS, &nap_time, NULL);
|
|
/* Take deep nap */
|
|
_power_manager_do_deep_nap();
|
|
/* regular nap time upon wakeup */
|
|
nap_time = NAP_TIME_1;
|
|
rtc_alarm_enable(ALARM_IN_SECS, &nap_time, NULL);
|
|
}
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_TIMER) {
|
|
rtc_current_time_info();
|
|
|
|
rtc_get_date_time_in_secs(¤t_time);
|
|
elapsed_time = current_time - idle_entry_time_in_secs;
|
|
|
|
dbg_msg("Idle: %d\n", elapsed_time);
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_ERROR) {
|
|
err_msg("!!! scpu: error\n");
|
|
#if 0
|
|
kdrv_power_sw_reset();
|
|
#else
|
|
// for debug
|
|
for (;;)
|
|
osDelay(10);
|
|
#endif
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_PWRBTN_FALL) {
|
|
rtc_get_date_time_in_secs(&pwrbtn_release_time);
|
|
elapsed_time = pwrbtn_release_time - pwrbtn_press_time;
|
|
info_msg("!!! PWR Button pressed for %d seconds:\n", elapsed_time);
|
|
if (elapsed_time > 6)
|
|
_power_manager_do_shutdown();
|
|
else if (ptn_cb)
|
|
ptn_cb(1);
|
|
}
|
|
|
|
if (status & FLAG_SYSTEM_PWRBTN_RISE) {
|
|
rtc_get_date_time_in_secs(&pwrbtn_press_time);
|
|
info_msg("!!! PWR Button Press&Hold 7+ seconds for shutdown (RTC mode)\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Registration APIs */
|
|
int kmdw_power_manager_register(enum kmdw_power_manager_device_id dev_id, struct kmdw_power_manager_s *pm_p)
|
|
{
|
|
int i;
|
|
|
|
if (dev_id >= KMDW_POWER_MANAGER_DEVICE_MAX || pm_p == NULL)
|
|
return -1;
|
|
|
|
for (i = 0; i < KMDW_POWER_MANAGER_DEVICE_MAX; i++) {
|
|
if (_pm_dev_fns[i].inuse == 0) {
|
|
memcpy(&_pm_dev_fns[i].pm, pm_p, sizeof(struct kmdw_power_manager_s));
|
|
_pm_dev_fns[i].dev_id = dev_id;
|
|
_pm_dev_fns[i].inuse = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void kmdw_power_manager_unregister(enum kmdw_power_manager_device_id dev_id, struct kmdw_power_manager_s *pm_p)
|
|
{
|
|
int i;
|
|
|
|
if (dev_id >= KMDW_POWER_MANAGER_DEVICE_MAX || pm_p == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < KMDW_POWER_MANAGER_DEVICE_MAX; i++) {
|
|
if (_pm_dev_fns[i].dev_id == dev_id && _pm_dev_fns[i].pm.sleep == pm_p->sleep && _pm_dev_fns[i].inuse) {
|
|
memset(&_pm_dev_fns[i].pm, 0, sizeof(struct kmdw_power_manager_s));
|
|
_pm_dev_fns[i].dev_id = KMDW_POWER_MANAGER_DEVICE_NONE;
|
|
_pm_dev_fns[i].inuse = 0;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void kmdw_power_manager_power_button_register(kmdw_power_manager_ptn_handler button_handler)
|
|
{
|
|
ptn_cb = button_handler;
|
|
}
|
|
|
|
void kmdw_power_manager_init(void)
|
|
{
|
|
osThreadAttr_t attr;
|
|
|
|
memset(&attr, 0, sizeof(attr));
|
|
attr.stack_size = 512;
|
|
attr.priority = osPriorityRealtime7;
|
|
power_tid = osThreadNew(_kmdw_power_manager_thread, NULL, &attr);
|
|
|
|
NVIC_SetVector(HardFault_IRQn, (uint32_t)_scpu_hard_fault);
|
|
NVIC_SetVector(MemoryManagement_IRQn, (uint32_t)_scpu_mem_mnmt);
|
|
NVIC_SetVector(BusFault_IRQn, (uint32_t)_scpu_bus_fault);
|
|
NVIC_SetVector(UsageFault_IRQn, (uint32_t)_scpu_usage_fault);
|
|
}
|