Saturday 29 December 2012

Rope making machine at BuildBrighton

With Xmas and New Year occupying so much of everyone's time, there's not really been much time for nerding about lately. Well, not for some of us. But thankfully Stephen Cropp from BuildBrighton hasn't been so pre-occupied, and set about 3D-printing this awesome rope-making machine.


It's really quite simple in design. At one end of the table is clamped a central cog, which drives three outer cogs (each spaced 60 degrees apart). By turning the central cog with a handle, all the outer cogs turn the same way and at the same rate.

Steve threads his twine through hooks on these outer cogs to a weighted clip at the other end of the table then cranks the handle...



Sunday 23 December 2012

Wiegand26 protocol RFID reader

We recently received an RFID reader from eBay for a door tagging/entry system project due to start in the New Year. This one was going to stay on hold for a while, but with a few hours to spare one evening at a BuildBrighton Thursday night, it seemed like the perfect opportunity to have a play about and see what this thing could do.



Firstly, it uses some weird protocol called Wiegand26 rather than the slightly more straight-forward serial/TTL level communications. But the protocol itself seems quite straightforward: the device consists of two data lines - when a zero is transmitted, one line goes low for a few microseconds, while the other stays high and when a one is transmitted, the other line goes low, keeping the first line high.

This seems easy enough. We simply monitor both lines and when one goes low, wait for it to come high again, and add a zero or a one to a binary buffer value. The tricky part comes in detecting the end of the binary stream:

