前言

概述

本文档主要用于BS2X平台日志分析指导,包括平台日志分类、重启场景、panic类型等。为开发人员、验证人员、使用人员提供参考,提高使用者问题定位效率。

读者对象

本文档主要适用以下工程师:

  • 技术支持工程师

  • 软件开发工程师

符号约定

在本文中可能出现下列标志,它们所代表的含义如下。

符号

说明

表示如不避免则将会导致死亡或严重伤害的具有高等级风险的危害。

表示如不避免则可能导致死亡或严重伤害的具有中等级风险的危害。

表示如不避免则可能导致轻微或中度伤害的具有低等级风险的危害。

用于传递设备或环境安全警示信息。如不避免则可能会导致设备损坏、数据丢失、设备性能降低或其它不可预知的结果。

“须知”不涉及人身伤害。

对正文中重点信息的补充说明。

“说明”不是安全警示信息,不涉及人身、设备及环境伤害信息。

修改记录

文档版本

发布日期

修改说明

03

2025-06-20

  • 更新“维侧日志解析”小节内容。

02

2025-05-30

  • 删除“BT睡眠日志”小节内容。
  • 删除“BT panic日志”小节内容。
  • 更新“异常类型描述”小节内容。
  • 删除“BT核NMI异常”小节内容。
  • 删除“BT PANIC异常”小节内容。
  • 更新“ADC常见问题排查”小节内容。

01

2024-07-05

第一次正式版本发布。

概述

文档针对PLT的各类业务,从日志类型、异常场景等方面给PLT维测指导。

日志说明

平台日志接口

BS2X SDK中提供了普通串口打印和HSO(协议日志)串口打印两种串口LOG打印方式,帮助用户添加、分析维测信息。

普通串口打印

普通打印方式通过串口工具直接解析,默认使用UART_BUS0【软件配置参数所选UART句柄名称】(UART_L0【硬件PIN脚名称】)打印串口日志以及发送AT命令,UART BUS具体对照如下表1所示。使用普通打印接口需要包含soc_osal.h头文件,调用osal_printk接口格式化输出LOG。

表 1 UART默认对应表

软件配置参数UART句柄名称

硬件PIN脚名称

UART_BUS0

UART_L0

UART_BUS1

UART_H0

UART_BUS2

UART_L1

DIAG串口打印

DIAG打印方式通过DebugKits工具解析日志,默认使用UART_BUS1【软件配置参数所选UART句柄名称】(UART_H0【硬件PIN脚名称】)打印DIAG日志。HSO维测功能模块提供以下功能:

  • 日志打印。用户可以通过日志打印接口将调试信息打印到DebugKits的Message界面。

  • 命令的注册和处理。用户可以通过注册命令和命令处理函数,来实现在DebugKits工具的命令行界面输入命令来控制单板侧的操作。

  • 系统维测信息获取。DIAG支持获取系统统计类信息(如内存使用、任务信息),帮助用户定位问题。

以用户在chips/bs2x/main_init/app_os_init.c中增加调试日志为例,流程如下:

  1. 在chips/bs2x/main_init/app_os_init.c中调用日志打印接口,输出调试信息。需要包含log_def.h、log_common.h头文件。

    函数

    说明

    oml_pf_log_print0(mid, lognum, lvl, fmt)

    mid:本条打印归属的模块,调试使用LOG_PFMODULE模块。

    lognum:打印的log编号,调试使用LOG_NUM_DEBUG。

    lvl:打印等级,定义在middleware/utils/common_headers/log_types.h中。

    fmt:打印字符串。

    oml_pf_log_print1(mid, lognum, lvl, fmt, p1)

    前四个参数含义同oml_pf_log_print0接口描述一致,p1表示打印字符串里携带的1个参数

    oml_pf_log_print2(mid, lognum, lvl, fmt, p1, p2)

    前四个参数含义同oml_pf_log_print0接口描述一致,p1,p2表示打印字符串里携带的2个参数

    oml_pf_log_print3(mid, lognum, lvl, fmt, p1, p2, p3)

    前四个参数含义同oml_pf_log_print0接口描述一致,p1,p2,p3表示打印字符串里携带的3个参数

    oml_pf_log_print4(mid, lognum, lvl, fmt, p1, p2, p3, p4)

    前四个参数含义同oml_pf_log_print0接口描述一致,p1,p2,p3,p4表示打印字符串里携带的4个参数

  2. 用户在使用DIAG日志之前,需要先确认调用接口的文件是否被添加到模块当中。例如在chips/bs2x/main_init/app_os_init.c文件中使用LOG_PFMODULE模块打印接口,需要在chips/bs2x/dfx/include/log_def_pf.h添加文件ID,文件ID的格式为:调用日志接口的文件的文件名大写并加_C后缀,如:MAIN_C。

  3. 编译程序,编译过程中将生成output/bs2x/database_evb目录。

  4. 在DebugKits中执行update HDB,将“步骤3”生成的数据库更新至DebugKits的数据库中。打开DebugKits的Message界面查看日志信息(请参见《BS2XV100 DebugKits工具 使用指南》)。

