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-PERF2 | PERF2 标准系统,支持超级待机模式,超低功耗待机模式,关机模式 | 支持 |
V821-PERF2B | PERF2B 标准系统,支持PMC电源管理,支持超级待机模式,超低功耗待机模式,关机模式 | 支持 |
V821-PERF2-FASTBOOT | PERF2 快起系统,支持超级待机模式,超低功耗待机模式,关机模式 | 支持 |
V821-PERF2B-FASTBOOT | PERF2B 快起系统,支持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
另外 V821 扩展了多种休眠唤醒模式,需要开启功能配置节点
Allwinner BSP --->
Device Drivers --->
RISCV suspend Drivers --->
<*> Allwinner sunxi riscv suspend support
<*> Andes sunxi Standby Debugging Driver
设备树配置:
/{
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
则对应配置 96
如果配置是 128
则对应配置 128 即可
配置按键唤醒源驱动
在 V821 芯片中,PL组的引脚均可作为 WUPIO 唤醒引脚,我们可以配置 PL 组引脚作为唤醒源。此时需要勾选相关驱动。
Allwinner BSP --->
Device Drivers --->
WUPIO Drivers --->
<*> WUPIO Support for Allwinner SoCs
下面的功能为 SDK 1.2 所支持的,SDK 1.1 暂未支持
如果该 WUPIO 需要作为普通按键使用,则需要开启 CONFIG_AW_WUPIO_KEYBOARD_GPIO
,以支持 Linux 将其看作普通按键。
Allwinner BSP --->
Device Drivers --->
WUPIO Drivers --->
<*> GPIO Buttons With WUPIO Support
使用 CONFIG_AW_WUPIO_KEYBOARD_GPIO
驱动,请一定关闭内核的 CONFIG_KEYBOARD_GPIO
驱动,不要开下图的驱动否则导致驱动资源冲突
CONFIG_AW_WUPIO_KEYBOARD_GPIO
驱动仅为内核原生 CONFIG_KEYBOARD_GPIO
驱动增加 WUPIO 共享支持,其用法与内核原生驱动一致!
可以用这行命令确认是否开了两个驱动:
dmesg | grep gpio-key
正常情况,只开了一个驱动:
开多了驱动打印是这样的
配置按键唤醒源设备树
WUPIO 配置向导
Step 1: 选择作为 WUPIO 的引脚
设备树配置唤醒按键,这里以 PL7 作为示例,PL7 可作为普通按键和 WUPIO。在系统正常启动使用的时候,是作为普通按键,当系统进入休眠自动注册为 WUPIO。
#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";
};
};
};
若休眠唤醒发现 super standby 启动卡死,可以在这里增加代码修复该问题
#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
以下是关于配置项的说明表:
配置项 | 描述 |
---|---|
(0x02000000) PM Firmware's space base | PM固件的空间基地址,表示固件在内存中的起始地址。这里运行在 SRAM 中 |
(0x21c00) PM Firmware's space size | PM固件的空间大小,以字节为单位,指示固件在 SRAM 内存中所占用的大小。 |
(0x81244000) Rtos firmware reserved memory address | 实时操作系统(RTOS)固件保留的内存地址,用于系统唤醒后加载 RTOS 固件。需要与设备树中 e907_mem_fw 配置项对应 |
(500) Dram power open duration of us | DRAM供电开启持续时间,以微秒为单位,指示系统初始化和内存供电的持续时间。与外部 DCDC 上电时间强相关,一般建议留有裕度,否则会造成休眠唤醒失败。 |
Select standby load storage type (SPINOR) | 选择待机时加载的存储类型,这里使用 SPINOR。 |
[*] pm_standby_memory | 指示启用待机模式时使用内存 SRAM,需要勾选。 |
(plat_sun300iw1p1) pm plat name | PM平台名称,描述当前正在使用的电源管理平台的版本或型号。不用修改。 |
[ ] 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
启用 RTC_WATCHDOG 相关驱动
Drivers Options --->
soc related device drivers --->
RTC WATCHDOG Devices --->
[*] enable rtc watchdog driver
另外还需要配置休眠内存分配,需要修改板级对应的链接脚本,将不需要休眠的数据放到非休眠内容段内。这里以 perf2b 板级为例,修改文件
此部分仅为示例实现,具体使用到需要保留现场的函数需要根据 RTOS 开发功能而定。
完整的配置可以参考已经配置休眠唤醒的板级。
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_saved
和 data_unsaved
段配置
增加了栈指针导出
增加了 bss_saved
和 bss_unsaved
段配置
另外方案对应的 main.c 函数也需要增加 PM 会使用到的 init_openamp
,deinit_openamp_sync
函数功能,这两个函数不可在线程中运行,必须同步阻塞运行。
例如这里在 rtos/lichee/rtos/projects/v821_e907/perf2b/src/main.c
中实现的功能:
此部分仅为示例实现,具体使用到需要初始化与反初始化的函数需要根据 RTOS 开发功能而定。
完整的配置可以参考已经配置休眠唤醒的板级。
需要增加的内容已在下方示例代码中高亮说明:
#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 ---> (取消勾选)
小核关闭压缩后可能分区表配置放不下,报错如下:
此时需要修改对应方案的分区表,配置到小核固件的大小。需要对齐到 128
内核端也需要关闭小核解压功能
Allwinner BSP --->
Device Drivers --->
Remoteproc drivers --->
< > Allwinner remoteproc decompress firmware from partition # 取消勾选
软件方案配置
除了软件上的配置,休眠唤醒如果需要使用超低功耗待机模式, 还需要增加休眠唤醒引导 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
如果配置不压缩模式,打包报错,则是因为没有压缩的情况下原先的 flash_map 已经放不下固件了,需要适当扩大配置。
ERROR flashmap logic_offset start block: 608 is less than uboot_start last block: 896
此时需要修改板级对应的 uboot-board.dts
扩大分区表,例如这里 IPC 板级,修改文件:device/config/chips/v821/configs/ipc/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.cfg
或 boot_package.cfg
时,需要文件底部留空行,否则会出现打包报错!
另外还需要配置设备树配置同步 BOOT0 联动机制,方便动态配置 BOOT0 的参数内容。这个配置大部分板级已经默认启用,若未启用例如 IPC 板级,编辑 device/config/chips/v821/configs/ipc/BoardConfig_nor.mk
增加以下配置:
LICHEE_GEN_BOOT0_DTS_INFO:=yes
执行完成之后需要重新加载 SDK
source build/envsetup.sh
lunch
常用调试方法
控制台挂起时的日志输出
echo N > /sys/module/printk/parameters/console_suspend
说明:
console_suspend
是内核参数,控制系统进入挂起模式(如休眠)时是否输出控制台日志。- 设置为
N
表示禁用在系统挂起时的控制台日志输出。通常用于调试或优化电源管理,减少日志信息对系统的干扰。
示例:
- 设置为
N
:echo N > /sys/module/printk/parameters/console_suspend
,禁用挂起时的控制台日志输出。 - 设置为
Y
:echo Y > /sys/module/printk/parameters/console_suspend
,启用挂起时的控制台日志输出(会输出更多的日志信息,适合调试电源管理问题)。
内核初始化调用调试信息
echo Y > /sys/module/kernel/parameters/initcall_debug
说明:
initcall_debug
是一个内核调试参数,启用后,内核在启动时会输出详细的初始化调用调试信息。- 设置为
Y
,可以帮助开发者查看内核启动过程中初始化函数的详细过程,特别是在调试内核启动问题时非常有用。
示例:
- 设置为
Y
:echo Y > /sys/module/kernel/parameters/initcall_debug
,启用内核初始化调用调试,输出详细的启动过程信息。 - 设置为
N
:echo N > /sys/module/kernel/parameters/initcall_debug
,禁用内核初始化调用调试,减少启动过程中的调试信息输出。
电源管理调试信息输出
echo 1 > /sys/power/pm_debug_messages
说明:
pm_debug_messages
控制电源管理调试信息的输出。- 设置为
1
后,系统会输出与电源管理相关的调试信息,包括系统的睡眠、唤醒等操作。此命令适用于调试电源管理流程,帮助识别和解决电源管理中的问题。
示例:
- 设置为
1
:echo 1 > /sys/power/pm_debug_messages
,启用电源管理调试信息输出,详细记录睡眠、唤醒等操作。 - 设置为
0
:echo 0 > /sys/power/pm_debug_messages
,禁用电源管理调试信息输出,减少调试信息的量。
电源管理操作的时间打印
echo 0 > /sys/power/pm_print_times
说明:
pm_print_times
控制是否打印电源管理操作的时间信息。- 设置为
0
,表示禁用电源管理操作的时间打印。此命令适用于减少调试输出信息,优化日志,或在不需要时间打印时提高系统性能。
示例:
- 设置为
0
:echo 0 > /sys/power/pm_print_times
,禁用电源管理操作的时间打印,避免在日志中记录过多时间信息。 - 设置为
1
:echo 1 > /sys/power/pm_print_times
,启用电源管理操作的时间打印,记录系统在不同电源管理操作中的耗时(有助于诊断性能问题)。