跳到主要内容

Standby - 休眠唤醒

V821 是一款集成了 RISC-V MCU 和 RISC-V CPU 的多核芯片,旨在提供高效的应用处理和低功耗的通信功能。该芯片设计采用独立的 PM 软件框架,以实现两个核心的灵活管理和调度。

RISC-V MCU 运行于应用域,主要负责 Wi-Fi 通信功能,支持实时操作系统(RTOS),优化对实时任务的处理能力。与此同时,RISC-V CPU 位于独立的电源域上,运行 Linux 系统,主要负责用户应用的处理。芯片内部的 pwrctrl 硬件负责管理 APP 域的上下电。在启动和 Standby 休眠状态下,RISC-V MCU 通过 pwrctrl 直接控制其电源,而 RISC-V CPU 的电源控制则由 RISC-V MCU 负责,这样确保了 RISC-V MCU 不仅能够有效管理自身电源状态,还能协调 RISC-V CPU 的启动和休眠。

在应用功能划分中,Wi-Fi 保活场景下,RISC-V MCU 唤醒后能够进行保活交互,而不需要唤醒 RISC-V CPU。在 Wi-Fi 用户数据交互的场景中,RISC-V MCU 唤醒后需要唤醒 RISC-V CPU 以处理用户数据,这要求 RISC-V MCU 的休眠唤醒框架具备对不同场景的处理能力。

为了优化功耗和唤醒速度,V821 芯片支持两种类型的休眠场景:

  • DDR 掉电模式,具有低休眠功耗,但唤醒速度较慢。在该模式下,仅将 RISC-V MCU 的现场保存在 SRAM 中(SRAM 保持通电),而 RISC-V CPU 的现场不进行保存,唤醒时需重启。
  • DDR 自刷新模式,虽然休眠功耗较高,但唤醒速度较快。在这种模式下,DDR 处于自刷新状态,RISC-V MCU 和 RISC-V CPU 的现场均能保存于 DDR 中,唤醒时两个核心可以从最近的断点处恢复,从而提升系统的响应速度。

休眠唤醒功能

目前板级配置中,仅有部分板级配置了休眠唤醒功能,若需使用功能请使用如下支持板级。

提示

若使用的板级不支持,可以参考支持的板级进行修改,配置方法请参考 休眠唤醒功能配置

危险

由于休眠唤醒配置项较多较复杂,且休眠唤醒实现功能较多,建议基于现有配置完成的板级二次开发,减少工作量方便同步环境配置。

板级配置休眠唤醒支持
V821-IPC最小化压缩常电 8M Flash 系统,未配置休眠唤醒功能
V821-PERF2PERF2 标准系统,支持超级待机模式,超低功耗待机模式,关机模式支持
V821-PERF2BPERF2B 标准系统,支持PMC电源管理,支持超级待机模式,超低功耗待机模式,关机模式支持
V821-PERF2-FASTBOOTPERF2 快起系统,支持超级待机模式,超低功耗待机模式,关机模式支持
V821-PERF2B-FASTBOOTPERF2B 快起系统,支持PMC电源管理,支持超级待机模式,超低功耗待机模式,关机模式支持

超级待机模式

超级待机模式下,RISC-V CPU、大部分外设、RISC-V MCU关闭电源,DRAM 进入自刷新模式。唤醒时候RISC-V CPU,RISC-V MCU都会从休眠的现场恢复运行。

echo mem > /sys/power/state

超低功耗待机模式

超低功耗待机模式下,RISC-V CPU、大部分外设、RISC-V MCU关闭电源,DRAM 也关闭电源,唤醒时候RISC-V CPU会重启,RISC-V MCU会从休眠的现场恢复运行。

echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff

关机模式

超低功耗待机模式下,RISC-V CPU、大部分外设、RISC-V MCU关闭电源,DRAM 也关闭电源,仅有 RTC 与唤醒功能保留供电。唤醒时候 RISC-V CPU,RISC-V MCU 都是重启。

poweroff

休眠唤醒功能测试

支持 Wakeup IO 功能

项目内容
用例名称支持 Wakeup IO 功能
功能说明验证支持 Wakeup IO 唤醒源
前置条件正确配置 PM 功能,正确配置 Wakeup IO: PL7
操作步骤1. PL7 接地
2. PL7 接入高电平
3. 查看打印
预期结果PL7 状态变化后 2s 打印 Wupio 打印 (不可配置 share-io 功能)

关键日志:

root@(none):/# [   64.963238] sunxi_wupio soc@2002000:wakeup_io: sunxi:wupio_sunxiWakeIO[7] is detected!
[ 64.972110] sunxi_wupio soc@2002000:wakeup_io: sunxi:wupio_sunxiWakeIO[7] is detected!

支持 Wakeup IO 唤醒

项目内容
用例名称支持 Wakeup IO 唤醒,包括超级待机,关机,超低功耗待机三种模式
功能说明验证支持 Wakeup IO 唤醒源
前置条件正确配置 PM 功能,正确配置 Wakeup IO: PL7
操作步骤1. 进入超级待机模式:echo mem > /sys/power/state
2. 将 PL7 接地/拉高(根据硬件决定) 2 秒
3. 进入休眠状态:poweroff
4. 将 PL7 接地/拉高(根据硬件决定) 2 秒
5. 进入超低功耗待机:echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff
6. 将 PL7 接地/拉高(根据硬件决定)2秒
预期结果三种模式下 PL7 状态变化 2 秒后,系统成功唤醒

日志:

  • 超级待机模式:
root@(none):/# echo mem > /sys/power/state
[ 272.520921] PM: suspend entry (deep)
...
[ 272.839009] PM: suspend exit
root@(none):/# [ 272.931933] configfs-gadget gadget: high-speed config #1: c
  • 关机模式:
root@(none):/# poweroff
The system is going down NOW!
Sent SIGTERM to all processes
Requesting system poweroff
[ 181.422764] sunxi:rtc:[INFO]: reboot_deal(): empty arg
[ 181.428607] sunxi:sunxi_riscv_pm:[INFO]: hib poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 181.437953] sunxi:sunxi_riscv_pm:[INFO]: hib ultra_poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 181.471549] sunxi:twi-42502000.twi0:[INFO]: shutdown finish
ac327 send hard syn message: 0x280202
ac327 receive hard syn message feedback: 0x280202
[ 181.480515] sunxi-rproc 43030000.e907_rproc: skip shutdown
[ 181.491915] sunxi:vin:[WARN]: video4 device have been closed!
[ 181.498370] sunxi:vin:[WARN]: video0 device have been closed!
[ 181.524026] reboot: Power down
ae350_system_reset(): CPU[0] SHUTDOWN
ac327 send hard syn message: 0x80240202
ac327 receive hard syn message feedback: 0x240202
[0]HELLO! BOOT0 is starting!
[2]BOOT0 commit : 48a890f536-dirty
[6]set pll start
[9]set pll end
  • 超低功耗待机模式:
root@(none):/# echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff
ac327 send hard syn message: 0x300202
ac327 receive hard syn message feedback: 0x300202
The system is going down NOW!
Sent SIGTERM to all processes
Requesting system poweroff
[ 44.427630] sunxi:rtc:[INFO]: reboot_deal(): empty arg
[ 44.433439] sunxi:sunxi_riscv_pm:[INFO]: hib poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 44.442799] sunxi:sunxi_riscv_pm:[INFO]: hib ultra_poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 44.476406] sunxi:twi-42502000.twi0:[INFO]: shutdown finish
ac327 send hard syn message: 0x280202
ac327 receive hard syn message feedback: 0x280202
[ 44.485393] sunxi-rproc 43030000.e907_rproc: skip shutdown
[ 44.496726] sunxi:vin:[WARN]: video4 device have been closed!
[ 44.503179] sunxi:vin:[WARN]: video0 device have been closed!
[ 44.524184] reboot: Power down
ae350_system_reset(): CPU[0] SHUTDOWN
ac327 send hard syn message: 0x80240202
ac327 receive hard syn message feedback: 0x240202
......


[1]HELLO! PMBOOT is starting!
[3]PMBOOT commit : 48a890f536-dirty
[7]set pll end
[8]wakeup_req: wakeup io

支持 Wakeup Timer 唤醒

项目内容
用例名称支持 Wakeup Timer 唤醒,包括超级待机,关机,超低功耗待机三种模式
功能说明验证支持 Wakeup Timer 唤醒源
前置条件正确配置 PM 功能,正确配置 Wakeup Timer
操作步骤1. 设置唤醒定时器为7秒:echo 5000 > /sys/class/ae350_standby/time_to_wakeup_ms
2. 进入超级待机模式:echo mem > /sys/power/state
3. 等待设置唤醒时间。
4. 设置唤醒定时器为7秒:echo 7000 > /sys/class/ae350_standby/time_to_wakeup_ms
5. 进入超低功耗待机模式:echo 0 > /sys/class/ae350_standby/use_ultra_standby; poweroff
6. 等待设置唤醒时间。
7. 设置唤醒定时器为7秒:echo 7000 > /sys/class/ae350_standby/time_to_wakeup_ms
8. 进入休眠模式:echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff
9. 等待设置唤醒时间。
预期结果等待设置唤醒时间后系统唤醒

日志:

  • 超级待机模式:
root@(none):/# echo 7000 > /sys/class/ae350_standby/time_to_wakeup_ms
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 24.934525] sunxi:ae350_standby_debug:[INFO]: time_to_wakeup_ms change to 5000
root@(none):/# echo mem > /sys/power/state
[ 27.578271] PM: suspend entry (deep)
...
[ 27.800643] PM: suspend exit
root@(none):/# [ 27.949779] configfs-gadget gadget: high-speed config #1: c
  • 关机模式:
root@(none):/# echo 7000 > /sys/class/ae350_standby/time_to_wakeup_ms
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 28.897457] sunxi:ae350_standby_debug:[INFO]: time_to_wakeup_ms change to 7000
root@(none):/# echo 0 > /sys/class/ae350_standby/use_ultra_standby; poweroff
ac327 send hard syn message: 0x300202
ac327 receive hard syn message feedback: 0x300202
The system is going down NOW!
Sent SIGTERM to all processes
Requesting system poweroff
[ 34.087356] sunxi:rtc:[INFO]: reboot_deal(): empty arg
[ 34.093168] sunxi:sunxi_riscv_pm:[INFO]: hib poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 34.102519] sunxi:sunxi_riscv_pm:[INFO]: hib ultra_poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 34.136202] sunxi:twi-42502000.twi0:[INFO]: shutdown finish
ac327 send hard syn message: 0x280202
ac327 receive hard syn message feedback: 0x280202
[ 34.145182] sunxi-rproc 43030000.e907_rproc: skip shutdown
[ 34.156513] sunxi:vin:[WARN]: video4 device have been closed!
[ 34.162956] sunxi:vin:[WARN]: video0 device have been closed!
[ 34.184051] reboot: Power down
ae350_system_reset(): CPU[0] SHUTDOWN
ac327 send hard syn message: 0x80240202
ac327 receive hard syn message feedback: 0x240202
[0]HELLO! BOOT0 is starting!
[2]BOOT0 commit : 48a890f536-dirty
[6]set pll start
  • 超低功耗待机模式
root@(none):/# echo 7000 > /sys/class/ae350_standby/time_to_wakeup_ms
ac327 send hard syn message: 0x80260202
ac327 receive hard syn message feedback: 0x260202
[ 318.075397] sunxi:ae350_standby_debug:[INFO]: time_to_wakeup_ms change to 7000
root@(none):/# echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff
The system is going down NOW!
Sent SIGTERM to all processes
Requesting system poweroff
[ 343.208698] sunxi:rtc:[INFO]: reboot_deal(): empty arg
[ 343.214538] sunxi:sunxi_riscv_pm:[INFO]: hib poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 343.223860] sunxi:sunxi_riscv_pm:[INFO]: hib ultra_poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 343.257455] sunxi:twi-42502000.twi0:[INFO]: shutdown finish
ac327 send hard syn message: 0x280202
ac327 receive hard syn message feedback: 0x280202
[ 343.266455] sunxi-rproc 43030000.e907_rproc: skip shutdown
[ 343.277769] sunxi:vin:[WARN]: video4 device have been closed!
[ 343.284229] sunxi:vin:[WARN]: video0 device have been closed!
[ 343.304072] reboot: Power down
ae350_system_reset(): CPU[0] SHUTDOWN
ac327 send hard syn message: 0x80240202
ac327 receive hard syn message feedback: 0x240202
......


[1]HELLO! PMBOOT is starting!
[3]PMBOOT commit : 48a890f536-dirty
[7]set pll end

支持 RTC Alarm 唤醒