说明: 请注意,DIAG日志只能支持长度32位及以下的参数,如:"%d"、"%u"、"%x"、"%p",无法支持长度大于32位的参数,如"%ld"、"%s",无法支持浮点参数,如"%f"。 普通打印方式直接在接口调用的位置通过串口进行输出,如果日志过多会阻塞当前调用者线程,可能会出现非预期现象;而DIAG打印方式是通过事件方式抛消息给log线程进行打印,不会阻塞打印调用者,但是会导致codesize增大,内存足够的情况下建议使用,相对来说会比普通方式更灵活。请根据实际场景选择使用。

平台日志分类

SDK启动日志

图1所示,开机启动,Flashboot初始化后,串口会打印系统启动原因,系统启动次数及系统异常启动次数。APP启动后,会打印日志初始化、AT初始化以及SDK版本号。如图2所示,HSO同步打印系统上电表示及重启原因,重启次数以及异常重启次数。

图 1 平台启动日志(串口)

图 2 平台启动日志(HSO)

APP睡眠日志

App默认每隔一段时间会通过HSO日志记录一次调度空闲时间,打印睡眠统计的同时会喂狗(若出现长时间没有打印,可能会狗超时,因此会喂狗),如图1所示。该维测依赖于PM_MCPU_MIPS_STATISTICS_ENABLE宏,默认关闭,根据实际情况选择,用户可不关心。

图 1 APP睡眠日志

APP panic日志

Kernel panic是指操作系统在监测到内部的致命错误,并无法安全处理此错误时采取的动作。内核触发到某种异常情况,运行kernel_panic函数,并尽可能把异常发生时获取的全部信息打印出来。

  • 原理

    导致异常的原因多种多样,通过异常打印的调用信息,找到调用kernel_panic的原因。常见的原因包括内核堆栈溢出、内核空间的除0异常、内存访问越界、内核陷入死锁等。

  • 触发方法

    内核态读0地址。

APP核发生panic异常时会打印panic原因0x2003以及对应的panic id,如图APP panic日志所示。panic id见表1所示。

图 1 APP panic异常

APP异常重启

APP核发生xip异常,hardfault,狗超时等异常时,会打印重启原因0x200x以及pc和lr值,如图1表1所示。

图 1 APP异常重启

表 1 APP重启原因

异常类型

日志类型

重启原因

主动重启

Log_FLATFORM

0x2001

panic

Log_FLATFORM

0x2003

hardfault

Log_FLATFORM

0x2004

nmi

Log_FLATFORM

0x2005

狗超时

Log_FLATFORM

0x2008

xip异常

Log_FLATFORM

0x2009

xip cache异常

Log_FLATFORM

0x200a

mdma异常

Log_FLATFORM

0x200b

smdma异常

Log_FLATFORM

0x200c

强制狗复位

Log_FLATFORM

0x200d

lp狗/uvlo重启

Log_FLATFORM

0x200f

异常类型描述

表 1 重启描述分析(middleware/utils/dfx/dfx_reboot/reboot/shared/non_os_reboot.h)

id

描述

重启异常场景原因分析

0x0

未知重启原因

用户代码中直接写寄存器重启导致

0x2001

应用核主动重启

-

0x2003

APP panic异常

需要查看“PANIC ID”中panic id,进一步分析

0x2004

Hardfault异常

非法地址;

空指针;

XXX模块未初始化;

XXX模块没有时钟;

需要结合临终遗言中mepc,ra,mtval及通用寄存器进一步定位。

0x2008

APP狗超时

结合cpu trace及日志分析。

一般是一直在执行高优先级任务/中断流程,导致低优先级喂狗任务无法得到调度。

0x200D

APP硬狗超时

系统卡死后,无法响应狗超时中断,需要结合cpu trace分析

0x200f

ulp狗超时/uvlo重启

添加ulp喂狗日志进一步分析

0x2010

Pin reset

-

0x2040

升级完成

-

0x2042