Now the "official" Wiegand26 protocol involves 26 bits of data (that must be where it gets the -26 part of it's name from!). But some RFID cards and tags use much longer data for better security. Since we don't know much about the tags/cards we're going to use with this reader, we're going to have to assume there could be more or fewer bits of data coming down the wire(s).

So here's the approach:
We're going to set a flag to say whether or not we've started receiving some data.
As soon as one of the data lines changes, we start a timer running to time out after about 500ms.
Every time one of the data lines changes, we reset the timer.
When the timer times out (no activity for 500ms) we see what data we've got in the buffer and spit it out over serial.

We've doing this project in SourceBoost - not because we've fallen out with Oshonsoft, but because the first chip we picked up was one of the 16F1825s we've been using in our earlier audio project, so we stuck with it for ease of use.

This is the bulk of our program:
void main(){
   init();
   timer1Init();
   delay_ms(50);
   startTimer();
   while(1){
      checkforinput();
   }
}

The init routine simply sets up the input/output pins, and for debugging, starts the UART for writing data out over serial so we can debug what's actually going on inside the magic black box:


void init(){
   
   osccon           = 0b11110000;   //32 MHz clock   
   intcon           = 0b11000000;   //global/peripheral ints enabled
   apfcon0          = 0b01000000;   //MOSI on RA4
   option_reg         = 0b10000000; //no weak pull-ups, timer0 at OSC/4/2 = osc/ 8   

   UARTInit();
   ansela            = 0;         //no analog inputs
   anselc            = 0;         //no analog inputs
   trisa=00000000b;
   trisc=00000110b;
   
   porta=0;
   portc=0;
   tmp=0;   
   bitCount=0;
   bufferPointer=0;
   
   // now we pull pins low to activate the beeper and the lights
   // so force them high by default
   porta.2=1;
   portc.0=1;
   
   msCount=0;
   isReading=0;
   empty_buffer();
}

We couldn't be bothered to work out the values/pre-scalers for a 500ms timer, so just copied and pasted some code from another project which kept a 1ms timer, and used that with a counter to decide when 500ms had passed:


void preloadTimer1(){
   //------------------------------------
   // pre-load timer1 with 65172 (0xFE94)
   //------------------------------------
   // 1/22050 = 0.00004535147
   // at 32mhz, fosc=8,000,000
   // and 8m/22050 = 362.812
   // so we want our timer1 to only count up to 363
   // timer1 is a 16-bit timer (0-65535) so we need to
   // preload it with 65535-363 = 65172

   tmr1h=0xfe;
   tmr1l=0x94;
}   

void timer1Init(){
   //-------------------------------------------
   // interrupt on timer1 22050 times per second
   // ------------------------------------------
   pie1.0=1;   // timer1 rollover interrupt on bit zero
   intcon.7=1;   // global interrupts
   intcon.6=1;   // peripheral interrupts
   preloadTimer1();   
}

void startTimer(){   
   t1con.0=1;
}

void stopTimer(){
   // turn off the timer1 T1ON bit
   t1con.0=0;
}

void resumeTimer(){
   // turn on the timer1 T1ON bit
   t1con.0=1;
}

And in our timer interrupt:

void interrupt(void){
   
   // bit zero of pir1 is tmr1 overflow interrupt
   if(pir1.0==1){
      // clear the timer1 interrupt flag
      pir1.0=0;
      // preload timer1 to get the next interrupt to occur in a timely manner
      preloadTimer1();
      msCount++;   
      
      if(msCount>500){
         if(isReading==1){
            flushBuffer();
         }
         msCount=0;
      }         
   }
}


Now every time one of the data lines goes low, we wait for it to come back high, then add a one or a zero to the end of a stream of bits.

void checkforinput(){
   if(portc.2==0){
      // reset the timer if this is the start of a read
      if(isReading==0){msCount=0;}
      // set the flag to say we're reading some data
      isReading=1;
      //data1 has gone low: this is a one
      while(portc.2==0){
         // wait for the line to return high
         tmpBit=1;         
      }
      add_bit();
   }
   
   if(portc.1==0){   
      // reset the timer if this is the start of a read
      if(isReading==0){msCount=0;}
      // set the flag to say we're reading some data
      isReading=1;   
      //data1 has gone low: this is a one
      while(portc.1==0){
         // wait for the line to return high
         tmpBit=0;   
      }
      add_bit();
   }
   
}


To add a bit to the right-most end of the temporary value, we bit-shift all the data in the variable one place to the left, and simply OR the value (1 or zero) to the final result.
Here's an example:

Let's say we've already got the value 001101 in our buffer and we receive a one. First we bit-shift the value one place to the left. This gives us 011010. Now we OR this value with the number one (000001) and the result is 011011. This is the same as just tacking a one onto the end of the bit stream!

void add_bit(){
   tmp=tmp << 1;
   tmp=tmp | tmpBit;
   bitCount++;
   if(bitCount>=8){
      // this is a full byte
      // add it to the buffer
      porta.4=1;
      buffer[bufferPointer]=tmp;
      bufferPointer++;      
      tmp=0;
      bitCount=0;
   }   
}


So all that's left to do now is spit the data out so we can interrogate it:

void empty_buffer(){
   unsigned char i;
   for(i=0; i<=12; i++){
      buffer[i]=0;
   }
   bufferPointer=0;
}

void flushBuffer(){
   unsigned char i;
   
   // send out whatever's in the buffer
   // (first four bytes for a 26-bit protocol)
   isReading=0;
   UARTPrintLn("Buffer contents:");
   for(i=0; i<4; i++){
      tmp=buffer[i];
      UARTPrintNumber(tmp);
      UARTPrintLn(" ");
   }
   
   // reset the buffer for the next read
   tmp=0;
   bitCount=0;   
   empty_buffer();      
}

The reader we're working with has the following pinout:

power
ground
data0
data1
buzzer (low to activate)
led (low = green, high = blue)

So we wired the whole lot up to our PIC 16F1825 microcontroller, dumped some code onto it and read back what came out:


Amazingly, everything worked pretty much the first time out, with the results as follows:


Amazingly, the RFID reader could read a variety of RFID tags. We tried it with some of the phonics owl cards from an earlier BuildBrighton project, as well as the key fobs from the BuildBrighton door entry system, along with some other RFID tags from other people's various places of work. The RFID reader simply read them all and reported back the tag contents!

Now it'd be easy to call it a day and say we can read RFID tags successfully, but there's still the nagging doubt that we're not actually reading data, and just reporting a load of junk. What we needed was some way of confirming the data being read with a known value.
Luckily, the phonics owl cards (and a lot of RFID cards for that matter) have a Wiegand26 value printed onto them. If you have an RFID card with two sets of values, it's the second value (the one with the comma in it) that we're interested in:


What we need to do is compare our read-in value(s) against the Wiegand26 values printed onto the cards. So let's take a look at the actual bitstream from each of the card reads:

card no: 0006304068 096,12612
0000000048
0000000024
0000000162
0000000000
b00110000000110001010001000 (first 26 bits)

card no: 0012225140 186,35444
0000000093
0000000069
0000000058
0000000000
b01011101010001010011101000 (first 26 bits)

card no: 0006348080 096,56624
0000000176
0000000110
0000000152
0000000000
b10110000011011101001100000 (first 26 bits)

We've reported four bytes of data, because 26 bits is just over 3 bytes (3x8 = 24 bits).
In this case, all our fourth bytes are zero, but there's no guarantee that this will always be the case. So let's convert each decimal value to binary  and squash them all together (truncating once we get to 26 bits). Looking at it now, we could have created a single 32-bit value and simply bit-shifted the data 26 times, but then our code wouldn't work with 64-bit (or longer) cards. So by handling the data one byte at a time, we've got more work to do at this end (for validating) but it does mean we've a much more flexible system for future use.

Here's how the Wiegand26 protocol works, with 26 bits of data:



Let's look at the first set of values.
Splitting the byte stream up into groups of bits, we've got

0 01100000 0011000101000100 0

At the minute we're ignoring the parity bits, and are only interested in the "middle" section of the data stream. But already it's looking quite encouraging....

01100000 in decimal is 96
We've a couple of cards that begin with 096 followed by a comma.....
Taking the next group of 16-bits and converting to a single decimal gives us - 12612

That means we've correctly read the RFID data from the top-most card! Yay!
Comparing the values from the other cards, and we find we're accurately reading all the cards using the Wiegand26 protocol. We're not just reading junk, we're actually reading data.

With this in mind, we don't actually have to decode the bit-stream back to Wiegand values every time - we can simply report back the groups of bytes from the different cards, fobs and tags, confident that if we're reading them correctly (we are), the data from each will decode to the actual value on the card (if we need it to) but the parity bits will always give us the same groups of bytes for each card. As long as we have consistency each time a card is presented (i.e. we're not reading junk, we know we're reading the data correctly) we can simply compare the clumps of bytes to a look-up table to make the cards usable.

So to use this RFID reader for a door entry system, for example, it doesn't matter if we record a card as having the Wiegand26 value of 096,12612 or whether it's stored as 48,24,162,0 - each time the card with 096,12612 is presented to the card reader, we should expect to get back the bytes 48,24,162,0.
It's much easier to work with byte rather than splitting them up into bits, so we could just put these four bytes into our look-up table instead of converting back and forth between crazy 26-bit values!

In short, our first quick success for a long time.
After just a few hours of messing about, we've got a fully working RFID reading system.
In future posts, we'll look at writing our lookup table to an SD card and logging each time a card is swiped by writing a log file back to the card, making a completely PC-independent, embedded system!

Thursday 20 December 2012

Working word clock pcb at last!

Having created a pcb from our earlier design, we've finally had time to sit and work out the pinout. And this time we're delighted to report that it actually works. Each pin on the 24-pin connector performs just one task and the correct combination of power and ground onto the pins causes just one LED to light up at a time. Result!

Here's the pin-out from the earlier pcb. The pins along the bottom need to be pulled to ground, while the pins along the edge should have power applied to them:


So if, for example, we put power onto pin2 and pull pin 23 low (to ground) the single LED in the top left corner of the matrix should light up. Repeat as necessary for each individual pin and we've finally got a fully working, individually addressable LED matrix. Yay!

Source code for the word clock to follow.....

Tuesday 18 December 2012

Some SD cards don't like SPI mode and low voltages

It's a sad fact that some SD cards work differently to others.
Although there's a set of "standards" that all (most?) SD cards are supposed to adhere to, the degree of variance between cards is huge.

And we've just wasted about a month trying to fix a problem "properly" instead of doing the pragmatic thing and just hacking a solution together.

A while ago we started adapting some noise-playing alarm clocks. We completely replaced the onboard sound chip with one of our own design, which plays uncompressed wavs from an SD card. It took a lot of working out to get the SD card actually readable and when we thought we'd cracked it, put the audio player board back inside the alarm clock and gave it a try.

Incredibly, it worked first time!
And second time.
And third. But not the fourth.
In fact, after just a few plays, the SD card refused to initialise properly.

It all came down to the supply voltage. At 5v, we put the supply through a voltage regulator to give a steady 3.3v out. Everything worked fine. We put the boards into the alarm clocks and ran them off the 3v that 2xAA batteries created. In truth this was sometimes as high as 3.2v.

After just a few plays, the tiny voltage drop in the batteries was enough to stop the SD card from working.
But that's not where the story ends. Because we've spent about a month trying to use different triggering mechanisms, DC-to-DC converters, opto-isolators, PNP transistors and more yet all the time we had a working prototype on the desk. The circuit was exactly the same, we kept going back to the same (rough-and-ready) firmware. But all the time the prototype worked while every new version didn't.

And then we spotted the difference.
The prototype was using a genuine SanDisk micro sd card. The newer boards were using another brand. And that was enough to make a difference! SanDisk cards are pretty robust and can handle a wide range of supply voltages - cheaper, inferior brands can't.

So after a month of trying to build a circuit which is 100% compatible with all brands of SD cards, we've finally given up. And decided to only support a small sub-set of available cards on the market. It's not ideal. But it'll let us get these bloody clocks made up and shipped, hopefully this time of Christmas!!


Monday 17 December 2012

Another word clock update

Anyone who has tried making a word clock from our previous designs is likely to be as disappointed as we were - they still don't work! This despite us actually reading the datasheet and laying out the pcb accordingly.

The problem this time wasn't that we'd connected the wrong pins (earlier assuming that all the "row" pins were on the top and all the "column" pins were on the bottom) but more that we hadn't identified which pins were which!

The datasheet we found suggested that the pin layout was a little peculiar:


So our latest pcb followed this layout. Without further information, we'd assumed that the pins were numbered

 1   2   3   4   5   6   7   8


 9  10  11  12  13  14  15  16 

None of the pins caused the right LED to light up. Putting power and ground to various pins was lighting up lights, just not the ones we expected. Then something peculiar happened:


Now at no point should putting a single power source onto a single pin cause more than one LED at a time to light up. Something was obviously very wrong! And so began the painful, laborious task of applying 5v power to one pin (through a 220ohm resistor of course) and ground to another, and charting which combinations caused which LEDs to light up.


Our final chart didn't resemble the datasheet in any way - we were grounding pins which the datasheet said were LED anodes, and putting power onto pins that the datasheet said should be pulled to ground. 
Once we'd identified which pin caused which "row" to light up, and done the same to find which pin to ground caused the LEDs in a specific column to light, we stopped filling in the grid and just did some random sample testing to prove our theory. Each test worked fine, so we were confident that we'd correctly identified the row and column pins.

There was no denying the hand-written grids - they were what we'd actually witnessed, datasheet or not. But they just didn't match with the datasheet at all. Just before we binned the datasheet and presumed it belonged to another module, we tried changing the presumed layout of the pins on the board.

We'd assumed they were numbered 

 1   2   3   4   5   6   7   8
 9  10  11  12  13  14  15  16 


when - after much messing about -  it turns out that they're, in fact, numbered 

16  15  14  13  12  11  10   9 
 1   2   3   4   5   6   7   8

Following this layout, suddenly the datasheet made sense!
We could read the pins on the datasheet, work out which LED should light by putting power and ground onto the appropriate pins and then proving this to be correct.

(note the LED module spread over two breadboards: it was simply too large to fit onto a single breadboard for testing!)

This time, everything matched up. We'd finally worked out how to make the LEDs light up in the correct way. But one thing remained - the pcb was, once again, wrong!
A bit of re-work in ExpressPCB and we came up with this:
Word Clock v2

Hopefully, a working PCB. To keep the overall final dimensions small, we're going to connect this to the 40-pin PIC mcirocontroller using a simple ribbon cable (off an IDE hard drive). For now we'll keep the connector in place, to make it easier to breadboard the whole thing up during testing:


Monday 10 December 2012

Updated word clock PCBs

After making a complete cock-up of the earlier 16x8 word clock (made from two massive 8x8 LED matrices), we've had to revise the layout.

Here's the PCB for the LED face.
Since we're going to be connecting the 40-pin PIC microcontroller via some IDE ribbon cable, joining which pins on the connector to which pins on the LED board(s) isn't really that important - we just need to make sure all the pins from the boards are routed to some kind of ribbon connector:

Clock 8x8 v2

But since the pins for the rows and columns are all over the place, and we've just connected them any-old-how to the ribbon connector, we need some kind of look-up table:


The PCB for the PIC simply puts all the output pins to 0.1" pitched holes on the board.
So all we need to do is wire up the pins on the 24-way clock board connector to the appropriate pins on the PIC, following the table above.

That's the theory anyway.
Whether or not it actually works is another question.......

There's no getting away from it, we screwed up

In this earlier post, we designed a schematic and PCB for our 8x8 LED matrix and didn't really pay attention to the data sheet. Like a bunch of idiots, we just assumed that the pins along one edge were for the "rows" and the other set of pins were for "columns".

So it's no wonder that by sticking voltage across the pins resulting in some really peculiar behaviour. Where we expected the top-left corner LED to come on, one somewhere in the middle near the bottom lit up! The next pin along didn't light the next LED in the row, but one about three places along.


To get the top-left LED to light, we don't simply put power onto the first pin at the top, and ground the first pin on the bottom set - that won't actually light any LED!
Assuming our pins are labelled 1-8 across the top, and 9-16 along the bottom, connecting power to pin 1 and ground to pin 9 doesn't pass through any of the LEDs. If we put power onto pin 1, we need to ground one of either pins 3,4,6,11,13,15 or 16.

With this in mind, we've had to re-draw our schematic (and make a new PCB using a similar layout):

clock_8x8


Friday 7 December 2012

A quick Xmas-themed project with flashing LEDs!

Here's an idea for an Xmas themed project, using up a few components most people are likely to have floating around. At the heart of it is a 555 timer, which creates a regular "pulse".
We're using this on/off behaviour to drive two transistors - one NPN and one PNP

Xmas Tree Sch

When the 555 timer output goes high, the NPN transistor allows current to flow lighting up LEDs 1-4. At hte same time, the PNP blocks current and LEDs 5-8 go out. When the output goes low, the NPN stops the current flow, making LEDs 1-4 go out, while the PNP makes LEDs 5.8 light up.


Play about with the values of the two resistors, R1+R2, between pins 6+7 on the 555 timer, and the value of the capacitor to create different flashing frequencies.

The 555 timer can sink/source up to 200mA. As this is an untested design, and depending on the voltage of the battery used, a resistor between power and the common LED anodes may be required. The value of this resistor will depend on the power source used

Xmas Tree Pcb

Create two of these PCBs. Cut a slot from the top of the first board, to about the mid-point, and from the bottom to the same point on the second board. The common power supply to the LEDs makes a complete circuit around the outside of the board, so it shouldn't matter if it's cut at the top or the bottom (just not both!)

On the first board only, mount the 555 timer and associated discrete components. On the second board, simply populate with LEDs.

Slot the two boards together. Every LED has two holes alongside it. These are for connecting wires to the corresponding hole(s) on the other board. This creates a complete circuit between all the LEDs.
Don't use straight bits of bare wire - use coloured wire (coloured sleeves) and bend them slightly to make "loops" going across the branches. For a real Xmas feeling, cover in glitter or bits of tinsel.

Connect up a battery and see if it works.
(this design, at the time of writing, is untested!)
Here's the silkscreen/layout:



Wednesday 5 December 2012

There's no room for the pedantic Grammar Police

Try as I might, I can't bring myself to be happy with a word clock which potentially reads "it is just gone five minutes past six".

The sentence should read "it has just gone five minutes past six". But at the same time, we also need to be able to say "it is nearly quarter to seven", for example. A possible work-around (though still slightly clumsy) is "it's....." which could then be read as it is or it has depending on what follows. But that's still a bit nasty.

The problem is, wherever there's a possibility that one word could be immediately followed (light up) by another, we've had to leave a space (notice how there's a space between "it" and "is" on the earlier example, and between "minutes" and "past" - but not between "half" and "minutes"). Well, if we allow for both "it is" and "it has" there simply aren't enough squares left to spell out all the required times.

Unless we fudge it some other way:


We've had to spell out the word "ten" vertically rather than horizontally. It's a bit of a kludge and I'm still not 100% happy with it. But a bit happier than the nails-on-a-blackboard-sounding "it is just gone....x o'clock".

With this in mind, here's how we're going to write the time, at each of 0-59 minutes past each hour:


Bit-shifting. Shift over.

As part of our word clock made from two 8x8 LED matrix modules, we're trying to work out a way of quickly lighting up columns of 8 LEDs at a time.


Here's how it works: we set (and unset) any number of 8 different pins (connected to the "rows" line). Then we pull one of the 16 columns low, leaving the other column pins high, thus lighting up to eight LEDs in a single column. After a short delay, we then change the eight "row" pins and move along to the next column.

One way of achieving this is to have one single byte variable for the rows data, and a two byte (16-bit) variable for the columns data. If we start by lighting the first column, the two byte variable value would be 0111-1111-1111-1111 (in binary). After changing the row data, we need to make the two-byte variable value 1011-1111-1111-1111

In short, we need to make the zero value "move along" one space to the right.
A really easy way to do this is bit shifting.

We're going to simplify things (although not immediately obvious) by bit-shifting the (binary) value 1000-0000-0000-0000 one place to the right, then sending the inverse value to the column pins (so every 1 becomes a zero and every 0 becomes a one).

The reason for this is because bit-shifting isn't necessarily "circular". When a bit "drops off the end" it doesn't necessarily appear back at the start of the value. Consider a simpler example, the number 0110.
If we bit-shift one place to the right, the number becomes 0011. But if we bit-shift one more place to the right, the number becomes 0001. The trailing one has "dropped off the end" and disappeared - it doesn't appear back at the start of the value.

If we had the initial value 01111111 etc. and bit-shift one place to the right, we end up with 00111111 and not 10111111 (which is what we need). Whereas taking the value 10000000 and bit-shifting one place to the right gives us 01000000 which - when inverted - gives us the value we're after.

Right, that's that cleared up.
First we declare our variable:

unsigned short colData;  (SourceBoost)
Dim colData As Word (Oshonsoft)


Why unsigned rather than signed?
A two-byte signed value is simply a 15-bit value and the very first (leading) bit determines whether the value is positive (leading bit zero) or negative (leading bit one). If we used signed values, the leading bit would need to be toggled from zero to one depending on the position of the zero in the rest of the string. This is more hassle than just inverting an unsigned value (where the leading bit actually makes up part of the value represented by the binary pattern).

Then give our variable an initial value
colData=0x8000;
or
colData=32768;

The hex value 0x8000 is the same as binary value 1000-0000-0000-0000
Now when we need to move onto the next column, we bit-shift the colData value one place to the right:

colData = colData >> 1

This means that the value now becomes 0100-0000-0000-0000
And bit-shifting again:

colData = colData >> 1

returns the value 0010-0000-0000-0000
And so on and son on.

When the column is all the way over to the right, 0000-0000-0000-0001, and we bit-shift once more, we end up with 0000-0000-0000-0000 whereas we want the one to wrap around to the start again.
A simple if statement takes care of this:

If colData = 0 Then colData = 32768 (Oshonsoft)
if (colData==0){ colData = 0x8000;} (Sourceboost)

But as we've already stated, our colData is inverted to what we actually want. We don't want to pull 15 of the 16 columns low, we want only one column low at any one time. So we need to invert the value in the colData variable and put this value onto the output port(s):

tmp = colData XOR 0xFFFF

XOR is an exclusive OR statement:


If either of the bit patterns BUT NOT BOTH are one, the result is a one, otherwise it's zero. So simply XOR-ing our colData value with a load of ones 0xFFFF is binary 1111-1111-1111-1111 inverts the value, turning all the ones to zeros and all the zeros to ones.

Now we put the first (most significant) byte of the two byte variable onto PORTB and the second (least significant) onto PORTD:

Oshonsoft
Dim H As Byte
Dim L as Byte
H = colData.HB
L = colData.LB
PORTB = H
PORTD = L



SourceBoost
unsigned short b;
b=colData;
PORTD=b;  // only the lower 8-bits are put onto the output pins
b = b >> 8;  // move the upper 8-bits eight places to the right
PORTB=b;


The end result is that only one pin is pulled low at any one time.
Every time we use the bit-shift operator, the low pin "moves along" one place to the right, effectively lighting up the next column of LEDs in our matrix.

Heres's a quick guide to bit-shifting and unsigned/signed variables:
http://stackoverflow.com/questions/141525/absolute-beginners-guide-to-bit-shifting

Tuesday 4 December 2012

Word clock PCBs

These massive 16-pin 8x8 LED matrix modules are easy enough to work with - each row of LEDs has a common pin (so all 8 LEDs in a single row are potentially connected to the power supply) and you simply ground one of eight "column" pins to make the appropriate LED light up.



Although there are load of different driver chips for these display blocks, or we could use shift-registers and the like, we're going to do with the really simple direct-drive method. Basically this means choosing a microcontroller with loads of pins and connecting them directly to the pins on the LED matrix.

Word Clock Sch

To keep our final clock dimensions quite small, we're going to put the microcontroller on the back on the LEDs and use some IDE cable (which conveniently is 0.1" pitch spaced anyway) to connect the two boards:


Word Clock Pcb

Since these modules have a common anode, and you drive the appropriate pin(s) low to make the LEDs switch on, we've connected all the anodes on each "row" together. So each "row" output pin activates up to 16 LEDs at once.

This isn't an ideal way of driving these boards - using something like a Maxim MAX7219 constant current LED matrix driver would be better but two of those at a tenner each and the project starts to get a bit spend-y. Since we're only likely to actually light 3 or 4 LEDs (from a maximum of eight) at any one time, direct drive gives us a cheaper alternative to try out the design and check that everything works properly before committing to some rather expensive components.

We've gone for the PIC 16F877A chip, just because we've a few left over from years and years ago - they're the typical "starter" chip for people getting into PIC programming; loads of pins (it's a 40-pin DIP) and loads of peripherals (UART, SPI, I2C etc). It's probably a bit overkill, and there may be other, cheaper chips out there, but we're just using up what we've got.

We're going to be running the chip off a crystal and use this to keep time as well as provide the instruction clock cycle. We've some 4Mhz and some 20Mhz crystals knocking around - either will do. The idea is to keep an array of values representing the output state of each of the 16 vertical columns in the LED matrix. We'll create a timer interrupt every 1ms and use this for timekeeping (increase a seconds counter every second, when this rolls over to 60, increase a minute counter, when this rolls over to 60, incease an hours counter) as well as to drive the next column of LEDs.

By strobing all 16 columns once every millisecond, we're hoping to create an illusion of an always on display; depending on the results of this, we may strobe the columns every few milliseconds and try to find the optimum balance between the length of time each column remains lit and the "refresh rate": as each column stays on for longer, the LEDs may appear brighter, but the refresh rate (the number of times each column is "drawn" per second) reduces.

Monday 3 December 2012

More Christmas clocks

Last year we made some clocks for Xmas. This was because of an earlier ill-fated attempt to charlie-plex a load of LEDs (a 9x10 matrix) in order to create a word clock (which failed) and a bingo machine (which later worked, but using shift registers instead of charlie-plexing).

This year, since we've got a cheap audio playing device and having seen Jason's awesome digital led MatrixFaces, we thought that some digital caricatures of friends and family would make great stocking filling gifts. So promptly ordered a load of 8x8 LED matrices and waited until they arrived...


They're supposed to be two-colour (red and green) 3mm matrix blocks but the ones that arrived are massive! They're also single colour, with just 16 pins - one set of 8 pins for the "rows" and one set of 8 pins for the "columns". By driving the appropriate pins high/low you can activate any single LED in the matrix. Drive each of them quickly enough, and using POV (persistance of vision) you create the illusion of many LEDs being lit at the same time.

Which got us thinking back to our (failed) word clock project about a year ago.
Instead of a home-made 9x10 matrix, perhaps there's some way we could squeeze a word clock into an 8x8 matrix and use these ridiculously large (in LED matrix terms) modules to create a ridiculously small (in wall clock terms) erm wall clock...

No matter how we tried to spell out all the words required, we couldn't quite get them all to fit into an 8x8 grid. So what if we put two of these side-by-side?


Well now, a 16x8 LED matrix not only gives us more than enough letters to spell out all the words needed for our word clock, but also solves a little niggling issue we'd previously tried to ignore:

Word clocks with five minute increments are accurate to the last five minute segment. Between five to, and o'clock, say, the clock will always read "it is five minutes to x". Then at the o'clock position, it read "it is x o'clock" until it's five past.

By having a larger matrix (albeit by accident than design) we've got extra lights to add in some extra words. So we've added "nearly" and "just gone". This should make our clock accurate to about two minutes at worst.

  • At 2 minutes to six o'clock, it would read "it is nearly six o'clock".
  • At six o'clock, it would obviously read "it is six o'clock" 
  • At 2 minutes past six, it would read "it is just gone six o'clock"
  • And at 4 minutes past six, it would read "it is nearly five past six"
  • At five past, it reads "it is five past six" 

and so on - each two minute segment before a five/ten/quarter past would have "nearly" at the front, and each two minute segment after a five/ten/quarter past time would have "just gone" added to it. This means that you should be able to work out to within two minutes the actual time on the clock.

It's not millisecond accuracy, but it's a bit better than most word clocks manage!

To make the clock, we're planning a laser-cut face over the LED matrix with the letters as laid out in the spreadsheet above. We may even coat some glass with semi-opaque paint to give a smoked effect, and laser this off. The exact finish has yet to be decided.

Since the two LEDs matrices side-by-side give us a 16x8 grid, we can simply keep track of the current time and convert this into an array of single-byte values, each sent out over a full output port (PORTB for example) on a PIC microcontroller, while pulling the appropriate cathode "column" low to make the corresponding LED(s) light up:


In the above example, we want to light up the words to spell out "it is five minutes past six".
If we highlight the letters required, and at the bottom of every column add up the values of all the "lit" characters, we can see the array of value(s) required to make the LED matrix light up.

Friday 23 November 2012

Large format vinyl cutter at BuildBrighton Foison C24

Last night was BuildBrighton night (in fact, almost every night is a BuildBrighton night these days, but Thursdays are the "traditional" come-along-and-hang-out night) and as is usual, come the witching hour, cool things start to happen.

This video was taken at around ten past midnight, after we spent a couple of hours restoring the large format vinyl cutter that we donated a few months back. It's a Foison C24 and has been used about three times in it's lifetime. Hopefully, now it's in it's new home and working, and more people have access to it, it'll get used quite a bit more.

As you can see, it's quite a whizzy-fast machine. Because it's designed to use a drag knife, it takes corners quite slowly, but really flying down the straights!




For testing, we replaced the drag knife with a fat-tipped Sharpie and drew on some copper board. Of course, it's only a matter of time before we're drawing PCBs directly onto the copper board, by-passing the whole press-n-peel stage of etching ;-)