项目内容
用例名称支持 RTC Alarm 唤醒,包括超级待机,关机,超低功耗待机三种模式
功能说明验证支持 RTC Alarm 唤醒源
前置条件正确配置 PM 功能,正确配置 RTC Alarm
操作步骤1. 设置RTC闹钟,10秒后触发中断:date; echo +10 > /sys/class/rtc/rtc0/wakealarm
2. 进入超级待机模式:echo mem > /sys/power/state
3. 等待设置唤醒时间。
4. 设置RTC闹钟,10秒后触发中断:date; echo +10 > /sys/class/rtc/rtc0/wakealarm
5. 进入超低功耗待机模式:echo 0 > /sys/class/ae350_standby/use_ultra_standby; poweroff
6. 等待设置唤醒时间。
7. 设置RTC闹钟,10秒后触发中断:date; echo +10 > /sys/class/rtc/rtc0/wakealarm
8. 进入休眠模式:echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff
9. 等待设置唤醒时间。
预期结果等待设置唤醒时间后系统唤醒

日志:

  • 超级待机模式:
root@(none):/# date; echo +10 > /sys/class/rtc/rtc0/wakealarm
Thu Jan 1 00:22:33 UTC 1970[ 648.159665] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!

[ 648.172741] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 648.184092] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 648.195435] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
root@(none):/# echo mem > /sys/power/state
[ 651.296731] PM: suspend entry (deep)
[ 651.300953] Filesystems sync: 0.000 seconds
[ 651.317428] Freezing user space processes ... (elapsed 0.001 seconds) done.
[ 651.326631] OOM killer disabled.
[ 651.330258] Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done.
[ 651.341369] printk: Suspending console(s) (use no_console_suspend to debug)
l▒[ 651.350162] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 651.350193] sunxi:uart-ng-uart-ng0:[INFO]: uart0 suspend
[ 651.351103] sunxi:gpadc-42009000.gpadc0:[INFO]: sunxi gpadc suspend
[ 651.351258] sunxi:sunxi_spif-44f00000.spif:[INFO]: [spi-flash0] suspend finish
[ 651.364164] MBUS_PMU 43102000.mbus-controller: suspend okay
[ 651.364690] sunxi:twi-42502000.twi0:[INFO]: suspend late
[ 651.382204] sunxi:pin-42000000.pinctrl:[INFO]: pinctrl suspend
[ 651.382633] sunxi:pin-42000000.pinctrl:[INFO]: pinctrl resume
[ 651.383314] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 651.405279] sunxi:twi-42502000.twi0:[INFO]: resume early
[ 651.405677] MBUS_PMU 43102000.mbus-controller: resume okay
[ 651.406326] sunxi:sunxi_spif-44f00000.spif:[INFO]: [spi-flash0] mclk 24000000
[ 651.406340] sunxi:sunxi_spif-44f00000.spif:[INFO]: [spi-flash0] resume finish
[ 651.406525] sunxi:sunxi_mmc_host-44020000.sdmmc:[INFO]: dat3_imask c0000000
[ 651.406608] sunxi:gpadc-42009000.gpadc0:[INFO]: sunxi gpadc resume
[ 651.414208] sunxi:uart-ng-uart-ng0:[INFO]: uart0, select set 0, baud 115200, uartclk 192000000 beyond rance[24000000, 120000000]
[ 651.414353] sunxi:uart-ng-uart-ng0:[INFO]: uart0, select set 0, baud 115200, uartclk 192000000 beyond rance[24000000, 120000000]
[ 651.414366] sunxi:uart-ng-uart-ng0:[INFO]: uart0 resume. DLH: 0, DLL: 104.
[ 651.414390] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 651.574057] OOM killer enabled.
[ 651.577581] Restarting tasks ... done.
[ 651.582813] PM: suspend exit
  • 关机模式:
root@(none):/# date; echo +10 > /sys/class/rtc/rtc0/wakealarm
Thu Jan 1 00:23:05 UTC 1970[ 673.381634] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!

[ 673.394806] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 673.406200] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 673.417557] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
root@(none):/# echo 0 > /sys/class/ae350_standby/use_ultra_standby; poweroff
ac327 send hard syn message: 0x300202
ac327 receive hard syn message feedback: 0x300202
The system is going down NOW!
Sent SIGTERM to all processes
Requesting system poweroff
[ 678.015765] sunxi:rtc:[INFO]: reboot_deal(): empty arg
[ 678.021575] sunxi:sunxi_riscv_pm:[INFO]: hib poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 678.030943] sunxi:sunxi_riscv_pm:[INFO]: hib ultra_poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 678.064524] sunxi:twi-42502000.twi0:[INFO]: shutdown finish
ac327 send hard syn message: 0x280202
ac327 receive hard syn message feedback: 0x280202
[ 678.073488] sunxi-rproc 43030000.e907_rproc: skip shutdown
[ 678.084848] sunxi:vin:[WARN]: video4 device have been closed!
[ 678.091290] sunxi:vin:[WARN]: video0 device have been closed!
[ 678.114114] reboot: Power down
ae350_system_reset(): CPU[0] SHUTDOWN
ac327 send hard syn message: 0x80240202
ac327 receive hard syn message feedback: 0x240202
[0]HELLO! BOOT0 is starting!
[2]BOOT0 commit : 48a890f536-dirty
[6]set pll start
  • 超低功耗待机模式
root@(none):/# date; echo +10 > /sys/class/rtc/rtc0/wakealarm
Thu Jan 1 00:23:46 UTC 1970[ 27.467816] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!

[ 27.480910] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 27.492267] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
[ 27.503604] sunxi:rtc-4a000c00.rtc:[WARN]: Warning: Using internal RC 16M clock source. Time may be inaccurate!
root@(none):/# echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff
ac327 send hard syn message: 0x300202
ac327 receive hard syn message feedback: 0x300202
The system is going down NOW!
Sent SIGTERM to all processes
Requesting system poweroff
[ 31.982851] sunxi:rtc:[INFO]: reboot_deal(): empty arg
[ 31.988693] sunxi:sunxi_riscv_pm:[INFO]: hib poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 31.998029] sunxi:sunxi_riscv_pm:[INFO]: hib ultra_poweron_source is 0x7ff
ac327 send hard syn message: 0x260202
ac327 receive hard syn message feedback: 0x260202
[ 32.031627] sunxi:twi-42502000.twi0:[INFO]: shutdown finish
ac327 send hard syn message: 0x280202
ac327 receive hard syn message feedback: 0x280202
[ 32.040593] sunxi-rproc 43030000.e907_rproc: skip shutdown
[ 32.051973] sunxi:vin:[WARN]: video4 device have been closed!
[ 32.058433] sunxi:vin:[WARN]: video0 device have been closed!
[ 32.084244] reboot: Power down
ae350_system_reset(): CPU[0] SHUTDOWN
ac327 send hard syn message: 0x80240202
ac327 receive hard syn message feedback: 0x240202
......