升级失败

-

0xf0f0

系统上电

-

日志分析

常见的异常场景包括:watchdog超时,hardfault,mem fault,bus fault,use fault, panic异常,强制狗复位等。发生异常时,会打印异常重启原因,并引发系统重启。其中APP的重启异常用0x2xxx表示,具体有0x2000~0x2010、0x2040~0x2044、0x2080、0x2100。

死机信息获取

普通打印口维测信息获取

  • 当硬件与串口工具处于连接状态时,如果单板发生死机,串口工具能够接收到复位前DFX流程打印的死机信息。用户可以通过分析死机信息,定位死机原因。普通打印口死机LOG分为4个部分:

  • 死机现场:记录死机发生时RISCV通用寄存器以及部分CSR寄存器的现场值。各个寄存器的描述请参考附录中异常信息查看。

  • 线程栈信息:记录死机发生时正在运行的线程栈的栈顶、栈大小以及栈使用峰值。

  • 栈回溯:回溯死机栈信息,traceback 0为栈顶位置,sp addr,current sp为当前栈位置,sp content为栈内容。

  • CPU Trace:记录CPU过去一段时间的执行的PC与LR。step time存储记录时间,值越大,记录的时间越接近死机现场。

    说明: 注意:此处是数采功能,记录的PC值和真实的执行轨迹可能有所差异,并不一样能完全对应!

    Trace路径的分析有两种方式:

    方式一:用户可以根据编译时生成的application.lst文件查找LR和PC地址对应的函数,定位死机执行现场。

    方式二:用户使用IDE提供的CFBB Tools解析Trace,打开工具,选择用户使用的target。

    导入CPU Trace Information到CPU Trace end的Trace信息,点击解析可以获取到过去一段时间的执行信息,定位死机原因:

死机Dump信息获取

DebugKits工具提供了死机发生时,将死机现场内存以二进制格式导出功能,提供参考信息,帮助开发者定位分析死机问题。工具的详细安装使用请参考《BS2XV100 DebugKits工具使用指南》,此处只介绍Dump信息导出流程。

首先进入工具页面点击options再选择change chip,在弹框中选择BS2X确定芯片类型,参考图选择芯片。

然后点击Connection选择Connect在弹窗中选择连接方式以及对应的通道序号进行连接,参考图连接芯片。

如果是第一次连接芯片或者芯片有新版本的程序,需要更新HDB并重新连接之后,日志的打印才能正确的显示,在Option菜单下选择Update HDB,选择生成的database目录(\output\bs2x\database_evb)再点击OK即可完成配置,具体参考下图:配置database。

通过DebugKits工具可以实时观测芯片运行时打印的具体信息,可以参考图 DebugKits日志打印。当死机发生时Message视图将会打印出last word以及last dump信息。

last word信息是死机发生时,将PC地址、返回地址、栈地址、CPU寄存器信息发送出来,用户可以根据last word的具体信息分析错误类型、定位错误原因,具体可以参考下图:last word信息。

last dump信息将会把内存中的部分信息打包生成bin文件存储到DebugKits的安装目录中的DumpInfo子目录之下,具体参考下图:last dump生成文件。

说明: 注意:将内存dump到DebugKits中需要一定时间(1~2 min),因此如果需要使用last dump分析死机信息,不要在发生死机故障后立即复位,否则last dump信息可能无法完整获取。

狗超时重启

狗超时重启分为:CWDT、ULP WDT 重启。其中APP发生狗超时(CWDT超时),会有HSO日志和UART日志打印,显示对应的pc和lr,并且会导出内存信息。

APP核发生狗超时时,系统会进行重启。系统重启后,串口会打印异常时的pc和lr,如图1所示。HSO日志也会打印重启原因0x2008及对应的pc和lr,如图2所示。可以在lst文件中查找pc值确定问题归属。APP核的pc指针范围如表3-1所示。

表 1 APP代码空间范围

内存名称

开始地址

结束地址

ITCM

0x42000

0x56000

DTCM

0x20000000

0x20010000

SFC

0x90100000

0x90180000

图 1 CWDT超时重启UART打印

图 2 CWDT超时重启HSO日志打印

ULP_WDT超时

APP进入睡眠时,CWDT将掉电,WDT功能由ULP_WDT实现。发生狗超时时,系统会进行重启。系统重启后,串口和HSO日志也会打印重启原因0x200f,如图1所示。

图 1 WDT超时重启UART打印

hardfault、MEM fault、BUS fault、Usage fault异常