Wednesday 21 November 2012

DipTrace for home etching, gerber export, 3d views and milling outlines

The more time we spend with DipTrace, the more we like it, here at Nerd Towers.
We first came across it while designing PCBs for our miniature guitars last year - changing over from ExpressPCB because we needed to generate gerber files to have some circuit boards manufactured online.

It's easy to use, has a massive library of components, but uses an approach similar to Eagle; when placing components in the schematic, you have to choose the "correct" component with the appropriate footprint while you're drawing the schematic. We much prefer the ExpressPCB method: draw a schematic then link it to the PCB designer - so long as the number of pads in the PCB layout software matches the number of pins in the schematic, you can use pretty much any component footprint to represent any component in the schematic.

As a result, we still turn to ExpressPCB whenever we need to "knock out" a few boards for home etching.
But since we've had to design some more boards for manufacture (for a recent alarm clocks project) we've returned back to DipTrace to generate more gerbers.

And we've found that DipTrace has some pretty cool features - even for the homebrew enthusiast. Firstly, you can create homebrew boards easily and - using the ExpressPCB method - print to a PDF file using CutePDF and flip in Inkscape, reading for printing onto some press-n-peel.



Of course, DipTrace can export to Gerber (so the file(s) can be emailed for manufacture by a professional PCB fabricators). But it also has a few other handy export options.

