Using Maplins N00GA or AM03127 LED Display as an LED Matrix

May 5, 2015 at 10:47 pm (computers) (, , , )

One of the reasons for playing around with my N00GA (the AM03127 based LED sign you can get from Maplins) was to see if I could get to use it as a large LED matrix rather than as a scrolling text sign.  You can, but it is a bit involved.

As described in my previous post, the sign can be controlled over RS232, but to use it as a raw matrix, you need to do the following:

  • Send a message to the sign to define a series of graphic blocks
  • Send a message to the sign to display the graphic blocks

The technical manual does a pretty good job of telling you how to define the graphic blocks, but it is not a complete description and a bit of experimentation is in order.   Whilst there is some code around that appears to include functions to define and show graphic blocks, again there isn’t much by way of explanation of how it works, so here goes.

First, from the manual …

N00GA-DefineGraphicBlock1 N00GA-DefineGraphicBlock2

So what this means is that each block of 4 LEDs is encoded into a single byte, with 2 bits per LED.  The values for each LED are as follows:

00 - Off
01 - Green
10 - Red
11 - Both (i.e. orange/yellow)

Each graphic block is defined in an 8×8 chunk, and there are 4 of these 8×8 chunks in each graphics block – as per the diagram in the manual.  So that there are so that there are 32×8 “pixels” in each graphic block.
Each block itself is defined using a <Gpn> command and then incorporated into a message to be displayed so it is trivial to define one block and repeat it many times in the display (once you realise these are two different commands).

So, for the first block of 8×8 LEDs:

Row 1 Byte 1 = D0-D3 Byte 2 = D4-D7
Row 2 Byte 3 = D8-D11 Byte 4 = D12-15
Row 3 Byte 5 = D16-D19 Byte 6 = D20-23
Row 4 Byte 7 = D24-D27 Byte 8 = D28-D31
Row 5 Byte 9 = D32-D35 Byte 10 = D36-D39
Row 6 Byte 11 = D40-D43 Byte 12 = D44-D47
Row 7 Byte 13 = D48-D51 Byte 14 = D52-D55
Row 8 Byte 15 = D56-D59 Byte 16 = D60-D63

In my case, there is no Row 8 for the N00GA – it is a 80×7 display, so these two bytes are ignored (but still required).

  • Byte 17 -> Byte 32 is the next 8×8 rows (with Bytes 31+32 unused)
  • Byte 33 -> Byte 48 is the next 8×8 rows (with Bytes 47+48 unused)
  • Byte 49 -> Byte 64 is the last 8×8 rows (with Bytes 63+64 unused)

Now this is the bit that no-one seems to mention in anything I’ve found discussing these modules so far.

Whilst most of the protocol for driving these devices via RS232 uses ASCII encoded messages, this bit does not! These are encoded sequentially as raw binary values (not encoded into ASCII as dec or hex) so they will go over the serial line using the numerical range 0..255.

Yes, if echoed to a terminal, you’d see everything from NULL (0, 0x00) through the control characters right up to DEL (127, 0x7F) and then beyond using the extended 0x80-0xFF range.

So to use graphics, you really have to avoid any of the useful line-terminal related options – like echo or cat and just send it out ‘as is’. For me, this mean grabbing the Perl Device::SerialPort module.

These values are written sequentially following the <GA1>, <GA2> or <GA3> command, which defines graphic blocks 1, 2 or 3 for the first page (A).

So the full command to define graphics block 1 on page A is

   <GA1>nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn

where “<” “G” “A” “1” and “>” are all the ASCII characters for <GA1> as you’d expect, but each of the 64 “n”s is a single byte “raw” value from 0x00 through to 0xFF. To encode a full 80×7 matrix, it will need GA1, GA2 and some of GA3 (GA1 = columns 1 to 32, GA2 = columns 33 to 64, GA3 = columns 65 to 80, with 81 to 96 unused).

When it comes to actually insert the character into the display, then use the defined message format to create a static display of the three now defined graphics characters as follows:

   <ID01><L1><PA><FA><MA><WA><FK><GA1><GA2><GA3>48<E>

The commands used here are:

  • L1 – Select line 1
  • PA – Select page A
  • FA – Immediate display (no scrolling, etc)
  • MA – Normal display method (no blinking or “songs” playing)
  • WA – Waiting time (0.5 seconds – not sure if this has an effect for immediate displays?)
  • FK – Hold the display static (i.e. no “lagging” command to remove the display)
  • GA – As discussed above to insert the graphic blocks.
  • 48 – checksum for the command

So all that remains is to write a function to take an 80×7 structure as an input and turn it into the three 64-byte sequences required to define GA1, GA2 and GA3 and then send this command to display them.

The following perl subroutine will take a single 8 bit value, representing one of the rows in one of the 8×8 chunks of a graphics block, and return the two raw bytes ready to be inserted into the <GAn> command. I expect there is a much more elegant way to do this, but this will do for now!

sub led2gfxblock
{
    my ($row) = @_;
    
    # Expand - each pixel is 2 bits:
    #  10 - red
    #  01 - green
    #  11 - yellow
    #  00 - black (off)
    # defining the colour here:
    my $col = 2;
    
    # D0-3 returned first, then D4-7
    my $val1=0;
    my $val2=0;
    for (my $b=0; $b<4; $b++)
    {
        if ($row & (1 << (4+$b)))
        {
            $val1 += ($col << ($b*2));
        }
        if ($row & (1 << $b))
        {
            $val2 += ($col << ($b*2));
        }
    }
    
    return chr($val1).chr($val2);
}

Then something will need to chop the 80×7 input into these 8 bit rows calling this subroutine as required for each value (and not forgetting to insert a dummy “row 8” value each time).

Unfortunately, so far, every time I send a new command across to define a new graphics block, the display appears to flicker … not quite sure if that can be prevented. But it seems that once it has the message to display the three graphics blocks, that message does not need sending again if the graphic block changes.

Kevin.

Permalink Leave a Comment