Multiple channels in RTT

Segger RTT (Real-Time Terminal) supports multiple data channels.

RTT Viewer uses channel 0 only, and implements multiple virtual terminals on top of this. The terminal can be switched by SEGGER_RTT_SetTerminal(). Channel 0 is used by NRF_LOG. NRF_LOG does not do terminal switching, so you can do it yourself (be careful about reentracy though).

Data from other channels can be read using RTT Logger. To send data from NRF to RTT Logger:

  1. In sdk_config.h, adjust value of SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS. The default is 2, which gives you 1 extra channel besides channel 0. In the example below, it should be set to 3.

  2. Allocate data buffer (on heap!) for each channel

     uint8_t data1Buffer[128];
     uint8_t data2Buffer[128];
    
  3. Call SEGGER_RTT_Init() or let NRF_LOG_INIT() do it for you if you have configured logging via RTT.

  4. Call SEGGER_RTT_ConfigUpBuffer() to tell RTT to use your buffers.

     SEGGER_RTT_ConfigUpBuffer(1, "DATA1", data1Buffer, 128, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
     SEGGER_RTT_ConfigUpBuffer(2, "DATA2", data2Buffer, 128, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
    
  5. Call SEGGER_RTT_Write(), SEGGER_RTT_WriteString() or SEGGER_printf() specifying your channel number.

     int cnt = 0;
     char buf[32];
     while (1) {	
             for (int j=0; j<3; j++) {
                     sprintf(buf, "Message # %d channel %d\n", cnt, j);
                     SEGGER_RTT_WriteString(j, buf);
             }
             cnt++;
             nrf_delay_ms(2000);
     }
    
  6. Start RTT Logger and let the magic happen: https://i.imgur.com/GDNgoCM.png Note that by default RTT Logger creates log files in the same directory as its exe file.

  7. Detailed documentation for SEGGER_RTT_* functions can be found in chapter 13 of J-Link user manual.

  8. You can also use down buffers to send data to NRF. However, there is no host-side software to do this, except for sending data to channel 0 via RTT Viewer. But apparently you can do it yourself if you buy J-Link SDK license.

Anonymous
  • You are right of course! It should be:

     uint8_t data1Buffer[128];
     uint8_t data2Buffer[128];
    

    (post updated).

  • Hi,

    You use:

    uint8_t *data1Buffer[128];
    uint8_t *data2Buffer[128];
    

    ...and state that this is on the heap. This allocates 128 pointers to uint8_t twice, so 1 KB of memory. You either need a plain pointer (kill the array) and use the equivalent of "malloc" or just remove the * and use a plain array.

    Short: this is not a pointer to an array of 128 bytes.

  • Yes, I call SEGGER_RTT_Init. I do everything exactly as you, except I have 2 additional channels - 3 in all. I wonder whether the buffers shouldn't be placed like they are for channel 0 in "SEGGER_RTT.h":

    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]));
    
  • No, the RTT libs are from clean SDK14. Did you call SEGGER_RTT_Init()?

    Here's how I use it now, for reference. (You need to provide _ASSERT macro).

    #include <string.h>
    #include "SEGGER_RTT.h"
    #include "RTT_data.h"
    #include "sdk_config.h"
    
    #define RTT_DATA_BUFFER_SIZE 			128					// FIFO size
    #define RTT_DATA_CHANNEL 				1					// RTT channel number (RTT Viewer and NRF_LOG use 0)
    #define RTT_DATA_USE_BLOCKING_MODE 		1					// Block if not enough space in FIFO
    #define RTT_DATA_ASSERT_ON_OVERFLOW 	0					// If RTT_DATA_USE_BLOCKING_MODE is 0, assert if not enough space in the FIFO
    
    
    uint8_t RTT_buffer[RTT_DATA_BUFFER_SIZE];
    
    bool RTT_initialized = false;
    
    void RTT_data_init(void)
    {
    #if (RTT_DATA_CHANNEL > SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS-1)
    #error "Please increase SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS in sdk_config.h"
    #endif
    
    #if NRF_LOG_BACKEND_RTT_ENABLED
    	// NRF_LOG will initialize RTT for us
    #else
    	SEGGER_RTT_Init();
    #endif
    	
    #if RTT_DATA_USE_BLOCKING_MODE
    	int mode = SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL;
    #else
    	int mode = SEGGER_RTT_MODE_NO_BLOCK_SKIP;
    #endif
    		
    	int ret = SEGGER_RTT_ConfigUpBuffer(RTT_DATA_CHANNEL, "RTT_DATA", RTT_buffer, RTT_DATA_BUFFER_SIZE, mode);
    	_ASSERT(ret>=0);
    	RTT_initialized = true;
    }
    
    void RTT_data_send(uint8_t *data, int size)
    {
    	_ASSERT(RTT_initialized);
    	int ret = SEGGER_RTT_Write(RTT_DATA_CHANNEL, data, size);
    #if RTT_DATA_ASSERT_ON_OVERFLOW
    	_ASSERT(ret == size);
    #endif
    }
    
    void RTT_data_send_string(char *string)
    {
    	_ASSERT(RTT_initialized);
    	int ret = SEGGER_RTT_WriteString(RTT_DATA_CHANNEL, string);
    #if RTT_DATA_ASSERT_ON_OVERFLOW
    	_ASSERT(ret == strlen(string));
    #endif
    }
    
  • Hello,

    I did it exactly as you, but I'm having problems with data reception. It appears that I can't use more than one RTT listening application (no matter: Viewer, Client, Logger) to save proper data. When I try, either only one channel is actually receiving anything or data get corrupted. So, I can't seem to achieve what you present on your screenshot. Have you perhaps changed anything else in your RTT lib config?