We've already discovered the brilliant 3D view:


The great thing about this 3d generator is that you can place components so that they "hang off" the board. Not many tools let you do this. In the example above, we've created our audio board but cut the dimensions down, so that the SD card holder is fixed at one end. There's no need to waste copper board under the rest of the sd card holder - not all PCB layout tools allow you to create a board outline smaller than the components on it!

As well as 3D, and creating toner-tranfer images, DipTrace supports exporting to DXF.
Why is this so impressive? Well, if you've a CNC router, you can get it to draw around the outside of each of your pads and traces:


Wow! Now that's cool. Anyone with any experience of using Mach3 or similar CNC software knows that it's relatively easy to get from a DXF drawing to some g-code which we can use to drive the CNC router and - rather than all that nasty etching with stinky chemicals - we could rout out the PCB board from a sheet of copper-clad board.

All these output options from the same PCB layout. DipTrace is looking like a really useful bit of kit. And perhaps something we should persevere with for a little while. After all, up to 500 pins, it's FREE as well.

Tuesday 20 November 2012

Etching heater

Etching with Ferric Chloride is a messy business. So the quicker you can get it over with the better - and for a few reasons. One way to decrease the time taken to etch is agitation: basically stir the mixture or dunk the board in and out of the etchant.

The problem with this, of course, is more opportunity for spillage. And with ferric chloride being such a nasty staining solution, you don't want it splashing around the place.

