Advertisement
Guest User

TLC5940.cpp

a guest
Mar 29th, 2014
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.41 KB | None | 0 0
  1. #include "teensy_tlc5940.h"
  2.  
  3.  
  4. ////////////////////////////////////////////////////////////////////////////////
  5. /// Internal Forward Declarations
  6.  
  7. static inline void startGSCLK ();
  8. static inline void stopGSCLK ();
  9. static inline void resetGSCLK ();
  10. static inline void sleepGSCLK ();
  11. static inline void wakeGSCLK ();
  12.  
  13. static inline void startBLANKTimer ();
  14. static inline void stopBLANKTimer ();
  15. static inline void sleepBLANKTimer ();
  16. static inline void wakeBLANKTimer ();
  17.  
  18. static inline void startGSCLKandBLANKTimers ();
  19. #define SHIFT_LATCH_PIN  2
  20. #define SHIFT_CLK_PIN  7
  21. #define SHIFT_DATA_PIN  8
  22. #define SHIFT_OE_PIN 6
  23.  
  24.  
  25. ////////////////////////////////////////////////////////////////////////////////
  26. /// GSCLK Timer
  27. ///
  28. /// The grayscale clock is used to clock the PWM outputs of the TLC5940.  These
  29. /// are 12-bit, so one PWM cycle takes 4096 GSCLK ticks.  Blanking the output to
  30. /// latch in new data should only be done at the boundaries between PWM cycles
  31. /// for the smoothest looking output, so we use two counters:
  32. ///
  33. /// 1) GSCLK running at 2.0 MHz, will output a 50% duty cycle.  The PWM cycle
  34. ///    will then be ~488 Hz.
  35. ///
  36. /// 2) The BLANK timer will generate an interrupt every 4096 cycles of GSCLK.  
  37. ///
  38.  
  39. #define GSCLK_PRESCALE 0   // divide F_BUS by 1  = 48 MHz
  40.  
  41.  
  42. void initGSCLKTimer ()
  43. {// F_BUS = 48 MHz
  44.   //
  45.   // GSCLK will run at 2.0 MHz.  Since the TLC5940 has 4096 GSCLK pulses per
  46.   // PWM cycle, this means a PWM frequency of ~488 Hz.
  47.  
  48.   // Connect Teensy pin 9 to FTM0, Ch. 2 output:
  49.   CORE_PIN9_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE;
  50.  
  51.   stopGSCLK();       // disable while performing setup
  52.   FTM0_CNT = 0;
  53.   FTM0_MOD = 23;     // 48 MHz/24 = 2 MHz (period is FTM1_MOD + 1)
  54.  
  55.   // Edge-Aligned PWM, set output on FTM0, ch.2 match:
  56.   FTM0_C2SC = 0x24;  // MSnB:MSnA = 10, ELSnB:ELSnA = 01
  57.  
  58.   FTM0_C2V = 12;      // 50% duty cycle
  59.   FTM0_SC = GSCLK_PRESCALE;
  60.  
  61.   return;}
  62.  
  63. static inline void startGSCLK ()
  64. {FTM0_CNT = 0;
  65.   FTM0_SC = FTM_SC_CLKS(1) | GSCLK_PRESCALE;
  66.   return;}
  67.  
  68. static inline void stopGSCLK ()
  69. {FTM0_SC = 0;
  70.   return;}
  71.  
  72. static inline void resetGSCLK ()
  73. {FTM0_CNT = 0;
  74.   return;}
  75.  
  76. static inline void sleepGSCLK ()
  77. {stopGSCLK();
  78.   SIM_SCGC6 &= ~SIM_SCGC6_FTM0;
  79.   return;}
  80.  
  81. static inline void wakeGSCLK ()
  82. {SIM_SCGC6 |= SIM_SCGC6_FTM0;
  83.   return;}
  84.  
  85.  
  86. ////////////////////////////////////////////////////////////////////////////////
  87. /// BLANK Timer and output pin
  88. ///
  89. /// The BLANK signal should go high after 4096 GSCLK pulses.
  90. ///
  91. /// We'll use a Periodic Interrupt Timer for this.  I'm hoping that it's
  92. /// decently in sync with the Flex Timers since they are both driven from
  93. /// the same peripheral bus clock.
  94. ///
  95. /// The PITs run directly off the peripheral bus clock.  On a normally clocked
  96. /// Teensy 3, F_BUS is 48 MHz.
  97. ///
  98.  
  99. void initBLANKTimer ()
  100. {SIM_SCGC6 |= SIM_SCGC6_PIT;   // enable PIT peripheral at system level
  101.   PIT_MCR = 1;                  // disable PIT while performing setup
  102.   PIT_TCTRL3 = 0;               // disable PIT #3 while performing setup
  103.   PIT_LDVAL3 = 98304;           // FTM1 period * 4096
  104.   NVIC_ENABLE_IRQ(IRQ_PIT_CH3); // allow PIT #3 interrupts
  105.   PIT_MCR = 0;                  // enable PIT
  106.   return;}
  107.  
  108. static inline void startBLANKTimer ()
  109. {PIT_TFLG3 = 1;   // ensure that the interrupt is cleared
  110.   PIT_TCTRL3 = 3;  // enables PIT #3 and its interrupt
  111.   return;}
  112.  
  113. static inline void stopBLANKTimer ()
  114. {PIT_TCTRL3 = 0;  // disables PIT #3 and its interrupt
  115.   return;}
  116.  
  117. static inline void sleepBLANKTimer ()
  118. {
  119.   stopBLANKTimer();
  120.   PIT_MCR = 1;
  121.   SIM_SCGC6 &= ~SIM_SCGC6_PIT;
  122.   return;}
  123.  
  124. static inline void wakeBLANKTimer ()
  125. {
  126.   PIT_MCR = 0;
  127.   SIM_SCGC6 |= SIM_SCGC6_PIT;
  128.   return;}
  129.  
  130.  
  131. // The following pin outputs the BLANK signal:
  132. #define BLANK_PIN 10
  133.  
  134. void initBLANKPin ()
  135. {pinMode(BLANK_PIN, OUTPUT);
  136.   digitalWrite(BLANK_PIN, HIGH);  // start with BLANK active
  137.   return;}
  138.  
  139. static inline void setBLANK ()
  140. {CORE_PIN10_PORTSET = CORE_PIN10_BITMASK;
  141.   return;}
  142.  
  143. static inline void clearBLANK ()
  144. {CORE_PIN10_PORTCLEAR = CORE_PIN10_BITMASK;
  145.   return;}
  146.  
  147.  
  148. ////////////////////////////////////////////////////////////////////////////////
  149. /// XLAT
  150. ///
  151. /// Causes new data sent to the TLC5940 to be latched in.
  152. ///
  153.  
  154. #define XLAT_PIN 12
  155.  
  156. volatile boolean tlc_needXLAT = false;
  157. volatile boolean tlc_needExtraSCLKPulseAfterGSData = false;
  158.  
  159.  
  160. void initXLAT ()
  161. {pinMode(XLAT_PIN, OUTPUT);
  162.   digitalWrite(XLAT_PIN, LOW);  
  163.   return;}
  164.  
  165. static inline void pulseXLAT ()
  166. {CORE_PIN12_PORTSET = CORE_PIN12_BITMASK;
  167.   // Don't need a delay here.  This code takes longer than the minimum hold
  168.   // time needed for TLC5940 XLAT.
  169.   CORE_PIN12_PORTCLEAR = CORE_PIN12_BITMASK;
  170.   return;}
  171.  
  172.  
  173. ////////////////////////////////////////////////////////////////////////////////
  174. /// VPRG
  175. ///
  176. /// VRPG should be low to send grayscale data and high to send dot-correction
  177. /// data.
  178. ///
  179.  
  180. #define VPRG_PIN  14
  181.  
  182. void initVPRG ()
  183. {pinMode(VPRG_PIN, OUTPUT);
  184.   digitalWrite(VPRG_PIN, LOW);  
  185.   return;}
  186.  
  187.  
  188. ////////////////////////////////////////////////////////////////////////////////
  189. /// XERR
  190. ///
  191. /// This pin receives data from the TLC5940 describing problems.
  192. ///
  193. /// We're not currently using this.  I might not even connect it on the circuit
  194. /// board.  Need to decide.
  195. ///
  196.  
  197. //#define XERR_PIN 7
  198. //
  199. //void initXERR ()
  200. // {pinMode(XERR_PIN, INPUT);
  201. //  return;}
  202.  
  203.  
  204. ////////////////////////////////////////////////////////////////////////////////
  205. /// TLC5940 SPI Communications
  206. ///
  207. /// SCLK = Teensy pin 13
  208. /// TLC5940 SIN = Teensy pin 11
  209. ///
  210. /// We'll use a baud rate prescaler (PBR) of 2 and a baud rate scaler (BR) of 2
  211. /// which results in 12 MHz data transfer rate.  PBR 0 = prescaler 2; BR 0 =
  212. /// scaler 2.
  213. ///
  214.  
  215. #define SPI_SR_TXCTR_MASK 0x0000F000
  216. #define SPI_FIFO_DEPTH 4
  217.  
  218.  
  219. void setupTLC5940_SPI ()
  220. {SIM_SCGC6 |= SIM_SCGC6_SPI0;   // enable SPI peripheral at system level
  221.  
  222.   CORE_PIN11_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE;
  223.   CORE_PIN13_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE;
  224.  
  225.   SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_MDIS | SPI_MCR_HALT;   // stop while configuring
  226.   SPI0_CTAR0 = SPI_CTAR_FMSZ(11) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(0);  // 12-bit
  227.   SPI0_CTAR1 = SPI_CTAR_FMSZ( 5) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(0);   // 6-bit
  228.   SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_DOZE | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
  229.   return;}
  230.  
  231.  
  232. static inline void sleepSPI ()
  233. {SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_MDIS | SPI_MCR_HALT;
  234.   SIM_SCGC6 &= ~SIM_SCGC6_SPI0;
  235.   return;}
  236.  
  237. static inline void wakeSPI ()
  238. {SIM_SCGC6 |= SIM_SCGC6_SPI0;
  239.   SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_DOZE | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
  240.   return;}
  241.  
  242.  
  243. void pulseSPI_SCLK ()
  244. // After latching in GS data, the TLC5940 requires another SCLK pulse before
  245. // more GS data can be sent.  (It triggers the sending off status data on MISO.)
  246. // So after an XLAT, we need to manually pulse the SCLK once.
  247. {CORE_PIN13_CONFIG = PORT_PCR_MUX(1) | PORT_PCR_DSE;
  248.   CORE_PIN13_PORTSET = CORE_PIN13_BITMASK;
  249.   // Don't need a delay here.  This code takes longer than the minimum hold
  250.   // time needed for SCLK.
  251.   CORE_PIN13_PORTCLEAR = CORE_PIN13_BITMASK;
  252.   CORE_PIN13_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE;
  253.   return;}
  254.  
  255.  
  256. static inline void waitForSPITransmitFinish ()
  257. {while (!(SPI0_SR & SPI_SR_EOQF));}
  258.  
  259. static inline void waitForSPIFIFOSpace ()
  260. {while (((SPI0_SR & SPI_SR_TXCTR_MASK) >> 12) >= SPI_FIFO_DEPTH);}
  261.  
  262.  
  263. void sendSPIData12Bit (uint16_t* data, int n)
  264. {
  265.   SPI0_SR = SPI_SR_TCF;  // reset transfer complete flag
  266.   for (int j = n - 1; j >= 0; j--)
  267.    {waitForSPIFIFOSpace();
  268.     if (j == 0)
  269.      {SPI0_PUSHR = SPI_PUSHR_CTAS(0) | SPI_PUSHR_EOQ | data[j];}
  270.     else
  271.      {SPI0_PUSHR = SPI_PUSHR_CTAS(0) | data[j];}}
  272.   waitForSPITransmitFinish();
  273.   SPI0_SR = SPI_SR_EOQF;  // Re-enable SPI running state
  274.   return;}
  275.  
  276. void sendSPIData6Bit (uint8_t* data, int n)
  277. {SPI0_SR = SPI_SR_TCF;  // reset transfer complete flag
  278.   for (int j = n - 1; j >= 0; j--)
  279.    {waitForSPIFIFOSpace();
  280.     if (j == 0)
  281.      {SPI0_PUSHR = SPI_PUSHR_CTAS(1) | SPI_PUSHR_EOQ | data[j];}
  282.     else
  283.      {SPI0_PUSHR = SPI_PUSHR_CTAS(1) | data[j];}}
  284.   waitForSPITransmitFinish();
  285.   SPI0_SR = SPI_SR_EOQF;  // Re-enable SPI running state
  286.   return;}
  287.  
  288.  
  289. ////////////////////////////////////////////////////////////////////////////////
  290. /// Grayscale Data
  291. ///
  292. /// tlc_GSData[] is an array of bytes, each one representing the grayscale
  293. /// value for one of the TLC5940's output channels. tlc_GSData[0] is the value
  294. /// for OUT0 of the first TLC, tlc_GSData[15] is the value for OUT15 of the
  295. /// first TLC5940, tlc_GSData[16] is for OUT0 of the second TLC5940, etc.
  296. ///
  297. /// Valid grayscale values range from 0 through 4095 (i.e. they are 12-bit).
  298. ///
  299.  
  300. uint16_t tlc_GSData[NUM_TLCS * 16];
  301. boolean tlc_GSDataChangedSinceLastSend = true;
  302.  
  303.  
  304. void setGSData(int tlcOutput, uint16_t value)
  305.   // Sets a value in the local tlc_GSData array which will be used as the
  306.   // grayscale value for the specified TLC5940 output the next time sendGSData
  307.   // is called.  OUT0 of the first TLC is tlcOutput = 0, OUT0 of the next TLC
  308.   // is tlcOutput = 16, and so on.  4095 is the maximum allowed grayscale value.
  309. {tlc_GSData[tlcOutput] = value;
  310.   tlc_GSDataChangedSinceLastSend = true;
  311.   return;}
  312.  
  313.  
  314. uint16_t getGSData(int tlcOutput)
  315.   // Gets a value from the local tlc_GSData array.
  316. {return(tlc_GSData[tlcOutput]);}
  317.  
  318.  
  319. void setAllGSData(uint16_t value)
  320. // Sets all entries in the local tlc_GSData array to the specified value.
  321. {for (int j = 0; j < NUM_TLCS * 16; j++)
  322.    {tlc_GSData[j] = value;}
  323.   tlc_GSDataChangedSinceLastSend = true;
  324.   return;}
  325.  
  326.  
  327. void sendGSData (byte leds)
  328. {
  329.   if (tlc_GSDataChangedSinceLastSend)
  330.    {// If we get here and the last XLAT request hasn't been handled yet, set
  331.     // tlc_needXLAT back to false so we can send the latest data before latching
  332.     // it in.
  333.     tlc_needXLAT = false;
  334.     digitalWrite(VPRG_PIN, LOW); // VPRG low says we're setting the GS register
  335.     sendSPIData12Bit(tlc_GSData, NUM_TLCS * 16);
  336.         //delay(1);
  337.     digitalWrite(SHIFT_LATCH_PIN, LOW);
  338.     shiftOut(SHIFT_DATA_PIN, SHIFT_CLK_PIN, LSBFIRST, leds);
  339.     digitalWrite(SHIFT_LATCH_PIN, HIGH);
  340.     tlc_GSDataChangedSinceLastSend = false;
  341.     tlc_needXLAT = true;
  342.     digitalWrite(SHIFT_OE_PIN,LOW);
  343.     while(tlc_needXLAT);
  344.     digitalWrite(SHIFT_OE_PIN,HIGH);
  345. }
  346.   return;}
  347.  
  348.  
  349. extern boolean unlatchedGSData()
  350. // Returns true iff GSData was sent but has not yet been latched (which happens
  351. // during the BLANK interval.
  352. {return(tlc_needXLAT);}
  353.  
  354.  
  355. ////////////////////////////////////////////////////////////////////////////////
  356. /// Dot Correction
  357. ///
  358. /// tlc_DCData[] is an array of bytes, each one representing the dot-correction
  359. /// value for one of the TLC5940's output channels. tlc_DCData[0] is the value
  360. /// for OUT0 of the first TLC, tlc_DCData[15] is the value for OUT15 of the
  361. /// first TLC5940, tlc_DCData[16] is for OUT0 of the second TLC5940, etc.
  362. ///
  363. /// Valid dot-correction values range from 0 through 63 (i.e. they are 6-bit).
  364. ///
  365.  
  366. uint8_t tlc_DCData[NUM_TLCS * 16] = INITIAL_DCDATA;
  367.  
  368.  
  369. void setDCData(int tlcOutput, uint8_t value)
  370.   // Sets a value in the local tlc_DCData array which will be used as the
  371.   // dot-correction value for the specified TLC5940 output the next time sendDCData
  372.   // is called.  OUT0 of the first TLC is tlcOutput = 0, OUT0 of the next TLC
  373.   // is tlcOutput = 16, and so on.  63 is the maximum allowed value.
  374. {tlc_DCData[tlcOutput] = value;
  375.   return;}
  376.  
  377.  
  378. uint8_t getDCData(int tlcOutput)
  379.   // Gets a value from the local tlc_DCData array.
  380. {return(tlc_DCData[tlcOutput]);}
  381.  
  382.  
  383. void sendDCData ()
  384. // There are four 6-bit DC data values packed into every three bytes.
  385. {while (tlc_needXLAT);  // wait for pending GSData to be latched in
  386.   digitalWrite(VPRG_PIN, HIGH);  // VPRG high says we're setting the DC register
  387.   sendSPIData6Bit(tlc_DCData, NUM_TLCS * 16);
  388.   // Sending DC data can be done without blanking the output.  Just latch it
  389.   // in and magic happens.
  390.   pulseXLAT();
  391.   tlc_needExtraSCLKPulseAfterGSData = true;
  392.   return;}
  393.  
  394.  
  395. ////////////////////////////////////////////////////////////////////////////////
  396. /// TLC5940 overall
  397.  
  398. void initTLC5940 ()
  399. {setAllGSData(0);
  400.   initBLANKPin();
  401.   initXLAT();
  402.   initVPRG();
  403.   // initXERR();  // *** only do this if I actually connect the pin on the PCB
  404.   setupTLC5940_SPI();
  405.   sendDCData();
  406.   initGSCLKTimer();
  407.   initBLANKTimer();
  408.   clearBLANK();
  409.   startGSCLKandBLANKTimers();
  410.   sendGSData(0);
  411.   return;}
  412.  
  413.  
  414. static inline void startGSCLKandBLANKTimers ()
  415. {startBLANKTimer();
  416.   startGSCLK();
  417.   return;}
  418.  
  419.  
  420. void sleepTLC5940 ()
  421. {
  422.   sleepGSCLK();
  423.   stopGSCLK();
  424.   sleepBLANKTimer();
  425.   stopBLANKTimer();
  426.   sleepSPI();
  427.   digitalWrite(XLAT_PIN, LOW);
  428.   digitalWrite(VPRG_PIN, LOW);
  429.   clearBLANK();
  430.   return;}
  431.  
  432. void wakeTLC5940 ()
  433. {initBLANKPin();
  434.   initXLAT();
  435.   initVPRG();
  436.   wakeSPI();
  437.   clearBLANK();
  438.   wakeGSCLK();
  439.   wakeBLANKTimer();
  440.   startBLANKTimer();
  441.   //startGSCLKandBLANKTimers();
  442.   return;}
  443.  
  444.  
  445. void pit3_isr ()
  446. // BLANK interrupt
  447. {setBLANK();
  448. stopGSCLK();
  449. stopBLANKTimer();
  450. if (tlc_needXLAT)
  451.   {
  452.    tlc_needXLAT = false;
  453.    pulseXLAT();
  454. if (tlc_needExtraSCLKPulseAfterGSData)
  455.     {
  456.   pulseSPI_SCLK();
  457.   tlc_needExtraSCLKPulseAfterGSData = false;
  458. }
  459.   }
  460. clearBLANK();
  461. startGSCLKandBLANKTimers();
  462. return;}
  463.  
  464.  
  465. ////////////////////////////////////////////////////////////////////////////////
  466. /// End of Code
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement