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.

Advertisements

Permalink Leave a Comment

RPI UART and Maplins N00GA or AM03127 LED Display

April 27, 2015 at 9:42 pm (computers) (, , , , )

I have a tri-colour LED matrix sign from Maplins (a bit like this one) that has an 80×7 two-colour LED display (red and green, and when both are on, a kind of orange).  This has a serial port connection so I wanted to hook this up to my Raspberry Pi.  The original sign is supposed to come with a USB to DB9 Serial and then DB9 Serial to RJ11 set of leads to allow you to connect the sign to a PC, but mine doesn’t have these.

Now there are some excellent resources out there for programming these signs, see:

But what I wanted to do was drive this from the on-board GPIO UART from the Raspberry Pi, and I couldn’t find an obvious description of what was required to make this happen.

After much reading, searching and a bit of experimentation, eventually I managed to assemble all the bits and work through the joys of the many standard RS232 pin-outs for DB9 connectors and the non-standard RS232 pin-outs for RJ11 connectors and come up with the following.

First, to get to any kind of standard RS232 port from the GPIO UART a level shifter is required to go from the 3.3/5v RPi I/O to the +-12v required for RS232 serial ports.  Thankfully these are trivial to find based on the MAX3232 chip, so I got one that includes a built-in DB9 port and 4 pin connections for VCC, RXD, TXD, GND.

max3232

For some reason, these all seem to come with a female DB9 port, so I guess they are designed to link to a PC as if the jumper wires and MAX3232 breakout board make the equivalent of a null modem cable between the Pi and the PC.

So, then I needed to decipher the pin-outs for the RJ socket on the display.  The manual for the LED sign shows the socket view as  follows:

N00GA-SerialPort

I had an old RJ11 to RJ11 telephone cable, so I ripped the plug off one end and set about working out which wires go where.  The combination that worked for me was linking TXD on the display to TXD on the DB9 socket, RXD to RXD and GND to GND.  I think that sort of follows the diagram in the manual, but the cable colours of my telephone lead didn’t match that at all.

So, the resulting combination of pins to connectors to wires to sockets is as follows:

RPI GPIO MAX3232 DB9(F) Phone Lead RJ11 Plug AM03127 RJ11 Skt
4 VCC 1 VCC
6 GND 4 GND 5 GND Black 1 Black 4 GND (Red)
8 TXD 3 TXD 3 TXD Green 3 Green 2 TXD (Black)
10 RXD 2 RXD 2 RXD Red 2 Red 3 RXD (Green)

So once you realise that everything connects to the same labelled pin, you should be fine.

Unfortunately it is not possible to test this with a simple terminal program such as minicom, as the time between key presses is too much for the protocol to be followed (I guess if you had it line buffered it might work, but I didn’t look into this), but it is possible to “cat” some commands to the display to see if it is all working ok.

Also, you need to have disabled the RPi console, which by default will be attached to the serial port.  There are good instructions for that here.

Example – to set the ID and dim the display, create two text files with the following in them:

id.cmd:
   <ID><01><E>

dim.cmd:
   <ID01><DB>04<E>

The first sets the ID of the display to 01 (the display ID can be anything from 01 to FF, 00 means broadcast to all connected displays).  The second command sets the display to its dimmest setting.  The 04 is a checksum value and will depend on the command given.

To use, simply cat these files to the serial port:

   cat id.cmd > /dev/ttyAMA0
   cat dim.cmd > /dev/ttyAMA0

Of course, you will never see the returned acknowledgement or results, but whatever text was on the display should now be dimmed.  Ideally, use the remote control to reset the display first (FUNCT -> Setup -> Clear All -> Enter)

If this doesn’t work, you’ll need to get debugging and checking cables, etc.  One tool that is great for driving the sign programmatically is the sample python code mentioned above.  I had to install the python-serial library before using it, but then it worked very well.

   sudo apt-get install python-serial
   python am03127.py -p /dev/AMA0 -v --message Hello

The only slight quirk, is that the sample code doesn’t appear to call the sync_set_sign_id() function, so if you are not sure what ID your sign is (the default should be 01) you might need to set it using the cat method above or hack a call to the function into the code.  Having an incorrect ID may generate a “timeout” error when using the script in verbose mode (i.e. with -v as shown above).

