Arnaud VALLEY / Mbed 2 deprecated Pinscape_Controller_V2_arnoz

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
mjr
Date:
Thu Feb 18 07:32:20 2016 +0000
Revision:
47:df7a88cd249c
Parent:
40:cc0d9814522b
Child:
48:058ace2aed1d
3-channel linked DMA scheme for CCD image capture working

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 26:cb71c4af2912 4 // KL25Z, and simplified to just the functions needed for this
mjr 26:cb71c4af2912 5 // application. In particular, this version doesn't include support
mjr 26:cb71c4af2912 6 // for dot correction programming or status input. This version also
mjr 26:cb71c4af2912 7 // uses a different approach for sending the grayscale data updates,
mjr 26:cb71c4af2912 8 // sending updates during the blanking interval rather than overlapping
mjr 26:cb71c4af2912 9 // them with the PWM cycle. This results in very slightly longer
mjr 26:cb71c4af2912 10 // blanking intervals when updates are pending, effectively reducing
mjr 26:cb71c4af2912 11 // the PWM "on" duty cycle (and thus the output brightness) by about
mjr 26:cb71c4af2912 12 // 0.3%. This shouldn't be perceptible to users, so it's a small
mjr 26:cb71c4af2912 13 // trade-off for the advantage gained, which is much better signal
mjr 26:cb71c4af2912 14 // stability when using multiple TLC5940s daisy-chained together.
mjr 26:cb71c4af2912 15 // I saw a lot of instability when using the overlapped approach,
mjr 26:cb71c4af2912 16 // which seems to be eliminated entirely when sending updates during
mjr 26:cb71c4af2912 17 // the blanking interval.
mjr 26:cb71c4af2912 18
mjr 26:cb71c4af2912 19
mjr 26:cb71c4af2912 20 #ifndef TLC5940_H
mjr 26:cb71c4af2912 21 #define TLC5940_H
mjr 26:cb71c4af2912 22
mjr 38:091e511ce8a0 23 // Data Transmission Mode.
mjr 38:091e511ce8a0 24 //
mjr 38:091e511ce8a0 25 // NOTE! This section contains a possible workaround to try if you're
mjr 38:091e511ce8a0 26 // having data signal stability problems with your TLC5940 chips. If
mjr 40:cc0d9814522b 27 // things are working properly, you can ignore this part.
mjr 33:d832bcab089e 28 //
mjr 38:091e511ce8a0 29 // The software has two options for sending data updates to the chips:
mjr 38:091e511ce8a0 30 //
mjr 40:cc0d9814522b 31 // Mode 0: Send data *during* the grayscale cycle. This is the default,
mjr 40:cc0d9814522b 32 // and it's the standard method the chips are designed for. In this mode,
mjr 40:cc0d9814522b 33 // we start sending an update just after then blanking interval that starts
mjr 40:cc0d9814522b 34 // a new grayscale cycle. The timing is arranged so that the update is
mjr 40:cc0d9814522b 35 // completed well before the end of the grayscale cycle. At the next
mjr 40:cc0d9814522b 36 // blanking interval, we latch the new data, so the new brightness levels
mjr 40:cc0d9814522b 37 // will be shown starting on the next cycle.
mjr 40:cc0d9814522b 38
mjr 38:091e511ce8a0 39 // Mode 1: Send data *between* grayscale cycles. In this mode, we send
mjr 38:091e511ce8a0 40 // each complete update during a blanking period, then latch the update
mjr 38:091e511ce8a0 41 // and start the next grayscale cycle. This isn't the way the chips were
mjr 38:091e511ce8a0 42 // intended to be used, but it works. The disadvantage is that it requires
mjr 40:cc0d9814522b 43 // the blanking interval to be extended long enough for the full data
mjr 40:cc0d9814522b 44 // update (192 bits * the number of chips in the chain). Since the
mjr 40:cc0d9814522b 45 // outputs are turned off throughout the blanking period, this reduces
mjr 38:091e511ce8a0 46 // the overall brightness/intensity of the outputs by reducing the duty
mjr 38:091e511ce8a0 47 // cycle. The TLC5940 chips can't achieve 100% duty cycle to begin with,
mjr 40:cc0d9814522b 48 // since they require a brief minimum time in the blanking interval
mjr 38:091e511ce8a0 49 // between grayscale cycles; however, the minimum is so short that the
mjr 38:091e511ce8a0 50 // duty cycle is close to 100%. With the full data transmission stuffed
mjr 38:091e511ce8a0 51 // into the blanking interval, we reduce the duty cycle further below
mjr 38:091e511ce8a0 52 // 100%. With four chips in the chain, a 28 MHz data clock, and a
mjr 38:091e511ce8a0 53 // 500 kHz grayscale clock, the reduction is about 0.3%.
mjr 33:d832bcab089e 54 //
mjr 40:cc0d9814522b 55 // Mode 0 is the method documented in the manufacturer's data sheet.
mjr 40:cc0d9814522b 56 // It works well empirically with the Pinscape expansion boards.
mjr 40:cc0d9814522b 57 //
mjr 38:091e511ce8a0 58 // So what's the point of Mode 1? In early testing, with a breadboard
mjr 38:091e511ce8a0 59 // setup, I saw some problems with data signal stability, which manifested
mjr 38:091e511ce8a0 60 // as sporadic flickering in the outputs. Switching to Mode 1 improved
mjr 38:091e511ce8a0 61 // the signal stability considerably. I'm therefore leaving this code
mjr 38:091e511ce8a0 62 // available as an option in case anyone runs into similar signal problems
mjr 38:091e511ce8a0 63 // and wants to try the alternative mode as a workaround.
mjr 38:091e511ce8a0 64 //
mjr 38:091e511ce8a0 65 #define DATA_UPDATE_INSIDE_BLANKING 0
mjr 33:d832bcab089e 66
mjr 26:cb71c4af2912 67 #include "mbed.h"
mjr 26:cb71c4af2912 68 #include "FastPWM.h"
mjr 30:6e9902f06f48 69 #include "SimpleDMA.h"
mjr 47:df7a88cd249c 70 #include "DMAChannels.h"
mjr 26:cb71c4af2912 71
mjr 26:cb71c4af2912 72 /**
mjr 26:cb71c4af2912 73 * SPI speed used by the mbed to communicate with the TLC5940
mjr 26:cb71c4af2912 74 * The TLC5940 supports up to 30Mhz. It's best to keep this as
mjr 33:d832bcab089e 75 * high as possible, since a higher SPI speed yields a faster
mjr 33:d832bcab089e 76 * grayscale data update. However, I've seen some slight
mjr 33:d832bcab089e 77 * instability in the signal in my breadboard setup using the
mjr 33:d832bcab089e 78 * full 30MHz, so I've reduced this slightly, which seems to
mjr 33:d832bcab089e 79 * yield a solid signal. The limit will vary according to how
mjr 33:d832bcab089e 80 * clean the signal path is to the chips; you can probably crank
mjr 33:d832bcab089e 81 * this up to full speed if you have a well-designed PCB, good
mjr 33:d832bcab089e 82 * decoupling capacitors near the 5940 VCC/GND pins, and short
mjr 33:d832bcab089e 83 * wires between the KL25Z and the PCB. A short, clean path to
mjr 33:d832bcab089e 84 * KL25Z ground seems especially important.
mjr 26:cb71c4af2912 85 *
mjr 26:cb71c4af2912 86 * The SPI clock must be fast enough that the data transmission
mjr 26:cb71c4af2912 87 * time for a full update is comfortably less than the blanking
mjr 26:cb71c4af2912 88 * cycle time. The grayscale refresh requires 192 bits per TLC5940
mjr 26:cb71c4af2912 89 * in the daisy chain, and each bit takes one SPI clock to send.
mjr 26:cb71c4af2912 90 * Our reference setup in the Pinscape controller allows for up to
mjr 26:cb71c4af2912 91 * 4 TLC5940s, so a full refresh cycle on a fully populated system
mjr 26:cb71c4af2912 92 * would be 768 SPI clocks. The blanking cycle is 4096 GSCLK cycles.
mjr 26:cb71c4af2912 93 *
mjr 26:cb71c4af2912 94 * t(blank) = 4096 * 1/GSCLK_SPEED
mjr 26:cb71c4af2912 95 * t(refresh) = 768 * 1/SPI_SPEED
mjr 26:cb71c4af2912 96 * Therefore: SPI_SPEED must be > 768/4096 * GSCLK_SPEED
mjr 26:cb71c4af2912 97 *
mjr 26:cb71c4af2912 98 * Since the SPI speed can be so high, and since we want to keep
mjr 26:cb71c4af2912 99 * the GSCLK speed relatively low, the constraint above simply
mjr 26:cb71c4af2912 100 * isn't a factor. E.g., at SPI=30MHz and GSCLK=500kHz,
mjr 26:cb71c4af2912 101 * t(blank) is 8192us and t(refresh) is 25us.
mjr 26:cb71c4af2912 102 */
mjr 38:091e511ce8a0 103 #define SPI_SPEED 28000000
mjr 26:cb71c4af2912 104
mjr 26:cb71c4af2912 105 /**
mjr 26:cb71c4af2912 106 * The rate at which the GSCLK pin is pulsed. This also controls
mjr 26:cb71c4af2912 107 * how often the reset function is called. The reset function call
mjr 38:091e511ce8a0 108 * interval is (1/GSCLK_SPEED) * 4096. The maximum reliable rate is
mjr 26:cb71c4af2912 109 * around 32Mhz. It's best to keep this rate as low as possible:
mjr 26:cb71c4af2912 110 * the higher the rate, the higher the refresh() call frequency,
mjr 40:cc0d9814522b 111 * so the higher the CPU load. Higher frequencies also make it more
mjr 40:cc0d9814522b 112 * challenging to wire the chips for clean signal transmission, so
mjr 40:cc0d9814522b 113 * minimizing the clock speed will help with signal stability.
mjr 26:cb71c4af2912 114 *
mjr 40:cc0d9814522b 115 * The lower bound depends on the application. For driving lights,
mjr 40:cc0d9814522b 116 * the limiting factor is flicker: the lower the rate, the more
mjr 40:cc0d9814522b 117 * noticeable the flicker. Incandescents tend to look flicker-free
mjr 40:cc0d9814522b 118 * at about 50 Hz (205 kHz grayscale clock). LEDs need slightly
mjr 40:cc0d9814522b 119 * faster rates.
mjr 26:cb71c4af2912 120 */
mjr 40:cc0d9814522b 121 #define GSCLK_SPEED 350000
mjr 26:cb71c4af2912 122
mjr 26:cb71c4af2912 123 /**
mjr 26:cb71c4af2912 124 * This class controls a TLC5940 PWM driver IC.
mjr 26:cb71c4af2912 125 *
mjr 26:cb71c4af2912 126 * Using the TLC5940 class to control an LED:
mjr 26:cb71c4af2912 127 * @code
mjr 26:cb71c4af2912 128 * #include "mbed.h"
mjr 26:cb71c4af2912 129 * #include "TLC5940.h"
mjr 26:cb71c4af2912 130 *
mjr 26:cb71c4af2912 131 * // Create the TLC5940 instance
mjr 26:cb71c4af2912 132 * TLC5940 tlc(p7, p5, p21, p9, p10, p11, p12, 1);
mjr 26:cb71c4af2912 133 *
mjr 26:cb71c4af2912 134 * int main()
mjr 26:cb71c4af2912 135 * {
mjr 26:cb71c4af2912 136 * // Enable the first LED
mjr 26:cb71c4af2912 137 * tlc.set(0, 0xfff);
mjr 26:cb71c4af2912 138 *
mjr 26:cb71c4af2912 139 * while(1)
mjr 26:cb71c4af2912 140 * {
mjr 26:cb71c4af2912 141 * }
mjr 26:cb71c4af2912 142 * }
mjr 26:cb71c4af2912 143 * @endcode
mjr 26:cb71c4af2912 144 */
mjr 26:cb71c4af2912 145 class TLC5940
mjr 26:cb71c4af2912 146 {
mjr 26:cb71c4af2912 147 public:
mjr 26:cb71c4af2912 148 /**
mjr 26:cb71c4af2912 149 * Set up the TLC5940
mjr 26:cb71c4af2912 150 * @param SCLK - The SCK pin of the SPI bus
mjr 26:cb71c4af2912 151 * @param MOSI - The MOSI pin of the SPI bus
mjr 26:cb71c4af2912 152 * @param GSCLK - The GSCLK pin of the TLC5940(s)
mjr 26:cb71c4af2912 153 * @param BLANK - The BLANK pin of the TLC5940(s)
mjr 26:cb71c4af2912 154 * @param XLAT - The XLAT pin of the TLC5940(s)
mjr 26:cb71c4af2912 155 * @param nchips - The number of TLC5940s (if you are daisy chaining)
mjr 26:cb71c4af2912 156 */
mjr 26:cb71c4af2912 157 TLC5940(PinName SCLK, PinName MOSI, PinName GSCLK, PinName BLANK, PinName XLAT, int nchips)
mjr 47:df7a88cd249c 158 : sdma(DMAch_TLC5940),
mjr 47:df7a88cd249c 159 spi(MOSI, NC, SCLK),
mjr 26:cb71c4af2912 160 gsclk(GSCLK),
mjr 26:cb71c4af2912 161 blank(BLANK),
mjr 26:cb71c4af2912 162 xlat(XLAT),
mjr 33:d832bcab089e 163 nchips(nchips)
mjr 26:cb71c4af2912 164 {
mjr 40:cc0d9814522b 165 // start up initially disabled
mjr 40:cc0d9814522b 166 enabled = false;
mjr 40:cc0d9814522b 167
mjr 33:d832bcab089e 168 // set XLAT to initially off
mjr 30:6e9902f06f48 169 xlat = 0;
mjr 33:d832bcab089e 170
mjr 33:d832bcab089e 171 // Assert BLANK while starting up, to keep the outputs turned off until
mjr 33:d832bcab089e 172 // everything is stable. This helps prevent spurious flashes during startup.
mjr 33:d832bcab089e 173 // (That's not particularly important for lights, but it matters more for
mjr 33:d832bcab089e 174 // tactile devices. It's a bit alarming to fire a replay knocker on every
mjr 33:d832bcab089e 175 // power-on, for example.)
mjr 30:6e9902f06f48 176 blank = 1;
mjr 30:6e9902f06f48 177
mjr 26:cb71c4af2912 178 // Configure SPI format and speed. Note that KL25Z ONLY supports 8-bit
mjr 26:cb71c4af2912 179 // mode. The TLC5940 nominally requires 12-bit data blocks for the
mjr 26:cb71c4af2912 180 // grayscale levels, but SPI is ultimately just a bit-level serial format,
mjr 26:cb71c4af2912 181 // so we can reformat the 12-bit blocks into 8-bit bytes to fit the
mjr 26:cb71c4af2912 182 // KL25Z's limits. This should work equally well on other microcontrollers
mjr 38:091e511ce8a0 183 // that are more flexible. The TLC5940 requires polarity/phase format 0.
mjr 26:cb71c4af2912 184 spi.format(8, 0);
mjr 26:cb71c4af2912 185 spi.frequency(SPI_SPEED);
mjr 33:d832bcab089e 186
mjr 33:d832bcab089e 187 // Send out a full data set to the chips, to clear out any random
mjr 33:d832bcab089e 188 // startup data from the registers. Include some extra bits - there
mjr 33:d832bcab089e 189 // are some cases (such as after sending dot correct commands) where
mjr 33:d832bcab089e 190 // an extra bit per chip is required, and the initial state is
mjr 33:d832bcab089e 191 // somewhat unpredictable, so send extra just to make sure we cover
mjr 33:d832bcab089e 192 // all bases. This does no harm; extra bits just fall off the end of
mjr 33:d832bcab089e 193 // the daisy chain, and since we want all registers set to 0, we can
mjr 33:d832bcab089e 194 // send arbitrarily many extra 0's.
mjr 33:d832bcab089e 195 for (int i = 0 ; i < nchips*25 ; ++i)
mjr 33:d832bcab089e 196 spi.write(0);
mjr 33:d832bcab089e 197
mjr 33:d832bcab089e 198 // do an initial XLAT to latch all of these "0" values into the
mjr 33:d832bcab089e 199 // grayscale registers
mjr 33:d832bcab089e 200 xlat = 1;
mjr 33:d832bcab089e 201 xlat = 0;
mjr 29:582472d0bc57 202
mjr 39:b3815a1c3802 203 // Allocate our DMA buffers. The transfer on each cycle is 192 bits per
mjr 40:cc0d9814522b 204 // chip = 24 bytes per chip. Allocate two buffers, so that we have a
mjr 40:cc0d9814522b 205 // stable buffer that we can send to the chips, and a separate working
mjr 40:cc0d9814522b 206 // copy that we can asynchronously update.
mjr 40:cc0d9814522b 207 dmalen = nchips*24;
mjr 40:cc0d9814522b 208 dmabuf = new uint8_t[dmalen*2];
mjr 40:cc0d9814522b 209 memset(dmabuf, 0, dmalen*2);
mjr 26:cb71c4af2912 210
mjr 40:cc0d9814522b 211 zerobuf = new uint8_t[dmalen];//$$$
mjr 40:cc0d9814522b 212 memset(zerobuf, 0xff, dmalen);//$$$
mjr 40:cc0d9814522b 213
mjr 40:cc0d9814522b 214 // start with buffer 0 live, with no new data pending
mjr 40:cc0d9814522b 215 livebuf = dmabuf;
mjr 40:cc0d9814522b 216 workbuf = dmabuf + dmalen;
mjr 40:cc0d9814522b 217 dirty = false;
mjr 40:cc0d9814522b 218
mjr 30:6e9902f06f48 219 // Set up the Simple DMA interface object. We use the DMA controller to
mjr 30:6e9902f06f48 220 // send grayscale data updates to the TLC5940 chips. This lets the CPU
mjr 30:6e9902f06f48 221 // keep running other tasks while we send gs updates, and importantly
mjr 30:6e9902f06f48 222 // allows our blanking interrupt handler return almost immediately.
mjr 30:6e9902f06f48 223 // The DMA transfer is from our internal DMA buffer to SPI0, which is
mjr 30:6e9902f06f48 224 // the SPI controller physically connected to the TLC5940s.
mjr 40:cc0d9814522b 225 sdma.source(livebuf, true, 8);
mjr 38:091e511ce8a0 226 sdma.destination(&(SPI0->D), false, 8);
mjr 30:6e9902f06f48 227 sdma.trigger(Trigger_SPI0_TX);
mjr 30:6e9902f06f48 228 sdma.attach(this, &TLC5940::dmaDone);
mjr 30:6e9902f06f48 229
mjr 30:6e9902f06f48 230 // Enable DMA on SPI0. SimpleDMA doesn't do this for us; we have to
mjr 30:6e9902f06f48 231 // do it explicitly. This is just a matter of setting bit 5 (TXDMAE)
mjr 38:091e511ce8a0 232 // in the SPI controller's Control Register 2 (C2).
mjr 30:6e9902f06f48 233 SPI0->C2 |= 0x20; // set bit 5 = 0x20 = TXDMAE in SPI0 control register 2
mjr 30:6e9902f06f48 234
mjr 30:6e9902f06f48 235 // Configure the GSCLK output's frequency
mjr 26:cb71c4af2912 236 gsclk.period(1.0/GSCLK_SPEED);
mjr 33:d832bcab089e 237
mjr 33:d832bcab089e 238 // mark that we need an initial update
mjr 40:cc0d9814522b 239 dirty = true;
mjr 33:d832bcab089e 240 needXlat = false;
mjr 40:cc0d9814522b 241 }
mjr 40:cc0d9814522b 242
mjr 40:cc0d9814522b 243 // Global enable/disble. When disabled, we assert the blanking signal
mjr 40:cc0d9814522b 244 // continuously to keep all outputs turned off. This can be used during
mjr 40:cc0d9814522b 245 // startup and sleep mode to prevent spurious output signals from
mjr 40:cc0d9814522b 246 // uninitialized grayscale registers. The chips have random values in
mjr 40:cc0d9814522b 247 // their internal registers when power is first applied, so we have to
mjr 40:cc0d9814522b 248 // explicitly send the initial zero levels after power cycling the chips.
mjr 40:cc0d9814522b 249 // The chips might not have power even when the KL25Z is running, because
mjr 40:cc0d9814522b 250 // they might be powered from a separate power supply from the KL25Z
mjr 40:cc0d9814522b 251 // (the Pinscape Expansion Boards work this way). Global blanking helps
mjr 40:cc0d9814522b 252 // us start up more cleanly by suppressing all outputs until we can be
mjr 40:cc0d9814522b 253 // reasonably sure that the various chip registers are initialized.
mjr 40:cc0d9814522b 254 void enable(bool f)
mjr 40:cc0d9814522b 255 {
mjr 40:cc0d9814522b 256 // note the new setting
mjr 40:cc0d9814522b 257 enabled = f;
mjr 40:cc0d9814522b 258
mjr 40:cc0d9814522b 259 // if disabled, apply blanking immediately
mjr 40:cc0d9814522b 260 if (!f)
mjr 40:cc0d9814522b 261 {
mjr 40:cc0d9814522b 262 gsclk.write(0);
mjr 40:cc0d9814522b 263 blank = 1;
mjr 40:cc0d9814522b 264 }
mjr 40:cc0d9814522b 265
mjr 40:cc0d9814522b 266 // do a full update with the new setting
mjr 40:cc0d9814522b 267 dirty = true;
mjr 40:cc0d9814522b 268 }
mjr 29:582472d0bc57 269
mjr 30:6e9902f06f48 270 // Start the clock running
mjr 29:582472d0bc57 271 void start()
mjr 29:582472d0bc57 272 {
mjr 26:cb71c4af2912 273 // Set up the first call to the reset function, which asserts BLANK to
mjr 26:cb71c4af2912 274 // end the PWM cycle and handles new grayscale data output and latching.
mjr 26:cb71c4af2912 275 // The original version of this library uses a timer to call reset
mjr 26:cb71c4af2912 276 // periodically, but that approach is somewhat problematic because the
mjr 26:cb71c4af2912 277 // reset function itself takes a small amount of time to run, so the
mjr 26:cb71c4af2912 278 // *actual* cycle is slightly longer than what we get from counting
mjr 26:cb71c4af2912 279 // GS clocks. Running reset on a timer therefore causes the calls to
mjr 26:cb71c4af2912 280 // slip out of phase with the actual full cycles, which causes
mjr 26:cb71c4af2912 281 // premature blanking that shows up as visible flicker. To get the
mjr 26:cb71c4af2912 282 // reset cycle to line up exactly with a full PWM cycle, it works
mjr 26:cb71c4af2912 283 // better to set up a new timer on each cycle, *after* we've finished
mjr 26:cb71c4af2912 284 // with the somewhat unpredictable overhead of the interrupt handler.
mjr 26:cb71c4af2912 285 // This ensures that we'll get much closer to exact alignment of the
mjr 26:cb71c4af2912 286 // cycle phase, and in any case the worst that happens is that some
mjr 26:cb71c4af2912 287 // cycles are very slightly too long or short (due to imperfections
mjr 26:cb71c4af2912 288 // in the timer clock vs the PWM clock that determines the GSCLCK
mjr 26:cb71c4af2912 289 // output to the TLC5940), which is far less noticeable than a
mjr 26:cb71c4af2912 290 // constantly rotating phase misalignment.
mjr 38:091e511ce8a0 291 resetTimer.attach(this, &TLC5940::reset, (1.0/GSCLK_SPEED)*4096.0);
mjr 26:cb71c4af2912 292 }
mjr 26:cb71c4af2912 293
mjr 26:cb71c4af2912 294 ~TLC5940()
mjr 26:cb71c4af2912 295 {
mjr 30:6e9902f06f48 296 delete [] dmabuf;
mjr 26:cb71c4af2912 297 }
mjr 26:cb71c4af2912 298
mjr 39:b3815a1c3802 299 /*
mjr 39:b3815a1c3802 300 * Set an output
mjr 26:cb71c4af2912 301 */
mjr 26:cb71c4af2912 302 void set(int idx, unsigned short data)
mjr 26:cb71c4af2912 303 {
mjr 39:b3815a1c3802 304 // validate the index
mjr 39:b3815a1c3802 305 if (idx >= 0 && idx < nchips*16)
mjr 39:b3815a1c3802 306 {
mjr 40:cc0d9814522b 307 // this is a critical section, since we're updating a static buffer and
mjr 40:cc0d9814522b 308 // can call this routine from application context or interrupt context
mjr 40:cc0d9814522b 309 __disable_irq();
mjr 40:cc0d9814522b 310
mjr 40:cc0d9814522b 311 // If the buffer isn't dirty, it means that the previous working buffer
mjr 40:cc0d9814522b 312 // was swapped into the live buffer on the last blanking interval. This
mjr 40:cc0d9814522b 313 // means that the working buffer hasn't been updated to the live data yet,
mjr 40:cc0d9814522b 314 // so we need to copy it now.
mjr 40:cc0d9814522b 315 if (!dirty)
mjr 40:cc0d9814522b 316 {
mjr 40:cc0d9814522b 317 memcpy(workbuf, livebuf, dmalen);
mjr 40:cc0d9814522b 318 dirty = true;
mjr 40:cc0d9814522b 319 }
mjr 40:cc0d9814522b 320
mjr 39:b3815a1c3802 321 // Figure the DMA buffer location of the data. The DMA buffer has the
mjr 39:b3815a1c3802 322 // packed bit format that we send across the wire, with 12 bits per output,
mjr 39:b3815a1c3802 323 // arranged from last output to first output (N = number of outputs = nchips*16):
mjr 39:b3815a1c3802 324 //
mjr 39:b3815a1c3802 325 // byte 0 = high 8 bits of output N-1
mjr 39:b3815a1c3802 326 // 1 = low 4 bits of output N-1 | high 4 bits of output N-2
mjr 39:b3815a1c3802 327 // 2 = low 8 bits of N-2
mjr 39:b3815a1c3802 328 // 3 = high 8 bits of N-3
mjr 39:b3815a1c3802 329 // 4 = low 4 bits of N-3 | high 4 bits of N-2
mjr 39:b3815a1c3802 330 // 5 = low 8bits of N-4
mjr 39:b3815a1c3802 331 // ...
mjr 39:b3815a1c3802 332 // 24*nchips-3 = high 8 bits of output 1
mjr 39:b3815a1c3802 333 // 24*nchips-2 = low 4 bits of output 1 | high 4 bits of output 0
mjr 39:b3815a1c3802 334 // 24*nchips-1 = low 8 bits of output 0
mjr 39:b3815a1c3802 335 //
mjr 39:b3815a1c3802 336 // So this update will affect two bytes. If the output number if even, we're
mjr 39:b3815a1c3802 337 // in the high 4 + low 8 pair; if odd, we're in the high 8 + low 4 pair.
mjr 39:b3815a1c3802 338 int di = nchips*24 - 3 - (3*(idx/2));
mjr 39:b3815a1c3802 339 if (idx & 1)
mjr 39:b3815a1c3802 340 {
mjr 39:b3815a1c3802 341 // ODD = high 8 | low 4
mjr 40:cc0d9814522b 342 workbuf[di] = uint8_t((data >> 4) & 0xff);
mjr 40:cc0d9814522b 343 workbuf[di+1] &= 0x0F;
mjr 40:cc0d9814522b 344 workbuf[di+1] |= uint8_t((data << 4) & 0xf0);
mjr 39:b3815a1c3802 345 }
mjr 39:b3815a1c3802 346 else
mjr 39:b3815a1c3802 347 {
mjr 39:b3815a1c3802 348 // EVEN = high 4 | low 8
mjr 40:cc0d9814522b 349 workbuf[di+1] &= 0xF0;
mjr 40:cc0d9814522b 350 workbuf[di+1] |= uint8_t((data >> 8) & 0x0f);
mjr 40:cc0d9814522b 351 workbuf[di+2] = uint8_t(data & 0xff);
mjr 39:b3815a1c3802 352 }
mjr 39:b3815a1c3802 353
mjr 40:cc0d9814522b 354 // end the critical section
mjr 40:cc0d9814522b 355 __enable_irq();
mjr 39:b3815a1c3802 356 }
mjr 26:cb71c4af2912 357 }
mjr 40:cc0d9814522b 358
mjr 40:cc0d9814522b 359 // Update the outputs. We automatically update the outputs on the grayscale timer
mjr 40:cc0d9814522b 360 // when we have pending changes, so it's not necessary to call this explicitly after
mjr 40:cc0d9814522b 361 // making a change via set(). This can be called to force an update when the chips
mjr 40:cc0d9814522b 362 // might be out of sync with our internal state, such as after power-on.
mjr 40:cc0d9814522b 363 void update(bool force = false)
mjr 40:cc0d9814522b 364 {
mjr 40:cc0d9814522b 365 if (force)
mjr 40:cc0d9814522b 366 dirty = true;
mjr 40:cc0d9814522b 367 }
mjr 26:cb71c4af2912 368
mjr 26:cb71c4af2912 369 private:
mjr 26:cb71c4af2912 370 // current level for each output
mjr 26:cb71c4af2912 371 unsigned short *gs;
mjr 26:cb71c4af2912 372
mjr 30:6e9902f06f48 373 // Simple DMA interface object
mjr 30:6e9902f06f48 374 SimpleDMA sdma;
mjr 30:6e9902f06f48 375
mjr 40:cc0d9814522b 376 // DMA transfer buffers - double buffer. Each time we have data to transmit to the
mjr 40:cc0d9814522b 377 // TLC5940 chips, we format the data into the working half of this buffer exactly as
mjr 40:cc0d9814522b 378 // it will go across the wire, then hand the buffer to the DMA controller to move
mjr 40:cc0d9814522b 379 // through the SPI port. This memory block is actually two buffers, one live and
mjr 40:cc0d9814522b 380 // one pending. When we're ready to send updates to the chips, we swap the working
mjr 40:cc0d9814522b 381 // buffer into the live buffer so that we can send the latest updates. We keep a
mjr 40:cc0d9814522b 382 // separate working copy so that our live copy is stable, so that we don't alter
mjr 40:cc0d9814522b 383 // any data in the midst of an asynchronous DMA transmission to the chips.
mjr 40:cc0d9814522b 384 uint8_t *dmabuf;
mjr 40:cc0d9814522b 385
mjr 40:cc0d9814522b 386 uint8_t *zerobuf; // $$$ buffer for all zeroes to flush chip registers when no updates are needed
mjr 40:cc0d9814522b 387
mjr 40:cc0d9814522b 388 // The working and live buffer pointers. At any give time, one buffer is live and
mjr 40:cc0d9814522b 389 // the other is active.
mjr 40:cc0d9814522b 390 // dmabuf1 is live and the other is the working buffer. When there's pending work,
mjr 40:cc0d9814522b 391 // we swap them to make the pending data live.
mjr 40:cc0d9814522b 392 uint8_t *livebuf;
mjr 40:cc0d9814522b 393 uint8_t *workbuf;
mjr 40:cc0d9814522b 394
mjr 40:cc0d9814522b 395 // length of each DMA buffer, in bytes - 12 bits = 1.5 bytes per output, 16 outputs
mjr 40:cc0d9814522b 396 // per chip -> 24 bytes per chip
mjr 40:cc0d9814522b 397 uint16_t dmalen;
mjr 40:cc0d9814522b 398
mjr 40:cc0d9814522b 399 // Dirty: true means that the non-live buffer has new pending data. False means
mjr 40:cc0d9814522b 400 // that the non-live buffer is empty.
mjr 40:cc0d9814522b 401 bool dirty;
mjr 40:cc0d9814522b 402
mjr 40:cc0d9814522b 403 // Enabled: this enables or disables all outputs. When this is true, we assert the
mjr 40:cc0d9814522b 404 // BLANK signal continuously.
mjr 40:cc0d9814522b 405 bool enabled;
mjr 30:6e9902f06f48 406
mjr 26:cb71c4af2912 407 // SPI port - only MOSI and SCK are used
mjr 26:cb71c4af2912 408 SPI spi;
mjr 26:cb71c4af2912 409
mjr 26:cb71c4af2912 410 // use a PWM out for the grayscale clock - this provides a stable
mjr 26:cb71c4af2912 411 // square wave signal without consuming CPU
mjr 26:cb71c4af2912 412 FastPWM gsclk;
mjr 26:cb71c4af2912 413
mjr 26:cb71c4af2912 414 // Digital out pins used for the TLC5940
mjr 26:cb71c4af2912 415 DigitalOut blank;
mjr 26:cb71c4af2912 416 DigitalOut xlat;
mjr 26:cb71c4af2912 417
mjr 26:cb71c4af2912 418 // number of daisy-chained TLC5940s we're controlling
mjr 26:cb71c4af2912 419 int nchips;
mjr 26:cb71c4af2912 420
mjr 26:cb71c4af2912 421 // Timeout to end each PWM cycle. This is a one-shot timer that we reset
mjr 26:cb71c4af2912 422 // on each cycle.
mjr 38:091e511ce8a0 423 Timeout resetTimer;
mjr 26:cb71c4af2912 424
mjr 33:d832bcab089e 425 // Do we need an XLAT signal on the next blanking interval?
mjr 33:d832bcab089e 426 volatile bool needXlat;
mjr 40:cc0d9814522b 427 volatile bool newGSData;//$$$
mjr 26:cb71c4af2912 428
mjr 40:cc0d9814522b 429 // Reset the grayscale cycle and send the next data update
mjr 26:cb71c4af2912 430 void reset()
mjr 26:cb71c4af2912 431 {
mjr 30:6e9902f06f48 432 // start the blanking cycle
mjr 30:6e9902f06f48 433 startBlank();
mjr 33:d832bcab089e 434
mjr 40:cc0d9814522b 435 // if we have pending grayscale data, update the DMA data
mjr 40:cc0d9814522b 436 /*$$$bool*/ newGSData = false;
mjr 40:cc0d9814522b 437 if (dirty)
mjr 40:cc0d9814522b 438 {
mjr 40:cc0d9814522b 439 // swap live and working buffers
mjr 40:cc0d9814522b 440 uint8_t *tmp = livebuf;
mjr 40:cc0d9814522b 441 livebuf = workbuf;
mjr 40:cc0d9814522b 442 workbuf = tmp;
mjr 40:cc0d9814522b 443
mjr 40:cc0d9814522b 444 // set the new DMA source
mjr 40:cc0d9814522b 445 sdma.source(livebuf, true, 8);
mjr 40:cc0d9814522b 446
mjr 40:cc0d9814522b 447 // no longer dirty
mjr 40:cc0d9814522b 448 dirty = false;
mjr 40:cc0d9814522b 449
mjr 40:cc0d9814522b 450 // note the new data
mjr 40:cc0d9814522b 451 newGSData = true;
mjr 40:cc0d9814522b 452 }
mjr 40:cc0d9814522b 453 else { sdma.source(zerobuf, true, 8); }//$$$
mjr 40:cc0d9814522b 454
mjr 33:d832bcab089e 455 #if DATA_UPDATE_INSIDE_BLANKING
mjr 33:d832bcab089e 456 // We're configured to send the new GS data entirely within
mjr 33:d832bcab089e 457 // the blanking interval. Start the DMA transfer now, and
mjr 33:d832bcab089e 458 // return without ending the blanking interval. The DMA
mjr 33:d832bcab089e 459 // completion interrupt handler will do that when the data
mjr 33:d832bcab089e 460 // update has completed.
mjr 33:d832bcab089e 461 //
mjr 33:d832bcab089e 462 // Note that we do the data update/ unconditionally in the
mjr 33:d832bcab089e 463 // send-during-blanking case, whether or not we have new GS
mjr 33:d832bcab089e 464 // data. This is because the update causes a 0.3% reduction
mjr 33:d832bcab089e 465 // in brightness because of the elongated BLANK interval.
mjr 33:d832bcab089e 466 // That would be visible as a flicker on each update if we
mjr 33:d832bcab089e 467 // did updates on some cycles and not others. By doing an
mjr 33:d832bcab089e 468 // update on every cycle, we make the brightness reduction
mjr 33:d832bcab089e 469 // uniform across time, which makes it less perceptible.
mjr 40:cc0d9814522b 470 sdma.start(dmalen);
mjr 33:d832bcab089e 471
mjr 33:d832bcab089e 472 #else // DATA_UPDATE_INSIDE_BLANKING
mjr 33:d832bcab089e 473
mjr 33:d832bcab089e 474 // end the blanking interval
mjr 33:d832bcab089e 475 endBlank();
mjr 33:d832bcab089e 476
mjr 40:cc0d9814522b 477 // send out the DMA contents if we have new data
mjr 40:cc0d9814522b 478 //$$$ if (newGSData)
mjr 40:cc0d9814522b 479 sdma.start(dmalen);
mjr 26:cb71c4af2912 480
mjr 33:d832bcab089e 481 #endif // DATA_UPDATE_INSIDE_BLANKING
mjr 30:6e9902f06f48 482 }
mjr 30:6e9902f06f48 483
mjr 30:6e9902f06f48 484 void startBlank()
mjr 30:6e9902f06f48 485 {
mjr 30:6e9902f06f48 486 // turn off the grayscale clock, and assert BLANK to end the grayscale cycle
mjr 30:6e9902f06f48 487 gsclk.write(0);
mjr 40:cc0d9814522b 488 blank = 0; // for a slight delay - chip requires 20ns GSCLK up to BLANK up
mjr 30:6e9902f06f48 489 blank = 1;
mjr 30:6e9902f06f48 490 }
mjr 26:cb71c4af2912 491
mjr 33:d832bcab089e 492 void endBlank()
mjr 30:6e9902f06f48 493 {
mjr 33:d832bcab089e 494 // if we've sent new grayscale data since the last blanking
mjr 33:d832bcab089e 495 // interval, latch it by asserting XLAT
mjr 33:d832bcab089e 496 if (needXlat)
mjr 30:6e9902f06f48 497 {
mjr 26:cb71c4af2912 498 // latch the new data while we're still blanked
mjr 26:cb71c4af2912 499 xlat = 1;
mjr 26:cb71c4af2912 500 xlat = 0;
mjr 33:d832bcab089e 501 needXlat = false;
mjr 26:cb71c4af2912 502 }
mjr 26:cb71c4af2912 503
mjr 40:cc0d9814522b 504 // End the blanking interval and restart the grayscale clock. Note
mjr 40:cc0d9814522b 505 // that we keep the blanking on if the chips are globally disabled.
mjr 40:cc0d9814522b 506 blank = enabled ? 0 : 1;
mjr 26:cb71c4af2912 507 gsclk.write(.5);
mjr 26:cb71c4af2912 508
mjr 26:cb71c4af2912 509 // set up the next blanking interrupt
mjr 38:091e511ce8a0 510 resetTimer.attach(this, &TLC5940::reset, (1.0/GSCLK_SPEED)*4096.0);
mjr 26:cb71c4af2912 511 }
mjr 26:cb71c4af2912 512
mjr 30:6e9902f06f48 513 // Interrupt handler for DMA completion. The DMA controller calls this
mjr 30:6e9902f06f48 514 // when it finishes with the transfer request we set up above. When the
mjr 30:6e9902f06f48 515 // transfer is done, we simply end the blanking cycle and start a new
mjr 30:6e9902f06f48 516 // grayscale cycle.
mjr 30:6e9902f06f48 517 void dmaDone()
mjr 30:6e9902f06f48 518 {
mjr 33:d832bcab089e 519 // mark that we need to assert XLAT to latch the new
mjr 33:d832bcab089e 520 // grayscale data during the next blanking interval
mjr 40:cc0d9814522b 521 needXlat = newGSData;//$$$ true;
mjr 33:d832bcab089e 522
mjr 33:d832bcab089e 523 #if DATA_UPDATE_INSIDE_BLANKING
mjr 33:d832bcab089e 524 // we're doing the gs update within the blanking cycle, so end
mjr 33:d832bcab089e 525 // the blanking cycle now that the transfer has completed
mjr 33:d832bcab089e 526 endBlank();
mjr 33:d832bcab089e 527 #endif
mjr 30:6e9902f06f48 528 }
mjr 30:6e9902f06f48 529
mjr 26:cb71c4af2912 530 };
mjr 26:cb71c4af2912 531
mjr 26:cb71c4af2912 532 #endif