RTT打印在分区跳转后无法打印问题

场景:

RTT打印仅占用JLINK的带宽,比串口传输更快更简洁,同时RTT可以使用jscope对代码里面的变量实时绘图显示波形,而采用串口打印波形无法实时打印。同时可以保存原始数据到本地进行分析,RTT在各方面完胜串口。


问题描述

正常使用RTT没有太大的问题,而对FLASH进行分区后,跳转不同的分区需要重新连接RTT才可以输出,造成极大的不便。


原因分析:

RTT跳转后,都会重新初始化RTT的block地址,就会导致RTT VIEWER不能及时识别新的blcik地址,从对应的地址取数据显示了。那么通过固定RTT的block地址是不是就可以了,打开SEGGER_RTT.c在290行的位置,注销_SEGGER_RTT _acDownBuffer _acUpBuffer的初始化,将其固定在0x2000000的地址,如下:

// #if SEGGER_RTT_CPU_CACHE_LINE_SIZE
//   #if ((defined __GNUC__) || (defined __clang__))
//     SEGGER_RTT_CB _SEGGER_RTT                                                             __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE)));
//     static char   _acUpBuffer  [SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)]   __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE)));
//     static char   _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)] __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE)));
//   #elif (defined __ICCARM__)
//     #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE
//     SEGGER_RTT_CB _SEGGER_RTT;
//     #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE
//     static char   _acUpBuffer  [SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)];
//     #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE
//     static char   _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)];
//   #else
//     #error "Don't know how to place _SEGGER_RTT, _acUpBuffer, _acDownBuffer cache-line aligned"
//   #endif
// #else
//   SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT));
//   SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer  [BUFFER_SIZE_UP]));
//   SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN]));
// #endif

__attribute__((section(".ARM.__at_0x20000000"))) SEGGER_RTT_CB _SEGGER_RTT;
__attribute__((section(".ARM.__at_0x200000B0"))) static char _acDownBuffer[BUFFER_SIZE_DOWN];
__attribute__((section(".ARM.__at_0x200000C0"))) static char _acUpBuffer[BUFFER_SIZE_UP]; 

但是发现还是不行,每次烧录完芯片都要重新连接RTT,而且要很久,RTT每次都要搜索地址很费时间,搜索block后,分区都已经跳转完毕,跳转前的信息无法查看。最后需要RTT VIEWER中的地址为固定地址后就实时打印跳转的信息了。
在这里插入图片描述


结果:

测试后发现分区跳转后可以打印,但是还是存在偶尔打印缺失的情况,查找后发现block中还有内容未被RTT VIEWER读取就执行了跳转,block里面的内容被重置,也就无法读取了,在跳转前判断一下block是否还有内容就Ok了,跳转的内容如下:

uint32_t *inputAddr;  // !声明为全局变量,防止执行__set_MSP后,变量被释放
uint32_t jumpAddr;    // !设置MSP后改变了栈底地址,导致原来的局部变量范围出了新栈的空间,被系统释放

void JumpToCode(uint32_t addr) {
    inputAddr = (uint32_t *)addr;
    jumpAddr  = *(uint32_t *)(addr + 4);
    if ((*inputAddr & 0x2FFE0000) == 0x20000000) {
        // 等待rtt打印完毕 超时退出, rtt viewer中需要指定block地址,避免搜索地址耗费太长时间
        uint32_t start = HAL_GetTick();
        while (SEGGER_RTT_GetBytesInBuffer(0) > 0) {
            if (HAL_GetTick() - start > 100)
                break;
        }

        HAL_RCC_DeInit();
        HAL_DeInit();
        __set_FAULTMASK(1);
        __set_CONTROL(0);

        __set_MSP(*inputAddr);
        ((void (*)(void))jumpAddr)();
    }
}

在这里插入图片描述
最后附上方便打印的宏,类似ROS里面的开头

#ifndef LOG_H
#define LOG_H
#include "SEGGER_RTT.h"

#define USE_LOG_DEBUG 1

#define TERMINAL_0    0
#define TERMINAL_1    1
#define TERMINAL_2    2
#define TERMINAL_3    3
#define TERMINAL_4    4
#define TERMINAL_5    5

#if USE_LOG_DEBUG
    #define LOG_PROTO(type, color, format, ...) SEGGER_RTT_printf(0, "  %s%s" format "\r\n%s", color, type, ##__VA_ARGS__, RTT_CTRL_RESET)
    #define LOG_INFO(format, ...)               LOG_PROTO("[INFO]:", "", format, ##__VA_ARGS__)                           // 无颜色日志输出
    #define LOG_DEBUG(format, ...)              LOG_PROTO("[DEBUG]:", RTT_CTRL_TEXT_BRIGHT_GREEN, format, ##__VA_ARGS__)  // 绿色日志输出
    #define LOG_WARN(format, ...)               LOG_PROTO("[WARN]:", RTT_CTRL_TEXT_BRIGHT_YELLOW, format, ##__VA_ARGS__)  // 黄色日志输出
    #define LOG_ERROR(format, ...)              LOG_PROTO("[ERROR]:", RTT_CTRL_TEXT_BRIGHT_RED, format, ##__VA_ARGS__)    // 红色日志输出
    #define LOG_CLEAR()                         SEGGER_RTT_WriteString(0, "\r\n" RTT_CTRL_CLEAR)                          // 清屏

    // 打印数组
    #define LOG_ARRAY(pbuf, len, terminal)                \
        do {                                              \
            SEGGER_RTT_SetTerminal(terminal);             \
            uint8_t* _pbuf = (pbuf);                      \
            int _len       = (len);                       \
            for (int _i = 0; _i < _len; _i++) {           \
                SEGGER_RTT_printf(0, "%02x ", _pbuf[_i]); \
            }                                             \
            SEGGER_RTT_printf(0, "\r\n");                 \
            SEGGER_RTT_SetTerminal(0);                    \
        } while (0)

#else

    #define LOG_INFO(format, ...)
    #define LOG_DEBUG(format, ...)
    #define LOG_WARN(format, ...)
    #define LOG_ERROR(format, ...)
    #define LOG_CLEAR()
    #define LOG_ARRAY(pbuf, len, terminal)

#endif

#endif

同时RTT不能打印浮点数,RTT的格式化字符串函数没有对浮点进行格式化,可以手动添加即可,参考了某论坛的(找不到出处了),在SEGGER_RTT_printf.c的523行switch的default语句前面添加下面的case

                case 'f':  // 添加输出浮点数的功能。默认带两位小数。
                case 'F': {
                    float fv = (float)va_arg(*pParamList, double);  // 取出输入的浮点数值
                    if (fv < 0)
                        _StoreChar(&BufferDesc, '-');                                    // 判断正负号
                    v = abs((int)fv);                                                    // 取正整数部分
                    _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);  // 显示整数
                    _StoreChar(&BufferDesc, '.');                                        // 显示小数点
                    v = abs((int)(fv * 100));
                    v = v % 100;
                    _PrintInt(&BufferDesc, v, 10u, 2, FieldWidth, FormatFlags);  // 显示小数点后两位
                    break;
                }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值