Last time I mentioned the chokes were buzzing too much, so I’d have to dip them in epoxy. Doing that helped somewhat with the noise, and I expect it to be a non-issue once they’re in a closed case.

Three slaves without heatsinks, with chokes covered in epoxy

It took me a few days or so to wire it all up – stripping wires, checking the power cable, yada-yada.

I couldn’t run it at full-power just yet. Software was being non-cooperative. Previously, I’ve tested the system with the master and just one slave. Now, with three slaves connected, there were conflicts. One of them was all the slaves using the same physical OK line. (After the master sends an interrupt, the slave uses that to signal it’s ready to receive data.) How silly of me. Luckily, there were still some unused pins on the master board, so I didn’t have to invent a yet another multiplexer, and just use separate OK lines. It’s all in the code now, and the schematic, too, but I haven’t propagated it to the PCB (as of this writing).

That didn’t fix another problem: the master locking up, as if all slaves were receiving an interrupt, even though separate lines have always been used for that. After a few days of bewilderment, I decided to do the one thing which is known to solve issues almost universally. Namely, get drunk.

The hangover helped me in looking over the design calmly and realising that, although the interrupt lines are separate, the Master-In-Slave-Out is connected to all three slaves, and they are not in Hi-Z state by default. There is no reason for the master to receive data from slaves, really, other than verifying the slave is functional. But rather than disconnecting the MISO line, I fixed it in software.

After that, I was finally able to run the full-power tests. The heatsink goes to 50 °C in half an hour, and stays that way, with 8 kW (4 channels set at 100%). Triacs’ package was 5-10 °C above that. So with heatsinks as big as these, I might not even need a fan in the case, alhough that is yet to be proven.

45 degrees celsius on the heatsink

Still there were 3 more things to do with software:

  • DMX address selection – turned out two address lines got accidentally swapped; fixed in software, not fixed in hardware;
  • setting preheat an maximum value – involved mucking with ADC multiplexing, and I eventually convinced myself this is not needed at all, and should be handled by the lighting console anyway; the UNIX philosophy works in hardware, too: do one thing and do it well (well, try at least);
  • setting a light curve – chopping a sinusoid’s half-period in 256 equal parts means the lower and upper percentage changes give a small delta in output power, whereas the middle is rather sensitive.

The last one is rather important, and I thought it could be solved by chopping the half-period in non-equal parts. That didn’t work: either the timer interrupt routine wasn’t fast enough, or you can’t really change a timer’s TOP value while the timer is running in CTC mode. Turning the timer off, changing the TOP and then turning it back on helped, but it introduced an unacceptable lag. Modifying the timer value to accomodate the lag sounds like too much guesswork. Bored with the project by now, I decided not to implement this feature.

Here’s a dirty Python script I used to generate the timer’s values. Note that a 16 bit timer is required with these if no prescaling is used.

#!/usr/bin/env python

import math

a = 0
b = 0
# tmp = 0
step = 2.0/256
durzc = []   # duration (total time) passed from zero crossing
delays = []  # duration between two durzc values
cycles = 6000000.0/(2*50)  # cycles between two zero crossings

for n in range(0,255):
    b = math.acos(math.cos(a) - step)
    # print(n, a, b)  # debug
    durzc.append((b/math.pi) * cycles)
    a = b

durzc.append(1.0 * cycles)
# print(durzc)  # debug

delays.append(durzc[0])
for n in range(1,256):
    delays.append(durzc[n] - durzc[n-1])
delays = [round(x) for x in delays]
print(delays)

# for n in range(0,256):
#     tmp += delays[n]
# print(tmp)  # debug

Its output, slightly formatted:

[2389, 992, 762, 644, 569, 515, 475, 443,
417, 395, 376, 360, 346, 334, 323, 313,
304, 296, 288, 281, 275, 269, 264, 258,
254, 249, 245, 241, 237, 234, 230, 227,
224, 221, 218, 216, 213, 211, 209, 207,
204, 202, 201, 199, 197, 195, 194, 192,
190, 189, 187, 186, 185, 183, 182, 181,
180, 179, 178, 177, 176, 175, 174, 173,
172, 171, 170, 169, 169, 168, 167, 166,
166, 165, 164, 164, 163, 162, 162, 161,
161, 160, 160, 159, 159, 158, 158, 157,
157, 156, 156, 156, 155, 155, 155, 154,
154, 154, 153, 153, 153, 153, 152, 152,
152, 152, 151, 151, 151, 151, 151, 150,
150, 150, 150, 150, 150, 150, 150, 150,
149, 149, 149, 149, 149, 149, 149, 149,
149, 149, 149, 149, 149, 149, 149, 149,
150, 150, 150, 150, 150, 150, 150, 150,
150, 151, 151, 151, 151, 151, 152, 152,
152, 152, 153, 153, 153, 153, 154, 154,
154, 155, 155, 155, 156, 156, 156, 157,
157, 158, 158, 159, 159, 160, 160, 161,
161, 162, 162, 163, 164, 164, 165, 166,
166, 167, 168, 169, 169, 170, 171, 172,
173, 174, 175, 176, 177, 178, 179, 180,
181, 182, 183, 185, 186, 187, 189, 190,
192, 194, 195, 197, 199, 201, 202, 204,
207, 209, 211, 213, 216, 218, 221, 224,
227, 230, 234, 237, 241, 245, 249, 254,
258, 264, 269, 275, 281, 288, 296, 304,
313, 323, 334, 346, 360, 376, 395, 417,
443, 475, 515, 569, 644, 762, 992, 2389]

And, finally, the whole thing, all wired and waiting for a case:

Dimmer completely wired, still on the cardboard