系统发生上述异常时,HSO日志会记录异常时的pc、lr和mtval,如图1所示。

系统重启后,也会打印重启原因及对应的pc、lr和mtval,如图2所示。。

APP核异常

APP核发生上述重启会打印重启原因0x2004。

图 1 APP hardfault重启HSO日志

图 2 APP hardfault重启UART打印

NMI异常

系统发生如下NMI异常时,重启后会打印如下重启原因。HSO日志会记录pc、lr和mtval。

XIP异常

系统发生XIP重启会打印重启原因0x2009。HSO日志会输出pc、lr和mtval。如图1图2所示

图 1 XIP重启HSO日志

图 2 XIP重启UART打印

XIP CACHE异常

系统发生XIP cache异常会打印重启原因0x200a。HSO日志会记录pc、lr和mtval。如图1图2所示

图 1 XIP cache异常HSO日志

图 2 XIP cache异常UART打印

MDMA异常

系统发生MDMA异常会打印重启原因0x200b。HSO日志会记录pc、lr和mtval。如图1图2所示

图 1 MDMA异常HSO日志

图 2 MDMA异常UART打印

SMDMA异常

系统发生SMDMA异常会打印重启原因0x200c。HSO日志会记录pc、lr和mtval。如图1图2所示

图 1 SMDMA异常HSO日志

图 2 SMDMA异常UART打印

A核NMI异常

A核发生NMI异常会打印重启原因0x2005。HSO日志会记录pc、lr和mtval。如图1图2所示

图 1 A核NMI异常HSO日志

图 2 A核NMI异常UART打印

panic异常

发生panic异常时,会打印panic id,code以及调用的lr。并获取对端的pc,lr。其中normal core表示对端。Normal core为0表示A核异常。Normal core为1表示bt核异常。

APP PANIC异常

APP Panic异常会打印重启原因0x2003和panic日志。如图1图2所示。

图 1 panic异常HSO日志

图 2 panic异常UART打印

PANIC ID

表 1 PANIC ID描述(middleware/utils/dfx/panic/public/panic.h)

id(十进制值)

描述

备注

0

no panic

NO USE

1

arm core

NO USE

2

HAL

NO USE

3

DSP

NO USE

4

malloc

BT/APP

5

uart

BT/APP

6

flash

APP

7

adc

APP

8

watchdog

NO USE

9

log

BT/APP

10

dma

BT/APP

11

assert

BT/APP

12

reboot

NO USE

13

update

NO USE

14

I2C0

APP

15

I2C1

APP

16

I2C2

APP

17

SPI0

APP

18

SPI1

APP

19

SPI2

APP

20

SPI4

APP

21

SPI5

APP

22

RPC

BT/APP

23

mem monitor

BT/APP

24

panic exit

NO USE

25

create task

liteOS

26

memcpy buffer overlap

NO USE

27

xip

APP

28

btc malloc fail

BTC

29

low power

BT/APP

30

system status

BT/APP

31

Btc int err

BTC

32

Lpc wakeup fail

APP

33

Clock glb err

BT/APP

34

Pmu cmu

APP

35

Pmu ldo

APP

36

Chip wdt frst

APP

37

Non os

NO USE

38

Lpc veto

BT/APP

39

timer

BT/APP

40

lpc

BT/APP

41

rtc

BT/APP

42

memory

BT/APP

43

Cpu hifi

APP

44

Exception test

APP

45

kv

SSB ONLY

46

eflash

APP

47

lib

NO USE

48

codeloader

SSB ONLY

49

criticla

BT/APP

50

ipc

BT/APP

51

int

BT/APP

52

os

liteOS

53

Lpc wakeup time

BT/APP

54

btc bt frm dismatch1

BTC

55

btc bt frm dismatch2

BTC

56

btc ble frm dismatch

BTC

57

btc wakeup

BTC

58

bth memory

BTH

59

mpu config

BT/APP

60

gpu

wear APP

61

sdio

wear APP

62

ir

wear APP

63

btc cmd

BTC

64

cap

APP

65

epmu

APP

66

bts writeproperty

BTS

67

mmc host

wear APP

68

btc oscen

BTC

69

I2C3

APP

70

RGB888

wear APP

71

ap commu

BTC

72

Cpu clocks

BT/APP

73

clocks switch

APP

74

pmu

NO USE

75

log dump

BT/APP

76

coul

APP

77

dsp0 power off

BT/APP

78

dsp1 power off

BT/APP

98

UT

PLT UT

99

testsuite

PLT UT

强制狗复位

