Monday, 5 October 2015

Guitar tutor with PIC 16F1829 microcontroller and 74HC595 shift registers

Griff Hamlin, Steve Stine and Papastache all have one thing in common. Ok, they have lots of things in common. Mostly, they're all awesome guitarists. Not just "a bit good" - but amazing. I love Griff Hamlin's way of teaching blues guitar with his Blues Guitar Unleashed course. I've even got a copy (though haven't yet gone much beyond the very basics). And, being a bit of a how-does-it-work geek, I love how well Steve Stine explains not just what notes to play, but why you should play them. And while Steve plays some great blues licks too, he's a wizard on just about any genre (his Thunder Rock Riffs looks pretty cool for example).

But for me, +papastache102 has some of the best "how to play and why you're playing it that way" video lessons on the interwebs. His mixing of major and minor pentatonic sounds, and targeting notes in the underlying chords is incredible. His moustache is almost as impressive as his guitar playing, and he regularly teams up with session supremo Tim Pierce (whose guitar playing is on a whole other level). But there's something about Bret Papa's playing that immediately identifies it as him. It's kind of Hendrix-y mixed in with some late 70s classic rock and even a bit of 80s stadium heavy metal. Just my kind of thing!

Anyway, enough about how great these guys are (but, honestly, they really are) and how great their lessons are (but, honestly, they really are) and more about microcontrollers and shift registers. And how they have anything to do with guitar playing anyway.

Well, over at Nerd Towers, we've a whole heap of LEDs and plenty of 595 shift registers knocking about. After creating a MIDI keyboard to learn how to play chords and scales on the piano, a guitar tutor was a project that some of us (mostly me, I admit it) were keen to make. And after watching a recent Papastache video ( we just knew it's time had come!

Yeeaaaahhh. Welcome, welcome, welcome to the Nerd Club blog, Papastache!

The key to a lot of getting a guitar to sound "right" is to target the notes in the underlying chords. Sure you can just noodle around on a blues/pentatonic scale right over the top of a standard I-IV-V progression - but it'll only ever sound like someone noodling around with a scale over a chord progression. Maybe throw in a few "stock licks" to break it up a bit, but it's quite difficult to sound musical with just one scale under your fingertips!

Bret's video demonstrates how different scales can "attach" to different chords. And he talks a lot about mixing major and minor scales by seeing them over one another in the same place on the fretboard. Which is great. I love the theory behind it. I'm totally with Papa' all the way. Until I pick up my guitar - and then look blankly at the fretboard, as all the notes and positions fall away and I don't really even know where to start.

Which is why, with a bunch of surface mount LEDs, a handful of shift registers and an afternoon free to play about with a vat of ferric chloride, we decided it was time to start our guitar tutor in earnest.

On a very basic level, it's simply a bunch of LEDs connected to some shift registers that we can turn on and off. The firmware will need to get quite complex after that, but it's basically just a rework of the MIDI keyboard but with knobs on. The keyboard was a great "starter" project for LEDs, but it did involve a lot of wiring. This time, we're simplifying things, by making a few PCBs.

We decided to make the guitar fingerboard in sections, rather than one great big long PCB. The most obvious reason was, of course, because most of our copper clad board is 160mm x 100mm eurocard size, and our etching tank doesn't really like taking great big boards. But it also means we can build and test the "light-up-fingerboard" in sections, instead of having to build the whole thing, only to find one little bit doesn't work, and it junks the rest of the project!

Here's the top section (first four frets) with LED markers for each of the strings.

This design gets us six strings worth of markers for four frets, using three shift registers. The whole design can be repeated, but moving the LEDs closer together (vertically) and spacing them horizontally further apart for the next four frets on the guitar neck (look at a guitar fingerboard - the frets get closer together, and the neck widens as it gets closer to the guitar body).

The modular design meant we could build and test our idea in sections

And soldering up each section wasn't so daunting. Once you've done a (horizontal) row of six surface mount LEDs by hand, you're a quarter of the way through each section!

For testing, we connected wires to each section and plugged it into the breadboard testing rig. We created a single 8-bit value (starting at 0x01) and bit-shifted it left, one place every half a second. This allows us to check that every LED is working as it should, before trying to debug more complex problems in the future.

