当前位置: 首页 > news >正文

【MCU ATS323X】PM电源管理系统

目录

1、概述

2、功耗状态

3、zephyr 功耗模式切换

4、pm_system_suspend()

4.1..\zephyr\subsys\pm\pm.c

4.2..\hal\actions\soc\arm\actions\falcon\power.c

4.3..\hal\actions\soc\arm\actions\falcon\soc_sleep.c

4.4..\hal\actions\soc\arm\actions\falcon\soc_sleep.s

5、投票与仲裁

6、other

6.1..\application\...\main.c

6.2..\application\...\MMI_SAVE_PWR.c

6.3 应用唤醒过程

7、zephyr - work(延时队列)


1、概述

       本文的电源管理系统是比较狭义的定义主要包含:设备功耗模式申明(多少种);不同功耗模式如何切换;投票与仲裁;功能模式切换回调。

        ATS323X的SDK使用OS是zephyr分析电源管会涉及到zyphyr子系统pm的内容。

2、功耗状态

        zephyr是一个支持多核心的系统所有使用一个数组来记录多核的状态。为每一个CPU实现独立控制提供的基础。..\zephyr\subsys\pm\state.c内容如下:

/** CPU power states information for each CPU */
static const struct pm_state_info *cpus_states[] = {DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), CPU_STATE_REF, (,))
};/** Number of states for each CPU */
static const uint8_t states_per_cpu[] = {DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), DT_NUM_CPU_POWER_STATES, (,))
};uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states)
{if (cpu >= ARRAY_SIZE(cpus_states)) {return 0;}*states = cpus_states[cpu];return states_per_cpu[cpu];
}

3、zephyr 功耗模式切换

        所有有OS的功耗模式切换都是发生在idlex线程。如代码中我们可以看到如果没有PM子系统进入idle线程是直接调用k_cpu_idle()此接口不同架构的实现是不一样。此接口只是让CPU停下来并没有让外设也进入低功耗所以功耗降低不是很明显,实践中这种方式不常使用。

        如果PM子系统被开启则会调用pm_system_suspend()接口,pm_system_suspend()作用一个PM模块的接口是很方便用户扩展而且对底层OS影响。当pm_system_suspend()进入低功耗失败时OS则调用k_cpu_idle()仅让CPU进入低功耗。