系统发生强制狗复位时,不会主动触发hardfault或者nmi异常。等待芯片内部的狗超时后,芯片会主动触发复位。芯片复位后,检测到复位原因0x200d,并触发一次panic异常,系统会导出上次的cpu trace并触发重启。系统重启后,会打印panic重启,重启原因:0x2003;panic id:0x24。如图1所示。

图 1 ULP RTC超时重启打印

问题定位

外设问题定位方法

外设类异常,绝大部分都是初始化没有完成导致的异常。

外设初始化主要由以下步骤:

  1. 上电、开时钟。

  2. 配置管脚模式。

  3. 注册hal层回调函数。

  4. 注册回调。

  5. 初始化寄存器配置。

排查思路:

  • 首先确认时钟/电源是否打开,当前默认大部分驱动时钟都是关闭的,使用前,查看XXX驱动初始化代码中,CONFIG_XXX_SUPPORT_LPC宏是否打开,如果没有打开,访问XXX驱动相关的寄存器会立刻挂死。

  • 查看uapi_xxx_init返回值,确认初始化是否完成。

  • 软件流程排查(请参见《BS2XV100 设备驱动开发指南》)。

  • 排查硬件:上电是否正常,外围电流是否正常,同样的软件在不同硬件上烧录,查看结果是否一致。

  • 其他外设问题,查到外设说明。

死机问题定位方法

图 1 定位步骤

低功耗问题定位方法

管脚漏电排查

睡眠状态下,芯片功耗不达标,需要用户按照如下流程排查IO漏电:

  1. 对于板级电路IO管脚:

    • 若管脚有外接上拉电阻,该管脚需配置为浮空。

    • 管脚有外接下拉电阻,该管脚可配置为下拉。

    • 其余情况,该管脚配置为下拉。

  2. 对于接入外部设备的管脚:

    • 请查阅该外设手册,若外设内部带上拉/下拉电阻,根据上述说明进行配置。

    • 其他问题可以参考《BS2XV100 低功耗FAQ》。

OSAL接口维测方法

BS2X SDK提供了OSAL接口帮助用户使用RTOS,用户在使用接口前请参见《BS2XV100 SDK 开发指南》,避免出现接口使用错误,客户在使用OSAL接口开发时,可以通过判断OSAL接口返回值或者打印OSAL接口返回值进行维测。OSAL接口错误码请参考《BS2XV100 SDK 开发指南》。

内存维测功能

内存的维测在任何一个系统中都是重要的维测手段,比如:想知道系统中,当前内存的分配和占用情况;想知道各个task的栈占用情况;想知道某个task内存分配具体分配情况。这些内存信息对于内存优化、以及内存定位(比如内存泄露)至关重要。

本文描述如何在B2X系列上如何进行内存维测,包括:

  • 查看系统heap内存总体分配和使用情况。

  • 查看每个task的malloc情况(当前分配和峰值分配)。

  • 查看每个task的栈分配和使用情况;(当前使用和峰值使用)。

  • 查看每个内存在哪里分配。

    AIOT的内存维测命令已经集成到AT命令中,用户可以直接使用这些命令。

查看系统heap总体信息

该维测功能,用来查看系统中heap内存使用看情况;

查看系统heap信息命令:AT+HEAPSTAT

查看task栈使用情况

该维测功能,用来查看各个Task的栈的分配使用使用情况;

可以通过该命令,来优化调整stack的分配大小,节约内存;

查看任务栈使用情况:AT+TASKSTACK

查看每个task的内存分配情况

查看某个task的malloc情况:AT+TASKMALLOC=“任务id”;

这里的“任务id”,可以通过“AT+HEAPSTAT”或“AT+TASKSTACK”命令获取。

查看中断中、启动阶段的内存分配情况

系统中,除了task中分配内存外,还有中断中分配的内存、系统启动阶段的分配的内存,这些地方分配的地方没有对应的task,因此通过归类到一个特殊id中;

可以通过“AT+HEAPSTAT” 命令,获取non-task alloc对应的id;

查看非任务中内存分配情况的命令,也是:AT+TASKMALLOC=“id”,显示格式也是一样;

内存维测开关

由于内存维测需要消耗一定内存空间,默认情况下是关闭的;因此需要手动打开;

以BS21E为例,开启内存维测功能需要打开下面两个宏:打开“kernel\liteos\liteos_v208.6.0_b017\Huawei_LiteOS\tools\build\config\bs21e.config”,将

# LOSCFG_MEM_TASK_STAT is not set
# LOSCFG_MEM_DFX_SHOW_CALLER_RA is not set

