Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
arnoz
Date:
Fri Oct 01 08:19:46 2021 +0000
Revision:
116:7a67265d7c19
Parent:
98:4df3c0f7e707
- Correct information regarding your last merge

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 26:cb71c4af2912 1 // Pinscape Controller TLC5940 interface
mjr 26:cb71c4af2912 2 //
mjr 26:cb71c4af2912 3 // Based on Spencer Davis's mbed TLC5940 library. Adapted for the
mjr 55:4db125cd11a0 4 // KL25Z and simplified (removes dot correction and status input
mjr 55:4db125cd11a0 5 // support).
mjr 26:cb71c4af2912 6
mjr 26:cb71c4af2912 7
mjr 26:cb71c4af2912 8 #ifndef TLC5940_H
mjr 26:cb71c4af2912 9 #define TLC5940_H
mjr 26:cb71c4af2912 10
mjr 77:0b96f6867312 11 #include "NewPwm.h"
mjr 54:fd77a6b2f76c 12
mjr 55:4db125cd11a0 13 // --------------------------------------------------------------------------
mjr 38:091e511ce8a0 14 // Data Transmission Mode.
mjr 38:091e511ce8a0 15 //
mjr 38:091e511ce8a0 16 // NOTE! This section contains a possible workaround to try if you're
mjr 38:091e511ce8a0 17 // having data signal stability problems with your TLC5940 chips. If
mjr 40:cc0d9814522b 18 // things are working properly, you can ignore this part.
mjr 33:d832bcab089e 19 //
mjr 38:091e511ce8a0 20 // The software has two options for sending data updates to the chips:
mjr 38:091e511ce8a0 21 //
mjr 40:cc0d9814522b 22 // Mode 0: Send data *during* the grayscale cycle. This is the default,
mjr 40:cc0d9814522b 23 // and it's the standard method the chips are designed for. In this mode,
mjr 40:cc0d9814522b 24 // we start sending an update just after then blanking interval that starts
mjr 40:cc0d9814522b 25 // a new grayscale cycle. The timing is arranged so that the update is
mjr 40:cc0d9814522b 26 // completed well before the end of the grayscale cycle. At the next
mjr 40:cc0d9814522b 27 // blanking interval, we latch the new data, so the new brightness levels
mjr 40:cc0d9814522b 28 // will be shown starting on the next cycle.
mjr 55:4db125cd11a0 29 //
mjr 38:091e511ce8a0 30 // Mode 1: Send data *between* grayscale cycles. In this mode, we send
mjr 38:091e511ce8a0 31 // each complete update during a blanking period, then latch the update
mjr 38:091e511ce8a0 32 // and start the next grayscale cycle. This isn't the way the chips were
mjr 38:091e511ce8a0 33 // intended to be used, but it works. The disadvantage is that it requires
mjr 40:cc0d9814522b 34 // the blanking interval to be extended long enough for the full data
mjr 40:cc0d9814522b 35 // update (192 bits * the number of chips in the chain). Since the
mjr 40:cc0d9814522b 36 // outputs are turned off throughout the blanking period, this reduces
mjr 38:091e511ce8a0 37 // the overall brightness/intensity of the outputs by reducing the duty
mjr 38:091e511ce8a0 38 // cycle. The TLC5940 chips can't achieve 100% duty cycle to begin with,
mjr 40:cc0d9814522b 39 // since they require a brief minimum time in the blanking interval
mjr 38:091e511ce8a0 40 // between grayscale cycles; however, the minimum is so short that the
mjr 38:091e511ce8a0 41 // duty cycle is close to 100%. With the full data transmission stuffed
mjr 38:091e511ce8a0 42 // into the blanking interval, we reduce the duty cycle further below
mjr 38:091e511ce8a0 43 // 100%. With four chips in the chain, a 28 MHz data clock, and a
mjr 38:091e511ce8a0 44 // 500 kHz grayscale clock, the reduction is about 0.3%.
mjr 33:d832bcab089e 45 //
mjr 40:cc0d9814522b 46 // Mode 0 is the method documented in the manufacturer's data sheet.
mjr 40:cc0d9814522b 47 // It works well empirically with the Pinscape expansion boards.
mjr 40:cc0d9814522b 48 //
mjr 38:091e511ce8a0 49 // So what's the point of Mode 1? In early testing, with a breadboard
mjr 38:091e511ce8a0 50 // setup, I saw some problems with data signal stability, which manifested
mjr 38:091e511ce8a0 51 // as sporadic flickering in the outputs. Switching to Mode 1 improved
mjr 38:091e511ce8a0 52 // the signal stability considerably. I'm therefore leaving this code
mjr 38:091e511ce8a0 53 // available as an option in case anyone runs into similar signal problems
mjr 38:091e511ce8a0 54 // and wants to try the alternative mode as a workaround.
mjr 38:091e511ce8a0 55 //
mjr 38:091e511ce8a0 56 #define DATA_UPDATE_INSIDE_BLANKING 0
mjr 33:d832bcab089e 57
mjr 26:cb71c4af2912 58 #include "mbed.h"
mjr 55:4db125cd11a0 59
mjr 55:4db125cd11a0 60
mjr 55:4db125cd11a0 61 // --------------------------------------------------------------------------
mjr 55:4db125cd11a0 62 // Some notes on the data transmission design
mjr 55:4db125cd11a0 63 //
mjr 55:4db125cd11a0 64 // I spent a while working on using DMA to send the data, thinking that
mjr 55:4db125cd11a0 65 // this would reduce the CPU load. But I couldn't get this working
mjr 55:4db125cd11a0 66 // reliably; there was some kind of timing interaction or race condition
mjr 55:4db125cd11a0 67 // that caused crashes when initiating the DMA transfer from within the
mjr 55:4db125cd11a0 68 // blanking interrupt. I spent quite a while trying to debug it and
mjr 55:4db125cd11a0 69 // couldn't figure out what was going on. There are some complications
mjr 55:4db125cd11a0 70 // involved in using DMA with SPI that are documented in the KL25Z
mjr 55:4db125cd11a0 71 // reference manual, and I was following those carefully, but I suspect
mjr 55:4db125cd11a0 72 // that the problem was somehow related to that, because it seemed to
mjr 55:4db125cd11a0 73 // be sporadic and timing-related, and I couldn't find any software race
mjr 55:4db125cd11a0 74 // conditions or concurrency issues that could explain it.
mjr 55:4db125cd11a0 75 //
mjr 55:4db125cd11a0 76 // I finally decided that I wasn't going to crack that and started looking
mjr 55:4db125cd11a0 77 // for alternatives, so out of curiosity, I measured the time needed for a
mjr 55:4db125cd11a0 78 // synchronous (CPU-driven) SPI send, to see how it would fit into various
mjr 55:4db125cd11a0 79 // places in the code. This turned out to be faster than I expected: with
mjr 55:4db125cd11a0 80 // SPI at 28MHz, the measured time for a synchronous send is about 72us for
mjr 55:4db125cd11a0 81 // 4 chips worth of GS data (192 bits), which I expect to be the typical
mjr 55:4db125cd11a0 82 // Expansion Board setup. For an 8-chip setup, which will probably be
mjr 55:4db125cd11a0 83 // about the maximum workable setup, the time would be 144us. We only have
mjr 55:4db125cd11a0 84 // to send the data once per grayscale cycle, and each cycle is 11.7ms with
mjr 55:4db125cd11a0 85 // the grayscale clock at 350kHz (4096 steps per cycle divided by 350,000
mjr 55:4db125cd11a0 86 // steps per second = 11.7ms per cycle), so this is only 1% overhead. The
mjr 55:4db125cd11a0 87 // main loop spends most of its time polling anyway, so we have plenty of
mjr 55:4db125cd11a0 88 // cycles to reallocate from idle polling to the sending the data.
mjr 55:4db125cd11a0 89 //
mjr 55:4db125cd11a0 90 // The easiest place to do the send is in the blanking interval ISR, but
mjr 55:4db125cd11a0 91 // I wanted to keep this out of the ISR. It's only ~100us, but even so,
mjr 55:4db125cd11a0 92 // it's critical to minimize time in ISRs so that we don't miss other
mjr 55:4db125cd11a0 93 // interrupts. So instead, I set it up so that the ISR coordinates with
mjr 55:4db125cd11a0 94 // the main loop via a flag:
mjr 55:4db125cd11a0 95 //
mjr 55:4db125cd11a0 96 // - In the blanking interrupt, set a flag ("cts" = clear to send),
mjr 55:4db125cd11a0 97 // and arm a timeout that fires 2/3 through the next blanking cycle
mjr 55:4db125cd11a0 98 //
mjr 55:4db125cd11a0 99 // - In the main loop, poll "cts" each time through the loop. When
mjr 55:4db125cd11a0 100 // cts is true, send the data synchronously and clear the flag.
mjr 55:4db125cd11a0 101 // Do nothing when cts is false.
mjr 55:4db125cd11a0 102 //
mjr 55:4db125cd11a0 103 // The main loop runs on about a 1.5ms cycle, and 2/3 of the grayscale
mjr 55:4db125cd11a0 104 // cycle is 8ms, so the main loop will poll cts on average 5 times per
mjr 55:4db125cd11a0 105 // 8ms window. That makes it all but certain that we'll do a send in
mjr 55:4db125cd11a0 106 // a timely fashion on every grayscale cycle.
mjr 55:4db125cd11a0 107 //
mjr 55:4db125cd11a0 108 // The point of the 2/3 window is to guarantee that the data send is
mjr 55:4db125cd11a0 109 // finished before the grayscale cycle ends. The TLC5940 chips require
mjr 55:4db125cd11a0 110 // this; data transmission has to be entirely between blanking intervals.
mjr 55:4db125cd11a0 111 // The main loop and interrupt handler are operating asynchronously
mjr 55:4db125cd11a0 112 // relative to one another, so the exact phase alignment will vary
mjr 55:4db125cd11a0 113 // randomly. If we start a transmission within the 2/3 window, we're
mjr 55:4db125cd11a0 114 // guaranteed to have at least 3.5ms (1/3 of the cycle) left before
mjr 55:4db125cd11a0 115 // the next blanking interval. The transmission only takes ~100us,
mjr 55:4db125cd11a0 116 // so we're leaving tons of margin for error in the timing - we have
mjr 55:4db125cd11a0 117 // 34x longer than we need.
mjr 55:4db125cd11a0 118 //
mjr 55:4db125cd11a0 119 // The main loop can easily absorb the extra ~100us of overhead without
mjr 55:4db125cd11a0 120 // even noticing. The loop spends most of its time polling devices, so
mjr 55:4db125cd11a0 121 // it's really mostly idle time to start with. So we're effectively
mjr 55:4db125cd11a0 122 // reallocating some idle time to useful work. The chunk of time is
mjr 55:4db125cd11a0 123 // only about 6% of one loop iteration, so we're not even significantly
mjr 55:4db125cd11a0 124 // extending the occasional iterations that actually do this work.
mjr 55:4db125cd11a0 125 // (If we had a 2ms chunk of monolithic work to do, that could start
mjr 55:4db125cd11a0 126 // to add undesirable latency to other polling tasks. 100us won't.)
mjr 55:4db125cd11a0 127 //
mjr 55:4db125cd11a0 128 // We could conceivably reduce this overhead slightly by adding DMA,
mjr 55:4db125cd11a0 129 // but I'm not sure it would actually do much good. Setting up the DMA
mjr 55:4db125cd11a0 130 // transfer would probably take at least 20us in CPU time just to set
mjr 55:4db125cd11a0 131 // up all of the registers. And SPI is so fast that the DMA transfer
mjr 55:4db125cd11a0 132 // would saturate the CPU memory bus for the 30us or so of the transfer.
mjr 55:4db125cd11a0 133 // (I have my suspicions that this bus saturation effect might be part
mjr 55:4db125cd11a0 134 // of the problem I was having getting DMA working in the first place.)
mjr 55:4db125cd11a0 135 // So we'd go from 100us of overhead per cycle to at maybe 50us per
mjr 55:4db125cd11a0 136 // cycle. We'd also have to introduce some concurrency controls to the
mjr 55:4db125cd11a0 137 // output "set" operation that we don't need with the current scheme
mjr 55:4db125cd11a0 138 // (because it's synchronous). So overall I think the current
mjr 55:4db125cd11a0 139 // synchronous approach is almost as good in terms of performance as
mjr 55:4db125cd11a0 140 // an asynchronous DMA setup would be, and it's a heck of a lot simpler
mjr 55:4db125cd11a0 141 // and seems very reliable.
mjr 55:4db125cd11a0 142 //
mjr 55:4db125cd11a0 143 // --------------------------------------------------------------------------
mjr 26:cb71c4af2912 144
mjr 54:fd77a6b2f76c 145
mjr 26:cb71c4af2912 146 /**
mjr 26:cb71c4af2912 147 * SPI speed used by the mbed to communicate with the TLC5940
mjr 26:cb71c4af2912 148 * The TLC5940 supports up to 30Mhz. It's best to keep this as
mjr 33:d832bcab089e 149 * high as possible, since a higher SPI speed yields a faster
mjr 33:d832bcab089e 150 * grayscale data update. However, I've seen some slight
mjr 33:d832bcab089e 151 * instability in the signal in my breadboard setup using the
mjr 33:d832bcab089e 152 * full 30MHz, so I've reduced this slightly, which seems to
mjr 33:d832bcab089e 153 * yield a solid signal. The limit will vary according to how
mjr 33:d832bcab089e 154 * clean the signal path is to the chips; you can probably crank
mjr 33:d832bcab089e 155 * this up to full speed if you have a well-designed PCB, good
mjr 33:d832bcab089e 156 * decoupling capacitors near the 5940 VCC/GND pins, and short
mjr 33:d832bcab089e 157 * wires between the KL25Z and the PCB. A short, clean path to
mjr 33:d832bcab089e 158 * KL25Z ground seems especially important.
mjr 26:cb71c4af2912 159 *
mjr 26:cb71c4af2912 160 * The SPI clock must be fast enough that the data transmission
mjr 26:cb71c4af2912 161 * time for a full update is comfortably less than the blanking
mjr 26:cb71c4af2912 162 * cycle time. The grayscale refresh requires 192 bits per TLC5940
mjr 26:cb71c4af2912 163 * in the daisy chain, and each bit takes one SPI clock to send.
mjr 26:cb71c4af2912 164 * Our reference setup in the Pinscape controller allows for up to
mjr 26:cb71c4af2912 165 * 4 TLC5940s, so a full refresh cycle on a fully populated system
mjr 26:cb71c4af2912 166 * would be 768 SPI clocks. The blanking cycle is 4096 GSCLK cycles.
mjr 26:cb71c4af2912 167 *
mjr 26:cb71c4af2912 168 * t(blank) = 4096 * 1/GSCLK_SPEED
mjr 26:cb71c4af2912 169 * t(refresh) = 768 * 1/SPI_SPEED
mjr 26:cb71c4af2912 170 * Therefore: SPI_SPEED must be > 768/4096 * GSCLK_SPEED
mjr 26:cb71c4af2912 171 *
mjr 26:cb71c4af2912 172 * Since the SPI speed can be so high, and since we want to keep
mjr 26:cb71c4af2912 173 * the GSCLK speed relatively low, the constraint above simply
mjr 26:cb71c4af2912 174 * isn't a factor. E.g., at SPI=30MHz and GSCLK=500kHz,
mjr 26:cb71c4af2912 175 * t(blank) is 8192us and t(refresh) is 25us.
mjr 26:cb71c4af2912 176 */
mjr 38:091e511ce8a0 177 #define SPI_SPEED 28000000
mjr 26:cb71c4af2912 178
mjr 26:cb71c4af2912 179 /**
mjr 26:cb71c4af2912 180 * The rate at which the GSCLK pin is pulsed. This also controls
mjr 26:cb71c4af2912 181 * how often the reset function is called. The reset function call
mjr 98:4df3c0f7e707 182 * interval in seconds is (4096/GSCLK_SPEED). The maximum reliable
mjr 98:4df3c0f7e707 183 * rate is around 32Mhz. It's best to keep this rate as low as
mjr 98:4df3c0f7e707 184 * possible: the higher the rate, the higher the refresh() call
mjr 98:4df3c0f7e707 185 * frequency, so the higher the CPU load. Higher frequencies also
mjr 98:4df3c0f7e707 186 * make it more challenging to wire the chips for clean signal
mjr 98:4df3c0f7e707 187 * transmission. Lower clock speeds are more forgiving of wiring
mjr 98:4df3c0f7e707 188 * quality.
mjr 26:cb71c4af2912 189 *
mjr 40:cc0d9814522b 190 * The lower bound depends on the application. For driving lights,
mjr 40:cc0d9814522b 191 * the limiting factor is flicker: the lower the rate, the more
mjr 40:cc0d9814522b 192 * noticeable the flicker. Incandescents tend to look flicker-free
mjr 98:4df3c0f7e707 193 * at about 50 Hz (205 kHz grayscale clock). LEDs need significantly
mjr 98:4df3c0f7e707 194 * faster rates than incandescents, since they don't have the thermal
mjr 98:4df3c0f7e707 195 * lag of incandescents; for flicker-free LEDs, you usually need at
mjr 98:4df3c0f7e707 196 * least 200Hz (GSCLK_SPEED 819200).
mjr 26:cb71c4af2912 197 */
mjr 40:cc0d9814522b 198 #define GSCLK_SPEED 350000
mjr 26:cb71c4af2912 199
mjr 26:cb71c4af2912 200 class TLC5940
mjr 26:cb71c4af2912 201 {
mjr 26:cb71c4af2912 202 public:
mjr 26:cb71c4af2912 203 /**
mjr 26:cb71c4af2912 204 * Set up the TLC5940
mjr 54:fd77a6b2f76c 205 *
mjr 26:cb71c4af2912 206 * @param SCLK - The SCK pin of the SPI bus
mjr 26:cb71c4af2912 207 * @param MOSI - The MOSI pin of the SPI bus
mjr 26:cb71c4af2912 208 * @param GSCLK - The GSCLK pin of the TLC5940(s)
mjr 26:cb71c4af2912 209 * @param BLANK - The BLANK pin of the TLC5940(s)
mjr 26:cb71c4af2912 210 * @param XLAT - The XLAT pin of the TLC5940(s)
mjr 26:cb71c4af2912 211 * @param nchips - The number of TLC5940s (if you are daisy chaining)
mjr 26:cb71c4af2912 212 */
mjr 26:cb71c4af2912 213 TLC5940(PinName SCLK, PinName MOSI, PinName GSCLK, PinName BLANK, PinName XLAT, int nchips)
mjr 55:4db125cd11a0 214 : spi(MOSI, NC, SCLK),
mjr 26:cb71c4af2912 215 gsclk(GSCLK),
mjr 64:ef7ca92dff36 216 blank(BLANK, 1),
mjr 26:cb71c4af2912 217 xlat(XLAT),
mjr 33:d832bcab089e 218 nchips(nchips)
mjr 26:cb71c4af2912 219 {
mjr 40:cc0d9814522b 220 // start up initially disabled
mjr 40:cc0d9814522b 221 enabled = false;
mjr 40:cc0d9814522b 222
mjr 33:d832bcab089e 223 // set XLAT to initially off
mjr 30:6e9902f06f48 224 xlat = 0;
mjr 33:d832bcab089e 225
mjr 33:d832bcab089e 226 // Assert BLANK while starting up, to keep the outputs turned off until
mjr 33:d832bcab089e 227 // everything is stable. This helps prevent spurious flashes during startup.
mjr 33:d832bcab089e 228 // (That's not particularly important for lights, but it matters more for
mjr 33:d832bcab089e 229 // tactile devices. It's a bit alarming to fire a replay knocker on every
mjr 33:d832bcab089e 230 // power-on, for example.)
mjr 30:6e9902f06f48 231 blank = 1;
mjr 30:6e9902f06f48 232
mjr 64:ef7ca92dff36 233 // Configure SPI format and speed. The KL25Z only supports 8-bit mode.
mjr 64:ef7ca92dff36 234 // We nominally need to write the data in 12-bit chunks for the TLC5940
mjr 26:cb71c4af2912 235 // grayscale levels, but SPI is ultimately just a bit-level serial format,
mjr 26:cb71c4af2912 236 // so we can reformat the 12-bit blocks into 8-bit bytes to fit the
mjr 26:cb71c4af2912 237 // KL25Z's limits. This should work equally well on other microcontrollers
mjr 38:091e511ce8a0 238 // that are more flexible. The TLC5940 requires polarity/phase format 0.
mjr 26:cb71c4af2912 239 spi.format(8, 0);
mjr 26:cb71c4af2912 240 spi.frequency(SPI_SPEED);
mjr 33:d832bcab089e 241
mjr 33:d832bcab089e 242 // Send out a full data set to the chips, to clear out any random
mjr 33:d832bcab089e 243 // startup data from the registers. Include some extra bits - there
mjr 33:d832bcab089e 244 // are some cases (such as after sending dot correct commands) where
mjr 33:d832bcab089e 245 // an extra bit per chip is required, and the initial state is
mjr 54:fd77a6b2f76c 246 // unpredictable, so send extra bits to make sure we cover all bases.
mjr 54:fd77a6b2f76c 247 // This does no harm; extra bits just fall off the end of the daisy
mjr 54:fd77a6b2f76c 248 // chain, and since we want all registers initially set to 0, we can
mjr 33:d832bcab089e 249 // send arbitrarily many extra 0's.
mjr 33:d832bcab089e 250 for (int i = 0 ; i < nchips*25 ; ++i)
mjr 54:fd77a6b2f76c 251 spi.write(0x00);
mjr 33:d832bcab089e 252
mjr 33:d832bcab089e 253 // do an initial XLAT to latch all of these "0" values into the
mjr 33:d832bcab089e 254 // grayscale registers
mjr 33:d832bcab089e 255 xlat = 1;
mjr 33:d832bcab089e 256 xlat = 0;
mjr 29:582472d0bc57 257
mjr 55:4db125cd11a0 258 // Allocate our SPI buffer. The transfer on each cycle is 192 bits per
mjr 55:4db125cd11a0 259 // chip = 24 bytes per chip.
mjr 55:4db125cd11a0 260 spilen = nchips*24;
mjr 55:4db125cd11a0 261 spibuf = new uint8_t[spilen];
mjr 55:4db125cd11a0 262 memset(spibuf, 0x00, spilen);
mjr 30:6e9902f06f48 263
mjr 30:6e9902f06f48 264 // Configure the GSCLK output's frequency
mjr 77:0b96f6867312 265 gsclk.getUnit()->period(1.0f/GSCLK_SPEED);
mjr 33:d832bcab089e 266
mjr 55:4db125cd11a0 267 // we're not yet ready to send new data to the chips
mjr 55:4db125cd11a0 268 cts = false;
mjr 55:4db125cd11a0 269
mjr 55:4db125cd11a0 270 // we don't need an XLAT signal until we send data
mjr 33:d832bcab089e 271 needXlat = false;
mjr 40:cc0d9814522b 272 }
mjr 40:cc0d9814522b 273
mjr 40:cc0d9814522b 274 // Global enable/disble. When disabled, we assert the blanking signal
mjr 40:cc0d9814522b 275 // continuously to keep all outputs turned off. This can be used during
mjr 40:cc0d9814522b 276 // startup and sleep mode to prevent spurious output signals from
mjr 40:cc0d9814522b 277 // uninitialized grayscale registers. The chips have random values in
mjr 40:cc0d9814522b 278 // their internal registers when power is first applied, so we have to
mjr 40:cc0d9814522b 279 // explicitly send the initial zero levels after power cycling the chips.
mjr 40:cc0d9814522b 280 // The chips might not have power even when the KL25Z is running, because
mjr 40:cc0d9814522b 281 // they might be powered from a separate power supply from the KL25Z
mjr 40:cc0d9814522b 282 // (the Pinscape Expansion Boards work this way). Global blanking helps
mjr 40:cc0d9814522b 283 // us start up more cleanly by suppressing all outputs until we can be
mjr 40:cc0d9814522b 284 // reasonably sure that the various chip registers are initialized.
mjr 40:cc0d9814522b 285 void enable(bool f)
mjr 40:cc0d9814522b 286 {
mjr 40:cc0d9814522b 287 // note the new setting
mjr 40:cc0d9814522b 288 enabled = f;
mjr 40:cc0d9814522b 289
mjr 55:4db125cd11a0 290 // If disabled, apply blanking immediately. If enabled, do nothing
mjr 55:4db125cd11a0 291 // extra; we'll drop the blanking signal at the end of the next
mjr 55:4db125cd11a0 292 // blanking interval as normal.
mjr 40:cc0d9814522b 293 if (!f)
mjr 40:cc0d9814522b 294 {
mjr 55:4db125cd11a0 295 // disable interrupts, since the blanking interrupt writes gsclk too
mjr 55:4db125cd11a0 296 __disable_irq();
mjr 55:4db125cd11a0 297
mjr 55:4db125cd11a0 298 // turn off the GS clock and assert BLANK to turn off all outputs
mjr 77:0b96f6867312 299 gsclk.glitchFreeWrite(0);
mjr 77:0b96f6867312 300 wait_us(3);
mjr 40:cc0d9814522b 301 blank = 1;
mjr 55:4db125cd11a0 302
mjr 55:4db125cd11a0 303 // done messing with shared data
mjr 55:4db125cd11a0 304 __enable_irq();
mjr 40:cc0d9814522b 305 }
mjr 40:cc0d9814522b 306
mjr 40:cc0d9814522b 307 }
mjr 29:582472d0bc57 308
mjr 30:6e9902f06f48 309 // Start the clock running
mjr 29:582472d0bc57 310 void start()
mjr 29:582472d0bc57 311 {
mjr 26:cb71c4af2912 312 // Set up the first call to the reset function, which asserts BLANK to
mjr 26:cb71c4af2912 313 // end the PWM cycle and handles new grayscale data output and latching.
mjr 98:4df3c0f7e707 314 // The original version of this library used a timer to call reset
mjr 26:cb71c4af2912 315 // periodically, but that approach is somewhat problematic because the
mjr 26:cb71c4af2912 316 // reset function itself takes a small amount of time to run, so the
mjr 26:cb71c4af2912 317 // *actual* cycle is slightly longer than what we get from counting
mjr 26:cb71c4af2912 318 // GS clocks. Running reset on a timer therefore causes the calls to
mjr 26:cb71c4af2912 319 // slip out of phase with the actual full cycles, which causes
mjr 26:cb71c4af2912 320 // premature blanking that shows up as visible flicker. To get the
mjr 54:fd77a6b2f76c 321 // reset cycle to line up more precisely with a full PWM cycle, it
mjr 54:fd77a6b2f76c 322 // works better to set up a new timer at the end of each cycle. That
mjr 54:fd77a6b2f76c 323 // organically accounts for the time spent in the interrupt handler.
mjr 54:fd77a6b2f76c 324 // This doesn't result in perfectly uniform timing, since interrupt
mjr 54:fd77a6b2f76c 325 // latency varies slightly on each interrupt, but it does guarantee
mjr 54:fd77a6b2f76c 326 // that the blanking will never be premature - all variation will go
mjr 54:fd77a6b2f76c 327 // into the tail end of the cycle after the 4096 GS clocks. That
mjr 54:fd77a6b2f76c 328 // might cause some brightness variation, but it won't cause flicker,
mjr 54:fd77a6b2f76c 329 // and in practice any brightness variation from this seems to be too
mjr 54:fd77a6b2f76c 330 // small to be visible.
mjr 54:fd77a6b2f76c 331 armReset();
mjr 26:cb71c4af2912 332 }
mjr 26:cb71c4af2912 333
mjr 76:7f5912b6340e 334 // stop the timer
mjr 76:7f5912b6340e 335 void stop()
mjr 76:7f5912b6340e 336 {
mjr 76:7f5912b6340e 337 disarmReset();
mjr 76:7f5912b6340e 338 }
mjr 76:7f5912b6340e 339
mjr 39:b3815a1c3802 340 /*
mjr 64:ef7ca92dff36 341 * Set an output. 'idx' is the output index: 0 is OUT0 on the first
mjr 64:ef7ca92dff36 342 * chip, 1 is OUT1 on the first chip, 16 is OUT0 on the second chip
mjr 64:ef7ca92dff36 343 * in the daisy chain, etc. 'data' is the brightness value for the
mjr 64:ef7ca92dff36 344 * output, 0=off, 4095=full brightness.
mjr 26:cb71c4af2912 345 */
mjr 26:cb71c4af2912 346 void set(int idx, unsigned short data)
mjr 26:cb71c4af2912 347 {
mjr 39:b3815a1c3802 348 // validate the index
mjr 39:b3815a1c3802 349 if (idx >= 0 && idx < nchips*16)
mjr 39:b3815a1c3802 350 {
mjr 55:4db125cd11a0 351 #if DATA_UPDATE_INSIDE_BLANKING
mjr 55:4db125cd11a0 352 // If we send data within the blanking interval, turn off interrupts while
mjr 55:4db125cd11a0 353 // modifying the buffer, since the send happens in the interrupt handler.
mjr 54:fd77a6b2f76c 354 __disable_irq();
mjr 55:4db125cd11a0 355 #endif
mjr 40:cc0d9814522b 356
mjr 55:4db125cd11a0 357 // Figure the SPI buffer location of the output we're changing. The SPI
mjr 54:fd77a6b2f76c 358 // buffer has the packed bit format that we send across the wire, with 12
mjr 54:fd77a6b2f76c 359 // bits per output, arranged from last output to first output (N = number
mjr 54:fd77a6b2f76c 360 // of outputs = nchips*16):
mjr 39:b3815a1c3802 361 //
mjr 39:b3815a1c3802 362 // byte 0 = high 8 bits of output N-1
mjr 39:b3815a1c3802 363 // 1 = low 4 bits of output N-1 | high 4 bits of output N-2
mjr 39:b3815a1c3802 364 // 2 = low 8 bits of N-2
mjr 39:b3815a1c3802 365 // 3 = high 8 bits of N-3
mjr 39:b3815a1c3802 366 // 4 = low 4 bits of N-3 | high 4 bits of N-2
mjr 39:b3815a1c3802 367 // 5 = low 8bits of N-4
mjr 39:b3815a1c3802 368 // ...
mjr 39:b3815a1c3802 369 // 24*nchips-3 = high 8 bits of output 1
mjr 39:b3815a1c3802 370 // 24*nchips-2 = low 4 bits of output 1 | high 4 bits of output 0
mjr 39:b3815a1c3802 371 // 24*nchips-1 = low 8 bits of output 0
mjr 39:b3815a1c3802 372 //
mjr 39:b3815a1c3802 373 // So this update will affect two bytes. If the output number if even, we're
mjr 39:b3815a1c3802 374 // in the high 4 + low 8 pair; if odd, we're in the high 8 + low 4 pair.
mjr 39:b3815a1c3802 375 int di = nchips*24 - 3 - (3*(idx/2));
mjr 39:b3815a1c3802 376 if (idx & 1)
mjr 39:b3815a1c3802 377 {
mjr 39:b3815a1c3802 378 // ODD = high 8 | low 4
mjr 55:4db125cd11a0 379 spibuf[di] = uint8_t((data >> 4) & 0xff);
mjr 55:4db125cd11a0 380 spibuf[di+1] &= 0x0F;
mjr 55:4db125cd11a0 381 spibuf[di+1] |= uint8_t((data << 4) & 0xf0);
mjr 39:b3815a1c3802 382 }
mjr 39:b3815a1c3802 383 else
mjr 39:b3815a1c3802 384 {
mjr 39:b3815a1c3802 385 // EVEN = high 4 | low 8
mjr 55:4db125cd11a0 386 spibuf[di+1] &= 0xF0;
mjr 55:4db125cd11a0 387 spibuf[di+1] |= uint8_t((data >> 8) & 0x0f);
mjr 55:4db125cd11a0 388 spibuf[di+2] = uint8_t(data & 0xff);
mjr 39:b3815a1c3802 389 }
mjr 55:4db125cd11a0 390
mjr 55:4db125cd11a0 391 #if DATA_UPDATE_INSIDE_BLANKING
mjr 55:4db125cd11a0 392 // re-enable interrupts
mjr 55:4db125cd11a0 393 __enable_irq();
mjr 55:4db125cd11a0 394 #endif
mjr 39:b3815a1c3802 395 }
mjr 26:cb71c4af2912 396 }
mjr 40:cc0d9814522b 397
mjr 55:4db125cd11a0 398 // Send updates if ready. Our top-level program's main loop calls this on
mjr 55:4db125cd11a0 399 // every iteration. This lets us send grayscale updates to the chips in
mjr 55:4db125cd11a0 400 // regular application context (rather than in interrupt context), to keep
mjr 55:4db125cd11a0 401 // the time in the ISR as short as possible. We return immediately if
mjr 55:4db125cd11a0 402 // we're not within the update window or we've already sent updates for
mjr 55:4db125cd11a0 403 // the current cycle.
mjr 55:4db125cd11a0 404 void send()
mjr 55:4db125cd11a0 405 {
mjr 55:4db125cd11a0 406 // if we're in the transmission window, send the data
mjr 55:4db125cd11a0 407 if (cts)
mjr 55:4db125cd11a0 408 {
mjr 55:4db125cd11a0 409 // Write the data to the SPI port. Note that we go directly
mjr 55:4db125cd11a0 410 // to the hardware registers rather than using the mbed SPI
mjr 55:4db125cd11a0 411 // class, because this makes the operation about 50% faster.
mjr 55:4db125cd11a0 412 // The mbed class checks for input on every byte in case the
mjr 55:4db125cd11a0 413 // SPI connection is bidirectional, but for this application
mjr 55:4db125cd11a0 414 // it's strictly one-way, so we can skip checking for input
mjr 55:4db125cd11a0 415 // and just blast bits to the output register as fast as
mjr 55:4db125cd11a0 416 // it'll take them. Before writing the output register
mjr 55:4db125cd11a0 417 // ("D"), we have to check the status register ("S") and see
mjr 55:4db125cd11a0 418 // that the Transmit Empty Flag (SPTEF) is set. The
mjr 98:4df3c0f7e707 419 // procedure is: spin until SPTEF is set in "S", write the
mjr 55:4db125cd11a0 420 // next byte to "D", loop until out of bytes.
mjr 55:4db125cd11a0 421 uint8_t *p = spibuf;
mjr 55:4db125cd11a0 422 for (int i = spilen ; i > 0 ; --i) {
mjr 55:4db125cd11a0 423 while (!(SPI0->S & SPI_S_SPTEF_MASK)) ;
mjr 55:4db125cd11a0 424 SPI0->D = *p++;
mjr 55:4db125cd11a0 425 }
mjr 55:4db125cd11a0 426
mjr 55:4db125cd11a0 427 // we've sent new data, so we need an XLAT signal to latch it
mjr 55:4db125cd11a0 428 needXlat = true;
mjr 55:4db125cd11a0 429
mjr 55:4db125cd11a0 430 // done - we don't need to send again until the next GS cycle
mjr 55:4db125cd11a0 431 cts = false;
mjr 55:4db125cd11a0 432 }
mjr 40:cc0d9814522b 433 }
mjr 26:cb71c4af2912 434
mjr 26:cb71c4af2912 435 private:
mjr 55:4db125cd11a0 436 // SPI port. This is master mode, output only, so we only assign the MOSI
mjr 55:4db125cd11a0 437 // and SCK pins.
mjr 55:4db125cd11a0 438 SPI spi;
mjr 30:6e9902f06f48 439
mjr 55:4db125cd11a0 440 // SPI transfer buffer. This contains the live grayscale data, formatted
mjr 55:4db125cd11a0 441 // for direct transmission to the TLC5940 chips via SPI.
mjr 55:4db125cd11a0 442 uint8_t *volatile spibuf;
mjr 40:cc0d9814522b 443
mjr 55:4db125cd11a0 444 // Length of the SPI buffer in bytes. The native data format of the chips
mjr 55:4db125cd11a0 445 // is 12 bits per output = 1.5 bytes. There are 16 outputs per chip, which
mjr 55:4db125cd11a0 446 // comes to 192 bits == 24 bytes per chip.
mjr 55:4db125cd11a0 447 uint16_t spilen;
mjr 40:cc0d9814522b 448
mjr 40:cc0d9814522b 449 // Dirty: true means that the non-live buffer has new pending data. False means
mjr 40:cc0d9814522b 450 // that the non-live buffer is empty.
mjr 54:fd77a6b2f76c 451 volatile bool dirty;
mjr 54:fd77a6b2f76c 452
mjr 40:cc0d9814522b 453 // Enabled: this enables or disables all outputs. When this is true, we assert the
mjr 40:cc0d9814522b 454 // BLANK signal continuously.
mjr 40:cc0d9814522b 455 bool enabled;
mjr 30:6e9902f06f48 456
mjr 26:cb71c4af2912 457 // use a PWM out for the grayscale clock - this provides a stable
mjr 26:cb71c4af2912 458 // square wave signal without consuming CPU
mjr 77:0b96f6867312 459 NewPwmOut gsclk;
mjr 26:cb71c4af2912 460
mjr 26:cb71c4af2912 461 // Digital out pins used for the TLC5940
mjr 26:cb71c4af2912 462 DigitalOut blank;
mjr 26:cb71c4af2912 463 DigitalOut xlat;
mjr 26:cb71c4af2912 464
mjr 26:cb71c4af2912 465 // number of daisy-chained TLC5940s we're controlling
mjr 26:cb71c4af2912 466 int nchips;
mjr 26:cb71c4af2912 467
mjr 26:cb71c4af2912 468 // Timeout to end each PWM cycle. This is a one-shot timer that we reset
mjr 26:cb71c4af2912 469 // on each cycle.
mjr 38:091e511ce8a0 470 Timeout resetTimer;
mjr 26:cb71c4af2912 471
mjr 55:4db125cd11a0 472 // Timeout to end the data window for the PWM cycle.
mjr 55:4db125cd11a0 473 Timeout windowTimer;
mjr 55:4db125cd11a0 474
mjr 55:4db125cd11a0 475 // "Clear To Send" flag:
mjr 55:4db125cd11a0 476 volatile bool cts;
mjr 55:4db125cd11a0 477
mjr 33:d832bcab089e 478 // Do we need an XLAT signal on the next blanking interval?
mjr 33:d832bcab089e 479 volatile bool needXlat;
mjr 55:4db125cd11a0 480
mjr 40:cc0d9814522b 481 // Reset the grayscale cycle and send the next data update
mjr 26:cb71c4af2912 482 void reset()
mjr 26:cb71c4af2912 483 {
mjr 30:6e9902f06f48 484 // start the blanking cycle
mjr 30:6e9902f06f48 485 startBlank();
mjr 33:d832bcab089e 486
mjr 55:4db125cd11a0 487 // we're now clear to send the new GS data
mjr 55:4db125cd11a0 488 cts = true;
mjr 55:4db125cd11a0 489
mjr 55:4db125cd11a0 490 #if DATA_UPDATE_INSIDE_BLANKING
mjr 55:4db125cd11a0 491 // We're configured to send the new GS data inline during each
mjr 55:4db125cd11a0 492 // blanking cycle. Send it now.
mjr 55:4db125cd11a0 493 send();
mjr 55:4db125cd11a0 494 #else
mjr 55:4db125cd11a0 495 // We're configured to send GS data during the GS cycle. This means
mjr 55:4db125cd11a0 496 // we can defer the GS data transmission to any point within the next
mjr 55:4db125cd11a0 497 // GS cycle, which will last about 12ms (assuming a 350kHz GS clock).
mjr 55:4db125cd11a0 498 // That's a ton of time given that our GS transmission only takes about
mjr 55:4db125cd11a0 499 // 100us. With such a leisurely time window to work with, we can move
mjr 55:4db125cd11a0 500 // the transmission out of the ISR context and into regular application
mjr 55:4db125cd11a0 501 // context, which is good because it greatly reduces the time we spend
mjr 55:4db125cd11a0 502 // in this ISR, which is good in turn because more ISR time means more
mjr 55:4db125cd11a0 503 // latency for other interrupts and more chances to miss interrupts
mjr 55:4db125cd11a0 504 // entirely.
mjr 33:d832bcab089e 505 //
mjr 55:4db125cd11a0 506 // The mechanism for deferring the transmission to application context
mjr 55:4db125cd11a0 507 // is simple. The main program loop periodically polls the "cts" flag
mjr 55:4db125cd11a0 508 // and transmits the data if it finds "cts" set. To conform to the
mjr 55:4db125cd11a0 509 // hardware spec for the TLC5940 chips, the data transmission has to
mjr 55:4db125cd11a0 510 // finish before the next blanking interval. This means our time
mjr 55:4db125cd11a0 511 // window to do the transmission is the 12ms of the grayscale cycle
mjr 55:4db125cd11a0 512 // minus the ~100us to do the transmission. So basically 12ms.
mjr 55:4db125cd11a0 513 // Timing is never exact on the KL25Z, though, so we should build in
mjr 55:4db125cd11a0 514 // a little margin for error. To be conservative, we'll say that the
mjr 55:4db125cd11a0 515 // update must begin within the first 2/3 of the grayscale cycle time.
mjr 55:4db125cd11a0 516 // That's an 8ms window, and leaves a 4ms margin of error. It's
mjr 55:4db125cd11a0 517 // almost inconceivable that any of the timing factors would be
mjr 55:4db125cd11a0 518 // outside of those bounds.
mjr 55:4db125cd11a0 519 //
mjr 55:4db125cd11a0 520 // To coordinate this 2/3-of-a-cycle window with the main loop, set
mjr 55:4db125cd11a0 521 // up a timeout to clear the "cts" flag 2/3 into the cycle time. If
mjr 55:4db125cd11a0 522 // for some reason the main loop doesn't do the transmission before
mjr 55:4db125cd11a0 523 // this timer fires, it'll see the "cts" flag turned off and won't
mjr 55:4db125cd11a0 524 // attempt the transmission on this round. (That should essentially
mjr 76:7f5912b6340e 525 // never happen, but it wouldn't be a problem even if it happened with
mjr 55:4db125cd11a0 526 // some regularity, because we'd just transmit the data on the next
mjr 76:7f5912b6340e 527 // cycle.)
mjr 76:7f5912b6340e 528 windowTimer.attach_us(this, &TLC5940::closeSendWindow,
mjr 76:7f5912b6340e 529 uint32_t((1.0f/GSCLK_SPEED)*4096.0f*2.0f/3.0f*1000000.0f));
mjr 48:058ace2aed1d 530 #endif
mjr 48:058ace2aed1d 531
mjr 55:4db125cd11a0 532 // end the blanking interval
mjr 55:4db125cd11a0 533 endBlank();
mjr 54:fd77a6b2f76c 534
mjr 55:4db125cd11a0 535 // re-arm the reset handler for the next blanking interval
mjr 54:fd77a6b2f76c 536 armReset();
mjr 54:fd77a6b2f76c 537 }
mjr 55:4db125cd11a0 538
mjr 55:4db125cd11a0 539 // End the data-send window. This is a timeout routine that fires halfway
mjr 55:4db125cd11a0 540 // through each grayscale cycle. The TLC5940 chips allow new data to be
mjr 55:4db125cd11a0 541 // sent at any time during the grayscale pulse cycle, but the transmission
mjr 55:4db125cd11a0 542 // has to fit into this window. We do these transmissions from the main loop,
mjr 55:4db125cd11a0 543 // so that they happen in application context rather than interrupt context,
mjr 55:4db125cd11a0 544 // but this means that we have to synchronize the main loop activity to the
mjr 55:4db125cd11a0 545 // grayscale timer cycle. To make sure the transmission is done before the
mjr 55:4db125cd11a0 546 // next grayscale cycle ends, we only allow the transmission to start for
mjr 55:4db125cd11a0 547 // the first 2/3 of the cycle. This gives us plenty of time to send the
mjr 55:4db125cd11a0 548 // data and plenty of padding to make sure we don't go too late. Consider
mjr 55:4db125cd11a0 549 // the relative time periods: we run the grayscale clock at 350kHz, and each
mjr 55:4db125cd11a0 550 // grayscale cycle has 4096 steps, so each cycle takes 11.7ms. For the
mjr 55:4db125cd11a0 551 // typical Expansion Board setup with 4 TLC5940 chips, we have 768 bits
mjr 55:4db125cd11a0 552 // to send via SPI at 28 MHz, which nominally takes 27us. The actual
mjr 55:4db125cd11a0 553 // measured time to send 768 bits via send() is 72us, so there's CPU overhead
mjr 55:4db125cd11a0 554 // of about 2.6x. The biggest workable Expnasion Board setup would probably
mjr 55:4db125cd11a0 555 // be around 8 TLC chips, so we'd have twice the bits and twice the
mjr 55:4db125cd11a0 556 // transmission time of our 4-chip scenario, so the send time would be
mjr 55:4db125cd11a0 557 // about 150us. 2/3 of the grayscale cycle gives us an 8ms window to
mjr 55:4db125cd11a0 558 // perform a 150us operation. The main loop runs about every 1.5ms, so
mjr 55:4db125cd11a0 559 // we're all but certain to poll CTS more than once during each 8ms window.
mjr 55:4db125cd11a0 560 // Even if we start at the very end of the window, we still have about 3.5ms
mjr 55:4db125cd11a0 561 // to finish a <150us operation, so we're all but certain to finish in time.
mjr 55:4db125cd11a0 562 void closeSendWindow()
mjr 55:4db125cd11a0 563 {
mjr 55:4db125cd11a0 564 cts = false;
mjr 55:4db125cd11a0 565 }
mjr 55:4db125cd11a0 566
mjr 54:fd77a6b2f76c 567 // arm the reset handler - this fires at the end of each GS cycle
mjr 54:fd77a6b2f76c 568 void armReset()
mjr 54:fd77a6b2f76c 569 {
mjr 76:7f5912b6340e 570 resetTimer.attach_us(this, &TLC5940::reset,
mjr 76:7f5912b6340e 571 uint32_t((1.0/GSCLK_SPEED)*4096.0*1000000.0f));
mjr 76:7f5912b6340e 572 }
mjr 76:7f5912b6340e 573
mjr 76:7f5912b6340e 574 void disarmReset()
mjr 76:7f5912b6340e 575 {
mjr 76:7f5912b6340e 576 resetTimer.detach();
mjr 30:6e9902f06f48 577 }
mjr 30:6e9902f06f48 578
mjr 30:6e9902f06f48 579 void startBlank()
mjr 30:6e9902f06f48 580 {
mjr 77:0b96f6867312 581 // turn off the grayscale clock
mjr 77:0b96f6867312 582 gsclk.glitchFreeWrite(0);
mjr 77:0b96f6867312 583
mjr 79:682ae3171a08 584 // Make sure the gsclk cycle ends, since the TLC5940 data sheet
mjr 79:682ae3171a08 585 // says we can't take BLANK high until GSCLK has been low for 20ns.
mjr 79:682ae3171a08 586 // (We don't have to add any padding for the 20ns, since it'll take
mjr 79:682ae3171a08 587 // at least one CPU cycle of 60ns to return from waitEndCycle().
mjr 79:682ae3171a08 588 // That routine won't return until GSCLK is low, so it will have
mjr 79:682ae3171a08 589 // low for at least 60ns by the time we get back from this call.)
mjr 79:682ae3171a08 590 gsclk.waitEndCycle();
mjr 77:0b96f6867312 591
mjr 79:682ae3171a08 592 // assert BLANK to end the grayscale cycle
mjr 77:0b96f6867312 593 blank = 1;
mjr 30:6e9902f06f48 594 }
mjr 26:cb71c4af2912 595
mjr 33:d832bcab089e 596 void endBlank()
mjr 30:6e9902f06f48 597 {
mjr 33:d832bcab089e 598 // if we've sent new grayscale data since the last blanking
mjr 33:d832bcab089e 599 // interval, latch it by asserting XLAT
mjr 33:d832bcab089e 600 if (needXlat)
mjr 30:6e9902f06f48 601 {
mjr 26:cb71c4af2912 602 // latch the new data while we're still blanked
mjr 26:cb71c4af2912 603 xlat = 1;
mjr 26:cb71c4af2912 604 xlat = 0;
mjr 33:d832bcab089e 605 needXlat = false;
mjr 26:cb71c4af2912 606 }
mjr 26:cb71c4af2912 607
mjr 40:cc0d9814522b 608 // End the blanking interval and restart the grayscale clock. Note
mjr 40:cc0d9814522b 609 // that we keep the blanking on if the chips are globally disabled.
mjr 54:fd77a6b2f76c 610 if (enabled)
mjr 54:fd77a6b2f76c 611 {
mjr 54:fd77a6b2f76c 612 blank = 0;
mjr 54:fd77a6b2f76c 613 gsclk.write(.5);
mjr 54:fd77a6b2f76c 614 }
mjr 26:cb71c4af2912 615 }
mjr 26:cb71c4af2912 616 };
mjr 26:cb71c4af2912 617
mjr 26:cb71c4af2912 618 #endif