Working with Pi-Lite on Raspberry Pi with FreeBSD

Here is a description how to work with Pi-Lite connected to Raspberry Pi with FreeBSD.

What is a Pi-Lite

The Pi-Lite is a very versatile 9 x 14 LED matrix display with an on-board Arduino ATmega 328 processor. Each pixel is individually addressable, so we can display anything in the grid. The Pi-Lite is a fully assembled board. It was primarilly designed as a Raspberry Pi add-on board, but works equally well without the Raspberry Pi. The idea comes from the very popular Arduino LoL shield by Jimmy Rodgers and brings the capabilities of such a shield to the world of the Raspberry Pi. LoL stands for “Lots of LEDs”.

Pi-Lite

We can drive the Pi-Lite via its serial port. We can access the serial port in two ways:

  1. By plugging the Pi-Lite into the GPIO pins of our Raspberry Pi we access it via the Raspberry Pi’s serial comms port at 9600bps.
  2. By using the serial port brought out on the FTDI connector, we can use other devices than the Raspberry Pi.

When we send any text into serial port it will be scrolled on the Pi-Lite.
All commands are preceeded by $$$ and terminated with <CR>.

Commands are:

$$$SPEEDval
Set scrolling delay in ms. 1 is scrolling very fast, 1000 is scrolling very slow.
$$$F01010110101
Set the frame buffer (one digit per pixel – 126 digits in total).
Format: Columns left to right starting at the top, e.g. (1,1) … (1,9)(2,1)…(2,9) etc.
$$$Bc,val
Bargraph vertical (14 columns). Set column c (1-14) to val (0-100)
$$$Vr,val
Bargraph horizontal (2 rows). Set row r (1-2) to val (0-100)
$$$Pc,r,action
Set the pixel at column c (1-14), row r(1-9) to action (ON, OFF, TOGGLE)
$$$ALL,ON
Set all pixels on
$$$ALL,OFF
Set all pixels off
$$$SCROLLval
Scroll val columns left (val is positive) or right (val is negative)
$$$Tc,r,char
Display char at c,r

As soon as $$$ is received then any scrolling stops, scrolling will start again when a non-command character is received.

Connecting Pi-Lite to the Raspberry Pi

I have connected Pi-Lite to the GPIO pins on my Raspberry Pi. I have freed serial port in the FreeBSD to access Pi-Lite via it.

Using the cu(1)

First variant is using the cu(1) utility:

PiLite2

We can send text and commands to the Pi-Lite but we don’t see our inputs. (I have tried to use “-h” option.)

Direct write to serial device

We can write text and commands directly to serial device, but we need to setup it first with stty(1) utility:

PiLite1

The results of these commands are here:

Using Programming Languages

We can also drive Pi-Lite from some programming languages.

Small program to draw a smile in a frame on the C language.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

#define TDEV "/dev/ttyu0"

void usage ( void )  {
  printf( "usage: %s [-f terminal_device]\n", getprogname() );
}


void writecmd( int fd, char *cmd )  {
  int cmdsize;

  cmdsize = strlen ( cmd );
  write (fd, cmd, cmdsize );

  return;
}


int main ( int argc, char** argv )  {
  char *tdev, buf[20];
  int i, ch, tfd;
  struct termios cntrl;

  tdev = TDEV;

  while ( (ch = getopt ( argc, argv, "f:" )) != -1 )  {
    switch (ch)  {
      case 'f':  tdev = optarg;
                 break;
      default:   usage();
    }
  }
  argc -= optind;
  argv += optind;

  if ( (tfd = open ( tdev, O_RDWR | O_NONBLOCK | O_NOCTTY )) == -1 )  {
    fprintf ( stderr, "Cann't open terminal device %s\n", tdev );
    exit(-1);
  }

  tcgetattr ( tfd, &cntrl ); 
  cntrl.c_cflag |= B9600;
  cntrl.c_lflag &= ~ECHO;
  cntrl.c_iflag &= ~( ICRNL |IXANY ); 
  cntrl.c_iflag |= IGNPAR;
  cntrl.c_cflag &= ~( PARENB | HUPCL); 
  cntrl.c_cflag |= CS8 | CLOCAL; 
  cntrl.c_oflag &= ~OPOST;
  tcsetattr ( tfd, TCSANOW, &cntrl ); 

  writecmd ( tfd, "$$$ALL,OFF\r" );
  writecmd ( tfd, "$$$B1,100\r" );
  for ( i = 2; i &lt; 14; i++ )  {
    sprintf ( buf, "$$$P%d,1,ON\r", i );
    writecmd ( tfd, buf );
    sprintf ( buf, "$$$P%d,9,ON\r", i );
    writecmd ( tfd, buf );
  }
  writecmd ( tfd, "$$$P6,3,ON\r" );
  writecmd ( tfd, "$$$P9,3,ON\r" );
  writecmd ( tfd, "$$$P5,5,ON\r" );
  writecmd ( tfd, "$$$P10,5,ON\r" );
  writecmd ( tfd, "$$$P6,6,ON\r" );
  writecmd ( tfd, "$$$P9,6,ON\r" );
  writecmd ( tfd, "$$$P7,7,ON\r" );
  writecmd ( tfd, "$$$P8,7,ON\r" );
  writecmd ( tfd, "$$$B14,100\r" );

  close(tfd);
  exit(0);
}

Same program on the Python language but using “$$$F” command.

#!/usr/local/bin/python2

import serial, time, sys

s = serial.Serial()
s.baudrate = 9600
s.timeout = 0
s.port = "/dev/ttyu0"

try:
  s.open()
except serial.SerialException, e:
  sys.stderr.write("could not open port %r: %s\n" % (s.port, e))
  sys.exit(1)