改成:

LOSCFG_MEM_TASK_STAT=y
LOSCFG_MEM_DFX_SHOW_CALLER_RA=y”

注意事项

说明:

  • 必须要找对项目对应的config文件。

  • LOSCFG_MEM_DFX_SHOW_CALLER_RA用来查看在哪里调用了内存分配的函数,该宏打开会占用一定内存空间;如果只是进行内存统计,可以不打开。

  • 功能开启后需要对SDK进行全量编译;否则可能会有不生效的情况。

OS及中断维测

维测原理

使用LiteOs提供的OSCFG_HWI_PRE_POST_PROCESS和LOSCFG_BASE_CORE_TSK_MONITOR(liteos menuconfig中默认开启)特性,记录中断和任务调用轨迹。该功能默认不开启,用户使用的时候,需要手动开启OS_DFX_SUPPORT和USER_PRINT_OS_DFX两个宏。

注意:

  1. 开启该功能,可能会导致部分任务栈空间增加,导致死机(参考“案例一 栈溢出”),需要调整对应任务栈大小。

  2. 开启该功能,会导致无法中断频繁打印,不需要观测的中断,可以手动关闭。参考下图,关闭不需要观测的中断。

  3. 该功能,可能会造成一些性能问题,定位狗超时问题时,可以临时打开该功能。

维侧日志解析

  1. 中断维测:

    下面的维测表示进入75号中断处理函数(hwi_pre表示);75号中断处理期间,又被66号中断打断(支持中断嵌套,66优先级更高),66号中断连续处理两次后,75号中断无法退出,大概率是中断栈爆了,需要修改中断栈大小。参考下图:

  2. 任务调度维测:

锁中断时间与中断时间维测

维测原理

使用osal提供的锁中断时间和中断时间维测特性,记录锁中断时间和中断时间。该功能默认不开启,用户使用的时候,需要手动添加osal_adapt组件和开启OSAL_IRQ_RECORD_DEBUG这个宏。通过osal_irq_record_flag_set函数参数设置1统计锁中断时间,参数设置2统计中断时间。

注意:

  1. 开启该功能,可能会导致部分任务栈空间增加,导致死机(参考“案例一 栈溢出”),需要调整对应任务栈大小。

  2. 开启该功能,不需要观测的中断,可以手动关闭。参考下图,关闭不需要观测的中断。

  3. 在app_os_init中使用维测时间打印函数,将记录的时间打印出来。

维测日志解析

查询系统CPU占用率维测功能

CPU占用率的统计是分析系统负载的重要的维测手段,比如:通过CPU占用率判断当前系统负载是否超出设计规格;通过系统中各个任务的CPU占用率,判断各个任务的CPU占用率是否符合设计的预期。

查看各个任务和中断的CPU占用情况

可以通过该命令,查看各个Task和中断的CPU占用率情况:AT+CPUP

说明:

  • CPU占用率是以百分比显示。

  • CPU占用率的计算方法:任务(或者中断)运行总时间/系统运行总时间.

  • CPUP列显示系统启动至今总的CPU占用率。

  • CPUP 10.0s列显示系统最近10s的CPU占用率。

  • CPUP 1.0s列显示系统最近1s的CPU占用率。

维测开关

CPU占用率统计对性能有影响,一般只在开发阶段时需要了解各个任务的占用率,因此默认情况该功能是关闭的;如果要使用该功能需要手动打开。

以BS21E为例,打开“kernel\liteos\liteos_v208.6.0_b017\Huawei_LiteOS\tools\build\config\bs21e.config”,CPUP维测功能需要打开下面宏:

LOSCFG_KERNEL_EXTKERNEL=y
LOSCFG_KERNEL_CPUP=y
LOSCFG_CPUP_INCLUDE_IRQ=y
LOSCFG_CPUP_SAMPLE_PERIOD=1000
LOSCFG_CPUP_HISTORY_RECORD_NUM=10
LOSCFG_DEBUG_VERSION=y
LOSCFG_DEBUG_KERNEL=y
LOSCFG_DEBUG_TASK=y
LOSCFG_DEBUG_HWI=y

注意事项

说明:

  • 必须要找对项目对应的config文件。

  • 功能开启后需要对SDK进行全量编译;否则可能会有不生效的情况。

  • 关闭配置项LOSCFG_CPUP_INCLUDE_IRQ后,系统中的中断耗时会被统计到中断发生的任务中,即被中断打断的任务中。

典型案例

案例一 栈溢出

