How the HL1606 REALLY works

I've explained in my last two Arduino posts how I got the HL1606 working with the Arduino's SPI support and hardware timers. If you haven't already read them, I suggest you read at least the first post before this one, otherwise what follows won't make much sense.

The setup I'm building needs to drive four strips at the same time, so the next step was to add another strip. The SPI protocol uses a /SS line for each slave, so that multiple devices can coexist on the bus. To communicate with a particular slave, you pull /SS for that slave low, send the data on the bus, then pull /SS high. The other devices on the bus ignore the traffic as their /SS lines are held high during the transaction. After wiring everything up and making the necessary code changes, I ran my existing text code to make sure the first strip was till working OK. Well, it was, but the new, second strip was going completely nuts, displaying a flickering version of the pattern I was sending to the the first strip - not at all what I expected. I did the usual things of checking the wiring and the code, which was all OK. I even tried tying the /CS line of the second strip to +5V to be sure it was unselected, but it made no difference. Hmm...

After some further thought, I began to suspect that despite what the datasheet said, the HL1606 was not in fact a SPI device. A clue to this was that the datasheet shows a high pulse on the /SS line (labelled L_I on the datasheet) rather than a continuous high level. OK, so what was it doing? As I said in my earlier post, the HL1606 has two shift buffers (A & B) and two output drivers (A & B). Pulling the /SS line low does indeed suppress the copying of the shift buffer contents into the output latches, and pulling it high does indeed result in the shift buffer contents being copied into the output driver to light the LEDS. However there's one vital but missing piece of behaviour - when the /SS line is high the HL1606 should ignore the contents of the data bus, but it doesn't. Instead, if /SS is high the current contents of the shift buffers are copied to the output driver immediately. That explained why the second strip was displaying a manically-flashing version of the pattern displayed on the first strip - as the data was being shifted out to the first strip, the second strip was shifting in and displaying the data as it progressed down the strip. Duh, that is clearly not how SPI works.

OK, that's a big problem. The AVR only has one set of SPI hardware and I didn't have enough pins to implement five SPI buses using bit-banging, as each requires four pins. What I needed was some way of disabling each strip other than using the dysfunctional /SS line. The SPI bus uses clock line supplied by the bus master, with the clock line determining when the data should be sampled. Perhaps if I suppressed the clock, the HL1606 would ignore the data on the bus? That was easy to test, I just disconnected the clock line on the second strip and the mad flashing stopped. Yay.

So now I needed to come up with a way of controlling the SPI clock being supplied to each strip. I could have done that by using another pin per strip to control an external gate on the clock line but I already had such a line, the per-strip /SS line, even though it didn't actually work correctly. All I needed was something that could use an active-low input to gate the clock line. After a little digging I found a 7400 series chip, the 74HC125 quad bus buffers. Each one has four channels - great, I had four strips to control, and at 32p each they weren't going to break the bank. I connected the /CS lines to the /G pin of the 74125, the clock line from the Arduino to the A lines and the clock line of the strips to the Y lines and fired everything up - perfect, the strips now only respond when their particular /SS line was active. The only extra tweak required was the addition of a 20K pull-down resistor - the outputs of the 74HC125 are tri-state when switched off, so the resistors are needed to stop the clock lines to the LED strips from floating (and false-triggering) when the strips are deselected.

Each strip has 20 LEDs so I extended my existing code to generate a 40-LED pattern and then in the output code I split the pattern into two halves, sending each half to one strip so that I could test out patterns that span more than one strip. You can see the results below.

I've still more work to do - I need to drive the SPI radio chipsets I'm going to be using, I need a task management framework to coordinate everything, I need a way of generating the patterns easily and so forth, but the major hurdle of driving multiple strips simultaneously using the minimum number of pins has been solved. I'll be writing further posts as I go, so please check back for more :-)

Categories : Tech, AVR