[1]HELLO! PMBOOT is starting!
[3]PMBOOT commit : 48a890f536-dirty
[7]set pll end
[8]wakeup_req: sysrtc
[10]reset_src: rtc wdg rst
[12]reset_src: det rst

休眠状态中 LDO 开关控制

项目内容
用例名称支持 RTC Alarm 唤醒,包括超级待机,关机,超低功耗待机三种模式
功能说明验证支持 RTC Alarm 唤醒源
前置条件正确配置 PM 功能,万用表
操作步骤1. 设置LDO1V8/LDO2V8休眠关闭:echo 0 > /sys/class/ae350_standby/standby_ldo_onoff
2. 进入超级待机模式:echo mem > /sys/power/state
3. 用万用表测量LDO1V8/LDO2V8电压。
4. 设置LDO1V8/LDO2V8休眠关闭:echo 3 > /sys/class/ae350_standby/standby_ldo_onoff
5. 进入超级待机模式:echo mem > /sys/power/state
6. 用万用表测量LDO1V8/LDO2V8电压。
7. 设置LDO1V8/LDO2V8休眠关闭:echo 0 > /sys/class/ae350_standby/standby_ldo_onoff
8. 进入超低功耗待机模式:echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff
9. 用万用表测量LDO1V8/LDO2V8电压。
10. 设置LDO1V8/LDO2V8休眠关闭:echo 3 > /sys/class/ae350_standby/standby_ldo_onoff
11. 进入超低功耗待机模式:echo 1 > /sys/class/ae350_standby/use_ultra_standby; poweroff
12. 用万用表测量LDO1V8/LDO2V8电压。
预期结果用万用表测量LDO1V8 / LDO2V8电压和实际配置开关状态一致

休眠唤醒功能配置

Linux 端软件配置

配置休眠唤醒功能