栈溢出

死机现场如下:

死在OsHeapAlloc,那么可在下图位置加日志,在死机时把栈统计打出来:

打印结果如下:

可以得出app栈爆结论,需要加大线程栈大小。

案例二 通过MEPC分析

根据mepc分析死机

死机现场如下:

问题分析

  1. 挂死在“app”中,且可以看到mepc为0x90122458,mtval为:0xffffffff。

  2. 在lst中找到mepc所对应的汇编代码。

  3. 确认是软件操作非法地址writel(0xffffffff, 0)导致的死机。

案例三 通过RA分析

PC异常,根据RA分析死机

死机现场如下:

问题分析

  1. 挂死在“Swt_Task”中,且pc非法,只能看到ra。

  2. 根据lst文件,发现在跳转“g_hal_funcs->set_group”的异常。

  3. 怀疑是g_hal_funcs->set_group为空导致的,继续查看lst文件中,pwm初始化代码。发现只有ir中有调用,而且出现问题的时候,没有执行红外学习。

  4. 找客户确认,客户的确把pwm初始化代码删掉。添加初始化代码后,问题解决。

问题拓展

  1. 如果客户判断一下uapi_pwm_open返回值,就能快速发现这个问题。

    软件代码可以增加判断,异常不让系统挂死。

  2. 为什么挂死的时候,pc会变成deadbeee?

    注意:芯片把0x0~0x10000初始化为0xDEADBEEF,mepc的bit0 硬控为0

    • 分析:汇编代码g_hal_funcs

    g_hal_funcs是bss段,初始化为0,没有赋值的时候g_hal_funcs里面的值是0

    • 汇编流程

案例四 访问死机

软件执行过程中因为代码逻辑或者内存踩踏等问题,常常造成部分数据变成空地址或者其他非法地址,访问时出现死机。本案例通过实例分析,结合BS2X提供的死机维测方式分析定位空指针执行。如图执行空指针造成的死机log:

首先参考普通打印口维测信息获取章节分析死机现场,当前mcause为1,参考分析mcause对照表,死机原因是指令访问错误,同时mepc、ra均被设置为难以通过application.lst或者application.asm汇编文件直接追溯的地址值,对于此类问题,通常使用CPU Trace工具解析串口Trace,分析死机前执行流程,使用工具解析串口Trace,进入异常前,最后一个执行的函数为plt_at_dumptest:

通过application.lst文件查找plt_at_dumptest函数偏移0x10位置,此处进行了空指针访问操作,造成挂死。

总结:对于mcause为0x0、0x1、0x2等类型的指令访问挂死,在死机现场的寄存器难以追溯异常位置时,使用串口Trace解析工具解析Trace,结合application.lst文件追溯死机流程。

案例五 内存Malloc失败

代码执行过程中如果出现panic内存不足以及malloc失败,可以借助当前的内存维测接口进行维测:

参考“内存维测开关”章节,打开内存维测开关,打开之后进入panic时就会打印内存使用信息,如下图在打开内存维测之后,内存申请不足时,维测信息内会打印各个线程内存使用信息,以及死机时各个线程的内存信息。

参考下图,app线程peak峰值异常,根据内存详细使用信息,可以看到0x4523e地址频繁申请内存。

结合lst文件观察调用位置,可以看到异常调用函数异常申请,没有释放。

常见问题FAQ

异常信息查看

异常信息汇总

表 1 异常信息描述

成员

描述

task

死机的任务名称。

thrdPid

死机的任务ID。

type

死机类型。

CPU寄存器信息

表 1 死机相关CPU寄存器描述

成员

描述

mepc

机器异常程序计数器。当发生异常时,mepc指向导致异常的指令;对于中断,mepc指向中断处理后应该恢复的位置。

mstatus

机器状态寄存器。

mtval

机器陷入寄存器。保存地址异常中出错的地址或者发生指令异常的指令本身,对于其他错误,其值为零。

mcause

机器异常寄存器。保存目前异常或者中断的原因,通过查询表 mcause&ccause异常描述表得到目前异常或者中断的类型。

ccause

与mcause类似,ccause为mcause的补充说明,对于某些异常通过读取ccause寄存器的内容可以进一步明确异常类型。

ra

返回地址。

表 2 mcause&ccause异常描述表

异常码

mcause异常描述

ccause异常描述

0x0

Instruction address misaligned

Not available

0x1

Instruction access fault

Memory map region access fault

0x2

Illegal instruction

AXIM error response

0x3

Breakpoint

AHBM error response

0x4

