Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
CmBacktrace
CmBacktrace软件 Log 信息保存移植重写
发布于 2024-03-14 13:57:09 浏览:553
订阅该版
[tocm] 首先打开CmBacktrace ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240314/818c4e6530a13a17b776240f42b1ff2a.png.webp) `prm`是我的fal分区, 根据实际修改 然后编译, 报错, 解决错误 首先先注释掉 引用头文件 和 `error` 宏 ```C #if !defined(PKG_USING_FAL) || !defined(RT_USING_DFS) //#error "please enable the FAL package and DFS component" #endif #include
//#include
``` 明明我使用了DFS, 不知道为什么找不到 之后就是 `cmb_backup_flash_log_to_file` 函数的错误了 根据函数名知道这个函数是保存文件用的, 这个可以关闭 `Backup the flash log to file when next reboot` 重新编译是可以通过的, 所以为了能保存文件, 需要修改这段代码 其实这里报错的都是操作文件的函数, 之前操作文件使用的是 `dfs_posix.h` 的API, 我们修改使用 `stdio.h`的API 添加头文件 `#include
` 修改后的函数 ```C #ifdef CMB_USING_FAL_BACKUP_LOG_TO_FILE #define ULOG_LINE_BUF_SIZE 128 int cmb_backup_flash_log_to_file(void) { cmb_log_part = fal_partition_find(CMB_FAL_FLASH_LOG_PART); RT_ASSERT(cmb_log_part != NULL); size_t len; uint32_t addr = 0; rt_bool_t has_read_log = RT_FALSE; FILE* log_fd = NULL; while (1) { fal_partition_read(cmb_log_part, addr, (uint8_t *)&len, sizeof(size_t)); if (len != 0xFFFFFFFF) { char log_buf[ULOG_LINE_BUF_SIZE]; if (!has_read_log) { has_read_log = RT_TRUE; LOG_I("An CmBacktrace log was found on flash. Now will backup it to file ("CMB_LOG_FILE_PATH")."); //TODO check the folder log_fd = fopen(CMB_LOG_FILE_PATH, "wb+"); if (log_fd == NULL) { LOG_E("Open file ("CMB_LOG_FILE_PATH") failed."); break; } } addr += CMB_LOG_LEN_SIZE; /* read log content */ fal_partition_read(cmb_log_part, addr, (uint8_t *)log_buf, MIN(ULOG_LINE_BUF_SIZE, len)); addr += RT_ALIGN(len, CMB_FLASH_LOG_PART_WG); /* backup log to file */ fwrite(log_buf, MIN(ULOG_LINE_BUF_SIZE, len), 1, log_fd); fflush(log_fd); } else { break; } } if (has_read_log) { if (log_fd >= 0) { LOG_I("Backup the CmBacktrace flash log to file ("CMB_LOG_FILE_PATH") successful."); fclose(log_fd); fal_partition_erase_all(cmb_log_part); } } return 0; } INIT_APP_EXPORT(cmb_backup_flash_log_to_file); #endif /* CMB_USING_FAL_BACKUP_LOG_TO_FILE */ ``` 这样编译就没有问题了 结论: 无法使用 ## 更新2024-7-8 又触发随机Bug了, 但是由于没有监控终端错过了信息, 还是研究一下log保存吧 查看源码, 将报错信息写进flash的代码根本没有使用 ```C void cmb_flash_log_println(const char *fmt, ...) { va_list args; rt_size_t length; static char rt_log_buf[RT_CONSOLEBUF_SIZE]; va_start(args, fmt); length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args); if (length > RT_CONSOLEBUF_SIZE - 1 - 2) length = RT_CONSOLEBUF_SIZE - 3; /* add CRLF */ rt_log_buf[length++] = '\r'; rt_log_buf[length++] = '\n'; cmb_flash_log_write(rt_log_buf, length); va_end(args); } ``` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240708/81a2cf4951f9580d9803e761b0fd65b0.png) 也就是说这个库根本没有保存log信息的能力, 那只能自己实现了, 这里我凭印象知道, STM32触发硬件错误会进入Hard-Fault中断, 并在里面打印信息后一直死循环 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240708/0451c6670512b803143889e5c9c56b30.png) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240708/0451c6670512b803143889e5c9c56b30.png) ```C void rt_hw_hard_fault_exception(struct exception_info *exception_info) { #if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) extern long list_thread(void); #endif struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame; struct stack_frame *context = &exception_info->stack_frame; if (rt_exception_hook != RT_NULL) { rt_err_t result; result = rt_exception_hook(exception_stack); if (result == RT_EOK) return; } rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr); rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0); rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1); rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2); rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3); rt_kprintf("r04: 0x%08x\n", context->r4); rt_kprintf("r05: 0x%08x\n", context->r5); rt_kprintf("r06: 0x%08x\n", context->r6); rt_kprintf("r07: 0x%08x\n", context->r7); rt_kprintf("r08: 0x%08x\n", context->r8); rt_kprintf("r09: 0x%08x\n", context->r9); rt_kprintf("r10: 0x%08x\n", context->r10); rt_kprintf("r11: 0x%08x\n", context->r11); rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12); rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr); rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc); if (exception_info->exc_return & (1 << 2)) { rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name); #if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS) list_thread(); #endif } else { rt_kprintf("hard fault on handler\r\n\r\n"); } if ( (exception_info->exc_return & 0x10) == 0) { rt_kprintf("FPU active!\r\n"); } #ifdef RT_USING_FINSH hard_fault_track(); #endif /* RT_USING_FINSH */ while (1); } ``` 尽然进入错误中断串口都能使用, 那SPI应该也能使用吧, 试试, 我这里提前做好了spi flash, 文件系统等工作, 就先尝试创建一个Hello, World ```C // cmb_port.c line:264 #include
RT_WEAK void assert_hook(const char* ex, const char* func, rt_size_t line) { volatile uint8_t _continue = 1; rt_cm_backtrace_assert_hook(ex, func, line); FILE* f = fopen("/h.txt", "w"); fprintf(f, "Hello World"); fclose(f); while (_continue == 1); } ``` 人为的制造一个错误 ```C int main(void) { // int count = 1; // // while (count++) // { // LOG_D("Hello RT-Thread!"); // rt_thread_mdelay(1000); // } void (*fun)() = 0; fun(); return RT_EOK; } ``` 失败并没有输出文件, 但奇怪的是, 我输出的printf也没有, 貌似并没有运行这个函数, 把代码换个位置 ```C // cmb_port.c go:327 #include
void rt_cm_backtrace_assert_hook(const char* ex, const char* func, rt_size_t line) { rt_enter_critical(); #ifdef RT_USING_FINSH extern long list_thread(void); list_thread(); #endif cmb_println(""); cmb_println("(%s) has assert failed at %s:%ld.", ex, func, line); cm_backtrace_assert(cmb_get_sp()); cmb_println("Current system tick: %ld", rt_tick_get()); FILE* f = fopen("/h.txt", "w"); fprintf(f, "Hello World"); fclose(f); rt_kprintf("finish"); } ``` 又不是, 这个函数好像是处理断言的函数, 在他的上面还有一个函数, 试试 ```C void rt_cm_backtrace_exception_hook(void *context) { uint8_t lr_offset = 0; uint32_t lr; #define CMB_LR_WORD_OFFSET_START 6 #define CMB_LR_WORD_OFFSET_END 20 #define CMB_SP_WORD_OFFSET (lr_offset + 1) #if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M0) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M3) #define EXC_RETURN_MASK 0x0000000F // Bits[31:4] #else #define EXC_RETURN_MASK 0x0000000F // Bits[31:5] #endif rt_enter_critical(); #ifdef RT_USING_FINSH extern long list_thread(void); list_thread(); #endif /* the PSP is changed by RT-Thread HardFault_Handler, so restore it to HardFault context */ #if (defined (__VFP_FP__) && !defined(__SOFTFP__)) || (defined (__ARMVFP__)) || (defined(__ARM_PCS_VFP) || defined(__TARGET_FPU_VFP)) cmb_set_psp(cmb_get_psp() + 4 * 10); #else cmb_set_psp(cmb_get_psp() + 4 * 9); #endif /* auto calculate the LR offset */ for (lr_offset = CMB_LR_WORD_OFFSET_START; lr_offset <= CMB_LR_WORD_OFFSET_END; lr_offset ++) { lr = *((uint32_t *)(cmb_get_sp() + sizeof(uint32_t) * lr_offset)); /* * Cortex-M0: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Babefdjc.html * Cortex-M3: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babefdjc.html * Cortex-M4: http://infocenter.arm.com/help/topic/com.arm.doc.dui0553b/DUI0553.pdf P41 * Cortex-M7: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0646c/Babefdjc.html */ if ((lr == 0xFFFFFFF1) || (lr == 0xFFFFFFF9) || (lr == 0xFFFFFFFD) || (lr == 0xFFFFFFE1) || (lr == 0xFFFFFFE9) || (lr == 0xFFFFFFED)) { break; } } cm_backtrace_fault(lr, cmb_get_sp() + sizeof(uint32_t) * CMB_SP_WORD_OFFSET); cmb_println("Current system tick: %ld", rt_tick_get()); FILE* f = fopen("/h.txt", "w"); fprintf(f, "Hello World"); fclose(f); rt_kprintf("finish"); } ``` 确实触发了, 但是好像有互斥锁, 在操作文件的时候触发了断言又触发了一遍错误中断, 也就是打印了两次 开来常规方法确实不能保存错误信息, 只能沿用库作者的方法了, 我现在不能确定fal库是能在错误中断中正常工作, 只能试试了 ```C #include
#include
static const struct fal_partition * dl_part = RT_NULL; void write_fal(){ const char *txt = "Hello World!"; const int size = strlen(txt); dl_part = fal_partition_find("prm"); fal_partition_erase(dl_part, 0, 10); fal_partition_write(dl_part, 0, (uint8_t*)txt, size); } ``` 替换掉原来的位置 ```C ... cmb_println("Current system tick: %ld", rt_tick_get()); extern void write_fal(); write_fal(); } ``` 没有报错 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240708/21220617e1f6e6903179db8a1f2f43f3.png) 真写进去了, 也就是说库主的方法没有问题, 那就完善一下吧. ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240708/8e00b2b77081e022666d673c56294b06.png) 打开保存的功能 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240708/0ce39dda099adef8125b7c380076f6b4.png) 毫不意外报错了 开始修改, 先改为上面我写的文件报错的代码 没问题不报错了, 现在开始把 本来打算重写cmb_println宏就可以, 但是看到这个宏的定义 ```C #ifndef RT_USING_ULOG #ifndef CMB_USING_FLASH_LOG_BACKUP #define cmb_println(...) rt_kprintf(__VA_ARGS__);rt_kprintf("\r\n") #else extern void cmb_flash_log_println(const char *fmt, ...); #define cmb_println(...) rt_kprintf(__VA_ARGS__);rt_kprintf("\r\n");cmb_flash_log_println(__VA_ARGS__) #endif /* CMB_USING_FLASH_LOG_BACKUP */ #else #include
#define CMB_LOG_TAG "cmb" #define cmb_println(...) ulog_e(CMB_LOG_TAG, __VA_ARGS__);ulog_flush() #endif /* RT_USING_ULOG */ ``` 原来是写了的, 就是CMB_USING_FLASH_LOG_BACKUP这个宏本来就没有定义, 看来这是一个bug 把这个宏改为CMB_USING_FAL_FLASH_LOG就能切换到输出文件模式了, 试试 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240708/d58ee43f405cc6db21642590cdb39a66.png.webp) 成功了, 靠
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
ThinkCode
这家伙很懒,什么也没写!
文章
4
回答
16
被采纳
0
关注TA
发私信
相关文章
1
使用CmBacktrace定位错误异常,请教分析原因
2
cm_backtrack 使用ulog时,不能打印最后的堆栈调用信息
3
rtthread studio 中使用 cm_backtrace没有正常输出
4
rt thread studio下nano工程如何使用Cmb组件
5
cmBackTrace定位后无法分析出问题原因
6
程序运行一段时间后出现hardfault?CmBacktrace需要的是啥文件?
7
keil5 移植 finsh 串口打印 hard fault on thread
8
hard fault on thread: mqtt0,请教怎么解决
9
rt1052 移植cm_backtrace库,无法定位错误
10
有没有人能帮忙解决一下hard fault on main
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
11
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
rv666
9
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
6
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部