If you want to experiment with your own commands, then you’ll have to implement something to calculate the checksums.  The following simple Perl script will take a command message for the display and output the text you’ll need for the complete command, including the checksum value.

#!/usr/bin/perl

my $str = $ARGV[0];
my @ch = split (//, $str);
my $chk =0 ;
foreach my $c (@ch)
{
    $chk ^= ord ($c);
}

printf "<ID01>$str%02X<E>\n", $chk;

So, for example, a Hello World message will be:

  <ID01><L1><PA><FE><MA><WB><FE>hello world55<E>

I now plan to get to work on the technical manual and decipher some of the more sophisticated commands, especially those that let me get graphics sent to the display.  All this was possible thanks to those who have already worked out how to drive this thing.  All I needed was the details of how to connect it physically to my  RPi GPIO.  Which I now have.

Standard disclaimer – this worked for me, YMMV, I won’t be held responsible for you pumping 12v or worse into your RPi GPIO if something goes wrong! 🙂

Kevin

Permalink 1 Comment

RPi Ethernet and Wifi at the same time

May 25, 2014 at 9:34 pm (computers) (, , , )

This should have been a lot easier than it ended up being!  I wanted to turn one RPi into a router between its Ethernet and Wifi networks, so that a single wifi dongle could be shared across a few Ethernet devices (via a simple dumb Ethernet hub I had lying around).

Well there are lots of posts around the Internet showing how to configure the Pi as an Access Point or an Ethernet Bridge, but in all discussions of the /etc/network/interfaces file I’ve found, no-one has really (that I’ve found so far) mentioned quite how the wpa_supplicant, ifconfig and ifplugd systems all interact and fit together.

Whilst a number of people have speculated that there might be power supply issues that will knock out your Wifi if you plug in an Ethernet cable, I didn’t see any evidence of that.  What I was actually seeing is ifplugd detecting the plugging in of the cable and then running its action scripts in /etc/ifplugd/action.d.  On my version of Raspbian, one of these scripts is a symlink over to /etc/wpa_supplicant/action_wpa.sh which basically disconnects any wpa-roam managed interfaces if the Ethernet is plugged in.

This is the designed-in behaviour, as the basic idea is that if you are using Ethernet and Wifi, then typically it will be to the same network (and ultimately connected to the Internet) so it will only need Wifi when the Ethernet is not connected.  If you have a wired connection, it will disable the wireless connection to use the wired for preference, which is the desired behaviour in the vast majority of cases.

There are a number of “fixes” around the Internet, from killing ifplugd to removing or adding auto or hotplug related options in /etc/network/interfaces.  I’m sure there must be some magic combination of options that means that the hotplugging of cables and dongles can still work, but will not automatically turn the wifi on and off – but I haven’t found it yet.

Instead, I went for the very simple, but almost definitely “quick hack” version of including an “exit 0” command near the top of /etc/wpa_supplicant/action_wpa.sh before it actually did anything.  This way, I get to keep the automatic configuration on plugging cables and dongles in, but the arrival of a new interface does not automatically shutdown the wpa-roam managed ones.

This seems to work really well for keeping Wifi connections open when plugging in an Ethernet cable.  When plugging in a Wifi dongle, that also seems to work, in that both Ethernet and Wifi end up active – although I did get a break in continuity over the Ethernet when this happened – but it reconnected again fine.

Of course, this may well completely shaft true wifi roaming across networks – I don’t know – I don’t take this RPi out and about to test it and I haven’t read enough how the wpa-roam system is meant to work to see.

I expect there is a more elegant way to achieve this, but the Internet wasn’t providing it; the Debian networking configuration manual seemed to be suggesting that I should probably use the GUI and that everything else is legacy; and I’d had enough of reading man pages. If you know of a good reference for how these scripts all interact and how this can be achieved in a nicer way, I’d very much like to hear from you!

But, this will do for now for my relatively static setup of single Wifi network, routed across to the Ethernet network.

Kevin.

 

Permalink 1 Comment

Find my (R)Pi

March 17, 2014 at 8:42 pm (computers) (, , , )

I like tinkering with my Raspberry Pi, but I also tend to have them configured for remote SSH to save dragging out a keyboard and screen. I also use the small Edimax WiFi USB dongles, but I also just like to let the pi find its own address on the network using DHCP … so I often need to either hook up to my routers admin/status page to see what nodes it has found or just attempt to connect to a few nodes in the range I know will be used for the pi.

Eventually I got fed up with doing this, so instead I wrote a very simple perl script to use Net::Ping to scan a small range of addresses and report on which ones are responding, and then see if port 22 (SSH) or 80 (web) are open.  Then I know where my pi is.

Net::Ping can use the tcp for ping, which has the advantage that you don’t need privileges for the script to use icmp.  The disadvantage is that most things won’t respond to the tcp echo port.  Consequently, I use Net::Ping in two modes – first with icmp to see if the host is alive, then with tcp to probe the ports I’m interested in.  This does require it to be run with administrator privileges, but that is fine for me.

I don’t scan a whole range, that would take too long for this very simplistic case, so I just scan 20 or so addresses that I am interested in.

There are a wealth of network scanning and management applications out there, but this has the advantage of being very simple.  Just what I needed.  Below is the code.  Nothing exciting – about as simple as it gets, but it works. 

To run from Windows, I use a simple batch file to call the perl interpreter with the script, then pause afterwards (to give me a chance to read the output).  This can then be used by right-click -> run as administrator.

Kevin

#!/usr/bin/perl -w
use Net::Ping;

my $subnet="192.168.0.";
my @ports = (22, 80);
my $timeout = 1;

my $p_icmp = Net::Ping->new ("icmp", $timeout) or die "Can't start icmp ping";
my $p_tcp = Net::Ping->new ("tcp", $timeout) or die "Can't start tcp ping";
for ($i = 50; $i<70; $i++) {
    my $host = $subnet.$i;
    print "$host: ";
    if ($p_icmp->ping ($host)) {
        print "ok ";
        foreach my $port (@ports) {
            $p_tcp->port_number($port);
            if ($p_tcp->ping ($host)) {
                print "$port ";
            }
        }
        print "\n";
    } else {
        print "nok\n";
    }
}

Permalink Leave a Comment

Adafruit 8×8 Backpack, HT16K33, RPi

July 20, 2013 at 11:20 pm (computers) (, , , , )

I have recently acquired one of the great little 8×8 LED matrix boards from Adafruit, that uses the HT16K33 driver chip to give you access to the 8×8 matrix using the I2C bus.  With just four wires between your GPIO 5v, GND, SDA, SCL and the equivalent pins on the matrix board, you are ready to go. I wanted to use it with my Raspberry Pi and whilst their tutorials are excellent for getting you going quickly, I like to know a little more about what is actually going on when I call some of their higher-level functions. For this, I wanted to know what was actually going out on the I2C bus to make the magic happen.  However, apart from the data sheet for the chip itself, this information wasn’t actually that easy to come by! From looking through their sample C (for the Arduino) and Python (for Raspberry Pi) code, and messing around with i2cdump, and then comparing that with the datasheet, I seem to have got into the position of being able to drive the matrix using i2cset. My board appears on I2C bus number 1 (I have the second edition board that changed the GPIO I2C bus address from 0 to 1) at address 0x70, so all the following commands assume those values. The following commands are the main ‘initialisation’ commands:

i2cset -y 1 0x70 0x21

i2cset -y 1 0x70 0x81

i2cset -y 1 0x70 0xe0

The first turns on the oscillator – setting bit S in the “system setup” register – labelled D8 in the data sheet. The next enables the display with no blinking – setting bit D in the “display setup register” – D8 again in the data sheet.  To enable blinking then B1+B0 must be set to 01, 10 or 11 – i.e. replace 0x81 with 0x83, 0x85 or 0x87 respectively. The last command sets the brightness level – in this case, leaving the brightness to the dimmest setting, P0, P1, P2, P3 are all zero in the “digital dimming data input”.  Use a different value instead of 0 in the 0xe0 value – e.g. 0xef would be the brightest setting (all 1s). Now in order to actually turn on some LEDs, the rows are found at even addresses, starting from address 0x00, so the 8 rows of my matrix can be set using:

i2cset -y 1 0x70 0x00 0xaa

i2cset -y 1 0x70 0x02 0xaa

i2cset -y 1 0x70 0x04 0xaa

and so on up to

i2cset -y 1 0x70 0x0e 0xaa

In this case, I’m setting all rows to the value 0xaa (i.e. binary 10101010).  However, there is a complication – the bits are actually offset against the LEDs, so writing 0x01 actually illuminates the 2nd LED of each row.  So you actually need to do the following (taken from the source code of the library):

bitnum0to7 = (LED + 7) mod 8

So to set the first LED, write the hex pattern 0x80.  For the second LED, use 0x01; the third 0x02; fourth 0x04 and so on up to the last LED on the row being 0x40. I assume this is quirk of the wiring of the LED matrix to the driver pins of the HT16K33.

So thats it.  To turn off the display, turn off the oscillator or turn of the display (or both):

i2cset -y 1 0x70 0x20

i2cset -y 1 0x70 0x80

Everything else is built up from these basic commands.  And with this knowledge, the data sheet for the chip makes a lot more sense! One final note – the data sheet has an input mode too – the chip can be used to scan a simple keyboard.  Obviously in the case of the 8×8 LED matrix displays, this is not used. So, I’ll take another look at the C and Python code, but at least now I know what is going on underneath all that. Kevin.

Permalink 1 Comment

Listening to Numbers

October 31, 2012 at 11:19 pm (art, computers, interesting, internet, music) (, , , , , , , , , )

I get Make Magazine and from time to time find something that peaks my (software related) curiosity.  This time it was an article about making synthesized music from data using the algorithms from Dr Jonathan Middleton’s Music Algorithms website – http://musicalgorithms.ewu.edu/

Basically this takes a sequence of numbers, scales it to a pitch range you select, gives you options for translating pitch – e.g. scale backwards, replace specific notes with another note, use division or modulo arithmetic, etc – and then gives you options for applying a duration to each note – either a fixed duration or using a scaling formula.

Finally you have the option to play it, download it as a MIDI file or see it in a crude representation of notation.

There are a number of ‘preset’ options to get you going – I experimented listening to pi, the Fibonacci sequence and their ‘chaos algorithm‘ using ranges of 0 to 88 (a full piano range) and 40 to 52 (basically an octave starting from middle C).  I tended to use a fixed duration of 0 or 1 as it went by suitably quickly and kept things interesting.

Then I thought I’d try something a little different.  Using the option to ‘import your own sequence’ I took a wander over to Google Trends.  This plots the frequency of people searching for specific terms over time.  If you login with your Google account you can download the results as a CSV and then its trivial to open it in a spreadsheet, select the column of results and paste it into the Music Algorithms form and listen to what something sounds like.

For my own entertainment, I had a listen to the following:

  • Default ‘swine flu‘ search that Google Trends offers.  This works well scaled 0 to 88, as the pitch then mirrors the graph quite well.  I didn’t paste in all the zeros, just the portion with the shape and got a nice quickly peaking and decaying piece.
  • Facebook is a good one … it goes from continuous low through a slowly rising scale, increasing in pitch and frequency of change as time moves on, finally tinkling along in the high register as search frequency fluctuates.  This would be a really interesting one to do with number of users, scaling from Mark Zuckerberg as #1 up to user 1 billion …
  • Considering the date, Halloween was an interesting one – you get a random sounding very quickly rising and falling scale and then silence … the ration of silence to scale is around 1 in 12 funnily enough and the pattern repeats 8 times (for 2004 to the present day) … this works well with a duration of 0 across the full piano range – nice and quick.
  • The text ‘music algorithms‘ generated a curious pattern – reasonably random around a specific value, but that value has slowly decayed over time.
  • Then I tried a whole range of whatever came into my head looking for an interesting graph – seeing fluctuating searches, lots of rising trends – then finally settled on Tim Berners-Lee.  Not sure why!  But that gives a nice, angry sounding (especially on duration zero) left-hand piano line for the majority of the data set, generally getting slightly lower, adding to the angry nature, until there is a quick high flourish representing him appearing in the Olympics opening ceremony!

I only played the MIDI files back using the standard instrument, i.e. a basic piano sound. It would be really interesting to actually use some of these data sets to define a synthesized timbre too.  Could be the start of a very interesting musical piece.

What would be really interesting is to hook it up live to some Google or other Internet stats and then allow you to hear what is going on, say on Twitter.  A bit like a musical version of The Listening Post.  Maybe that could be a job for my Raspberry Pi

Kevin.

 

Permalink Leave a Comment