Use Wio Terminal as a serial logger

When making IoT development, you need to debug on the Field. I’ve been using some serial logger to store information and analyze them after (I’ll post something about it once a day). But sometime you want to watch it in real time. So you need a small terminal you can easily transport with you. Smartphone could be cool and I’m sure we can hack something fun with a BLE connectivity. By the way, what I had in stock for doing a such thing was a Wio Terminal from Seeed.

This device is an Arduino compatible solution including a LCD screen 320×200, some interesting embedded sensors and a lot of IO to play with. The only bad point for me and the design I want to do is the absence of internal battery so you need to power it a different way.

What I need is just a Serial line to print on the LCD screen all what my IoT device want to share. Let see how I did make it.

Transparency

I’ve got this WIO terminal because Seeed send it to my in place of some E5 board I was looking to test. So this device as been offered to me by Seeed. My condition for such partnership is that I stay free to talk or not about the device when I found an interesting way to use it. So even, if this post is related to a partnership with Seeed, this is not a sponsored blog post. Just my own feeling and experience.

Configure Arduino environment

The seedstudio documentation page is really well made for this device, honestly I did not see many time a such content for a “Chinese” product so I really appreciated the ability to quickly starting with it.

I do not need to detail the installation steps, just follow the documentation. The board installation is a bit long about 5 minutes to download and install the whole stack for SAMD boards.

I encountered a difficulty: when the USB cable is not correctly plug in the device, you can have the power but not the USB. As a consequence the serial communication with the Mac was not possible and the sketch upload was not possible. So make sure you correctly plugged the cable in. On mac, you will see the serial port with the Seeeduino Wio Terminal mention to identify it. If you not see it, check your USB cable.

Let’s make a Hello World example:

Create a new sketch for this device. In parallel, open the following example

Font example sketch to get the Free_Fonts.h file

From this example sketch, copy the content of the Fee_Fonts.h file to your new sketch is a file with the same name. Once done we can create the Hello World test:

#include "TFT_eSPI.h"
#include "Free_Fonts.h" //include the header file
TFT_eSPI tft = TFT_eSPI();
 
void setup() {
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK); 
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(1);
  tft.setFreeFont(FM9);
  tft.println();
  tft.println("Hello World !");
}
void loop() {}

Now you can compile and upload and get the result on the screen:

Connecting to the IoT device serial output

The grove connector does not have the Serial pin. It would have been easier but they don’t have. So the 40 pin header will do the job.

We have the RX/ TX pin available on the pin 8 and 10. As I just need to receive the data from the device, I will just have to connect RXD and a GROUND I can ind on pin 9. The use of a 40 pin header is good to connect to a raspberryPi. It has been designed for it. In my point of view it not really easy to cable it for a hack like what i’m looking to do. By the way, good to get it, I don’t have better solution to propose. I also assume we can power the Wio Terminal using the 5V pin (eventually 3.3) from this connector. So I’ll do some tests with a LiPo battery on the 5V connector to see what is happening. Let’s keep that part for later. there is an existing extension corresponding to my need basically. But I will have to make it myself.

I’ve built a simple board on the 40 pin header to connect the battery and the serial port:

Wio Treminal Serial + Power board

Use the TFT screen as a console

We have different font. The Mono 9 seems the best solution for the console logger. The screen can display 29 characters per line and 13 lines. There is no scroll solution apparently but is goes to the next line after printing it.

After some investigation, I found another method to print char on screen: tft.drawChar(). this one is more easier than print to draw the screen from a circular buffer. This one has a different font with smaller characters. So we can get have 39 columns and 18 lines.

I’ll use a circular buffer of lines to store the Serial content and I’ll display 13 lines of that buffer on the screen. It will later be possible to scroll over this buffer using the 5 directions button. With 192KB of RAM … we can have a big circular buffer 😉

Only disappointing point fro this device, the TFT screen not correctly placed inside the device with a rotation.

Wio Terminal Tft screen not correctly parallel

Serial port

The serial line you can access from the 40Pin header is Serial1. the RXD pin is corresponding to Wio Terminal Reception. I’ve been a bit surprizes as it is also the RXD pin for raspberry Pi so it will be reversed when using Wio Terminal as a Pi Hat.

Powering and power consumption

The Wio Terminal can be powered with a LiPo using the pins 4 & 6 for connecting it. It seems to work correctly, at least for the usage I’ve been described here. the average consumption is high with 180mA like you can see on this graph:

Wio Terminal power consumption with a 3,75V source (TFT on)

But turning off the LCD back-light:

#define LCD_BACKLIGHT (72Ul) // TFT Backlight Pin
...
pinMode(LCD_BACKLIGHT,OUTPUT);
...
digitalWrite(LCD_BACKLIGHT, LOW); // TFT off

You can save 65mA and have an average of 115mA power consumption. This is still really high, I did not found a lot of things about on Internet yet unfortunately and my objective is to quickly make a serial logger, no big investigation on this topic. If you have good links, please share in the comments.

Feature of the solution

The serial logger have some extra features:

  • Pushing on the 5 directions button stops scrolling. The screen have a red rectangle to notify this mode. A second push, will bring back the logger to the normal mode, displaying the last messages.
  • Going up & down with the 5 directions button allows to navigate in the log history.
  • Pushing the button C switch the TFT screen off to save energy
  • When new char are received, a green circle is printed on the corner of the screen to see it, even when the scrolling is disabled.

The full code is here:

#include "TFT_eSPI.h"
TFT_eSPI tft = TFT_eSPI();