Another way to speed up etching is using heat. Ferric Chloride works best at about 50 degrees. But sitting the solution in a bath of hot water only increases it's temperature by a few degrees at best. So we tried one of these things - it's called an etching heater, but really it's just a fancy aquarium heater!


It's like a super-duper tropical aquarium heater in a sealed glass case- complete with temperature control on the top, so you can set the thermostat to anywhere between 40 and 60 degrees: perfect for ferric chloride etching! Just search ebay for "etching heater". This one cost less than £15 including delivery to the UK and took about 8 days to arrive.

We put about a litre of ferric chloride solution (made up quite strong, with a full 500g packet of crystal dissolved into about 1L of warm water) into a sweetie jar. This should allow us to etch rather larger boards if we need to. Just stand the heater in the solution, switch on and back away. After about five minutes, the entire thing is up to perfect etching temperature.

(heating the solution is easy - plop in the heater and switch on!)

A relatively small board can now be etched in about two-to-three minutes, rather than the 15-20 minutes it has been taking recently, when etching "cold" (as the winter nights draw in, it does get colder in the nerd cupboard, so ambient temperature is about 16-20 degrees).


The great thing about etching quickly is that because the board is in the solution for a lot less time, the chance of under-cutting is much less (under-cutting is where the etchant eats away at the copper under the toner-transfer mask because the board is left for too long in the solution). By etching hot and quickly, we get really sharp, clear etching, even with thin traces. 


