Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FastAnalogIn FastIO FastPWM SimpleDMA USBDevice mbed
Fork of Pinscape_Controller by
TLC5940.h
00001 // Pinscape Controller TLC5940 interface 00002 // 00003 // Based on Spencer Davis's mbed TLC5940 library. Adapted for the 00004 // KL25Z, and simplified to just the functions needed for this 00005 // application. In particular, this version doesn't include support 00006 // for dot correction programming or status input. This version also 00007 // uses a different approach for sending the grayscale data updates, 00008 // sending updates during the blanking interval rather than overlapping 00009 // them with the PWM cycle. This results in very slightly longer 00010 // blanking intervals when updates are pending, effectively reducing 00011 // the PWM "on" duty cycle (and thus the output brightness) by about 00012 // 0.3%. This shouldn't be perceptible to users, so it's a small 00013 // trade-off for the advantage gained, which is much better signal 00014 // stability when using multiple TLC5940s daisy-chained together. 00015 // I saw a lot of instability when using the overlapped approach, 00016 // which seems to be eliminated entirely when sending updates during 00017 // the blanking interval. 00018 00019 00020 #ifndef TLC5940_H 00021 #define TLC5940_H 00022 00023 // Should we do the grayscale update within the blanking interval? 00024 // If this is set to 1, we'll send grayscale data during the blanking 00025 // interval; if 0, we'll send grayscale during the PWM cycle. 00026 // Mode 0 is the *intended* way of using these chips, but mode 1 00027 // produces a more stable signal in my test setup. 00028 // 00029 // In my breadboard testing, using the standard data-during-PWM 00030 // mode causes some amount of signal instability with multiple 00031 // daisy-chained TLC5940's. It appears that there's some signal 00032 // interference (maybe RF or electrical ringing in the wires) that 00033 // can make the bit data and/or clock prone to noise that causes 00034 // random bits to propagate down the daisy chain. This happens 00035 // frequently enough in my breadboard setup to be visible as 00036 // regular flicker. Careful wiring, short wire runs, and decoupling 00037 // capacitors noticeably improve it, but I haven't been able to 00038 // eliminate it entirely in my test setup. Using the data-during- 00039 // blanking mode, however, *does* eliminate it entirely. 00040 // 00041 // It clearly should be possible to eliminate the signal problems 00042 // in a well-designed PCB layout, but for the time being, I'm 00043 // making data-during-blanking the default, since it provides 00044 // such a noticeable improvement in my test setup, and the cost 00045 // is minimal. The cost is that it lengthens the blanking interval 00046 // slightly. With four chips and the SPI clock at 28MHz, the 00047 // full data update takes 27us; with the PWM clock at 500kHz, the 00048 // grayscale cycle is 8192us. This means that the 27us data send 00049 // keeps the BLANK asserted for an additional 0.3% of the cycle 00050 // time, which in term reduces output brightness by the same amount. 00051 // This brightness reduction isn't noticeable on its own, but it 00052 // can be seen as a flicker on data cycles if we send data on 00053 // some blanking cycles but not on others. To eliminate the 00054 // flicker, the code sends a data update on *every* cycle when 00055 // using this mode to ensure that the 0.3% brightness reduction 00056 // is uniform across time. 00057 // 00058 // When using this code with TLC5940 chips on a PCB, I recommend 00059 // doing a test: set this to 0, run the board, turn on all outputs 00060 // (connected to LEDs), and observe the results. If you don't 00061 // see any randomness or flicker in a minute or two of observation, 00062 // you're getting a good clean signal throughout the daisy chain 00063 // and don't need the workaround. If you do see any instability, 00064 // set this back to 1. 00065 #define DATA_UPDATE_INSIDE_BLANKING 1 00066 00067 #include "mbed.h" 00068 #include "FastPWM.h" 00069 #include "SimpleDMA.h" 00070 00071 /** 00072 * SPI speed used by the mbed to communicate with the TLC5940 00073 * The TLC5940 supports up to 30Mhz. It's best to keep this as 00074 * high as possible, since a higher SPI speed yields a faster 00075 * grayscale data update. However, I've seen some slight 00076 * instability in the signal in my breadboard setup using the 00077 * full 30MHz, so I've reduced this slightly, which seems to 00078 * yield a solid signal. The limit will vary according to how 00079 * clean the signal path is to the chips; you can probably crank 00080 * this up to full speed if you have a well-designed PCB, good 00081 * decoupling capacitors near the 5940 VCC/GND pins, and short 00082 * wires between the KL25Z and the PCB. A short, clean path to 00083 * KL25Z ground seems especially important. 00084 * 00085 * The SPI clock must be fast enough that the data transmission 00086 * time for a full update is comfortably less than the blanking 00087 * cycle time. The grayscale refresh requires 192 bits per TLC5940 00088 * in the daisy chain, and each bit takes one SPI clock to send. 00089 * Our reference setup in the Pinscape controller allows for up to 00090 * 4 TLC5940s, so a full refresh cycle on a fully populated system 00091 * would be 768 SPI clocks. The blanking cycle is 4096 GSCLK cycles. 00092 * 00093 * t(blank) = 4096 * 1/GSCLK_SPEED 00094 * t(refresh) = 768 * 1/SPI_SPEED 00095 * Therefore: SPI_SPEED must be > 768/4096 * GSCLK_SPEED 00096 * 00097 * Since the SPI speed can be so high, and since we want to keep 00098 * the GSCLK speed relatively low, the constraint above simply 00099 * isn't a factor. E.g., at SPI=30MHz and GSCLK=500kHz, 00100 * t(blank) is 8192us and t(refresh) is 25us. 00101 */ 00102 #define SPI_SPEED 2800000 00103 00104 /** 00105 * The rate at which the GSCLK pin is pulsed. This also controls 00106 * how often the reset function is called. The reset function call 00107 * rate is (1/GSCLK_SPEED) * 4096. The maximum reliable rate is 00108 * around 32Mhz. It's best to keep this rate as low as possible: 00109 * the higher the rate, the higher the refresh() call frequency, 00110 * so the higher the CPU load. 00111 * 00112 * The lower bound is probably dependent on the application. For 00113 * driving LEDs, the limiting factor is that lower rates will increase 00114 * visible flicker. 200 kHz seems to be a good lower bound for LEDs. 00115 * That provides about 48 cycles per second - that's about the same as 00116 * the 50 Hz A/C cycle rate in many countries, which was itself chosen 00117 * so that incandescent lights don't flicker. (This rate is a function 00118 * of human eye physiology, which has its own refresh cycle of sorts 00119 * that runs at about 50 Hz. If you're designing an LED system for 00120 * viewing by cats or drosophila, you might want to look into your 00121 * target species' eye physiology, since the persistence of vision 00122 * rate varies quite a bit from species to species.) Flicker tends to 00123 * be more noticeable in LEDs than in incandescents, since LEDs don't 00124 * have the thermal inertia of incandescents, so we use a slightly 00125 * higher default here. 500 kHz = 122 full grayscale cycles per 00126 * second = 122 reset calls per second (call every 8ms). 00127 */ 00128 #define GSCLK_SPEED 500000 00129 00130 /** 00131 * This class controls a TLC5940 PWM driver IC. 00132 * 00133 * Using the TLC5940 class to control an LED: 00134 * @code 00135 * #include "mbed.h" 00136 * #include "TLC5940.h" 00137 * 00138 * // Create the TLC5940 instance 00139 * TLC5940 tlc(p7, p5, p21, p9, p10, p11, p12, 1); 00140 * 00141 * int main() 00142 * { 00143 * // Enable the first LED 00144 * tlc.set(0, 0xfff); 00145 * 00146 * while(1) 00147 * { 00148 * } 00149 * } 00150 * @endcode 00151 */ 00152 class TLC5940 00153 { 00154 public: 00155 /** 00156 * Set up the TLC5940 00157 * @param SCLK - The SCK pin of the SPI bus 00158 * @param MOSI - The MOSI pin of the SPI bus 00159 * @param GSCLK - The GSCLK pin of the TLC5940(s) 00160 * @param BLANK - The BLANK pin of the TLC5940(s) 00161 * @param XLAT - The XLAT pin of the TLC5940(s) 00162 * @param nchips - The number of TLC5940s (if you are daisy chaining) 00163 */ 00164 TLC5940(PinName SCLK, PinName MOSI, PinName GSCLK, PinName BLANK, PinName XLAT, int nchips) 00165 : spi(MOSI, NC, SCLK), 00166 gsclk(GSCLK), 00167 blank(BLANK), 00168 xlat(XLAT), 00169 nchips(nchips) 00170 { 00171 // set XLAT to initially off 00172 xlat = 0; 00173 00174 // Assert BLANK while starting up, to keep the outputs turned off until 00175 // everything is stable. This helps prevent spurious flashes during startup. 00176 // (That's not particularly important for lights, but it matters more for 00177 // tactile devices. It's a bit alarming to fire a replay knocker on every 00178 // power-on, for example.) 00179 blank = 1; 00180 00181 // allocate the grayscale buffer, and set all outputs to fully off 00182 gs = new unsigned short[nchips*16]; 00183 memset(gs, 0, nchips*16*sizeof(gs[0])); 00184 00185 // Configure SPI format and speed. Note that KL25Z ONLY supports 8-bit 00186 // mode. The TLC5940 nominally requires 12-bit data blocks for the 00187 // grayscale levels, but SPI is ultimately just a bit-level serial format, 00188 // so we can reformat the 12-bit blocks into 8-bit bytes to fit the 00189 // KL25Z's limits. This should work equally well on other microcontrollers 00190 // that are more flexible. The TLC5940 appears to require polarity/phase 00191 // format 0. 00192 spi.format(8, 0); 00193 spi.frequency(SPI_SPEED); 00194 00195 // Send out a full data set to the chips, to clear out any random 00196 // startup data from the registers. Include some extra bits - there 00197 // are some cases (such as after sending dot correct commands) where 00198 // an extra bit per chip is required, and the initial state is 00199 // somewhat unpredictable, so send extra just to make sure we cover 00200 // all bases. This does no harm; extra bits just fall off the end of 00201 // the daisy chain, and since we want all registers set to 0, we can 00202 // send arbitrarily many extra 0's. 00203 for (int i = 0 ; i < nchips*25 ; ++i) 00204 spi.write(0); 00205 00206 // do an initial XLAT to latch all of these "0" values into the 00207 // grayscale registers 00208 xlat = 1; 00209 xlat = 0; 00210 00211 // Allocate a DMA buffer. The transfer on each cycle is 192 bits per 00212 // chip = 24 bytes per chip. 00213 dmabuf = new char[nchips*24]; 00214 00215 // Set up the Simple DMA interface object. We use the DMA controller to 00216 // send grayscale data updates to the TLC5940 chips. This lets the CPU 00217 // keep running other tasks while we send gs updates, and importantly 00218 // allows our blanking interrupt handler return almost immediately. 00219 // The DMA transfer is from our internal DMA buffer to SPI0, which is 00220 // the SPI controller physically connected to the TLC5940s. 00221 sdma.source(dmabuf, 1); 00222 sdma.destination(&(SPI0->D), 0, 8); 00223 sdma.trigger(Trigger_SPI0_TX); 00224 sdma.attach(this, &TLC5940::dmaDone); 00225 00226 // Enable DMA on SPI0. SimpleDMA doesn't do this for us; we have to 00227 // do it explicitly. This is just a matter of setting bit 5 (TXDMAE) 00228 // in the SPI controllers Control Register 2 (C2). 00229 SPI0->C2 |= 0x20; // set bit 5 = 0x20 = TXDMAE in SPI0 control register 2 00230 00231 // Configure the GSCLK output's frequency 00232 gsclk.period(1.0/GSCLK_SPEED); 00233 00234 // mark that we need an initial update 00235 newGSData = true; 00236 needXlat = false; 00237 } 00238 00239 // Start the clock running 00240 void start() 00241 { 00242 // Set up the first call to the reset function, which asserts BLANK to 00243 // end the PWM cycle and handles new grayscale data output and latching. 00244 // The original version of this library uses a timer to call reset 00245 // periodically, but that approach is somewhat problematic because the 00246 // reset function itself takes a small amount of time to run, so the 00247 // *actual* cycle is slightly longer than what we get from counting 00248 // GS clocks. Running reset on a timer therefore causes the calls to 00249 // slip out of phase with the actual full cycles, which causes 00250 // premature blanking that shows up as visible flicker. To get the 00251 // reset cycle to line up exactly with a full PWM cycle, it works 00252 // better to set up a new timer on each cycle, *after* we've finished 00253 // with the somewhat unpredictable overhead of the interrupt handler. 00254 // This ensures that we'll get much closer to exact alignment of the 00255 // cycle phase, and in any case the worst that happens is that some 00256 // cycles are very slightly too long or short (due to imperfections 00257 // in the timer clock vs the PWM clock that determines the GSCLCK 00258 // output to the TLC5940), which is far less noticeable than a 00259 // constantly rotating phase misalignment. 00260 reset_timer.attach(this, &TLC5940::reset, (1.0/GSCLK_SPEED)*4096.0); 00261 } 00262 00263 ~TLC5940() 00264 { 00265 delete [] gs; 00266 delete [] dmabuf; 00267 } 00268 00269 /** 00270 * Set the next chunk of grayscale data to be sent 00271 * @param data - Array of 16 bit shorts containing 16 12 bit grayscale data chunks per TLC5940 00272 * @note These must be in intervals of at least (1/GSCLK_SPEED) * 4096 to be sent 00273 */ 00274 void set(int idx, unsigned short data) 00275 { 00276 // store the data, and flag the pending update for the interrupt handler to carry out 00277 gs[idx] = data; 00278 newGSData = true; 00279 } 00280 00281 private: 00282 // current level for each output 00283 unsigned short *gs; 00284 00285 // Simple DMA interface object 00286 SimpleDMA sdma; 00287 00288 // DMA transfer buffer. Each time we have data to transmit to the TLC5940 chips, 00289 // we format the data into this buffer exactly as it will go across the wire, then 00290 // hand the buffer to the DMA controller to move through the SPI port. 00291 char *dmabuf; 00292 00293 // SPI port - only MOSI and SCK are used 00294 SPI spi; 00295 00296 // use a PWM out for the grayscale clock - this provides a stable 00297 // square wave signal without consuming CPU 00298 FastPWM gsclk; 00299 00300 // Digital out pins used for the TLC5940 00301 DigitalOut blank; 00302 DigitalOut xlat; 00303 00304 // number of daisy-chained TLC5940s we're controlling 00305 int nchips; 00306 00307 // Timeout to end each PWM cycle. This is a one-shot timer that we reset 00308 // on each cycle. 00309 Timeout reset_timer; 00310 00311 // Has new GS/DC data been loaded? 00312 volatile bool newGSData; 00313 00314 // Do we need an XLAT signal on the next blanking interval? 00315 volatile bool needXlat; 00316 00317 // Function to reset the display and send the next chunks of data 00318 void reset() 00319 { 00320 // start the blanking cycle 00321 startBlank(); 00322 00323 #if DATA_UPDATE_INSIDE_BLANKING 00324 // We're configured to send the new GS data entirely within 00325 // the blanking interval. Start the DMA transfer now, and 00326 // return without ending the blanking interval. The DMA 00327 // completion interrupt handler will do that when the data 00328 // update has completed. 00329 // 00330 // Note that we do the data update/ unconditionally in the 00331 // send-during-blanking case, whether or not we have new GS 00332 // data. This is because the update causes a 0.3% reduction 00333 // in brightness because of the elongated BLANK interval. 00334 // That would be visible as a flicker on each update if we 00335 // did updates on some cycles and not others. By doing an 00336 // update on every cycle, we make the brightness reduction 00337 // uniform across time, which makes it less perceptible. 00338 update(); 00339 00340 #else // DATA_UPDATE_INSIDE_BLANKING 00341 00342 // end the blanking interval 00343 endBlank(); 00344 00345 // if we have pending grayscale data, start sending it 00346 if (newGSData) 00347 update(); 00348 00349 #endif // DATA_UPDATE_INSIDE_BLANKING 00350 } 00351 00352 void startBlank() 00353 { 00354 // turn off the grayscale clock, and assert BLANK to end the grayscale cycle 00355 gsclk.write(0); 00356 blank = 1; 00357 } 00358 00359 void endBlank() 00360 { 00361 // if we've sent new grayscale data since the last blanking 00362 // interval, latch it by asserting XLAT 00363 if (needXlat) 00364 { 00365 // latch the new data while we're still blanked 00366 xlat = 1; 00367 xlat = 0; 00368 needXlat = false; 00369 } 00370 00371 // end the blanking interval and restart the grayscale clock 00372 blank = 0; 00373 gsclk.write(.5); 00374 00375 // set up the next blanking interrupt 00376 reset_timer.attach(this, &TLC5940::reset, (1.0/GSCLK_SPEED)*4096.0); 00377 } 00378 00379 void update() 00380 { 00381 // Send new grayscale data to the TLC5940 chips. 00382 // 00383 // To do this, we set up our DMA buffer with the bytes formatted exactly 00384 // as they will go across the wire, then kick off the transfer request with 00385 // the DMA controller. We can then return from the interrupt and continue 00386 // with other tasks while the DMA hardware handles the transfer for us. 00387 // When the transfer is completed, the DMA controller will fire an 00388 // interrupt, which will call our interrupt handler, which will finish 00389 // the blanking cycle. 00390 // 00391 // The serial format orders the outputs from last to first (output #15 on 00392 // the last chip in the daisy-chain to output #0 on the first chip). For 00393 // each output, we send 12 bits containing the grayscale level (0 = fully 00394 // off, 0xFFF = fully on). Bit order is most significant bit first. 00395 // 00396 // The KL25Z SPI can only send in 8-bit increments, so we need to divvy up 00397 // the 12-bit outputs into 8-bit bytes. Each pair of 12-bit outputs adds up 00398 // to 24 bits, which divides evenly into 3 bytes, so send each pairs of 00399 // outputs as three bytes: 00400 // 00401 // [ element i+1 bits ] [ element i bits ] 00402 // 11 10 9 8 7 6 5 4 3 2 1 0 11 10 9 8 7 6 5 4 3 2 1 0 00403 // [ first byte ] [ second byte ] [ third byte ] 00404 for (int i = (16 * nchips) - 2, dst = 0 ; i >= 0 ; i -= 2) 00405 { 00406 // first byte - element i+1 bits 4-11 00407 dmabuf[dst++] = (((gs[i+1] & 0xFF0) >> 4) & 0xff); 00408 00409 // second byte - element i+1 bits 0-3, then element i bits 8-11 00410 dmabuf[dst++] = ((((gs[i+1] & 0x00F) << 4) | ((gs[i] & 0xF00) >> 8)) & 0xFF); 00411 00412 // third byte - element i bits 0-7 00413 dmabuf[dst++] = (gs[i] & 0x0FF); 00414 } 00415 00416 // Start the DMA transfer 00417 sdma.start(nchips*24); 00418 00419 // we've now cleared the new GS data 00420 newGSData = false; 00421 } 00422 00423 // Interrupt handler for DMA completion. The DMA controller calls this 00424 // when it finishes with the transfer request we set up above. When the 00425 // transfer is done, we simply end the blanking cycle and start a new 00426 // grayscale cycle. 00427 void dmaDone() 00428 { 00429 // mark that we need to assert XLAT to latch the new 00430 // grayscale data during the next blanking interval 00431 needXlat = true; 00432 00433 #if DATA_UPDATE_INSIDE_BLANKING 00434 // we're doing the gs update within the blanking cycle, so end 00435 // the blanking cycle now that the transfer has completed 00436 endBlank(); 00437 #endif 00438 } 00439 00440 }; 00441 00442 #endif
Generated on Sun Jul 24 2022 05:27:38 by