#define LCD_BACKLIGHT (72Ul) // Control Pin of LCD
#define MAXLINE     1024
#define TFTLINE       18  // number of lines
#define TFTLINEHEIGHT 13  // pixel per line
#define MAXCOLUMN     42  // number of columns + 1 for the buffer
#define TFTCOLUMN (MAXCOLUMN-1) // number of column on TFT screen
#define TFT_XMIN       4 // first char offset
#define TFT_YMIN       3 // first char offset

#define INCPTR(v) v = (v+1) & (MAXLINE-1)
#define DECPTR(v) v = (v>0)?(v-1):(MAXLINE-1);



char lineBuffer[MAXLINE][MAXCOLUMN];
int  rdLine;
int  wrLine;
int  cColumn;
unsigned long  totalLineReceived;
boolean scroll;
boolean tftOn;

void setup() {
  pinMode(LCD_BACKLIGHT,OUTPUT);
  pinMode(WIO_5S_UP, INPUT_PULLUP);
  pinMode(WIO_5S_DOWN, INPUT_PULLUP);
  pinMode(WIO_5S_LEFT, INPUT_PULLUP);
  pinMode(WIO_5S_RIGHT, INPUT_PULLUP);
  pinMode(WIO_5S_PRESS, INPUT_PULLUP);
  pinMode(WIO_KEY_C, INPUT_PULLUP);
  
  Serial1.begin(9600);
  
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(TFT_BLACK); 
  tft.setTextColor(TFT_WHITE);
  tft.setTextSize(1);
  digitalWrite(LCD_BACKLIGHT, HIGH); // TFT on

  bzero(lineBuffer,sizeof(lineBuffer));
  rdLine=0;
  wrLine=0;
  cColumn=0;
  totalLineReceived=0;
  scroll=true;
  tftOn=true;
  
}


// redraw the screen
void printScreen() {
  tft.fillScreen(TFT_BLACK);
  if (!scroll) {
    tft.drawRect(0,0,320,240,TFT_RED);
    tft.drawRect(1,1,319,239,TFT_RED);    
  }
  //tft.fillRect(0, 0, 320, 240, TFT_BLACK);
  int cline=rdLine;
  int yPos = TFT_YMIN;
  for ( int y = 0 ; (y < TFTLINE) && (cline != wrLine) ; y++ ) {
    int x = 0;
    int xPos = TFT_XMIN;
    char c = lineBuffer[cline][x];
    while ( c != '\0' && x <= TFTCOLUMN ) {
      xPos += tft.drawChar(c,xPos,yPos,2);
      x++;
      c = lineBuffer[cline][x];
    }
    yPos+=TFTLINEHEIGHT;
    INCPTR(cline);
  }
}

// Return the number of lines to print according to the buffer data
int lineToPrint() {
  if ( wrLine >= rdLine ) {
      // normal case wr is before
      return wrLine - rdLine;
  }
  // wrLine has overflowed but rdLine not Yet
  return ( MAXLINE + wrLine ) - rdLine;
}


void loop() {
  boolean refresh = false;
  boolean keyPressed = false;
  boolean hasChar = false;

  if ( digitalRead(WIO_5S_PRESS) == LOW ) {
    scroll = ! scroll;
    if ( scroll ) {
      rdLine = wrLine;
      // back to the right index (quick & dirty)
      for ( int i = 0 ; i < TFTLINE && i < totalLineReceived ; i++ ) {
        DECPTR(rdLine);
      }
    }
    keyPressed = true;
  } else if ( digitalRead(WIO_5S_UP) == LOW ) {
    if ( rdLine != wrLine ) {
      INCPTR(rdLine);
    }
    keyPressed = true;
  } else if ( digitalRead(WIO_5S_DOWN) == LOW ) {
    if ( rdLine != wrLine ) {
      DECPTR(rdLine);
    }
    keyPressed = true;
  }
  if ( digitalRead(WIO_KEY_C) == LOW ) {
    tftOn = ! tftOn;
    digitalWrite(LCD_BACKLIGHT, ((tftOn)?HIGH:LOW));
    delay(500);
  }
  
  if (keyPressed) {
    refresh=true;
    delay(200);    
  }

  if (Serial1.available()) {
    hasChar = true;
    tft.fillCircle(310,10,3,TFT_GREEN);
  }
  while (Serial1.available()) {
    char c = Serial1.read();
    if ( c == '\n' ) {
      lineBuffer[wrLine][cColumn]='\0';
      totalLineReceived++;
      INCPTR(wrLine);
      if ( scroll && lineToPrint() > TFTLINE ) INCPTR(rdLine);
      cColumn = 0;
      if (scroll) refresh=true;
    } else {
      if ( c != '\r' ) {
        lineBuffer[wrLine][cColumn] = c;
        cColumn++;
        if ( cColumn == TFTCOLUMN ) {
          lineBuffer[wrLine][cColumn] = '\0';
          totalLineReceived++;
          INCPTR(wrLine);
          if ( scroll && lineToPrint() > TFTLINE ) INCPTR(rdLine);
          cColumn = 0;
          if (scroll) refresh=true;
        }
      }
    }
  }
  if ( hasChar ) {
    delay(50);
    tft.fillCircle(310,10,3,TFT_BLACK);    
  }

  if (refresh && tftOn ) {
    printScreen();
  }

}

2 thoughts on “Use Wio Terminal as a serial logger

  1. Hi I have been flashing the firmware with erpc features (complex process) and since that BLE advising is not working according to the wiki example. Having data logging and communication working simultaneously seems to be a challenge. I am maybe not good enough in programming but the Wio Terminal appears as a complex thing to use. I do not know how to debug that product, it does not pop up in the nrfConnect software and nothing happens in the arduino serial monitor .Best regards.

    • I’ve quickly taken a look to WiFi/BLE firmware flashing at the beginning and i agree, it looks complex. But you do not have especially to do it for using Wio Terminal. For what I had to do, the getting starting process has been really fast.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.