In the photo above, we've managed to get traces down to 0.2mm and they've etched perfectly. When etching "cold" we would rarely go below 0.38mm trace size to avoid over-etching the tiny thin traces.


Here's the board cleaned up, with a micro sd card connector soldered in place, ready for populating. In short, 

Friday 16 November 2012

DipTrace and the amazing 3D render

I recently had to get some PCBs made up for a little project, so had to leave my favoured ExpressPCB behind and use DipTrace again, in order to generate some gerber files for manufacturing (normally we'd just etch our own boards, but time is tight with this one, so they're on a three-day turnaround from a UK-based manufacturer).

I was looking for a gerber viewer when I came across Jason's post about a web-based 3d renderer: https://plus.google.com/u/0/105009608886388132613/posts/1oST39owVAZ

Now that looked exciting. I uploaded the gerber files generated from DipTrace and eagerly waiting for the image to appear..... nothing. Whether it was the gerber file, my lack of 3d graphics hardware in my little notebook or something else, I don't know. I do know that other people commented that they couldn't get it to work either. So no 3D renderings for us.....

Then I spotted this little icon on the toolbar:


So what would that do....?


Ta-da! A perfectly rendered (and populated) PCB. I'm not quite sure how to get the components to sit down in the board properly (seriously, who solders their components so they stand up like that?) but as a quick overview of how your final board could look (especially now we're moving away from through-hole and trying to use SMT wherever we can) it gives great results!

