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 :-)
Re: How the HL1606 REALLY works
Thanks for the HL6106 konw-how :) The datasheet is really a piece of shit :( It seems you saved a lot of my time - from now on it should be only a question of SW ... PS I am working on a ilumination of a living room - I need primarily three functions a) white light and static/dynamic white patterns for celebrations, b) changeable static pastel colours for ambience (dinner, TV watching, coffee/tea, chess/cards), c) colorfull dynamic discoefects for parties (of course controlled by music - FFT ?). Total count will be 24m of RGB stripes and 48m of white LED stripes ...
Re: How the HL1606 REALLY works
Thanks for the great information.
Did you try to daisy chain the 2nd strip to the end of the first strip and that did not work? They are daisy chain capable and there was no mention in this article about hooking the size out wires to the 6 input wires of the next strip and explaining what happened in that case. So I am curious if you tried it Since the strips are normally 200 leds daisy chained .. and a 20 led strip is only a part chopped off the longer length, it seems daisy chaining would work to run 5 strips.
Re: How the HL1606 REALLY works
As delivered from the factory, the 'near' end of the strip has a ribbon cable and separate ground and power wires, the 'far' end has a ribbon cable and ground (but no power) so you can connect the ground and control wires to another strip. You do however need to provide a separate 5V supply for each 200-LED strip. In electrical terms, until I chopped the strip into 20-LED segments it was in effect a daisy chain of 10 20-LED segments, so yes of course it would work.
In my case I'm using a 20-LED strip per arm and leg, and if I wanted to wire them up as a single, continuous chain I'd have to run a cable from the wrist/ankle end of each of the four strips back up the arm/leg and across to the next strip. That would be both more bulky and fragile than driving each strip separately. The downside is you then need a dedicated /SS pin per strip, plus the 74HC125 chip needed to make the strips into a 'proper' SPI device. but I think that's a worthwhile trade-off.
In my test code I actually model the strip as an array of 40 LEDs and generate the patterns to use all 40, then in the output code I simply split the array into two halves, sending out the 'left' 20 reversed, and the 'right' 20 normally, so it is easy to hide the actual electrical arrangement and treat a number of strips as being logically contiguous, even when they aren't physically contiguous.