s.write("$$$ALL,OFF\r")
s.write("$$$F111111111100000001100000001100000001100010001101001001100000101100000101101001001100010001100000001100000001100000001111111111\r")

Small program on the C language to send text and commands to the Pi-Lite.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

#define TDEV "/dev/ttyu0"
#define CMDS 512

void usage ( void )  {
  printf( "usage: %s [-f terminal_device] [-c command_file]\n", getprogname() );
}


void writecmd( int fd, char *cmd )  {
  int cmdsize;

  cmdsize = strlen ( cmd );
  write (fd, cmd, cmdsize );

  return;
}


int main ( int argc, char** argv )  {
  char *tdev, *cfile, cmd[CMDS];
  int ch, tfd, cmdf = 0;;
  FILE *cfd;
  struct termios cntrl;

  tdev = TDEV;

  while ( (ch = getopt ( argc, argv, "f:c:" )) != -1 )  {
    switch (ch)  {
      case 'f':  tdev = optarg;
                 break;
      case 'c':  cfile = optarg;
                 cmdf = 1;
                 break;
      default:   usage();
    }
  }
  argc -= optind;
  argv += optind;

  if ( (tfd = open ( tdev, O_RDWR | O_NONBLOCK | O_NOCTTY )) == -1 )  {
    fprintf ( stderr, "Cann't open terminal device %s\n", tdev );
    exit(-1);
  }

  tcgetattr ( tfd, &cntrl ); 
  cntrl.c_cflag |= B9600;
  cntrl.c_lflag &= ~ECHO;
  cntrl.c_iflag &= ~( ICRNL |IXANY );
  cntrl.c_iflag |= IGNPAR;
  cntrl.c_cflag &= ~( PARENB | HUPCL);
  cntrl.c_cflag |= CS8 | CLOCAL;
  cntrl.c_oflag &= ~OPOST;
  tcsetattr ( tfd, TCSANOW, &cntrl ); 

  if ( cmdf )  {
    if ( (cfd = fopen ( cfile, "r" )) == NULL )  {
      fprintf ( stderr, "Cann't open command file %s\n", cfile );
      exit(-1);
    }
  }   else
    cfd = stdin;

  while ( !feof ( cfd ) )  {
    fgets ( cmd, CMDS, cfd );
    writecmd ( tfd, cmd );
  }

  fclose(cfd);
  close(tfd);
  exit(0);
}

The example

PiLite3

and the result (black and white for a variety)

SDIM1094bws

Using C Library

I have written a simple C library to draw on the Pi-Lite.
The source code is available here: https://github.com/vzaigrin/PiLiteBSD

This library provides the following functions:

pilite_init
to initialize a Pi-Lite
pilite_close
to close a Pi-Lite
pilite_clear
to clear the screen
pilite_fill
to fill the screen
pilite_point
to draw a point on the screen
pilite_line
to draw a line on the screen
pilite_box
to draw a box on the screen
pilite_fillbox
to draw a filled box on the screen
pilite_circle
to draw a circle on the screen
pilite_fillcircle
to draw a filled circle on the screen

Small demo of using this library:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include "libpilite.h"

#define TDEV "/dev/ttyu0"
#define ON 0
#define OFF 1
#define TOGGLE 2

void usage ( void )  {
  printf( "usage: %s [-f terminal_device]\n", getprogname() );
}


int main ( int argc, char** argv )  {
  char *tdev;
  int ch, tfd;

  tdev = TDEV;

  while ( (ch = getopt ( argc, argv, "f:" )) != -1 )  {
    switch (ch)  {
      case 'f':  tdev = optarg;
                 break;
      default:   usage();
    }
  }
  argc -= optind;
  argv += optind;

  if ( (tfd = pilite_init ( tdev )) == -1 )  {
    fprintf ( stderr, "Cann't open terminal device %s\n", tdev );
    exit(-1);
  }

// Clear all
  pilite_clear ( tfd );

// Two horisontal line
  pilite_line ( tfd, 1, 1, 14, 1, ON );
  pilite_line ( tfd, 1, 9, 14, 9, ON );

// Two vertical line
  pilite_line ( tfd, 1, 1, 1, 9, ON );
  pilite_line ( tfd, 14, 1, 14, 9, ON );

// Four points
  pilite_point ( tfd, 1, 1, TOGGLE );
  pilite_point ( tfd, 1, 9, TOGGLE );
  pilite_point ( tfd, 14, 1, TOGGLE );
  pilite_point ( tfd, 14, 9, TOGGLE );

  sleep(2);
// Big filled circle
  pilite_fillcircle ( tfd, 7, 5, 3, ON );

// Small circle and point in center
  pilite_circle ( tfd, 7, 5, 1, OFF );
  pilite_point ( tfd, 7, 5, TOGGLE );

  sleep(2);
// Clear and two circle
  pilite_clear( tfd );
  pilite_circle ( tfd, 5, 5, 4, ON );
  sleep(1);
  pilite_circle ( tfd, 10, 5, 4, ON );

  sleep(2);
// Fill all
  pilite_fill ( tfd );

// Two diagonal line
  pilite_line ( tfd, 1, 1, 14, 9, OFF );
  pilite_line ( tfd, 1, 9, 14, 1, OFF );
  
  sleep(2);
// Clear and two box
  pilite_clear( tfd );
  pilite_fillbox ( tfd, 2, 2, 13, 8, ON );
  pilite_box ( tfd, 4, 4, 11, 6, OFF );

  sleep(4);
// Clear
  pilite_clear( tfd );

  pilite_close ( tfd );
  exit(0);
}

And the result:

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s