打印
[活动专区]

【AT-START-F405测评】移植RTT

[复制链接]
2684|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 hawk2003454 于 2024-5-20 16:44 编辑

RTT全称是Real Time Transmit(实时传输)是Segger公司推出的调试手段之一。它是一种用于嵌入式中与用户进行交互的技术。使用RTT可以从MCU快速输出调试信息和数据,且不影响MCU的实时性。只要支持J-Link的MCU就可使用RTT功能,兼容性非常强。RTT支持两个方向的多个通道,上到主机,下到目标,它可以用于不同的目的,为用户提供尽可能多的自由。默认实现每个方向使用一个通道,用户可在在调试终端输入和输出。使用J-Link RTT Viewer,可用于“虚拟”终端,允许打印到多个窗口(例如,一个用于标准输出,一个对于错误输出,一个用于调试输出)。
本演示基于官方固件库的模板工程。

移植RTT代码
1.安装Jlink软件包,相关的下载以及安装方式就不做过多的介绍。
2.在安装完成J-Link全家桶以后,在电脑安装路径下的D:\Program Files\SEGGER\JLink\Samples\RTT文件夹下面存放的就是RTT_Viewer的源代码。将此文件夹下面的SEGGER_RTT_Vxxxx.zip文件解压。

得到如下文件:

其中RTT文件夹下面存放的即为我们需要的源码,将RTT整个文件夹拷贝到我们的工程路径下面。


3.在工程中创建一个RTT的分组,添加两个源文件SEGGER_RTT.c和SEGGER_RTT_printf.c
4.将工程目录中的RTT文件夹包含进来:
在这里插入图片描述
5.在用到了RTT函数的文件添加头文件:
#include “SEGGER_RTT.h”
6.在main函数添加SEGGER_RTT_printf(0, “hello world\r\n”);
如果打印某个变量:SEGGER_RTT_printf(0, “n=%d\r\n”, n);
第一个参数0表示终端号。
编译成功后烧录。
连接RTT Viewer
在文件路径D:\Program Files \SEGGER\JLink找到JLinkRTTViewer.exe打开
(也可能在D:\Program Files(x86),具体情况可以自己去找找)

注意要先用Jlink连接MCU,打开File->Connect
选择对应的MCU型号,RTT控制块默认选择自动检测即可

如果没有对应型号选择,可以选择对应内核,然后手动填写控制块的起始地址
(为什么只有选择型号才能自动检测,因为选择型号就等于选择了芯片RAM的大小和起始地址,RTT Viewer就能在RAM区域自动搜索RTT控制块)
打开map文件,找到如下字段,该地址就是RTT控制块的地址,填入上面的地址栏中。

连接成功后:



这里要注意RTT与串口的不同,前面已经了解到RTT是MCU先把log缓存在一段RAM区,然后当我们用RTT Viewer连接上时,才会一次性读出来全部的数据,因为必须MCU先上电才能用jlink连接上,如果有一些上电立即打印的log也不会丢失,当连接后还是能读取到。
浮点数处理
修改SEGGER_RTT_printf.c,调用关系SEGGER_RTT_printf–>SEGGER_RTT_vprintf, 固在SEGGER_RTT_vprintf中添加如下代码:
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
  char c;
  SEGGER_RTT_PRINTF_DESC BufferDesc;
  int v;
  unsigned NumDigits;
  unsigned FormatFlags;
  unsigned FieldWidth;
  char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
  BufferDesc.pBuffer        = acBuffer;
  BufferDesc.BufferSize     = SEGGER_RTT_PRINTF_BUFFER_SIZE;
  BufferDesc.Cnt            = 0u;
  BufferDesc.RTTBufferIndex = BufferIndex;
  BufferDesc.ReturnValue    = 0;
  do {
    c = *sFormat;
    sFormat++;
    if (c == 0u) {
      break;
    }
    if (c == '%') {
      //
      // Filter out flags
      //
      FormatFlags = 0u;
      v = 1;
      do {
        c = *sFormat;
        switch (c) {
        case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
        case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO;     sFormat++; break;
        case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN;   sFormat++; break;
        case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE;    sFormat++; break;
        default:  v = 0; break;
        }
      } while (v);
      //
      // filter out field with
      //
      FieldWidth = 0u;
      do {
        c = *sFormat;
        if ((c < '0') || (c > '9')) {
          break;
        }
        sFormat++;
        FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
      } while (1);
      //
      // Filter out precision (number of digits to display)
      //
      NumDigits = 0u;
      c = *sFormat;
      if (c == '.') {
        sFormat++;
        do {
          c = *sFormat;
          if ((c < '0') || (c > '9')) {
            break;
          }
          sFormat++;
          NumDigits = NumDigits * 10u + ((unsigned)c - '0');
        } while (1);
      }
      //
      // Filter out length modifier
      //
      c = *sFormat;
      do {
        if ((c == 'l') || (c == 'h')) {
          sFormat++;
          c = *sFormat;
        } else {
          break;
        }
      } while (1);
  #if 0
      //
      // Handle specifiers
      //
      switch (c) {
      case 'c': {
        char c0;
        v = va_arg(*pParamList, int);
        c0 = (char)v;
        _StoreChar(&BufferDesc, c0);
        break;
      }
      case 'd':
        v = va_arg(*pParamList, int);
        _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
        break;
      case 'u':
        v = va_arg(*pParamList, int);
        _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
        break;
      case 'x':
      case 'X':
        v = va_arg(*pParamList, int);
        _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
        break;
      case 's':
        {
          const char * s = va_arg(*pParamList, const char *);
          do {
            c = *s;
            s++;
            if (c == '\0') {
              break;
            }
           _StoreChar(&BufferDesc, c);
          } while (BufferDesc.ReturnValue >= 0);
        }
        break;
      case 'p':
        v = va_arg(*pParamList, int);
        _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
        break;
      case '%':
        _StoreChar(&BufferDesc, '%');
        break;
      default:
        break;
      }
  #else
    //
  // Handle specifiers
  //
  switch (c) {
  case 'c': {
    char c0;
    v = va_arg(*pParamList, int);
    c0 = (char)v;
    _StoreChar(&BufferDesc, c0);
    break;
  }
  case 'd':
    v = va_arg(*pParamList, int);
    _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
    break;
  case 'u':
    v = va_arg(*pParamList, int);
    _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
    break;
  case 'x':
  case 'X':
    v = va_arg(*pParamList, int);
    _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
    break;
  case 's':
    {
      const char * s = va_arg(*pParamList, const char *);
      do {
        c = *s;
        s++;
        if (c == '\0') {
          break;
        }
       _StoreChar(&BufferDesc, c);
      } while (BufferDesc.ReturnValue >= 0);
    }
    break;
  case 'p':
    v = va_arg(*pParamList, int);
    _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
    break;
  case '%':
    _StoreChar(&BufferDesc, '%');
    break;
  // 添加输出浮点数的功能。默认带两位小数。
  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;
  }
  default:
    break;
  }
  #endif
      sFormat++;
    } else {
      _StoreChar(&BufferDesc, c);
    }
  } while (BufferDesc.ReturnValue >= 0);
  if (BufferDesc.ReturnValue > 0) {
    //
    // Write remaining data, if any
    //
    if (BufferDesc.Cnt != 0u) {
      SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
    }
    BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
  }
  return BufferDesc.ReturnValue;
}
至于Jlink RTT Viewer增加时间戳+打印不同颜色优先级LOG,均可参考网上的各位大神的教程,本人在此抛转引玉
另比较好用的上位机参考:https://gitee.com/bds123/rtt_t2

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

61

帖子

0

粉丝