void idle(void *unused1, void *unused2, void *unused3)
{ARG_UNUSED(unused1);ARG_UNUSED(unused2);ARG_UNUSED(unused3);__ASSERT_NO_MSG(_current->base.prio >= 0);while (true) {if (IS_ENABLED(CONFIG_SMP) && !IS_ENABLED(CONFIG_SCHED_IPI_SUPPORTED)) {for (volatile int i = 0; i < 100000; i++) {/* Empty loop */}z_swap_unlocked();}(void) arch_irq_lock();#ifdef CONFIG_PM_kernel.idle = z_get_next_timeout_expiry();if (k_is_pre_kernel() || !pm_system_suspend(_kernel.idle)) {k_cpu_idle();}
#elsek_cpu_idle();
#endif /* CONFIG_PM */#if !defined(CONFIG_PREEMPT_ENABLED)
# if !defined(CONFIG_USE_SWITCH) || defined(CONFIG_SPARC)if (_kernel.ready_q.cache != _current) {z_swap_unlocked();}
# endif /* !defined(CONFIG_USE_SWITCH) || defined(CONFIG_SPARC) */
#endif /* !defined(CONFIG_PREEMPT_ENABLED) */}
}

4、pm_system_suspend()

        入参为将要空闲的时长。接口的调用过程过如下:

4.1..\zephyr\subsys\pm\pm.c

        void pm_notifier_register(struct pm_notifier *notifier)//供用户注册切换回调

        pm_system_suspend() -> pm_state_set()//进低功耗

        pm_state_notify(true)//在进入低功耗前通知要外设。

        pm_system_resume() -> pm_state_notify(false)//在唤醒后通知注册

4.2..\hal\actions\soc\arm\actions\falcon\power.c

        pm_state_set() -> soc_enter_deep_sleep() /soc_enter_light_sleep()

4.3..\hal\actions\soc\arm\actions\falcon\soc_sleep.c

         soc_enter_deep_sleep() /soc_enter_light_sleep() -> cpu_enter_sleep() -> __cpu_enter_sleep() ->__cpu_suspend()

4.4..\hal\actions\soc\arm\actions\falcon\soc_sleep.s

        SECTION_FUNC(sleepfunc, __cpu_suspend)

bool pm_system_suspend(int32_t ticks)
{uint8_t id = _current_cpu->id;k_spinlock_key_t key;SYS_PORT_TRACING_FUNC_ENTER(pm, system_suspend, ticks);key = k_spin_lock(&pm_forced_state_lock);if (z_cpus_pm_forced_state[id].state != PM_STATE_ACTIVE) {z_cpus_pm_state[id] = z_cpus_pm_forced_state[id];z_cpus_pm_forced_state[id].state = PM_STATE_ACTIVE;} else {const struct pm_state_info *info;info = pm_policy_next_state(id, ticks);if (info != NULL) {z_cpus_pm_state[id] = *info;} else {z_cpus_pm_state[id].state = PM_STATE_ACTIVE;}}k_spin_unlock(&pm_forced_state_lock, key);if (z_cpus_pm_state[id].state == PM_STATE_ACTIVE) {LOG_DBG("No PM operations done.");SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks,z_cpus_pm_state[id].state);return false;}#ifdef CONFIG_PM_DEVICE_SYSTEM_MANAGEDif (atomic_sub(&_cpus_active, 1) == 1) {if ((z_cpus_pm_state[id].state != PM_STATE_RUNTIME_IDLE) &&!z_cpus_pm_state[id].pm_device_disabled) {if (!pm_suspend_devices()) {pm_resume_devices();z_cpus_pm_state[id].state = PM_STATE_ACTIVE;(void)atomic_add(&_cpus_active, 1);SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks,z_cpus_pm_state[id].state);return false;}}}
#endifif ((z_cpus_pm_state[id].exit_latency_us != 0) &&(ticks != K_TICKS_FOREVER)) {sys_clock_set_timeout(ticks -k_us_to_ticks_ceil32(z_cpus_pm_state[id].exit_latency_us),true);}k_sched_lock();pm_stats_start();/* Enter power state */pm_state_notify(true);atomic_set_bit(z_post_ops_required, id);pm_state_set(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id);//调用CPU停止接口pm_stats_stop();/* Wake up sequence starts here */pm_stats_update(z_cpus_pm_state[id].state);pm_system_resume();k_sched_unlock();SYS_PORT_TRACING_FUNC_EXIT(pm, system_suspend, ticks,z_cpus_pm_state[id].state);return true;
}

5、投票与仲裁

6、other

6.1..\application\...\main.c

        user_work_mode() -> mmi_save_pwr()

6.2..\application\...\MMI_SAVE_PWR.c

        mmi_save_pwr() -> pf_stop_radio_work_timer() //关定时器停任务

6.3 应用唤醒过程

依赖消息中心与pf_rpmsg_send_task线程,s_rpmsg_send_queue其实是线程的句柄。消息中心与普通队列是两明显区别,直接作用于线程有点类似于线程的事件。

..\application\...\system_init.c

wakelock_init() -> sys_wakelock_init(app_wakelock_ctx.standby,  WAKELOCK_STATE_NUM,  _wakelock_callback);
        wakelock_context.user_callback = cb;//初始化时注册进回调函数。

_wakelock_callback() -> //有唤醒源时执行些回调函数
_sys_wakelock_enter_normal -> rpmsg_comm_send_wakeup_dsp() -> OS_SendMsg( s_rpmsg_send_queue, &msg)//发送唤醒信号到pf_rpmsg_send_task线程。


pf_rpmsg_send_task//收到唤醒事件线程

        OS_GetMsg(s_rpmsg_send_queue, &rpmsg_comm)

        pf_start_radio_work_timer(10);//开定时器。

