PX4模块设计之十六:Hardfault模块

本文详细解析了PX4系统中的Hardfault模块,包括初始化流程、核心命令如检查、重新加载和故障记录,以及利用BBSRAM进行关键数据持久化。它展示了如何通过BBSRAM设备保存系统异常状态,确保重启后的故障分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Hardfault模块初始化

nsh_main之前的启动过程可参考:PX4模块设计之十:PX4启动过程。Hardfault是通过启动脚本进行启动的。

注:这个模块主要使用了电池供电情况下SRAM持续保持数据的特性,从而保证系统异常宕机后,再次重启仍能获取宕机时的异常情况(通常这种临界异常无法保存在日志中)。

nsh_main
 └──> nsh_initialize
     └──> boardctl(BOARDIOC_INIT, 0)
         └──> board_app_initialize
             └──> board_hardfault_init
                 └──> stm32_bbsraminitialize(BBSRAM_PATH, filesizes);  // "/fs/bbr", The path to the Battery Backed up SRAM
                     └──> stm32_bbsram_probe
                         └──> register_driver(devname, &stm32_bbsram_fops, 0666, &g_bbsram[i]);


static const struct file_operations stm32_bbsram_fops =
{
  .open   = stm32_bbsram_open,
  .close  = stm32_bbsram_close,
  .read   = stm32_bbsram_read,
  .write  = stm32_bbsram_write,
  .seek   = stm32_bbsram_seek,
  .ioctl  = stm32_bbsram_ioctl,
  .poll   = stm32_bbsram_poll,
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  .unlink = stm32_bbsram_unlink,
#endif
};

启动脚本类似如下:

if [ $SDCARD_AVAILABLE = yes ]
then
	if hardfault_log check
	then
		set STARTUP_TUNE 2 # tune 2 = ERROR_TUNE
		if hardfault_log commit
		then
			hardfault_log reset
		fi
	fi
fi

2. Hardfault模块主程序

hardfault_log_main
 ├──> <command:check>
 │   └──> hardfault_check_status
 ├──> <command:rearm>
 │   └──> hardfault_rearm
 ├──> <command:fault>
 │   └──> genfault
 ├──> <command:commit>
 │   └──> hardfault_commit
 ├──> <command:count>
 │   └──> hardfault_increment_reboot false
 └──> <command:reset>
     └──> hardfault_increment_reboot true

3. Hardfault命令