With one board out of the way, and inspired by the success, it didn't take long to create another two sections, to give us a total of 12 frets-worth of markers (as any guitar-player knows, the patterns simply repeat from the 12th fret onwards, so we'll stick at 12 for now).

Now we had to create some firmware to display chords, scales, patterns and shapes. That's not quite so easy! Because the boards were designed to be easy to create (single-sided, compact, etch-at-home) it means that the output patterns for the shift registers are not very intuitive.

We're using 32-bit values to record the positions of which LEDs we want to light up. So let's say we wanted to light up a simple C-major chord. In guitar-land, that looks like this:

So our 32-bit value for the second (A) string shown above would be 001000000000000
Similarly, the 32-bit value representing the D string would be 0100000000000
And the B string would be represented by 1000000000 (we've not included the open strings just for now, but in the final version, they'll need to be added in: we're just trying to keep things relatively simple by making the patterns match the charts in this example).

But if you watch the video above, you'll see that the first LED that lights up is not the first position on the first string. It's the fourth position/fret on the second string. Then the third (on the second string) then the second fret, then the first fret. Confusingly, the pattern doesn't repeat: it then goes to the first fret on the first string, then the second fret, third then fourth (all on the first string).

Then it skips down to the fourth fret on the fourth string (not the third), works it's way back to the first fret, before jumping up to the third string, and moving back out, from the first to the fourth fret position. This pattern repeats on the sixth and fifth strings also.

Which means, we've got to create some clever algorithms (or, if +Steve Carpenter were writing it, maybe just a bucketload of IF statements!) to turn our chord and scale patterns into "shift register" patterns, to get the right LEDs to light up at the right time.

Here's what we came up with:

Const pentatonic_box_one=1
root_fret = 1
Gosub load_pattern
Gosub strings_to_shift_patterns
Gosub send_shift_data

     'do nothing
Goto loop

     Select Case pattern_to_show
          Case pentatonic_box_one
          string6.4B = 00001001b
          string5.4B = 00001001b
          string4.4B = 00001010b
          string3.4B = 00001010b
          string2.4B = 00001010b
          string1.4B = 00001001b
          If blues_as_pentatonic = 1 Then
               string2.4B = string2.4B Or 00000100b
               string5.4B = string5.4B Or 00000010b
     'now we've drawn these onto fret 5 (A minor for
     'pentatonic scales, E-shape chords and for A-shape
     'chords, we've already started on fret12 and
     'D-shape chords, root on fret 10) so shift these
     'along depending on the start fret required
     If root_fret < 5 Then
          k = 5 - root_fret 'this is how many "spaces" left we need to move the box
          string6 = ShiftLeft(string6, k)
          string5 = ShiftLeft(string5, k)
          string4 = ShiftLeft(string4, k)
          string3 = ShiftLeft(string3, k)
          string2 = ShiftLeft(string2, k)
          string1 = ShiftLeft(string1, k)
     If root_fret > 5 Then
          k = root_fret - 5 'we need to move the box up k frets
          string6 = ShiftRight(string6, k)
          string5 = ShiftRight(string5, k)
          string4 = ShiftRight(string4, k)
          string3 = ShiftRight(string3, k)
          string2 = ShiftRight(string2, k)
          string1 = ShiftRight(string1, k)


     'firstly, make sure that any pattern on the strings is repeated
     'up and down, beyond the 12th fret
     For i = 1 To 6
          If i = 1 Then tmp_w = string1
          If i = 2 Then tmp_w = string2
          If i = 3 Then tmp_w = string3
          If i = 4 Then tmp_w = string4
          If i = 5 Then tmp_w = string5
          If i = 6 Then tmp_w = string6
          tmp_w = ShiftLeft(tmp_w, 12)
          If i = 1 Then string1 = string1 Or tmp_w
          If i = 2 Then string2 = string2 Or tmp_w
          If i = 3 Then string3 = string3 Or tmp_w
          If i = 4 Then string4 = string4 Or tmp_w
          If i = 5 Then string5 = string5 Or tmp_w
          If i = 6 Then string6 = string6 Or tmp_w

          If i = 1 Then tmp_w = string1
          If i = 2 Then tmp_w = string2
          If i = 3 Then tmp_w = string3
          If i = 4 Then tmp_w = string4
          If i = 5 Then tmp_w = string5
          If i = 6 Then tmp_w = string6
          tmp_w = ShiftRight(tmp_w, 12)

          If i = 1 Then string1 = string1 Or tmp_w
          If i = 2 Then string2 = string2 Or tmp_w
          If i = 3 Then string3 = string3 Or tmp_w
          If i = 4 Then string4 = string4 Or tmp_w
          If i = 5 Then string5 = string5 Or tmp_w
          If i = 6 Then string6 = string6 Or tmp_w
     Next i
     'because each shift register is wired up in an weird way
     'we need to translate the strings into shift patterns
     'shift pattern one is first four bits of string 2 followed by
     'the first four bits of string 1 in reverse
     k = string2.4B And 11110000b
     k = ShiftRight(k, 4)
     j = string1.4B And 11110000b
     Gosub reverse_j
     j = ShiftLeft(j, 4)
     shift_pattern1 = k Or j

     'similarly, shift pattern two is first four bits of string 4 followed by
     'the first four bits of string 3 in reverse

     k = string4.4B And 11110000b
     k = ShiftRight(k, 4)
     j = string3.4B And 11110000b
     Gosub reverse_j
     j = ShiftLeft(j, 4)
     shift_pattern2 = k Or j

     'and shift pattern three is first four bits of String 6 followed by
     'the first four bits of string 5 in reverse

     k = string6.4B And 11110000b
     k = ShiftRight(k, 4)
     j = string5.4B And 11110000b
     Gosub reverse_j
     j = ShiftLeft(j, 4)
     shift_pattern3 = k Or j

     Dim tmp_j As Byte
     tmp_j = 0
     If j.0 = 1 Then tmp_j.7 = 1
     If j.1 = 1 Then tmp_j.6 = 1
     If j.2 = 1 Then tmp_j.5 = 1
     If j.3 = 1 Then tmp_j.4 = 1
     If j.4 = 1 Then tmp_j.3 = 1
     If j.5 = 1 Then tmp_j.2 = 1
     If j.6 = 1 Then tmp_j.1 = 1
     If j.7 = 1 Then tmp_j.0 = 1
     j = tmp_j

     Low shift_latch

     'Since we're sinking not sourcing current to make
     'our LEDs light up, we want to set the shift register
     'output LOW to get it to light, not high. Easiest
     'way to do this is to XOR with 0xFF to invert.
     For i = 1 To 3
          Select Case i
               Case 1
               k = shift_pattern1 Xor 0xff
               Case 2
               k = shift_pattern2 Xor 0xff

               Case 3
               k = shift_pattern3 Xor 0xff

          'start with the MSB (bit 7)
          pattern = 128
          For j = 0 To 7
               bit_pattern = k And pattern
               If bit_pattern = 0 Then
                    Low shift_data
                    High shift_data
               'toggle the clock line
               High shift_clock
               Low shift_clock
               'move the pattern along, to send out bit6, then 5, then 4 etc.
               pattern = ShiftRight(pattern, 1)
          Next j
     Next i
     'rising edge on the latch sends shift register data to the output pins
     High shift_latch
     Low shift_latch

Amazingly, it actually works!
Here's one four-fret section showing the famous "box one" pattern of the pentatonic scale (with added "blues notes" on the flatted 5ths)

We're not done yet.
There's still plenty of coding to do, to get all the different scales, chords and patterns programmed in. But it's a very encouraging start. And hopefully it won't be too long before we can "dial in" a chord sequence, and have the guitar tutor show us which box shapes to play, where, and when........

Fixing a ferric chloride/aquarium heater - bodge warning!

We've had our aquarium heater for a while now. It's great for heating a vat of ferric chloride, prior to etching (there's a world of difference between etching "hot" and etching cold!). But every now and again it goes a bit wonky. Then, today, it stopped working altogether.

The heater itself is actually very simple. It's just a coil inside a large glass test-tube-shaped, um, tube. When in use, it sits inside the glass with a rubber bung in the top, to make it waterproof. It has a crude temperature controller on the top, which is a dial to set the temperature anywhere between about 45 and 70 degrees.

As we've had this thing for a while, it's unsurprising that the bi-metallic strip that makes up the temperature controller occasionally sticks, keeping the two contacts apart - and effectively stopping the heater from working.

We've actually repaired this particular heater before, and, at the time, jammed some extra padding in to keep the bi-metallic switch closed for longer. It looks like it's just about had enough, as the actual body of the heater is now so warped that the switch no longer closes properly.

No worries - we simply removed the bi-metallic strip and replaced it with a bit of wire, connecting the two points (the purple wire in the photo, above, is the "fix"). Now there's no temperature control at all - plug it in, and it just burns away, getting hotter and hotter!

This is a real nasty bodge. But it works. So we no longer have to wait hours and hours for a board to etch, cold. In fact, this afternoon I made a brew while the ferric was heating, answered a phone call, had a few biscuits, answered the door to the postie (yes, they only call in the afternoons, here in Hove!) and forgot that the ferric was still being heated, by an uncontrollable heating element.

Suffice to say that the ferric was rather warm when I returned to it. But it fully etched a 5" x 3.5" board in less than a minute! I'm still not sure whether this is a great hack, or a disaster just waiting to happen.

Wednesday, 30 September 2015

Cleaning a solder pot

Burning the enamel coating off magnet wire is hard work. It burns at about 390 degrees, meaning you need to have your iron really, really hot. Then when the enamel burns, it makes a mess of your tip. And sometimes it doesn't all come off cleanly, so you end up re-doing it, after failing to solder the wire to a PCB two or three times.

What we really need is a pot of super-hot moulten solder, into which we can simply dip the ends of the wires to both strip the coating as well as pre-tin the wires at the same time. What we really need is a solder pot.

We used to have a solder pot, which did make soldering a little easier. Except it was really smoky. Not a little bit, but really, really smoky. The reason for this is the flux core of most lead-free solder on the market. After melting a tube of Maplin's finest in the pot, there's a sticky, tarry, residue left in the pot. And when this gets hot, it really smokes!

What didn't help was that the pot we borrowed off Matt (ours had gone missing during one of numerous moves over the years) looked like it had been used as an ashtray! Even after loads of scrubbing, and even with brand new, fresh solder, it still smoked like crazy.

We decided that we needed to clean the solder, as well as the solder pot. So we melted a whole tube of solder and left the pot, switched on, outside to smoke as much as it liked! The solder inside was covered in a filthy scum, and the inside of the pot was black with tar.

We skimmed as much crud off the top of the solder as possible, while it was still moulten. We then placed some kitchen foil inside an eggcup and poured the solder into it. Then left everything to cool down.

Cleaning the solder pot was no easy task! Using a screwdriver head, craft knife and pan scourers, we managed to get a lot of the black off the inside of the pot. It wasn't perfect, but we managed to get a lot of junk out.

The actual solder, meanwhile, looked bright and shiny, with no trace of the impurities that made it so scummy-looking when it was in the solder pot earlier. With both solder and pot cleaned of any flux residue, we put the solder in the pot and let it melt.

This time, the solder melted without even the teeniest whiff of smoke! So little, in fact, that it made our heath-robinson smoke extractor (a PC fan and a piece of aquarium carbon filter) unnecessary. Now we had a nice, clean, smoke-free way of preparing our magnet wires, prior to soldering.

If you have any trouble with a smoking solder pot, try cleaning the solder, as well as the pot, and see if it improves things!

Testing rig for soldering pcb wires

After numerous builds, re-build, teardowns and start-again-from-the-ground-up-builds, we've got a pcb design we're happy with and firmware that works consistently well in all environments. All that remains is to wire the thing up to out board panels.

Since we're multiplexing the hall sensor array, we need only 15 wires (7 rows, 7 columns and absolutely not forgetting, no-way-we've-never-left-out-before, the ground connection) which is a massive improvement over the 50 or so we originally had to hand wire!

So far so good.

...actually wiring the thing is a right pain!
Since the PCB is on the underside of the board, it's a laborious task to solder one wire on the board, thread it through to the sensor row on the other side, solder it down to the correct row/column, then get the next wire and repeat. Not least because we always have to leave enough wire so the PCB isn't held up close against the back of the panel, so that it can be repeatedly flipped over for more wires to be soldered to it. The end result is a board with loads of big long loops of wire all over the place!

As well as being a pain to solder because of all the back-and-forth and board flipping, the AWG gauge wire is still a little too thick to be manageable for a final design.

So we had to come up with an idea to simplify the wiring process.
Firstly, we had to use the thinnest wire we could get hold of - which meant 0.125mm enamelled wire. Easy enough to get hold of, but tricky to solder (without the use of a solder pot). Then we had to come up with a method that would allow us to solder all the wires onto the PCB in one go, thread them through the board and solder them to the appropriate row/column on the topside.

The obvious solution would be to use a different coloured wire for every connection on the PCB. This seems obvious. Except it also means having to use relatively thick gauge wire (the coloured sleeve making up the bulk of the wire) and having a selection of at least 15 different coloured wires. It also means we'd have to be absolutely consistent with every coloured wire - so, for example, red would always have to go to pin1, blue to pin2 etc.

Instead of this, we built a "test rig".

The test rig allows us to "probe" each wire to find out which row/column it's connected to. We do this by putting the PCB into "test mode" when it boots up. We then send it serial commands to raise just one of the seven source-driver outputs high at any one time. So we send R1 and the driver output relating to row one goes high. R2 and all but the driver output relating to row two goes high. R3 and... well, you get the idea.

We now have a bunch of seven wires, one of which has been raised high to 5v. Simply brush each wire along the anode leg of an LED and when it lights up, you've found which wire is connected to which "row" output on the PCB.

Similarly the other seven wires are connected to the "column" inputs on the PCB. The PCB is continually monitoring these input pins (with internal pull-up resistors) waiting for one (or more) to go low (this is the basis of how the electronic board game actually works). So when one input goes from high to low, it sends out a serial message along the lines of C1 (for column one) C2 (for column two, and so on).

Touching each of these wires to ground sends a serial message back to our test rig, showing which column wire has been grounded - so we know which column on the board panel to connect it to.

All serial messages are displayed on the 16x2 character display (for no other reason than we had a few lying around!) and the status of each row/column is displayed so we can tell exactly which pin is wired to which wire, without having to keep flipping the board over and tracing each wire back to the PCB.

Being wired up on a breadboard, our test rig works. But it's a bit shonky. What it really needs is a nice PCB and enclosure, just to tidy it all up and make it a bit more reliable. Maybe we'll get round to that, once we've got a couple more of these board panels soldered up!

Thursday, 17 September 2015

I2C bit-banging between two PIC microcontrollers

After soldering up a few new style PCBs and trying out a couple of board game panel sections, we came across a fatal flaw in the design. Currently, we're using a three-pin audio stereo cable to join our board game sections.

In a perfect test environment, these work really well. But when we put four or five board panels onto a table and tried connecting them, things started to go a bit awry.

Firstly, we started getting spurious data at the controller end. If the plug was slightly tight fitting into the audio socket (as some were, the first time the socket was used) we received peculiar characters over serial at the controller. Not a major problem - we simply add a checksum to the end of each message and if the contents of the message don't match the checksum, we just ignore the entire message.

But something else started happening too - some of the previously connected boards started to reset. After placing pieces on them and tracking where they are, a board reset is a really bad thing. It makes the board section forget everything it knows about the pieces placed above it, so when you pick a piece up, it registers that something has changed (one of the hall sensors has changed state) but not that you've removed a piece (because the board has "forgotten" the piece above, it thinks the change is placing not removing a piece). Again, this is something that could be factored out using firmware changes, but it's a bit alarming that some boards are resetting.

So what's going on?
Well, it seems that putting the power on the tip of our stereo plug isn't great. The idea was that the power pins would be the last pins to connect as the plug is pushed into the socket, but in truth, it doesn't matter which (tip, centre or ring) carries the power and/or ground lines - if the plug isn't inserted absolutely square to the socket (so any part of the plug touches any part of the socket during insertion) we can get power shorts and reset conditions on the power line.

So now we're back to looking at keeping our pins a row, rather than "line them up" behind each other. Thanks to the popularity of RGB LED strips, four-way plugs and sockets can be found really cheaply.

And if we're going to use these, we'll have four (rather than three) wires in total. The shape of the plug and socket mean you can't plug them in the wrong way around (without really making an effort) and there are two cables, rather than one, available for sending data.

Now, with two wires, rather than a single one, and a topology consisting of a master controller and a whole load of clients/slaves on a common bus, and immediately we're thinking about I2C as a communications protocol.

I2C is a great protocol for common bus communications. Single wire is ok, but it does rather depend on each device only trying to talk one-at-a-time. I2C actually enforces this rule, using a clock and data line. To send data, you simply check the state of the clock line and if it's in use, wait for it to become free. But the best thing of all about I2C (when implemented properly) is that there's no danger of "power clashes".

I2C basically consists of a clock line and a data line. The sending device raises or lowers the data line, then toggles the clock line. When the listening device sees the clock line go high, it checks the state of the data line. If it is high, that's a binary one. If it's low, it's binary zero. Simple huh?

But it gets even better than that. Let's say two devices - for whatever reason - try to use the clock and data lines. One device sets the data line high (sending a binary value one) but the other device tries to send it low (sending a binary value zero). If we're actively driving the line(s) high and low, we've got a "power clash" - we're effectively shorting our power and our ground lines together!

To avoid this, I2C doesn't actually drive the lines high and low. It uses external pull-up resistors to let the lines float high, and actively pulls them down to ground. So instead of driving the line "up" and "down" we either drive the line low/down or simply let go of it (and it "rises" high of it's own accord).

This is the crucial idea behind the I2C bus. It allows loads of devices to share the lines, but if two or more devices try to talk at the same time, we don't get power shorts. Of course, the data coming off the lines would be garbage, but we've not actually damaged anything. Consider two devices now trying to talk at the same time. The first device drives the data line low (sending binary zero) but the second device - instead of driving the line high (which would create a short) - simply lets the line go (to send a binary one). The result is that binary zero gets sent: not what device two wanted, but it's not trying to force the line high against device one pulling it low.

To make the lines work properly, we need open drain collector transistors to pull the data and clock lines to ground. Rather than using external components, however, we're going to try to use our PIC i/o pins.

Now, PIC microcontrollers don't all have the ability to make their i/o pins "open collector" but they do have a tri-state: input, output, hi-z (high impedence). If we disable the internal pull-up resistors on an i/o pin and make it an input, it's treated as a hi-z pin (high impedence means we can treat it as if disconnected from the rest of the circuit). So rather than turn an output pin on and off to create our high and low signals, we're going to toggle the pins between output/low (drive the line to ground) and input/hi-z (disconnect and allow the line to  "float high").

With all this in mind, we threw together a few routines to generate an I2C output signal. One last thing of note: in the I2C protocol, the data line should only be changed while the clock line is being held low. There are only two scenarios when we should allow the data line state to change while the clock line is high - these are to generate the "start" and "stop" conditions on the line(s).

Here's some code to send a message out over two I2C wires:

Define CONFIG1 = 0x0984
Define CONFIG2 = 0x1dff

     Symbol i2c_clock = PORTA.0
     Symbol i2c_data = PORTA.1
     Dim msg_out As String
     WaitMs 1000
     msg_out = "Let's go"
     Gosub send_msg

Goto loop

     Gosub wait_for_free_clock
     'now we've got the clock line, wrench it low to tell everyone else we're talking
     'to pull the line low, we need to set the pin to an output then set it low
     'to raise the line, however, we set the pin to input (hi-z) and let it float high

     Gosub clock_low
     WaitMs 2 'give it a few milliseconds for everyone to start listening
     j = InStr(msg_out, 0x0d)
     If j = 0 Then msg_out = msg_out + CrLf
     j = Len(msg_out)
     j = j - 1
     For i = 0 To j
          k = msg_out(i)
          'send the data out, MSB-first
          For t = 0 To 7
               h = k And 10000000b
               If h = 0 Then
                    Gosub data_low
                    Gosub data_high
               Gosub clock_high
               WaitUs 2
               Gosub clock_low
               k = ShiftLeft(k, 1)
          Next t
     Next i

     'release the clock line to let it float high for the next message
     '(from whichever device on the bus wants to use it)
     Gosub clock_high
     'the stop command in i2c is SDA goes high while SCL is high
     Gosub data_high

     WaitMs 1
     While i2c_clock = 0
          'do nothing

     ConfigPin i2c_clock = Output
     Low i2c_clock

     ConfigPin i2c_clock = Input

     ConfigPin i2c_data = Output
     Low i2c_data

     ConfigPin i2c_data = Input

As it turns out, our PicKit2 programmer (clone) has a really handy feature- a simple three channel logic analyser. So all we needed to do was add the pull-up resistors between our clock and data lines and the power supply, set the clock line as the trigger condition (rising edge) and set our code running.

The results looked something like this:

Amazingly, we had a first-time success. The chart above shows the clock and data lines - the data line leads the clock line by a fraction of a millisecond (on the graphic they sometimes appear to be changing at exactly the same time). But it's important to note that the data line only ever changes when the clock line is  low (with the exception of the start and end bits).

We've also decoded the data line at each rising clock edge, and written out the ASCII characters for each byte received. And we can see that the output on the data line exactly matches the message we sent out!

Wednesday, 9 September 2015

New PCBs for electronic board sections

After getting our multiplexed hall sensor array working last week - and failing to demonstrate them at a Unity meetup in Brighton recently after wiring the one working prototype up incorrectly! - we made up some smaller sections, this time in a 7x7 grid.

This means we can use a single input port (PORTB) with pull-up resistors (since the hall sensors pull to ground when activated) and a single port to activate each transistor individually to turn on each row of hall sensors at a time. This means loads of discrete components:

For prototyping (and because of space restrictions on our breadboard) we've only actually wired up five of the seven transistors, but after proving the concept worked, went on to use all 7 in a test (we went on to wire up two of the SMT transistors at the top of the board).

Ok, not exactly loads. But quite a few. Enough to make wiring up each controller circuit for each board section quite fiddly. We etched up a few different circuit boards, using a variety of different mcus, surface-mount and through-hole components.

Even after making as many components as possible surface mounted, there were still a lot of discrete components to stick down on each PCB! Enough to make it worthwhile investigating an alternative, all-in-one integrated (IC) chip to do most of the work for us...

The A2982 may be relatively expensive, at about a quid a time when bought in bulk, but it does simplify the circuit a great deal.

The A2982 is a source current driver. It includes resistors on the transistor bases, to allow them to work at 5v logic levels, and each channel can source up to 500mA if needed. So all those discrete components are gone - and the entire circuit is now just two IC units: a single PIC 16F1829 and a single AS2982 chip.

Each panel is now much simplified from our earlier 12x12 design - both in terms of hall sensors and the controller PCB. Here we're using some thin hook-up wire just to get the board working (the final version will use ultra-thin magnet wire)

We're using 3.5mm stereo jack sockets to connect our PCBs to power/ground/data. So here's the final PCB design all soldered up and ready for the new firmware.

Right now we've got a couple of panels soldered up and working individually - so we're in for a marathon etching session tonight, to make up half-a-dozen or more controller PCBs for all the other panels. A few more like this and some updated firmware and we can create one, big, playing surface....

Monday, 7 September 2015

1206 resistor array

This is a 1206 component (third from left). It's pretty small.

When I recently created a pcb with 8 pull-down resistors, each connecting microcontroller pins to a common ground. Whenever I've got a load of resistors connected to a common point (whether pulled-up to Vcc or pulled-down to ground) the first thing that springs to mind is "resistor array".

So when there are a load of 1206 resistors that all need connecting to a common point, what about a 1206 resistor array? Here's a 595 shift register DIP with 8 x 1206 resistors (and, of course, a penny for scale).

What would be really cool would be a block of eight resistors, where one side all shared a "common bus". Then we'd have a nice big block that should be easily manageable. So what about those 1206 resistor arrays? A quick trip to and 16 hours later, and we've got some to try out

Except they're not quite what I was expecting. While the description read like it said "8 x 1206-sized resistors in an array", it turns out it was more like "8 x resistors in a 1206-sized array" (note the subtle difference).

That's right - all 8 resistors and a common connection squashed into a single, tiny, 1206 package. Given the size of those ridiculously tiny pins, I'm not entirely sure how this is less fiddly than dealing with 8 of the little buggers individually!