An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.

Dependencies:   mbed FastIO FastPWM USBDevice

Fork of Pinscape_Controller by Mike R

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TLC5940.h Source File

TLC5940.h

00001 // Pinscape Controller TLC5940 interface
00002 //
00003 // Based on Spencer Davis's mbed TLC5940 library.  Adapted for the
00004 // KL25Z and simplified (removes dot correction and status input 
00005 // support).
00006 
00007  
00008 #ifndef TLC5940_H
00009 #define TLC5940_H
00010 
00011 #include "NewPwm.h"
00012 
00013 // --------------------------------------------------------------------------
00014 // Data Transmission Mode.
00015 //
00016 // NOTE!  This section contains a possible workaround to try if you're 
00017 // having data signal stability problems with your TLC5940 chips.  If
00018 // things are working properly, you can ignore this part.
00019 //
00020 // The software has two options for sending data updates to the chips:
00021 //
00022 // Mode 0:  Send data *during* the grayscale cycle.  This is the default,
00023 // and it's the standard method the chips are designed for.  In this mode, 
00024 // we start sending an update just after then blanking interval that starts 
00025 // a new grayscale cycle.  The timing is arranged so that the update is 
00026 // completed well before the end of the grayscale cycle.  At the next 
00027 // blanking interval, we latch the new data, so the new brightness levels 
00028 // will be shown starting on the next cycle.
00029 //
00030 // Mode 1:  Send data *between* grayscale cycles.  In this mode, we send
00031 // each complete update during a blanking period, then latch the update
00032 // and start the next grayscale cycle.  This isn't the way the chips were
00033 // intended to be used, but it works.  The disadvantage is that it requires
00034 // the blanking interval to be extended long enough for the full data 
00035 // update (192 bits * the number of chips in the chain).  Since the
00036 // outputs are turned off throughout the blanking period, this reduces
00037 // the overall brightness/intensity of the outputs by reducing the duty
00038 // cycle.  The TLC5940 chips can't achieve 100% duty cycle to begin with,
00039 // since they require a brief minimum time in the blanking interval
00040 // between grayscale cycles; however, the minimum is so short that the
00041 // duty cycle is close to 100%.  With the full data transmission stuffed
00042 // into the blanking interval, we reduce the duty cycle further below
00043 // 100%.  With four chips in the chain, a 28 MHz data clock, and a
00044 // 500 kHz grayscale clock, the reduction is about 0.3%.
00045 //
00046 // Mode 0 is the method documented in the manufacturer's data sheet.
00047 // It works well empirically with the Pinscape expansion boards.
00048 //
00049 // So what's the point of Mode 1?  In early testing, with a breadboard 
00050 // setup, I saw some problems with data signal stability, which manifested 
00051 // as sporadic flickering in the outputs.  Switching to Mode 1 improved
00052 // the signal stability considerably.  I'm therefore leaving this code
00053 // available as an option in case anyone runs into similar signal problems
00054 // and wants to try the alternative mode as a workaround.
00055 //
00056 #define DATA_UPDATE_INSIDE_BLANKING  0
00057 
00058 #include "mbed.h"
00059 
00060 
00061 // --------------------------------------------------------------------------
00062 // Some notes on the data transmission design
00063 //
00064 // I spent a while working on using DMA to send the data, thinking that
00065 // this would reduce the CPU load.  But I couldn't get this working
00066 // reliably; there was some kind of timing interaction or race condition
00067 // that caused crashes when initiating the DMA transfer from within the
00068 // blanking interrupt.  I spent quite a while trying to debug it and
00069 // couldn't figure out what was going on.  There are some complications
00070 // involved in using DMA with SPI that are documented in the KL25Z
00071 // reference manual, and I was following those carefully, but I suspect
00072 // that the problem was somehow related to that, because it seemed to
00073 // be sporadic and timing-related, and I couldn't find any software race
00074 // conditions or concurrency issues that could explain it.
00075 //
00076 // I finally decided that I wasn't going to crack that and started looking
00077 // for alternatives, so out of curiosity, I measured the time needed for a 
00078 // synchronous (CPU-driven) SPI send, to see how it would fit into various
00079 // places in the code.  This turned out to be faster than I expected: with
00080 // SPI at 28MHz, the measured time for a synchronous send is about 72us for
00081 // 4 chips worth of GS data (192 bits), which I expect to be the typical
00082 // Expansion Board setup.  For an 8-chip setup, which will probably be 
00083 // about the maximum workable setup, the time would be 144us.  We only have
00084 // to send the data once per grayscale cycle, and each cycle is 11.7ms with 
00085 // the grayscale clock at 350kHz (4096 steps per cycle divided by 350,000 
00086 // steps per second = 11.7ms per cycle), so this is only 1% overhead.  The 
00087 // main loop spends most of its time polling anyway, so we have plenty of 
00088 // cycles to reallocate from idle polling to the sending the data.
00089 //
00090 // The easiest place to do the send is in the blanking interval ISR, but
00091 // I wanted to keep this out of the ISR.  It's only ~100us, but even so,
00092 // it's critical to minimize time in ISRs so that we don't miss other 
00093 // interrupts.  So instead, I set it up so that the ISR coordinates with
00094 // the main loop via a flag:
00095 //
00096 //  - In the blanking interrupt, set a flag ("cts" = clear to send),
00097 //    and arm a timeout that fires 2/3 through the next blanking cycle
00098 //
00099 //  - In the main loop, poll "cts" each time through the loop.  When 
00100 //    cts is true, send the data synchronously and clear the flag.
00101 //    Do nothing when cts is false.
00102 //
00103 // The main loop runs on about a 1.5ms cycle, and 2/3 of the grayscale
00104 // cycle is 8ms, so the main loop will poll cts on average 5 times per
00105 // 8ms window.  That makes it all but certain that we'll do a send in
00106 // a timely fashion on every grayscale cycle.
00107 //
00108 // The point of the 2/3 window is to guarantee that the data send is
00109 // finished before the grayscale cycle ends.  The TLC5940 chips require
00110 // this; data transmission has to be entirely between blanking intervals.
00111 // The main loop and interrupt handler are operating asynchronously
00112 // relative to one another, so the exact phase alignment will vary
00113 // randomly.  If we start a transmission within the 2/3 window, we're
00114 // guaranteed to have at least 3.5ms (1/3 of the cycle) left before
00115 // the next blanking interval.  The transmission only takes ~100us,
00116 // so we're leaving tons of margin for error in the timing - we have
00117 // 34x longer than we need.
00118 //
00119 // The main loop can easily absorb the extra ~100us of overhead without
00120 // even noticing.  The loop spends most of its time polling devices, so
00121 // it's really mostly idle time to start with.  So we're effectively
00122 // reallocating some idle time to useful work.  The chunk of time is
00123 // only about 6% of one loop iteration, so we're not even significantly
00124 // extending the occasional iterations that actually do this work.
00125 // (If we had a 2ms chunk of monolithic work to do, that could start
00126 // to add undesirable latency to other polling tasks.  100us won't.)
00127 //
00128 // We could conceivably reduce this overhead slightly by adding DMA, 
00129 // but I'm not sure it would actually do much good.  Setting up the DMA
00130 // transfer would probably take at least 20us in CPU time just to set
00131 // up all of the registers.  And SPI is so fast that the DMA transfer
00132 // would saturate the CPU memory bus for the 30us or so of the transfer.
00133 // (I have my suspicions that this bus saturation effect might be part
00134 // of the problem I was having getting DMA working in the first place.)
00135 // So we'd go from 100us of overhead per cycle to at maybe 50us per 
00136 // cycle.  We'd also have to introduce some concurrency controls to the 
00137 // output "set" operation that we don't need with the current scheme 
00138 // (because it's synchronous).  So overall I think the current
00139 // synchronous approach is almost as good in terms of performance as 
00140 // an asynchronous DMA setup would be, and it's a heck of a lot simpler
00141 // and seems very reliable.
00142 //
00143 // --------------------------------------------------------------------------
00144 
00145 
00146 /**
00147   * SPI speed used by the mbed to communicate with the TLC5940
00148   * The TLC5940 supports up to 30Mhz.  It's best to keep this as
00149   * high as possible, since a higher SPI speed yields a faster 
00150   * grayscale data update.  However, I've seen some slight
00151   * instability in the signal in my breadboard setup using the
00152   * full 30MHz, so I've reduced this slightly, which seems to
00153   * yield a solid signal.  The limit will vary according to how
00154   * clean the signal path is to the chips; you can probably crank
00155   * this up to full speed if you have a well-designed PCB, good
00156   * decoupling capacitors near the 5940 VCC/GND pins, and short
00157   * wires between the KL25Z and the PCB.  A short, clean path to
00158   * KL25Z ground seems especially important.
00159   *
00160   * The SPI clock must be fast enough that the data transmission
00161   * time for a full update is comfortably less than the blanking 
00162   * cycle time.  The grayscale refresh requires 192 bits per TLC5940 
00163   * in the daisy chain, and each bit takes one SPI clock to send.  
00164   * Our reference setup in the Pinscape controller allows for up to 
00165   * 4 TLC5940s, so a full refresh cycle on a fully populated system 
00166   * would be 768 SPI clocks.  The blanking cycle is 4096 GSCLK cycles.  
00167   *
00168   *   t(blank) = 4096 * 1/GSCLK_SPEED
00169   *   t(refresh) = 768 * 1/SPI_SPEED
00170   *   Therefore:  SPI_SPEED must be > 768/4096 * GSCLK_SPEED
00171   *
00172   * Since the SPI speed can be so high, and since we want to keep
00173   * the GSCLK speed relatively low, the constraint above simply
00174   * isn't a factor.  E.g., at SPI=30MHz and GSCLK=500kHz, 
00175   * t(blank) is 8192us and t(refresh) is 25us.
00176   */
00177 #define SPI_SPEED 28000000
00178 
00179 /**
00180   * The rate at which the GSCLK pin is pulsed.   This also controls 
00181   * how often the reset function is called.   The reset function call
00182   * interval in seconds is (4096/GSCLK_SPEED).  The maximum reliable 
00183   * rate is around 32Mhz.  It's best to keep this rate as low as 
00184   * possible:  the higher the rate, the higher the refresh() call 
00185   * frequency, so the higher the CPU load.  Higher frequencies also 
00186   * make it more challenging to wire the chips for clean signal 
00187   * transmission.  Lower clock speeds are more forgiving of wiring
00188   * quality.
00189   *
00190   * The lower bound depends on the application.  For driving lights,
00191   * the limiting factor is flicker: the lower the rate, the more
00192   * noticeable the flicker.  Incandescents tend to look flicker-free
00193   * at about 50 Hz (205 kHz grayscale clock).  LEDs need significantly 
00194   * faster rates than incandescents, since they don't have the thermal
00195   * lag of incandescents; for flicker-free LEDs, you usually need at
00196   * least 200Hz (GSCLK_SPEED 819200).
00197   */
00198 #define GSCLK_SPEED    350000
00199 
00200 class TLC5940
00201 {
00202 public:
00203     /**
00204       *  Set up the TLC5940
00205       *
00206       *  @param SCLK - The SCK pin of the SPI bus
00207       *  @param MOSI - The MOSI pin of the SPI bus
00208       *  @param GSCLK - The GSCLK pin of the TLC5940(s)
00209       *  @param BLANK - The BLANK pin of the TLC5940(s)
00210       *  @param XLAT - The XLAT pin of the TLC5940(s)
00211       *  @param nchips - The number of TLC5940s (if you are daisy chaining)
00212       */
00213     TLC5940(PinName SCLK, PinName MOSI, PinName GSCLK, PinName BLANK, PinName XLAT, int nchips)
00214         : spi(MOSI, NC, SCLK),
00215           gsclk(GSCLK),
00216           blank(BLANK, 1),
00217           xlat(XLAT),
00218           nchips(nchips)
00219     {
00220         // start up initially disabled
00221         enabled = false;
00222         
00223         // set XLAT to initially off
00224         xlat = 0;
00225         
00226         // Assert BLANK while starting up, to keep the outputs turned off until
00227         // everything is stable.  This helps prevent spurious flashes during startup.
00228         // (That's not particularly important for lights, but it matters more for
00229         // tactile devices.  It's a bit alarming to fire a replay knocker on every
00230         // power-on, for example.)
00231         blank = 1;
00232         
00233         // Configure SPI format and speed.  The KL25Z only supports 8-bit mode.
00234         // We nominally need to write the data in 12-bit chunks for the TLC5940
00235         // grayscale levels, but SPI is ultimately just a bit-level serial format,
00236         // so we can reformat the 12-bit blocks into 8-bit bytes to fit the 
00237         // KL25Z's limits.  This should work equally well on other microcontrollers 
00238         // that are more flexible.  The TLC5940 requires polarity/phase format 0.
00239         spi.format(8, 0);
00240         spi.frequency(SPI_SPEED);
00241         
00242         // Send out a full data set to the chips, to clear out any random
00243         // startup data from the registers.  Include some extra bits - there
00244         // are some cases (such as after sending dot correct commands) where
00245         // an extra bit per chip is required, and the initial state is 
00246         // unpredictable, so send extra bits to make sure we cover all bases.  
00247         // This does no harm; extra bits just fall off the end of the daisy 
00248         // chain, and since we want all registers initially set to 0, we can 
00249         // send arbitrarily many extra 0's.
00250         for (int i = 0 ; i < nchips*25 ; ++i)
00251             spi.write(0x00);
00252             
00253         // do an initial XLAT to latch all of these "0" values into the
00254         // grayscale registers
00255         xlat = 1;
00256         xlat = 0;
00257 
00258         // Allocate our SPI buffer.  The transfer on each cycle is 192 bits per
00259         // chip = 24 bytes per chip.
00260         spilen = nchips*24;
00261         spibuf = new uint8_t[spilen];
00262         memset(spibuf, 0x00, spilen);
00263         
00264         // Configure the GSCLK output's frequency
00265         gsclk.getUnit()->period(1.0f/GSCLK_SPEED);
00266         
00267         // we're not yet ready to send new data to the chips
00268         cts = false;
00269         
00270         // we don't need an XLAT signal until we send data
00271         needXlat = false;
00272     }
00273      
00274     // Global enable/disble.  When disabled, we assert the blanking signal
00275     // continuously to keep all outputs turned off.  This can be used during
00276     // startup and sleep mode to prevent spurious output signals from
00277     // uninitialized grayscale registers.  The chips have random values in
00278     // their internal registers when power is first applied, so we have to 
00279     // explicitly send the initial zero levels after power cycling the chips.
00280     // The chips might not have power even when the KL25Z is running, because
00281     // they might be powered from a separate power supply from the KL25Z
00282     // (the Pinscape Expansion Boards work this way).  Global blanking helps
00283     // us start up more cleanly by suppressing all outputs until we can be
00284     // reasonably sure that the various chip registers are initialized.
00285     void enable(bool f)
00286     {
00287         // note the new setting
00288         enabled = f;
00289         
00290         // If disabled, apply blanking immediately.  If enabled, do nothing
00291         // extra; we'll drop the blanking signal at the end of the next 
00292         // blanking interval as normal.
00293         if (!f)
00294         {
00295             // disable interrupts, since the blanking interrupt writes gsclk too
00296             __disable_irq();
00297         
00298             // turn off the GS clock and assert BLANK to turn off all outputs
00299             gsclk.glitchFreeWrite(0);
00300             wait_us(3);
00301             blank = 1;
00302 
00303             // done messing with shared data
00304             __enable_irq();
00305         }
00306         
00307     }
00308     
00309     // Start the clock running
00310     void start()
00311     {        
00312         // Set up the first call to the reset function, which asserts BLANK to
00313         // end the PWM cycle and handles new grayscale data output and latching.
00314         // The original version of this library used a timer to call reset
00315         // periodically, but that approach is somewhat problematic because the
00316         // reset function itself takes a small amount of time to run, so the
00317         // *actual* cycle is slightly longer than what we get from counting
00318         // GS clocks.  Running reset on a timer therefore causes the calls to
00319         // slip out of phase with the actual full cycles, which causes 
00320         // premature blanking that shows up as visible flicker.  To get the
00321         // reset cycle to line up more precisely with a full PWM cycle, it
00322         // works better to set up a new timer at the end of each cycle.  That
00323         // organically accounts for the time spent in the interrupt handler.
00324         // This doesn't result in perfectly uniform timing, since interrupt
00325         // latency varies slightly on each interrupt, but it does guarantee
00326         // that the blanking will never be premature - all variation will go
00327         // into the tail end of the cycle after the 4096 GS clocks.  That
00328         // might cause some brightness variation, but it won't cause flicker,
00329         // and in practice any brightness variation from this seems to be too 
00330         // small to be visible.
00331         armReset();
00332     }
00333     
00334     // stop the timer
00335     void stop()
00336     {
00337         disarmReset();
00338     }
00339     
00340      /*
00341       *  Set an output.  'idx' is the output index: 0 is OUT0 on the first
00342       *  chip, 1 is OUT1 on the first chip, 16 is OUT0 on the second chip
00343       *  in the daisy chain, etc.  'data' is the brightness value for the
00344       *  output, 0=off, 4095=full brightness.
00345       */
00346     void set(int idx, unsigned short data) 
00347     {
00348         // validate the index
00349         if (idx >= 0 && idx < nchips*16)
00350         {
00351 #if DATA_UPDATE_INSIDE_BLANKING
00352             // If we send data within the blanking interval, turn off interrupts while 
00353             // modifying the buffer, since the send happens in the interrupt handler.
00354             __disable_irq();
00355 #endif
00356 
00357             // Figure the SPI buffer location of the output we're changing.  The SPI
00358             // buffer has the packed bit format that we send across the wire, with 12 
00359             // bits per output, arranged from last output to first output (N = number 
00360             // of outputs = nchips*16):
00361             //
00362             //       byte 0  =  high 8 bits of output N-1
00363             //            1  =  low 4 bits of output N-1 | high 4 bits of output N-2
00364             //            2  =  low 8 bits of N-2
00365             //            3  =  high 8 bits of N-3
00366             //            4  =  low 4 bits of N-3 | high 4 bits of N-2
00367             //            5  =  low 8bits of N-4
00368             //           ...
00369             //  24*nchips-3  =  high 8 bits of output 1
00370             //  24*nchips-2  =  low 4 bits of output 1 | high 4 bits of output 0
00371             //  24*nchips-1  =  low 8 bits of output 0
00372             //
00373             // So this update will affect two bytes.  If the output number if even, we're
00374             // in the high 4 + low 8 pair; if odd, we're in the high 8 + low 4 pair.
00375             int di = nchips*24 - 3 - (3*(idx/2));
00376             if (idx & 1)
00377             {
00378                 // ODD = high 8 | low 4
00379                 spibuf[di]    = uint8_t((data >> 4) & 0xff);
00380                 spibuf[di+1] &= 0x0F;
00381                 spibuf[di+1] |= uint8_t((data << 4) & 0xf0);
00382             }
00383             else
00384             {
00385                 // EVEN = high 4 | low 8
00386                 spibuf[di+1] &= 0xF0;
00387                 spibuf[di+1] |= uint8_t((data >> 8) & 0x0f);
00388                 spibuf[di+2]  = uint8_t(data & 0xff);
00389             }
00390 
00391 #if DATA_UPDATE_INSIDE_BLANKING
00392             // re-enable interrupts
00393             __enable_irq();
00394 #endif
00395         }
00396     }
00397     
00398     // Send updates if ready.  Our top-level program's main loop calls this on
00399     // every iteration.  This lets us send grayscale updates to the chips in
00400     // regular application context (rather than in interrupt context), to keep
00401     // the time in the ISR as short as possible.  We return immediately if
00402     // we're not within the update window or we've already sent updates for
00403     // the current cycle.
00404     void send()
00405     {
00406         // if we're in the transmission window, send the data
00407         if (cts)
00408         {
00409             // Write the data to the SPI port.  Note that we go directly
00410             // to the hardware registers rather than using the mbed SPI
00411             // class, because this makes the operation about 50% faster.
00412             // The mbed class checks for input on every byte in case the
00413             // SPI connection is bidirectional, but for this application
00414             // it's strictly one-way, so we can skip checking for input 
00415             // and just blast bits to the output register as fast as 
00416             // it'll take them.  Before writing the output register 
00417             // ("D"), we have to check the status register ("S") and see
00418             // that the Transmit Empty Flag (SPTEF) is set.  The 
00419             // procedure is: spin until SPTEF is set in "S", write the 
00420             // next byte to "D", loop until out of bytes.
00421             uint8_t *p = spibuf;
00422             for (int i = spilen ; i > 0 ; --i) {
00423                 while (!(SPI0->S & SPI_S_SPTEF_MASK)) ;
00424                 SPI0->D = *p++;
00425             }
00426         
00427             // we've sent new data, so we need an XLAT signal to latch it
00428             needXlat = true;
00429             
00430             // done - we don't need to send again until the next GS cycle
00431             cts = false;
00432         }
00433     }
00434 
00435 private:
00436     // SPI port.  This is master mode, output only, so we only assign the MOSI 
00437     // and SCK pins.
00438     SPI spi;
00439 
00440     // SPI transfer buffer.  This contains the live grayscale data, formatted
00441     // for direct transmission to the TLC5940 chips via SPI.
00442     uint8_t *volatile spibuf;
00443     
00444     // Length of the SPI buffer in bytes.  The native data format of the chips
00445     // is 12 bits per output = 1.5 bytes.  There are 16 outputs per chip, which
00446     // comes to 192 bits == 24 bytes per chip.
00447     uint16_t spilen;
00448     
00449     // Dirty: true means that the non-live buffer has new pending data.  False means
00450     // that the non-live buffer is empty.
00451     volatile bool dirty;
00452     
00453     // Enabled: this enables or disables all outputs.  When this is true, we assert the
00454     // BLANK signal continuously.
00455     bool enabled;
00456     
00457     // use a PWM out for the grayscale clock - this provides a stable
00458     // square wave signal without consuming CPU
00459     NewPwmOut gsclk;
00460 
00461     // Digital out pins used for the TLC5940
00462     DigitalOut blank;
00463     DigitalOut xlat;
00464     
00465     // number of daisy-chained TLC5940s we're controlling
00466     int nchips;
00467 
00468     // Timeout to end each PWM cycle.  This is a one-shot timer that we reset
00469     // on each cycle.
00470     Timeout resetTimer;
00471     
00472     // Timeout to end the data window for the PWM cycle.
00473     Timeout windowTimer;
00474     
00475     // "Clear To Send" flag: 
00476     volatile bool cts;
00477     
00478     // Do we need an XLAT signal on the next blanking interval?
00479     volatile bool needXlat;
00480         
00481     // Reset the grayscale cycle and send the next data update
00482     void reset()
00483     {
00484         // start the blanking cycle
00485         startBlank();
00486         
00487         // we're now clear to send the new GS data
00488         cts = true;
00489         
00490 #if DATA_UPDATE_INSIDE_BLANKING
00491         // We're configured to send the new GS data inline during each 
00492         // blanking cycle.  Send it now.
00493         send();
00494 #else
00495         // We're configured to send GS data during the GS cycle.  This means
00496         // we can defer the GS data transmission to any point within the next
00497         // GS cycle, which will last about 12ms (assuming a 350kHz GS clock).
00498         // That's a ton of time given that our GS transmission only takes about
00499         // 100us.  With such a leisurely time window to work with, we can move
00500         // the transmission out of the ISR context and into regular application
00501         // context, which is good because it greatly reduces the time we spend 
00502         // in this ISR, which is good in turn because more ISR time means more 
00503         // latency for other interrupts and more chances to miss interrupts
00504         // entirely.  
00505         //
00506         // The mechanism for deferring the transmission to application context
00507         // is simple.  The main program loop periodically polls the "cts" flag
00508         // and transmits the data if it finds "cts" set.  To conform to the
00509         // hardware spec for the TLC5940 chips, the data transmission has to
00510         // finish before the next blanking interval.  This means our time 
00511         // window to do the transmission is the 12ms of the grayscale cycle 
00512         // minus the ~100us to do the transmission.  So basically 12ms.  
00513         // Timing is never exact on the KL25Z, though, so we should build in
00514         // a little margin for error.  To be conservative, we'll say that the 
00515         // update must begin within the first 2/3 of the grayscale cycle time.
00516         // That's an 8ms window, and leaves a 4ms margin of error.  It's
00517         // almost inconceivable that any of the timing factors would be 
00518         // outside of those bounds.
00519         //
00520         // To coordinate this 2/3-of-a-cycle window with the main loop, set
00521         // up a timeout to clear the "cts" flag 2/3 into the cycle time.  If
00522         // for some reason the main loop doesn't do the transmission before
00523         // this timer fires, it'll see the "cts" flag turned off and won't
00524         // attempt the transmission on this round.  (That should essentially
00525         // never happen, but it wouldn't be a problem even if it happened with
00526         // some regularity, because we'd just transmit the data on the next
00527         // cycle.)
00528         windowTimer.attach_us(this, &TLC5940::closeSendWindow, 
00529             uint32_t((1.0f/GSCLK_SPEED)*4096.0f*2.0f/3.0f*1000000.0f));
00530 #endif
00531 
00532         // end the blanking interval
00533         endBlank();
00534 
00535         // re-arm the reset handler for the next blanking interval
00536         armReset();
00537     }
00538     
00539     // End the data-send window.  This is a timeout routine that fires halfway
00540     // through each grayscale cycle.  The TLC5940 chips allow new data to be
00541     // sent at any time during the grayscale pulse cycle, but the transmission
00542     // has to fit into this window.  We do these transmissions from the main loop,
00543     // so that they happen in application context rather than interrupt context,
00544     // but this means that we have to synchronize the main loop activity to the
00545     // grayscale timer cycle.  To make sure the transmission is done before the
00546     // next grayscale cycle ends, we only allow the transmission to start for
00547     // the first 2/3 of the cycle.  This gives us plenty of time to send the
00548     // data and plenty of padding to make sure we don't go too late.  Consider
00549     // the relative time periods: we run the grayscale clock at 350kHz, and each
00550     // grayscale cycle has 4096 steps, so each cycle takes 11.7ms.  For the
00551     // typical Expansion Board setup with 4 TLC5940 chips, we have 768 bits 
00552     // to send via SPI at 28 MHz, which nominally takes 27us.  The actual
00553     // measured time to send 768 bits via send() is 72us, so there's CPU overhead 
00554     // of about 2.6x.  The biggest workable Expnasion Board setup would probably 
00555     // be around 8 TLC chips, so we'd have twice the bits and twice the 
00556     // transmission time of our 4-chip scenario, so the send time would be
00557     // about 150us.  2/3 of the grayscale cycle gives us an 8ms window to 
00558     // perform a 150us operation.  The main loop runs about every 1.5ms, so 
00559     // we're all but certain to poll CTS more than once during each 8ms window.  
00560     // Even if we start at the very end of the window, we still have about 3.5ms 
00561     // to finish a <150us operation, so we're all but certain to finish in time.
00562     void closeSendWindow() 
00563     { 
00564         cts = false; 
00565     }
00566     
00567     // arm the reset handler - this fires at the end of each GS cycle    
00568     void armReset()
00569     {
00570         resetTimer.attach_us(this, &TLC5940::reset, 
00571             uint32_t((1.0/GSCLK_SPEED)*4096.0*1000000.0f));
00572     }
00573     
00574     void disarmReset()
00575     {
00576         resetTimer.detach();
00577     }
00578 
00579     void startBlank()
00580     {
00581         // turn off the grayscale clock
00582         gsclk.glitchFreeWrite(0);
00583         
00584         // Make sure the gsclk cycle ends, since the TLC5940 data sheet
00585         // says we can't take BLANK high until GSCLK has been low for 20ns.
00586         // (We don't have to add any padding for the 20ns, since it'll take
00587         // at least one CPU cycle of 60ns to return from waitEndCycle().
00588         // That routine won't return until GSCLK is low, so it will have
00589         // low for at least 60ns by the time we get back from this call.)
00590         gsclk.waitEndCycle();
00591         
00592         // assert BLANK to end the grayscale cycle
00593         blank = 1;
00594     }
00595             
00596     void endBlank()
00597     {
00598         // if we've sent new grayscale data since the last blanking
00599         // interval, latch it by asserting XLAT
00600         if (needXlat)
00601         {
00602             // latch the new data while we're still blanked
00603             xlat = 1;
00604             xlat = 0;
00605             needXlat = false;
00606         }
00607 
00608         // End the blanking interval and restart the grayscale clock.  Note
00609         // that we keep the blanking on if the chips are globally disabled.
00610         if (enabled)
00611         {
00612             blank = 0;
00613             gsclk.write(.5);
00614         }
00615     }
00616 };
00617  
00618 #endif