hardfault_log <command> [arguments...]
 Commands:
   check         Check if there's an uncommitted hardfault

   rearm         Drop an uncommitted hardfault

   fault         Generate a hardfault (this command crashes the system :)
     [0|1]       Hardfault type: 0=divide by 0, 1=Assertion (default=0)

   commit        Write uncommitted hardfault to /fs/microsd/fault_%i.txt (and
                 rearm, but don't reset)

   count         Read the reboot counter, counts the number of reboots of an
                 uncommitted hardfault (returned as the exit code of the
                 program)

   reset         Reset the reboot counter

3.1 hardfault_check_status

检查是否有未提交的hardfault记录,如果有就打印输出。

hardfault_check_status
 ├──> int fd = hardfault_get_desc(caller, &desc, true);
 ├──> <fd == -ENOENT>
 │   └──> hfsyslog(LOG_INFO, "Failed to open Fault Log file [%s] (%d)\n", HARDFAULT_PATH, ret);
 ├──> <fd == -EIO>
 │   └──> hfsyslog(LOG_INFO, "Fault Log is Armed\n");
 └──> <else>
     ├──> int rv = close(fd);
     ├──> <rv < 0>
     │   └──> hfsyslog(LOG_INFO, "Failed to Close Fault Log (%d)\n", rv);
     └──> <else>
         ├──> hfsyslog(LOG_INFO, "Fault Log info File No %" PRIu8 " Length %" PRIu16 " flags:0x%02" PRIx16 " state:%d\n", desc.fileno, desc.len, desc.flags, state);
         ├──> <state == OK>
         │   ├──> format_fault_time(HEADER_TIME_FMT, &desc.lastwrite, buf, arraySize(buf));
         │   ├──> identify(caller);
         │   ├──> hfsyslog(LOG_INFO, "Fault Logged on %s - Valid\n", buf);
         └──> <else>
             └──> rv = hardfault_rearm(caller);

3.2 hardfault_rearm

删除内存中的hardfault数据。

hardfault_rearm
 ├──> int rv = unlink(HARDFAULT_PATH);
 ├──> <rv < 0>
 │   └──> hfsyslog(LOG_INFO, "Failed to re arming Fault Log (%d)\n", rv);
 └──> <else>
     └──> syslog(LOG_INFO, "Fault Log is Armed\n");

3.3 genfault

略,模拟产生一个除以0的异常,导致系统宕机。

3.4 hardfault_commit

将电池供电持续保持内存中的异常数据转存到crashdump文件和ULog文件。

hardfault_commit
 ├──> ret = hardfault_get_desc(caller, &desc, false);
 ├──> <ret < 0>
 │   └──> return
 ├──> state = (desc.lastwrite.tv_sec || desc.lastwrite.tv_nsec) ?  OK : 1;
 ├──> int rv = close(fd);
 ├──> <rv < 0>
 │   ├──> hfsyslog(LOG_INFO, "Failed to Close Fault Log (%d)\n", rv);
 │   └──> return
 ├──> <state != OK>
 │   ├──> hfsyslog(LOG_INFO, "Nothing to save\n");
 │   ├──> ret = -ENOENT;
 │   └──> return
 ├──> format_fault_file_name(&desc.lastwrite, path, arraySize(path));
 ├──> hardfault_write(caller, fdout, HARDFAULT_FILE_FORMAT, true);  //该函数内部将会unlink hardfault文件
 └──> hardfault_append_to_ulog(caller, fdout);

3.5 hardfault_increment_reboot

重启计数

hardfault_increment_reboot
 ├──> int fd = open(HARDFAULT_REBOOT_PATH, O_RDWR | O_CREAT);
 ├──> <fd < 0>
 │   ├──> hfsyslog(LOG_INFO, "Failed to open Fault reboot count file [%s] (%d)\n", HARDFAULT_REBOOT_PATH, ret);
 │   └──> return
 ├──> <reboot false>
 │   └──> [count++,并写入BBSRAM设备0]
 └──> <reboot true>
     └──> [count重置0,并写入BBSRAM设备0]

4. BBSRAM设备

总共是5个BBSRAM设备,使用用途如下:

  1. 【4字节】计数
  2. 【384字节】当前飞行参数拷贝A
  3. 【384字节】当前飞行参数拷贝B
  4. 【64字节】当前ULog全路径文件名
  5. 【剩余字节】宕机日志

注:STM32F7设备默认是4K字节(STM32F7_BBSRAM_SIZE 4096)。

#define HARDFAULT_REBOOT_FILENO 0
#define HARDFAULT_REBOOT_PATH BBSRAM_PATH "" STRINGIFY(HARDFAULT_REBOOT_FILENO)
#define HARDFAULT_ULOG_FILENO 3
#define HARDFAULT_ULOG_PATH BBSRAM_PATH "" STRINGIFY(HARDFAULT_ULOG_FILENO)
#define HARDFAULT_FILENO 4
#define HARDFAULT_PATH BBSRAM_PATH "" STRINGIFY(HARDFAULT_FILENO)


#if defined(CONFIG_STM32F7_STM32F74XX) || defined(CONFIG_STM32F7_STM32F75XX) || \
    defined(CONFIG_STM32F7_STM32F76XX) || defined(CONFIG_STM32F7_STM32F77XX)
#  define STM32F7_BBSRAM_SIZE 4096
#else
#  error "No backup SRAM on this STM32 Device"
#endif

#define HARDFAULT_MAX_ULOG_FILE_LEN 64 /* must be large enough to store the full path to the log file */

#define BBSRAM_SIZE_FN0 (sizeof(int))
#define BBSRAM_SIZE_FN1 384     /* greater then 2.5 times the size of vehicle_status_s */
#define BBSRAM_SIZE_FN2 384     /* greater then 2.5 times the size of vehicle_status_s */
#define BBSRAM_SIZE_FN3 HARDFAULT_MAX_ULOG_FILE_LEN
#define BBSRAM_SIZE_FN4 -1


/* The path to the Battery Backed up SRAM */
#define BBSRAM_PATH "/fs/bbr"
/* The sizes of the files to create (-1) use rest of BBSRAM memory */
#define BSRAM_FILE_SIZES { \
		BBSRAM_SIZE_FN0,   /* For Time stamp only */                  \
		BBSRAM_SIZE_FN1,   /* For Current Flight Parameters Copy A */ \
		BBSRAM_SIZE_FN2,   /* For Current Flight Parameters Copy B */ \
		BBSRAM_SIZE_FN3,   /* For the latest ULog file path */        \
		BBSRAM_SIZE_FN4,   /* For the Panic Log use rest of space */  \
		0                  /* End of table marker */                  \
	}

5. 总结

总体上看,这个BBSRAM设备主要用途就是记录coredump数据,类似系统的一个黑匣子。

注:配合ULog日志和之前做基站固件的时候所做的【基站软件Linux技术验证和分析:黑匣子技术】非常接近,只不过当时有多级Boot和版本管理回退等底层考虑。

6. 参考资料

【1】PX4开源软件框架简明简介
【2】PX4 Hardfault模块

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值