7、zephyr - work(延时队列)

..\framework\misc\sys_manager\wakelock.c

sys_wakelock_init()执行如下初始化:

os_delayed_work_init(&wakelock_context.work_handle_up_state, _sys_wakelock_up_state);

os_delayed_work_init(&wakelock_context.work_handle_down_state, _sys_wakelock_down_state);

_sys_wakelock_up_state()/_sys_wakelock_down_state() -> 延迟回调函数触发线程。

os_delayed_work_submit() -> k_work_reschedule()

..\zephyr\kernel\work.c中创建一个线程管理延时队列。

void k_work_queue_start(struct k_work_q *queue,k_thread_stack_t *stack,size_t stack_size,int prio,const struct k_work_queue_config *cfg)
{__ASSERT_NO_MSG(queue);__ASSERT_NO_MSG(stack);__ASSERT_NO_MSG(!flag_test(&queue->flags, K_WORK_QUEUE_STARTED_BIT));uint32_t flags = K_WORK_QUEUE_STARTED;SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_work_queue, start, queue);sys_slist_init(&queue->pending);z_waitq_init(&queue->notifyq);z_waitq_init(&queue->drainq);if ((cfg != NULL) && cfg->no_yield) {flags |= K_WORK_QUEUE_NO_YIELD;}flags_set(&queue->flags, flags);(void)k_thread_create(&queue->thread, stack, stack_size,work_queue_main, queue, NULL, NULL,prio, 0, K_FOREVER);if ((cfg != NULL) && (cfg->name != NULL)) {k_thread_name_set(&queue->thread, cfg->name);}if ((cfg != NULL) && (cfg->essential)) {queue->thread.base.user_options |= K_ESSENTIAL;}k_thread_start(&queue->thread);SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_work_queue, start, queue);
}

int k_work_reschedule(struct k_work_delayable *dwork, k_timeout_t delay)//加入到static sys_slist_t work_pending 双向链表。

http://www.dtcms.com/a/581006.html

相关文章:

  • 建网站一定要备案吗学生个人网站建设方案书框架栏目
  • 做兼职的网站都有哪些工作内容深圳建设网站首页
  • 【深入浅出】:人工智能从入门到实战
  • 日内瓦传动装置?不就是我们叫的间歇结构吗?
  • 基于SpringBoot的乡村支教全流程数字化管理平台 基于Django的智慧乡村支教综合管理系统 基于php与智能问答的乡村支教服务平台
  • dp|中位数贪心+裴蜀定理
  • 高集成低功耗RISC-V SoC收发芯片CI24R02
  • 中国科大创建乾坤网络精确求解多电子薛定谔方程
  • 世界著名的设计公司百度优化 几个网站内容一样
  • 【Debug】ChatGPT - Cli CodeX 登录报错 409 Route Error (409 ): 解决方案
  • C11期作业23(08.30)
  • 【JavaWeb】Tlias后台管理系统
  • 硬件工程师-基础知识电阻(四)
  • 网站设计建设那家好门户网站开发项目
  • 视频号下载视频思路
  • Visual Basic 手工制作工具栏
  • 电话交换机软件和录音转文字服务器部署笔记
  • 常州建站程序衡水高端网站建设
  • Java五大排序算法详解与实现
  • [特殊字符] Vue3 + WebView 双端通信桥:用 TypeScript 构建高可维护的 JSBridge 与 JSSDK
  • 自然科学笔记-微积分
  • iOS 上架要求全解析,App Store 审核标准、开发者准备事项与开心上架(Appuploader)跨平台免 Mac 实战指南
  • iOS app语言切换
  • Search-o1:增强大型推理模型的主动搜索能力
  • 个人笔记|IP分片不用TTL
  • 百汇游戏网站开发商南通网站推广公司
  • 【Linux】权限(2):文件权限的深入理解粘滞位
  • 做网站公司如何选百度广告联盟推广链接
  • BIM+GIS协同:RVT文件转3DTiles的技术路径与场景落地
  • 中颖AFE芯片:SH367303、SH367306 和 SH367309