Load address misaligned

Crossing PMP entries

0x5

Load access fault

System register access fault

0x6

Store/AMO address misaligned

No PMP entry matched

0x7

Store/AMO access fault

PMP access fault

0x8

Environment call from U-mode

CMO access fault

0x9

Environment call from S-mode

CSR access fault

0xa

Reserved

LDM/STMIA instruction

0xb

Environment call from M-mode

ITCM write access fault

0xc

Instruction page fault

Not available

0xd

Load page fault

Not available

0xe

Reserved

Not available

0xf

Store/AMO page fault

Not available

>0xf

Reserved

Not available

通用寄存器信息

表 1 通用寄存器描述

寄存器

ABI 名字

保存者

作用

整型通用寄存器

x0

zero

硬编码恒为0,写入数据忽略,读取永远为0

x1

ra

Caller(调用者)

函数调用的返回地址

x2

sp

Callee(被调用者)

栈指针

x3

gp

全局指针

x4

tp

线程指针

x5-x7

t0-2

Caller

临时寄存器

x8

s0/fp

Callee

需要保存的寄存器或者帧指针寄存器

x9

s1

Callee

需要保存的寄存器,保存原进程中的关键数据,避免在函数调用过程中被破坏

x10~x11

a0~1

Caller

函数参数/返回值

x12~x17

a2~7

Caller

函数参数

x18~x27

s2~11

Callee

需要保存的寄存器

x28~x31

t3~6

Caller

临时寄存器

浮点型通用寄存器

f0~f7

ft0~7

Caller

FP临时变量

f8~f9

fs0~1

Callee

FP保存的寄存器

f10~f11

fa0~fa1

Caller

FP参数/返回值

f12~f17

fa2~fa7

Caller

FP参数

f18~f27

fs2~fs11

Callee

FP保存的寄存器

f28~f31

ft8~ft11

Caller

FP临时变量

ADC常见问题排查

  1. 采样挂死

    采样挂死有三种常见原因:

    • 时钟电源被异常关闭:ADC上电时已经打开需要的时钟,如果进入低功耗或在其他业务流程中关闭了需要的时钟,可能导致校准采样等无法完成。需要排查的时钟包括:XO_2_AFE 0x57008410 bit4;XO_2_ADC 0x57008410 bit1。需要排查的电源包括NFCLDO 0x5702C230 bit0:3 配置为0xA;AFELDO,ADCLDO,VREFLDO。如果使用ADC进行音频采样,还需要打开电源MICLDO并配置为2.0V。

    • AMIC与GADC复用,因为音频采样与电压采集复用的是同一套电路,所以需要分时复用。

    • ADC采样未加锁中断,可能因为被其他中断打断导致采样挂死。

  2. 采样值异常

    采样值异常有多重原因和表现形式,下面枚举一些典型场景及排查方式:

    • 采样值与实际值误差比例恒定,即采样值越大偏差越大:因为BS2X使用的ADC量程为0~1.5V,常常使用分压电路将待测电压分压后传入ADC,分压电阻的精度可能引入误差,要求使用1%精度的电阻来降低偏差,且转换公式要严格按照电阻值带入,切莫做近似处理,因为不支持浮点运算,建议先乘法再除法。

    • 首次上电、睡眠唤醒后采样值偏低:如上文所述,分压电路中一般存在对地电容,实测100nF电容充电到稳定的时长约为60ms。

    • 使用记录好的校准值采样时,采集到的电压不准确:因为刷入记录好的校准值替换的是校准的流程,降低了大约180ms的启动时间,在此期间电路可能还未稳定,如果使用记录好的校准值,建议延时10~20ms再采样。

    排查方式:

    • ADC有一组较为关键的校准值,存储在0x570360D4~0x570360F4共9位,其默认值为:

      0x00008000 0x00004000 0x00002000 0x00001000 0x00000800 0x00000800 0x00000400 0x00000200

      一般校准的结果与默认值的绝对差值在0x20以内,偏差较大则表明校准失常,如果全部为默认值则表示未进行校准。多次校准出的校准值可能不同,但相差极小。

    • ADC的三路LDO有各自的trim值存在efuse中,初始化时会将其读取并写入ADC,可以比对两组地址里的值是否相等:

      efuse: 0x5702886C[0-3], AFELDO_trim: 0x570363F0[4-7]

      efuse: 0x5702886C[4-7], ADCLDO_trim: 0x570363E8[4-7]

      efuse: 0x5702886C[8-11], VREFLDO_trim: 0x570363F4[5-8]