Linux 端对接到的是标准的 Linux PM 框架,开启 Linux 的 PM 框架即可。执行 `make kernel

Power management options  --->
[*] Suspend to RAM and standby
-*- Device power management core functionality

image-20250430090528457

另外 V821 扩展了多种休眠唤醒模式,需要开启功能配置节点

Allwinner BSP  --->
Device Drivers --->
RISCV suspend Drivers --->
<*> Allwinner sunxi riscv suspend support
<*> Andes sunxi Standby Debugging Driver

image-20250430090917453

设备树配置:

board.dts
/{
poweron-source {
hib_poweron_source = <0x000007FF>;
ultra_poweron_source = <0x000007FF>;
};

ae350_standby_debug:ae350_standby_debug@1 {
compatible = "allwinner,sun300iw1-ae350-standby-debug";
mboxes = <&msgbox 2>;
mbox-names = "ae350-notify";
memory-region = <&efuse_ram_reserved>;
status = "okay";
};
};

配置 BOOT_PKG 偏移

提示

SPI NOR 需要配置这个部分。

配置内核选项 CONFIG_SPINOR_UBOOT_OFFSET 对应到 UBOOT 的 flash_map 配置中。

Allwinner BSP  --->
Device Drivers --->
<*> Memory Technology Device (AW_MTD) support --->
(96) spinor uboot offset

例如这里 IPC 方案的 device/config/chips/v821/configs/ipc/uboot-board.dts 是 96

image-20250430113038358

则对应配置 96

image-20250430112716215

如果配置是 128

image-20250430113124668

则对应配置 128 即可

配置按键唤醒源驱动

在 V821 芯片中,PL组的引脚均可作为 WUPIO 唤醒引脚,我们可以配置 PL 组引脚作为唤醒源。此时需要勾选相关驱动。

Allwinner BSP  --->
Device Drivers --->
WUPIO Drivers --->
<*> WUPIO Support for Allwinner SoCs

image-20250430091132633

提示

下面的功能为 SDK 1.2 所支持的,SDK 1.1 暂未支持

如果该 WUPIO 需要作为普通按键使用,则需要开启 CONFIG_AW_WUPIO_KEYBOARD_GPIO,以支持 Linux 将其看作普通按键。

Allwinner BSP  --->
Device Drivers --->
WUPIO Drivers --->
<*> GPIO Buttons With WUPIO Support

image-20250516172510858

危险

使用 CONFIG_AW_WUPIO_KEYBOARD_GPIO 驱动,请一定关闭内核的 CONFIG_KEYBOARD_GPIO 驱动,不要开下图的驱动否则导致驱动资源冲突

image-20250521163037415

CONFIG_AW_WUPIO_KEYBOARD_GPIO 驱动仅为内核原生 CONFIG_KEYBOARD_GPIO 驱动增加 WUPIO 共享支持,其用法与内核原生驱动一致!

可以用这行命令确认是否开了两个驱动:

dmesg | grep gpio-key

正常情况,只开了一个驱动:

image-20250606202719354

开多了驱动打印是这样的

image-20250606203320614

配置按键唤醒源设备树

WUPIO 配置向导

Step 1: 选择作为 WUPIO 的引脚

设备树配置唤醒按键,这里以 PL7 作为示例,PL7 可作为普通按键和 WUPIO。在系统正常启动使用的时候,是作为普通按键,当系统进入休眠自动注册为 WUPIO。

board.dts
#include <dt-bindings/input/linux-event-codes.h> // 导入 linux,code = <KEY_POWER>; 的定义

&soc {
gpio-keys {
compatible = "gpio-keys";
status = "okay";
wakeup_io = <&wakeup_pin1>;
power {
label = "Power";
gpios = <&rtc_pio PL 7 GPIO_ACTIVE_HIGH>;
linux,code = <KEY_POWER>;
debounce-interval = <30>;
status = "okay";
};
};
};

&wakeup_io {
status = "okay";
wakeup_pins {
wakeup_pin1:wakeup-pin@1 {
gpio_info = <&rtc_pio PL 7 GPIO_ACTIVE_HIGH>;
edge_mode = "positive";
clk_src = <0>;
debounce_us = <2000000>;
share-io; // 共享 IO
status = "okay";
};
};
};

如果该 WUPIO 是专用的,例如外挂 WIFI 的唤醒源,则不需要配置共用功能。配置如下(这里以 PL5 为例):

&wakeup_io {
status = "okay";
wakeup_pins {
wakeup_pin1:wakeup-pin@1 {
gpio_info = <&rtc_pio PL 5 GPIO_ACTIVE_HIGH>;
edge_mode = "positive";
clk_src = <0>;
debounce_us = <2000000>;
status = "okay";
};
};
};

如果既有专用 IO,也有共用IO,则配置如下:

#include <dt-bindings/input/linux-event-codes.h> // 导入 linux,code = <KEY_POWER>; 的定义

&soc {
gpio-keys {
compatible = "gpio-keys";
status = "okay";
wakeup_io = <&wakeup_pin1>;
power {
label = "Power";
gpios = <&rtc_pio PL 7 GPIO_ACTIVE_HIGH>;
linux,code = <KEY_POWER>;
debounce-interval = <30>;
status = "okay";
};
};
};

&wakeup_io {
status = "okay";
wakeup_pins {
wakeup_pin1:wakeup-pin@1 {
gpio_info = <&rtc_pio PL 7 GPIO_ACTIVE_HIGH>;
edge_mode = "positive";
clk_src = <0>;
debounce_us = <2000000>;
share-io; // 共享 IO
status = "okay";
};

wakeup_pin2:wakeup-pin@2 {
gpio_info = <&rtc_pio PL 5 GPIO_ACTIVE_HIGH>;
edge_mode = "positive";
clk_src = <0>;
debounce_us = <2000000>;
status = "okay";
};
};
};
已知 BUG

若休眠唤醒发现 super standby 启动卡死,可以在这里增加代码修复该问题

bsp/drivers/wupio/gpio-keys.c 987行
#if IS_ENABLED(CONFIG_AW_WUPIO)
for (i = 0; i < pdata->nbuttons; i++) {
if (!ddata->data[i].gpiod)
continue;

disable_irq(ddata->data[i].irq);
if (sunxi_wupio_is_illegal(dev, ddata->data[i].gpiod) == 0) {
ret = sunxi_share_wupio_enable(dev, ddata->data[i].gpiod);
if (ret)
dev_err(dev, "failed to enable wupio\n");
}
}
#endif

return 0;
}

RTOS 端软件配置

RTOS 端需要启用 PM 框架,配置相关功能,执行 mrtos menuconfig

System components  --->
aw components --->
[*] PowerManager Support --->
--- PowerManager Support
(0x02000000) PM Firmware's space base
(0x21c00) PM Firmware's space size
(0x81244000) Rtos firmware reserved memory address
(500) Dram power open dration of us
Select standby load storage type (SPINOR) --->
[*] pm_standby_memory
(plat_sun300iw1p1) pm plat name
[ ] Set CPU to VF 2_1 (1200MHz/1.00v)
[*] pm enable pmc
[ ] pm pmc using PL6 GPIO as power ctl

image-20250430092229394

以下是关于配置项的说明表:

配置项描述
(0x02000000) PM Firmware's space basePM固件的空间基地址,表示固件在内存中的起始地址。这里运行在 SRAM 中
(0x21c00) PM Firmware's space sizePM固件的空间大小,以字节为单位,指示固件在 SRAM 内存中所占用的大小。
(0x81244000) Rtos firmware reserved memory address实时操作系统(RTOS)固件保留的内存地址,用于系统唤醒后加载 RTOS 固件。需要与设备树中 e907_mem_fw 配置项对应
(500) Dram power open duration of usDRAM供电开启持续时间,以微秒为单位,指示系统初始化和内存供电的持续时间。与外部 DCDC 上电时间强相关,一般建议留有裕度,否则会造成休眠唤醒失败。
Select standby load storage type (SPINOR)选择待机时加载的存储类型,这里使用 SPINOR。
[*] pm_standby_memory指示启用待机模式时使用内存 SRAM,需要勾选。
(plat_sun300iw1p1) pm plat namePM平台名称,描述当前正在使用的电源管理平台的版本或型号。不用修改
[ ] Set CPU to VF 2_1 (1200MHz/1.00v)如果方案配置 CPU 运行频率最高 1.2GHz,需要勾选这个配置。
[*] pm enable pmc选项,表示启用电源管理控制器(PMC)以管理设备的电源状态。使用休眠唤醒必须启用PMC相关功能
[ ] pm pmc using PL6 GPIO as power表示PMC使用PL6 GPIO引脚控制电源,若硬件没有使用PMC且PL6不需要控制外部电源则无需配置

然后需要开启休眠唤醒相关的外设驱动:

CONFIG_DRIVERS_PRCM
CONFIG_DRIVERS_RTC_WATCHDOG

启用 PRCM 控制器驱动,mrtos menuconfig

Drivers Options  --->
soc related device drivers --->
PRCM Devices --->
[*] enable prcm driver

image-20250430155241759

启用 RTC_WATCHDOG 相关驱动

Drivers Options  --->
soc related device drivers --->
RTC WATCHDOG Devices --->
[*] enable rtc watchdog driver

image-20250430155315989

另外还需要配置休眠内存分配,需要修改板级对应的链接脚本,将不需要休眠的数据放到非休眠内容段内。这里以 perf2b 板级为例,修改文件

注意

此部分仅为示例实现,具体使用到需要保留现场的函数需要根据 RTOS 开发功能而定。

提示

完整的配置可以参考已经配置休眠唤醒的板级。

rtos/lichee/rtos/projects/v821_e907/perf2b/freertos.lds.S
OUTPUT_ARCH("riscv")
OUTPUT_FORMAT("elf32-littleriscv","elf32-littleriscv","elf32-littleriscv")

/* Linker script to configure memory regions. */
MEMORY
{
RAM (rwx) : ORIGIN = CONFIG_ARCH_START_ADDRESS, LENGTH = CONFIG_ARCH_MEM_LENGTH
}

__RAM_BASE = ORIGIN(RAM);
__MSP_STACK_LENGTH = 0x100;

ENTRY(_start)

SECTIONS
{
.flash_driver :
{
/* this section must be the first section which is before bss section,
* it is used for flash driver which is shared for rtos and pm_standby firmware,
* in standby wakeup process, firmware will load rtos without this section,
* so flash_bin section must 512 byte align, because a flash section is 512 byte,
* to avoid memory cover
*/
. = ALIGN(512);
__flash_driver_start__ = .;
KEEP(*(.flash_bin))
. = ALIGN(512);
__flash_driver_end__ = .;
} > RAM

.text :
{
. = ALIGN(4);
__text_start__ = .;
KEEP(*(.start))
*(.vectors)
*(*.text)
*(.text*)
*(.nonxip_text*)
*(.sram_text*)
KEEP(*(.init))
KEEP(*(.fini))

/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)

/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)

*(.rodata*)
*(.srodata*)
*(.nonxip_rodata*)
*(.sram_rodata*)

KEEP(*(.eh_frame*))

#ifdef CONFIG_PMP_ADDR_ALIGN
. = ALIGN(CONFIG_PMP_ADDR_ALIGN);
#else
. = ALIGN(4);
#endif
__text_end__ = .;
} > RAM

__etext = .;
_sidata = .;
#ifdef CONFIG_PM_STANDBY_MEMORY
.data_saved :
{
. = ALIGN(4);
__stby_saved_data_start__ = .;
KEEP(*(.standby_saved_data))
__stby_saved_data_end__ = .;
} > RAM

.data_unsaved :
{
. = ALIGN(4);
__stby_unsaved_data_start__ = .;
*(.standby_unsaved_data*)
*build/RTOS_TARGET_PROJECT_PATH/drivers/rtos-hal/hal/source/ccu/?*(.data*)
*build/RTOS_TARGET_PROJECT_PATH/components/common/aw/multi_console/?*(.data*)
*build/RTOS_TARGET_PROJECT_PATH/components/common/thirdparty/openamp/?*(.data*)
*build/RTOS_TARGET_PROJECT_PATH/components/common/aw/rpbuf/?*(.data*)
*build/RTOS_TARGET_PROJECT_PATH/components/common/aw/pm/common/pm_testlevel.o(.data*)
*build/RTOS_TARGET_PROJECT_PATH/components/thirdparty/console/commands/?*(.data*)
. = ALIGN(16);
__init_process_stack_start__ = .;
. += 4096;
__init_process_stack_end__ = .;
. = ALIGN(16);
__freertos_irq_stack_bottom = .;
. += 4096;
__freertos_irq_stack_top = .;
PROVIDE( __global_pointer$ = . + 0x400 );
__stby_unsaved_data_end__ = .;
} > RAM
#endif
.data :
{
. = ALIGN(4);
__data_start__ = .;
_sdata = .;

*(vtable)
*(.data*)
*(.sdata*)
*(.nonxip_data*)
*(.sram_data*)

. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);

. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
PROVIDE(__ctors_start__ = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE(__ctors_end__ = .);
PROVIDE_HIDDEN (__init_array_end = .);

. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);

KEEP(*(.jcr*))
#ifndef CONFIG_PM_STANDBY_MEMORY
. = ALIGN(16);
__init_process_stack_start__ = .;
. += 4096;
__init_process_stack_end__ = .;
. = ALIGN(16);
__freertos_irq_stack_bottom = .;
. += 4096;
__freertos_irq_stack_top = .;
PROVIDE( __global_pointer$ = . + 0x400 );
#endif
. = ALIGN(4);
__data_end__ = .;
_edata = .;
} > RAM

.version_table : {
KEEP(*(.version_table))
} > RAM

.resource_table : {
KEEP(*(.resource_table))
} > RAM

.digest : ALIGN(4)
{
_digest_start = ABSOLUTE(.);
KEEP (*(.digest))
. = ALIGN (4);
_digest_end = ABSOLUTE(.);
} > RAM

.FSymTab : {
_syscall_table_begin = .;
KEEP(*(FSymTab))
_syscall_table_end = .;
} > RAM

.VSymTab : {
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
} > RAM

.ttcall : {
_tt_begin = .;
KEEP(*(ttcall))
_tt_end = .;
} > RAM

#ifdef CONFIG_COMPONENTS_AMP_USER_RESOURCE
.amp_user_rsc (NOLOAD):
{
. = ALIGN(4);
__amp_user_rsc_start__ = .;
*(.amp_user_rsc)
. = ALIGN(4);
__amp_user_rsc_end__ = .;
} > RAM
#endif

.heap (COPY):
{
__end__ = .;
__heap_start__ = .;
_heap_start = .;
end = __end__;
*(.heap*)
__HeapLimit = .;
} > RAM

/* .stack_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign
* values to stack symbols later */
.stack_dummy (COPY):
{
*(.stack*)
} > RAM
#ifdef CONFIG_PM_STANDBY_MEMORY
.bss_saved :
{
. = ALIGN(4);
__stby_saved_bss_start__ = .;
KEEP(*(.standby_saved_bss))
__stby_saved_bss_end__ = .;
} > RAM

/* .bss_usnaved section must at last, but before .bss section, because .bss_unsaved section is NOLOAD */
.bss_unsaved (NOLOAD):
{
. = ALIGN(4);
__stby_unsaved_bss_start__ = .;
*(.standby_unsaved_bss*)
*build/RTOS_TARGET_PROJECT_PATH/drivers/rtos-hal/hal/source/ccu/?*(.bss*)
*build/RTOS_TARGET_PROJECT_PATH/components/common/aw/multi_console/?*(.bss*)
*build/RTOS_TARGET_PROJECT_PATH/components/common/thirdparty/openamp/?*(.bss*)
*build/RTOS_TARGET_PROJECT_PATH/components/common/aw/rpbuf/?*(.bss*)
*build/RTOS_TARGET_PROJECT_PATH/components/common/aw/pm/common/pm_testlevel.o(.bss*)
*build/RTOS_TARGET_PROJECT_PATH/components/thirdparty/console/commands/?*(.bss*)
__stby_unsaved_bss_end__ = .;
} > RAM
#endif
.bss (NOLOAD):
{
. = ALIGN(4);
__bss_start__ = .;
_sbss = .;
*(.bss*)
*(.sbss*)
*(COMMON)
*(.nonxip_bss*)
*(.sram_bss*)

. = ALIGN(4);
__bss_end__ = .;
_ebss = .;
} > RAM

. = ALIGN(8);

/* Set stack top to end of RAM, and stack limit move down by
* size of stack_dummy section */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
_estack = __StackTop;
__heap_end__ = _estack - __MSP_STACK_LENGTH;
_heap_end = __heap_end__;
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);

/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}

增加了 data_saveddata_unsaved 段配置

image-20250430093245619

增加了栈指针导出

image-20250430093210034

增加了 bss_savedbss_unsaved 段配置

image-20250430093145823

另外方案对应的 main.c 函数也需要增加 PM 会使用到的 init_openampdeinit_openamp_sync 函数功能,这两个函数不可在线程中运行,必须同步阻塞运行。

例如这里在 rtos/lichee/rtos/projects/v821_e907/perf2b/src/main.c 中实现的功能:

注意

此部分仅为示例实现,具体使用到需要初始化与反初始化的函数需要根据 RTOS 开发功能而定。

提示

完整的配置可以参考已经配置休眠唤醒的板级。

需要增加的内容已在下方示例代码中高亮说明:

rtos/lichee/rtos/projects/v821_e907/perf2b/src/main.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "interrupt.h"
#include <portmacro.h>
#include "FreeRTOS.h"
#include "task.h"
#include <hal_time.h>

#include <console.h>

#ifdef CONFIG_DRIVERS_MSGBOX
#include <hal_msgbox.h>
#endif

#ifdef CONFIG_COMPONENTS_PM
extern int pm_init(int argc, char **argv);
#endif

#ifdef CONFIG_GEN_DIGEST
/* format: 4bytes image size + 16bytes digest */
__attribute__((section(".digest"))) const unsigned char digest_data[20];
#endif

#ifdef CONFIG_COMPONENTS_OPENAMP
#include <openamp/sunxi_helper/rpmsg_master.h>
#include <openamp/sunxi_helper/openamp.h>

#ifdef CONFIG_COMPONENTS_RPBUF
extern int rpbuf_init(void);
#endif

void init_amp_app(void)
{
#ifdef CONFIG_COMPONENTS_AMP_USER_RESOURCE
extern void show_all_user_resource(void);
show_all_user_resource();
#endif

#ifdef CONFIG_RPMSG_CLIENT
rpmsg_ctrldev_create();
#endif

#ifdef CONFIG_RPMSG_HEARBEAT
extern int rpmsg_heart_init(void);
rpmsg_heart_init();
#endif

#ifdef CONFIG_MULTI_CONSOLE
extern int multiple_console_init(void);
multiple_console_init();
#endif

#ifdef CONFIG_COMPONENTS_RPBUF
rpbuf_init();
#endif
}

void deinit_amp_app(void)
{
#ifdef CONFIG_COMPONENTS_RPBUF
extern void rpbuf_deinit(int rproc_id);
rpbuf_deinit(0);
#endif

#ifdef CONFIG_MULTI_CONSOLE
extern int multiple_console_deinit(void);
multiple_console_deinit();
#endif

#ifdef CONFIG_RPMSG_HEARBEAT
extern int rpmsg_heart_deinit(void);
rpmsg_heart_deinit();
#endif

#ifdef CONFIG_RPMSG_CLIENT
rpmsg_ctrldev_release();
#endif

#ifdef CONFIG_RPMSG_NOTIFY
extern int rpmsg_notify_deinit(void);
rpmsg_notify_deinit();
#endif
}

void init_amp_framework(void)
{
#if defined(CONFIG_ARCH_RISCV_PMP) && !defined(CONFIG_PMP_EARLY_ENABLE)
__attribute__((__unused__)) int pmp_ret;

#ifdef CONFIG_COMPONENTS_RPBUF
extern int set_pmp_for_rpbuf_reserved_mem(void);
pmp_ret = set_pmp_for_rpbuf_reserved_mem();
if (pmp_ret)
{
printf("set PMP for rpbuf reserved mem faild, ret: %d\n", pmp_ret);
}
#endif

#endif

openamp_init();
}

void deinit_amp_framework(void)
{
openamp_deinit();
}

void openamp_init_thread(void *param)
{
(void)param;
init_amp_framework();
init_amp_app();

#ifdef CONFIG_INIT_NET_STACK
extern int xradio_link_init(int pm_flag);
xradio_link_init(0);
#endif
#ifdef CONFIG_DRIVERS_V821_USE_SIP_WIFI
extern int xradio_rpmsg_create(void);
xradio_rpmsg_create();
#endif

hal_thread_stop(NULL);
}

void pm_openamp_init_thread(void *param)
{
(void)param;
init_amp_framework();
init_amp_app();

#ifdef CONFIG_INIT_NET_STACK
extern int xradio_link_init(int pm_flag);
xradio_link_init(1);
#endif

hal_thread_stop(NULL);
}

void openamp_deinit_thread(void *param)
{
(void)param;

deinit_amp_app();
deinit_amp_framework();

hal_thread_stop(NULL);
}

int init_openamp(void)
{
void *thread;
thread = hal_thread_create(pm_openamp_init_thread, NULL,
"amp_init", 8 * 1024, HAL_THREAD_PRIORITY_SYS);
if (thread != NULL)
hal_thread_start(thread);
else
return -1;

return 0;
}

int deinit_openamp(void)
{
void *thread;
thread = hal_thread_create(openamp_deinit_thread, NULL,
"amp_deinit", 4 * 1024, HAL_THREAD_PRIORITY_SYS);
if (thread != NULL)
hal_thread_start(thread);
else
return -1;

return 0;
}

int deinit_openamp_sync(void)
{
#ifdef CONFIG_DRIVERS_V821_USE_SIP_WIFI
/* todo: implement this function */
//xradio_rpmsg_relaese();
#endif

#ifdef CONFIG_INIT_NET_STACK
extern void xradio_link_deinit(void);
// xradio_link_deinit();
#endif
deinit_amp_app();
deinit_amp_framework();

return 0;
}
#endif


#ifdef CONFIG_COMMAND_AUTO_START_MEMTESTER
static void auto_memtester_thread(void *param)
{
extern int cmd_memtest();
cmd_memtest();
hal_thread_stop(NULL);
}
#endif

#ifdef CONFIG_COMPONENTS_TCPIP
extern void cmd_tcpip_init(void);
#endif

void cpu0_app_entry(void *param)
{
(void)param;

#ifdef CONFIG_COMPONENTS_PM
pm_init(1, NULL);
#endif

#ifdef CONFIG_COMPONENTS_OPENAMP
void *thread;
thread = hal_thread_create(openamp_init_thread, NULL,
"amp_init", 8 * 1024, HAL_THREAD_PRIORITY_SYS);
if (thread != NULL)
hal_thread_start(thread);
#endif

#ifdef CONFIG_COMPONENTS_TCPIP
//tcpip stack init
cmd_tcpip_init();
#endif

#if defined(CONFIG_COMPONENT_CLI) && !defined(CONFIG_UART_MULTI_CONSOLE_AS_MAIN)
vCommandConsoleStart(0x1000, HAL_THREAD_PRIORITY_CLI, NULL);
#endif

#ifdef CONFIG_COMMAND_AUTO_START_MEMTESTER
void *autotest_thread;
autotest_thread = hal_thread_create(auto_memtester_thread, NULL,
"auto_memtester", 8 * 1024, HAL_THREAD_PRIORITY_SYS);

if (autotest_thread != NULL)
hal_thread_start(autotest_thread);
#endif

vTaskDelete(NULL);
}
注意

如果启用了小核压缩 & 自解压功能,PM 功能将不可用,需要配置小核镜像非压缩。执行 mrtos menuconfig

Kernel Options  --->
[*] kernel Compress Support ---> (取消勾选)

小核关闭压缩后可能分区表配置放不下,报错如下:

image-20250430095733175

此时需要修改对应方案的分区表,配置到小核固件的大小。需要对齐到 128

image-20250430095900994

内核端也需要关闭小核解压功能

Allwinner BSP  --->
Device Drivers --->
Remoteproc drivers --->
< > Allwinner remoteproc decompress firmware from partition # 取消勾选

image-20250430100248100

软件方案配置

除了软件上的配置,休眠唤醒如果需要使用超低功耗待机模式, 还需要增加休眠唤醒引导 PMBOOT,例如这里 IPC 方案,如果要配置则需要编辑 device/config/chips/v821/configs/ipc/boot_package_nor.cfg 增加配置项,另外超低功耗待机模式下,不支持对 opensbi,u-boot 进行压缩。如果配置了压缩请修改为不带压缩的版本。

item=opensbi,            opensbi.fex
item=u-boot, u-boot-spinor.fex
item=pmboot, pmboot_spinor.fex

image-20250430153051900

备注

如果配置不压缩模式,打包报错,则是因为没有压缩的情况下原先的 flash_map 已经放不下固件了,需要适当扩大配置。

ERROR flashmap logic_offset start block: 608 is less than uboot_start last block: 896

image-20250430153340914

此时需要修改板级对应的 uboot-board.dts 扩大分区表,例如这里 IPC 板级,修改文件:device/config/chips/v821/configs/ipc/uboot-board.dts

image-20250430153446624

device/config/chips/v821/configs/perf2b/uboot-board.dts
nor_map {
/*Unit: Sector, 8M flash:16384, 16M flash:32768, 32M flash:65536*/
/* logic offset requires block size(64K) alignment - 32(mbr size) */
flash_size = <16384>;
logic_offset = <2016>;
secure_logic_offset = <2016>;
rtos_logic_offset = <2016>;
rtos_secure_logic_offset = <2016>;
boot_param_start = <120>;
boot_param_size = <8>;
uboot_start = <128>;
uboot_size = <1888>;
boot0_start = <0>;
status = "okay";
};

另外还需要到 Linux 内核配置 BOOT_PKG 偏移,配置内核选项 CONFIG_SPINOR_UBOOT_OFFSET 对应到 UBOOT 的 flash_map 配置中。

Allwinner BSP  --->
Device Drivers --->
<*> Memory Technology Device (AW_MTD) support --->
(128) spinor uboot offset

如果是 MMC 方案休眠唤醒,则在 boot_package.cfg 中配置

item=pmboot,                 pmboot_sdcard.fex
注意

注意编辑 boot_package_nor.cfgboot_package.cfg 时,需要文件底部留空行,否则会出现打包报错!

另外还需要配置设备树配置同步 BOOT0 联动机制,方便动态配置 BOOT0 的参数内容。这个配置大部分板级已经默认启用,若未启用例如 IPC 板级,编辑 device/config/chips/v821/configs/ipc/BoardConfig_nor.mk 增加以下配置:

LICHEE_GEN_BOOT0_DTS_INFO:=yes

image-20250430134158579

执行完成之后需要重新加载 SDK

source build/envsetup.sh
lunch

常用调试方法

控制台挂起时的日志输出

echo N > /sys/module/printk/parameters/console_suspend

说明:

  • console_suspend 是内核参数,控制系统进入挂起模式(如休眠)时是否输出控制台日志。
  • 设置为 N 表示禁用在系统挂起时的控制台日志输出。通常用于调试或优化电源管理,减少日志信息对系统的干扰。

示例:

  • 设置为 Necho N > /sys/module/printk/parameters/console_suspend,禁用挂起时的控制台日志输出。
  • 设置为 Yecho Y > /sys/module/printk/parameters/console_suspend,启用挂起时的控制台日志输出(会输出更多的日志信息,适合调试电源管理问题)。

内核初始化调用调试信息

echo Y > /sys/module/kernel/parameters/initcall_debug

说明:

  • initcall_debug 是一个内核调试参数,启用后,内核在启动时会输出详细的初始化调用调试信息。
  • 设置为 Y,可以帮助开发者查看内核启动过程中初始化函数的详细过程,特别是在调试内核启动问题时非常有用。

示例:

  • 设置为 Yecho Y > /sys/module/kernel/parameters/initcall_debug,启用内核初始化调用调试,输出详细的启动过程信息。
  • 设置为 Necho N > /sys/module/kernel/parameters/initcall_debug,禁用内核初始化调用调试,减少启动过程中的调试信息输出。

电源管理调试信息输出

echo 1 > /sys/power/pm_debug_messages

说明:

  • pm_debug_messages 控制电源管理调试信息的输出。
  • 设置为 1 后,系统会输出与电源管理相关的调试信息,包括系统的睡眠、唤醒等操作。此命令适用于调试电源管理流程,帮助识别和解决电源管理中的问题。

示例:

  • 设置为 1echo 1 > /sys/power/pm_debug_messages,启用电源管理调试信息输出,详细记录睡眠、唤醒等操作。
  • 设置为 0echo 0 > /sys/power/pm_debug_messages,禁用电源管理调试信息输出,减少调试信息的量。

电源管理操作的时间打印

echo 0 > /sys/power/pm_print_times

说明:

  • pm_print_times 控制是否打印电源管理操作的时间信息。
  • 设置为 0,表示禁用电源管理操作的时间打印。此命令适用于减少调试输出信息,优化日志,或在不需要时间打印时提高系统性能。

示例:

  • 设置为 0echo 0 > /sys/power/pm_print_times,禁用电源管理操作的时间打印,避免在日志中记录过多时间信息。
  • 设置为 1echo 1 > /sys/power/pm_print_times,启用电源管理操作的时间打印,记录系统在不同电源管理操作中的耗时(有助于诊断性能问题)。