文章總列表

SEGGER RTT (1)

SEGGER RTT (1)

SEGGER RTT (1)

UART is Troublesome in Target-side

Printf() is probably the most handy debug tool since I learn C. In embedded world, we used UART to direct message to PC. After learning more things these years, I began to “hate” UART with following reasons:

  1. First, UART is quite slow. It requires ~0.1ms to transmit 1byte @ 9600bps. When CPU is running @ 16Mhz, it takes 1600 CPU cycles to transmit 1 character.
  2. Typical UART hardware had only few bytes of transmit buffer which is not sufficient to hold whole strings. A handy solution is polling the hardware to transmit data. The method is unacceptable when running time critical applications such as BLE.
  3. Most UART had interrupt mode which raises IRQ when transmit buffer is empty. This means additional effort to bring up such mechanism. Besides, we need a ring buffer to store string-to-send.
  4. To have “advanced” (troublesome) solution in (3), one shall deal with UART HW which varies chip by chip.
  5. Besides, use UART to transmit string is quite wasteful since it takes long time to do string format (probably we need some tiny C library).

UART is More Troublesome in PC-side

In PC side, the COM port is probably extinct and we need a UART to USB IC such as FTDI-based chip. The development board in nowadays (2016~) typically had such IC. However, the solution is still not perfect for me.

When running terminal program such as “Tera-Term”, I need to setup COM-port with following parameters:

  • COM port number
  • # of start bits
  • # of data bits
  • # of end bits
  • Parity bits

Among all parameters, COM port number is the most troublesome part. The port number changes as I plug the USB connector to different holes. I need to open “device manager” and find corresponding COM-port to have my port.

SEGGER RTT Introduction

Alt text

Every time when I have a new development board, I always tried to bring up UART interface to see “Hello World”. I don’t like the polling method to throw the log, which is ugly and not scalable. IRQ-style log service takes time and error-prone (IRQ is always harder to implement). For my personal aesthetic, I can’t accept both solutions such that the toy (development board) is thrown away very soon.

Thanks to the ARM’s AHB-AP capability which enables debugger reading system memories without halting system. More specifically, MCU is running the application while SEGGER-JLINK could read/write system memory. This is amazingly improvement for Embedded development. Let’s see how this could solve my problem.

SEGGER-RTT implemented a ring-buffer in target side looks like:

struct {
u8 token[11];
u8 buf[1024];
u32 wptr; // MCU updates when write to buf[]
u32 rptr; // PC updates the value
} ring_buf;

MCU uses following function to put a character in the buffer, which is quite faster (<30 cycles). The speed is ~50x faster than UART-polling mode @ 9600bps.

ring_buf rtt = {
.token = "SEGGER-RTT"; // Special token enables SEGGER-JLINK to find the structure
};

rtt_write_char(char c)
{
disable_irq();
rtt.buf[rtt.wptr] = c;
rtt.wptr = (rtt.wptr+1) & (1024-1); // ring buffer management
enable_irq();
}

SEGGER-JLINK first scan MCU’s data memory via AHB-AP to find the special token “SEGGER-RTT” to locate the ring-buffer address. Then SEGGER-JLINK periodically read the RTT control data to find whether data is available:

check_target_buf()
{
u8 local_buf[32KB];
u8 *ptr = &local_buf;
u32 wptr = read_target_memory(rtt.wptr);
u32 rptr = read_target_memory(rtt.rptr);

while(wptr != rptr) {
*ptr++ = read_target_memory(rtt.buf[rptr]);
rptr = (rptr + 1) & 1023;
}

write_target_memory(rtt.rptr, rptr); // updates rptr
}

PC-side application then prints the message to some window or do required post-processing.

Compare to the fastest UART solution (UART-IRQ), both solutions need a ring buffer that application writes the message to. Write to ring buffer is quite fast and clean. However, UART requires additional MCU effort to move data from rtt.buf[] to UART hardware. In RTT solution, the data movement is done in PC & JLINK hardware which doesn’t waste MCU cycles. In this aspect, logging system overhead is less in RTT approach.

RTT is based on SWD (Serial Wire Debug) interface which only requires 2 pins {SWDIO, SWCLK}. We could reuse SWD interface to have log service. In UART solution, we need additional 2 pins {RX, TX} to have log service. One significant drawback of RTT is that we need SEGGER-JLINK (~80USD) to read log message from target board. For UART, we only need a FTDI-based chip (<10USD).

I have a standalone SEGGER-JLINK and many development boards nowadays equipped it on board. So RTT is a portable solution for me. I would recommend to use RTT in replace of UART from now.

In next article, I would introduce how to port SEGGER-RTT to the development board.

留言

這個網誌中的熱門文章

STM32 UART + DMA,使用HAL實作TX/RX,以及不定長度接收

幼犬書桌椅選擇心得 升降桌 兒童桌椅

CANON G3000 廢墨瓶改裝