返回首页

通过 J-Link SWD 的 Cortex-M RTT CLI

本文描述了在 ARM Cortex-M 上通过 J-Link RTT 集成 CLI shell。提供了初始化代码、命令处理和响应发送。讨论了 Viewer 设置、TCP 访问以及与 UART 的比较。

通过 RTT 的 CLI:ARM 无需 UART 的 SWD shell
Advertisement 728x90

通过J-Link RTT为ARM Cortex-M搭建命令行界面

要在不使用UART的情况下通过SWD实现命令行界面,请使用SEGGER_RTT库。下载源文件:SEGGER_RTT.h(API,253行)、SEGGER_RTT.c(实现,1751行)、SEGGER_RTT_printf.c(printf,516行)、SEGGER_RTT_Conf.h(配置,333行)。

首先初始化零号RTT通道:

void SeggerInit() {
    SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
    SEGGER_RTT_ConfigDownBuffer(0, "RTTDOWN", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);    
    SEGGER_RTT_SetTerminal(0); 
}

bool segger_rtt_init_custom(void) {
    bool res = true;
    SeggerInit();
    return res;
}

在固件启动时调用SeggerInit()以配置非阻塞发送和接收缓冲区。

Google AdInline article slot

处理传入命令

在主循环或定时器中通过SEGGER_RTT_Read定期轮询通道:

bool segger_rtt_proc_one(uint8_t num) {
    bool res = false;
    LOG_PARN(SEGGER_RTT, "RTT%u,Proc", num);
    SeggerRttHandle_t* Node = SeggerRttGetNode(num);
    if(Node) {
        if(Node->RxBuffer) {
            if(Node->buffer_size) {
                unsigned rx_byte = SEGGER_RTT_Read(Node->BufferIndex, 
                                                   Node->RxBuffer, 
                                                   Node->buffer_size);
                if(rx_byte) {
                    res = segger_rtt_writer(num);
                    LOG_DEBUG(SEGGER_RTT,"RxData:[%s]=[%s],rxByteCnt:%u Bytes", 
                              ArrayToStr(Node->RxBuffer,rx_byte), 
                              ArrayToAsciiStr(Node->RxBuffer,rx_byte), 
                              rx_byte);
                    res = cli_process_data(Node->cli_num, 
                                           Node->RxBuffer, 
                                           rx_byte);
                    memset(Node->RxBuffer, 0, rx_byte);
                }
            }
        }
    }
    return res;
}

函数返回接收到的字节数。将数据传递给CLI处理程序:cli_process_data()

从固件发送响应

要传输字符串,请使用SEGGER_RTT_Write。实现putc/puts函数和FIFO缓冲区:

Google AdInline article slot
void segger_rtt1_puts(void* stream_ptr, const char* str, int32_t len) {
    SeggerRttHandle_t* Node = SeggerRttGetNode(1);
    if(Node) {
        if(str) {
            if(len) {
                unsigned tx_cnt = SEGGER_RTT_Write(Node->BufferIndex,
                                                   (void* )  str,
                                                   (unsigned) len);
                (void)tx_cnt;
            }
        }
    }
}

void segger_rtt1_putc(void* stream_ptr, char ch) {
    SeggerRttHandle_t* Node = SeggerRttGetNode(1);
    if(Node) {
        unsigned tx_cnt = SEGGER_RTT_Write(Node->BufferIndex,
                                           (void* )  &ch,
                                           (unsigned)  1);
        (void)tx_cnt;
    }
}

从Tx FIFO提取数据并写入RTT通道。这确保了异步传输且无数据丢失。

  • FIFO优势:缓冲可防止高峰负载时溢出。
  • 监控:记录tx_cnt以调试任何丢失的传输。
  • 扩展性:支持多个通道(num > 0)。

在PC上配置J-Link RTT Viewer

安装SEGGER J-Link软件包。从C:\Program Files\SEGGER\JLink_V834运行JLinkRTTViewer.exe

配置连接:

Google AdInline article slot
  • 选择SWDJTAG
  • 指定目标设备(ARM Cortex-M)。
  • 设置速度(最高兆赫兹)。
  • 确认连接。

终端0中输入命令——支持颜色高亮。如果FIFO溢出,请编辑SEGGER_RTT_Conf.h以增加缓冲区大小。

通过TCP替代访问

RTT Viewer在127.0.0.1:19021上打开一个套接字(使用netstat -ano | grep 19021检查)。

使用PuTTY或Tera Term连接:

  • 主机:127.0.0.1
  • 端口:19021
  • 类型:TCP

这模拟了一个UART终端。可通过WiFi网络远程工作。

RTT CLI的优势与局限

优势

  • 与逐步调试并行操作。
  • 无需ELF文件:烧录后传递给J-Link。
  • 以SWD速度即时传输。
  • 复制粘贴带高亮的日志。
  • 多个终端。

局限

  • 依赖J-Link(不适用于AVR/ESP32/RISC-V)。
  • MCU复位时断开连接——需要手动重连。
  • 单独的输入窗口(通过TCP解决)。
  • Viewer不支持\r(Tera Term中可用)。

| 方面 | SWD RTT | UART |

|--------|-------------|------|

| 速度 | SWD MHz | 115200+ |

| 引脚 | 3-4 | 2+ |

| 调试 | 并行 | 否 |

| 复位 | 断开连接 | 稳定 |

关键要点

  • 在main()之前初始化RTT以进行早期日志记录。
  • 使用NO_BLOCK_SKIP避免挂起。
  • 通过tx/rx_cnt日志监控FIFO溢出。
  • TCP 19021解决UI Viewer问题。
  • 适用于支持J-Link的Cortex-M。

— Editorial Team

Advertisement 728x90

继续阅读