This section takes the byte value for the full-on
brightness and turns it into a long called fill. The mask is
applied to this to control the number of LED chips used.
Finally, if we’re in the upper-end dead band, we can fill the
array and return.
channels though only one was used. Our final control
assignments are:
1. LEDs control
2. Fine brightness control
3. Coarse brightness control
Note that some lighting boards have built-in gamma
curves for LEDs and some do not. The USE_GAMMA
constant allows us to adjust the LED output for boards
with a linear output:
Since we were using APA102Cs with three white LEDs
per pixel, we decided that the third DMX channel would
control the number of LED chips lit in each; this would
give our colleagues on set the greatest flexibility.
if (level => 244)
longfill(@pixels, fill, 8)
return
npix := (level - 12) / 29
partial := map((level - 12) // 29, 0, 29,
0, 255)
partial := partial brightness / 255
Okay, let’s go through the whole thing. In the main
loop, we’ve read three channels from the DMX receiver:
level, brightness, and chips. Updating the LEDs in the
piece is a bit involved, so I’ll break it up:
pub update_leds | mask, fill, npix, partial
if (level < 12)
longfill(@pixels, 0, 8)
if (USE_GAMMA == ON)
bytefill(@partial, strip.gamma(partial),
4)
else
bytefill(@partial, partial, 4)
partial &= mask
The first check is for the low-end dead band; if we’re
in it, we clear the pixels array and return to the main loop:
longfill(@pixels, fill, npix)
pixels[n] := partial
if (npix < 7)
longfill(@pixels[n+1], 0, 7-npix)
if (USE_CHIPS == ON)
case chips
000..084 : mask := $FF_00_00_00
085..169 : mask := $FF_FF_00_00
170..255 : mask := $FF_FF_FF_00
other : mask := $FF_00_00_00
Finally, we calculate the partial brightness of the end
pixel, turn it into a long, apply the mask, and then put it
into the pixels array. The last step also clears any available
pixels at the end of the strip.
else
mask := MAN_MASK
This step is used to create a mask for the lit pixels.
The result is a smoother transition between pixels as
the lighting board operator adjusts the level control slider.
None of this is terribly complex but serves as a reminder
that in the real world, we have to deal with less-than-perfect circumstances. As my friend John would say, fixing
these little real world gotchas is SMOP (a small matter of
programming).
What we’re doing is dividing the 0..255 range into thirds
and setting the mask so that a pixel can use one, two, or
all three LED chips. This is optional and controlled by the
USE_CHIPS constant. If the third channel is not used, we
apply a manual mask:
The final demo uses the two-channel PWM input
object and tests the LED strip. That APA102C (Adafruit
calls it “DotStar”) driver is identical to my other pixel
driver and has the same method calls. The difference, of
course, is that the APA102C uses two wires (synchronous
serial).
if (USE_GAMMA == ON)
bytefill(@fill, strip.gamma(brightness),
4)
else
bytefill(@fill, brightness, 4)
fill &= mask
Ironically, I wrote the APA102C driver last May
because my friend Matt needed them to light the inside of
a robot for a movie. They’re popular with filmmakers
because they have a high PWM frequency which prevents
strobing when they’re in motion.
That’s it for this column. Until next time, keep
Spinning and winning with the Propeller! NV
May/June 2018 83
BOM
Activity Board Parallax #32912
APA102C Strip Adafruit #2437
APA102C Pixels Adafruit #2350