We might just give DIPTrace another go.
Familiarity and laziness have kept us using ExpressPCB. But these 3D renderings do add a fresh dimension to documenting projects (-no- pun intended) so maybe it's time to give it a whirl. The freeware version is quite restrictive with only 300 pins allowed. But for simple, little projects like this one, that's more than enough!

Thursday 15 November 2012

DC blocking capacitor

We've had a few questions about the in-line capacitor on our audio player board. This is the capacitor between the PIC pwm output pin and the gate pin on the transistor amplifier. At first glance, it seems a bit counter-intuitive: we're "blocking" the output from the PIC to the speaker. What's it there for?

Well, here's the thing - the circuit will actually work without the capacitor in place.
Go ahead, try it. You can connect the output from the PIC directly to the gate on the transistor, and you'll still hear sound. It might not be quite as loud, but it'll still be an amplified signal. So what does the "blocking capacitor" do?

Consider what's happening - we're using PWM to drive a speaker.
It's not the most efficient use of the speaker, since we're not generating negative voltages, so we're only every driving the speaker "forwards" using a positive voltage. But let's ignore that for a moment!

Our PWM is creating an "average" voltage over a particular time period, to move the speaker by a certain amount. Now most digitally recreated sound waves go from minus the maximum amplitude (let's call it -5V for simplicity) and plus maximum amplitude (e.g. +5V). When there's no sound/signal, there's no voltage 0V.


But because we don't have negative values in our PWM , we're having to use a value 0-255 to represent the full range from -5 (in this example) to +5.

So -5 (the lowest possible value in the wav file) becomes PWM value zero (the lowest possible value in our PWM output). And +5 (the maximum value in the wav file) becomes PWM value 255 (the highest possible value in our PWM output).

So where the audio file is normally zero (half-way between max and min) our output PWM value is actually 128 (half-way between 0-255). When there is no audio signal, our PWM output is 128, or half-duty cycle, or (on average) 2.5V output.



Now driving 2.5v continuously through the coil in our speaker is going to cause it to heat up and over time, eventually burn out the speaker. So what we do is put a capacitor between the output pin and the gate (which in turn controls the amount of current going into the speaker).

So now, while our audio is silent, there's nothing actually coming out of the other side of the capacitor.

  • When the wav signal falls, the capacitor discharges  and creates a high output.
  • When the wav signal rises, the capacitor starts charging up and the "output" side falls low.
  • The output from the capacitor lags the input by a single sample width.

This means that while the signal is fluctuating - ie. we're using an AC signal - the capacitor allows the signal to "pass-through" albeit one sample width behind the input. When the AC signal becomes DC (a period of sustained silence, for example) the output from the capacitor drops to zero and no voltage is passed into the speaker. The "blocking capacitor" acts like a filter - stopping DC current but allowing AC signals through.

This is a very crude method of driving the speaker, but one that works.
The downside is that where a very quiet audio signal is being played, with large gaps of silence, or very quiet background noise, the speaker is hardly active at all, and you can hear all the other "noise" in the line (the PWM carrier signal, for example).

We can hear this at the start of the song being played in the earlier video.
For the first ten seconds or so, the background sound of rain just sounds like a digital noise and you can hear the hum of the PWM signal. This is because parts of the audio signal are being treated as "rippling DC current" rather than a true AC signal. However, once the audio signal amplitude increases, a large AC signal is generated and the blocking capacitor allows all of the signal to pass into the speaker and the audio clarity improves.

Wednesday 14 November 2012

Different speakers sound different

It's almost so obvious as be incredible!
Here's our PIC-based wav audio player with a cheap 15p speaker from Farnell. The difference between this and the speaker on the alarm clock is amazing! We've tried all kinds of different ways of amplifying the output but the best/loudest to date is this 16 ohm, 700hz, 90dB piezeo speaker with a humble BS170 FET transistor.


The audio in this example is much clearer than with the earlier speaker (and louder too).
Perhaps this is because rather than put the speaker in a box, we're holding it to create a cavity behind the speaker cone. You can definitely hear the speaker gain more definition between hanging loosely and being "encased in flesh"!

Interestingly, the best sound came when we created a tube effect rather than a closed box shape with the hand holding the speaker. Whether this only applies to hands, or to enclosures in general, we've yet to see.....

Wednesday 7 November 2012

FAT/FAT16 tables - finding the data

Having successfully found the root directory on our sd card, we now need to start actually reading the data back from it. This is the last little link in a chain of
The easiest way to find a file is to load a filename into an 11-byte buffer. The easiest format to use is the name, padded with spaces plus the extension, minus the full-stop; so wav001.raw becomes wav001[space][space]raw. Or, perhaps more accurately, WAV001[space][space]RAW (since FAT16 likes to store filenames in uppercase).

A root directory entry looks like this:


  • The first eight bytes are the file name - FAT16/MSDOS only supported up to eight characters in a filename.
  • The next three bytes are the file extension
  • Then there's an attributes byte
  • Followed by time stamps for the file creation/modified date.
  • The next two bytes are the starting cluster for the data (note, cluster not sector)
  • The last four bytes are the total file length (in bytes)
  • Every root directory entry uses exactly 32 bytes
It's the first bunch of bytes we're interested in - the file name, starting cluster and total file length:
Now we just read the root directory, comparing the first 11 bytes of each 32-byte entry in the root directory to the bytes in our filename buffer and if they match, we've found the file we're interested in.

Once we've got our file, we need to work out the file-length (in bytes) and the starting sector for the first cluster of data.

Byte 26 of 32 is the least-significant byte of a two-byte word  (e.g. 0x02)
Byte 27 of 32 is the most-significant byte of a two-byte word (e.g. 0x00)
The starting cluster for the file in this example is therefore 0x0002

Bytes 28-31 represent the file length, starting with the least significant byte of a 4-byte value.
In this example:
Byte 28 = 0x43
Byte 29 = 0x5e
Byte 30 = 0x09
Byte 31 = 0x00

The total file length is 0x00095e43 which in decimal works out as 613,955
Looking at the file wav003.raw in Windows Explorer confirms that the file is, indeed, 613,955 bytes in size



Now previously, we worked out a whole heap of important things from our MBR (master boot record) including where the actual data started, and the number of sectors per cluster (in a FAT16 formatted disk, this is usually 32 sectors per cluster, making each cluster 16kb)

If we know which sector the actual data begins from, and which cluster to begin reading from, we can calculate at which sector the cluster begins.


unsigned long clusterToSector(unsigned long cluster){
     // a cluster is a complicated thing:
     // first there's an ofset to the master boot record
     // then some reserved sectors
     // then a fat table (maybe two)
     // then the root directory (fixed length)
     // THEN there's the first data block,
     // which is where we start reading our clusters from
     // BUT there's a catch - clusters start from zero not 2
     // so whichever cluster number we've been given, subtract 2
     
     unsigned il;
     il=cluster-2;
     il=il*sectorsPerCluster;
     il=il+dataStart;
     return(il);     
}


Great stuff!
Convert the cluster number (in this case, cluster 0x0002) into a sector (in this case, because clusters start from 2 - it's an anomaly of the FAT16 format - our first cluster is also the first sector where the data starts. We've already calculated this value)

"The actual data starts at sector 615 + 32 = 647"

If we jump to sector 647 and start reading back the data, we find that there is, indeed, data in there!
But with a file that's 613,955 bytes long, it's not all going to fit into a single cluster (one cluster is 32 sectors and each sector is 512 bytes, so that's only 32x512 = 16,384 bytes - 16kb)

So where's the rest of the data?
That's where the FAT table comes in!

Firstly, take the cluster number and double it. That's the same as bit-shifting the entire value one place to the left. In our example, our starting cluster was 0x02 so we double this and end up with 0x04
This tells us where in our FAT table to find the next (two-byte) cluster number.

Since the FAT tables themselves are written across a number of sectors, we need to convert this cluster_doubled value into a sector and byte offset, to read the actual "next cluster value" back.

Divide the cluster_doubled value by 512 to get the sector number
The remainder is the byte offset.
In our example, this gives us sectors zero, byte offset 4
So we want the first sector (sector zero) in our FAT table, fourth and fifth byte

Since the FAT table begins at sector 143, we add zero to this, open the sector (using our earlier functions) and read back all 512 bytes. When we get byte four, this makes up the least significant byte of a two-byte (16-bit) value. Byte five is the most significant byte.

In fact, when we open our sd card, read back bytes four and five from sector 143, we get
Byte 4 = 0x03
Byte 5 = 0x00

This tells us that the file continues at cluster 0x0003.
Using the same technique, we open and read the data from cluster 0x0003 (sector 647 + (3-2)*sectorsPerCluster = 647 + 32 = 679)

We continue reading data from the sector(s) and calculating the next cluster where the file continues until we've either read back the entire file (total bytes read > file size in bytes) or the FAT table returns 0xFF as the next cluster (this is a special response to say "no more clusters for this file").

This is summarised in the following function (remove comments around UART calls to see what the microcontroller is actually doing when calculating next FAT clusters).


unsigned char openNextBlock(){
     unsigned short iFATSector;
     unsigned short iFATBytes;
     unsigned short iy;
     unsigned short ix;
     
     //UARTPrintLn("opening next block of data");
     
     // the cluster_number_doubled is the location in the FAT table
     // where we can find the next block of data. If this entry is 0xFF
     // it means that there's no more blocks of data, otherwise the entry
     // is the next cluster where the file continues from
     
     iFATBytes=nextFatClusterDoubled & 511;
     iFATSector=nextFatClusterDoubled>>9;
     iFATSector=iFATSector+FATStart;
     
     //UARTPrintLn("look up next cluster in FAT ");
     //UARTPrint("sector ");
     //UARTPrintNumber(iFATSector);
     //UARTPrint(" byte offset ");
     //UARTPrintNumber(iFATBytes);
     //UARTPrintLn(" ");
     
     // check the FAT tables for the next cluster for the current file
     r=sdReadBlock(iFATSector);
     for(iy=0; iy < 512; iy++){
          r=readByte();
          if(iy==iFATBytes){ix=r; nextFatCluster=ix;}
          if(iy==(iFATBytes+1)){ix=r; ix=ix<<8; nextFatCluster=nextFatCluster+ix;}
     } 
          
     // close the currently open sector
     sdSecReadStop();

     nextFatClusterDoubled=nextFatCluster<<1; // this is the same as multiplying by two!


      
     //UARTPrint("next FAT cluster ");
     //UARTPrintNumber(nextFatCluster);
     //UARTPrintLn(" ");          
     
     if(nextFatCluster==0xFFFF){          
          // if we're at the end of the block, send the end of block marker
          //UARTPrintLn("no futher fat clusters to follow");
          return(0xFF);
     }else{
          
          // open the next sector
          iSector=clusterToSector(nextFatCluster);
          sectorCount=0;
          //UARTPrint("file continues at sector ");
          //UARTPrintNumber(iSector);
          //UARTPrintLn(" ");
          
          return(0);
     }
}