Advertisement
Guest User

FastLED_SPI.cpp

a guest
Aug 6th, 2014
18
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 19.28 KB | None | 0 0
  1. #if ARDUINO >= 100
  2.   #include "Arduino.h"
  3. #else
  4.    #include "WProgram.h"
  5. #endif
  6. #include <avr/interrupt.h>
  7. #include <avr/io.h>
  8. #include "FastSPI_LED.h"
  9. //#include "wiring.h"
  10. #include "pins_arduino.h"
  11.  
  12. // #define DEBUG_SPI
  13. #ifdef DEBUG_SPI
  14. #define DPRINT Serial.print
  15. #define DPRINTLN Serial.println
  16. #else
  17. #define DPRINT(x)
  18. #define DPRINTLN(x)
  19. #endif
  20.  
  21. // #define COUNT_ROUNDS 1
  22.  
  23. // some spi defines
  24. // Duemilanove and mini w/328
  25. #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
  26. #define SPI_PORT PORTB
  27. #define SPI_DDR  DDRB
  28. #define SPI_PIN  PINB
  29. #define SPI_MOSI 3       // Arduino pin 11.
  30. #define SPI_MISO 4       // Arduino pin 12.
  31. #define SPI_SCK  5       // Arduino pin 13.
  32. #define SPI_SSN  2       // Arduino pin 10.
  33. #define DATA_PIN 11
  34. #define SLAVE_PIN 12
  35. #define CLOCK_PIN 13
  36. #define LATCH_PIN 10
  37.  
  38. // Mega.
  39. #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  40. #define SPI_PORT PORTB
  41. #define SPI_DDR  DDRB
  42. #define SPI_PIN  PINB
  43. #define SPI_MOSI 2       // Arduino pin 51.
  44. #define SPI_MISO 3       // Arduino pin 50.
  45. #define SPI_SCK  1       // Arduino pin 52.
  46. #define SPI_SSN  0       // Arduino pin 53.
  47. #define DATA_PIN 51
  48. #define SLAVE_PIN 50
  49. #define CLOCK_PIN 52
  50. #define LATCH_PIN 53
  51. #endif
  52.  
  53. #define BIT_HI(R, P) (R) |= _BV(P)
  54. #define BIT_LO(R, P) (R) &= ~_BV(P)
  55.  
  56. #define MASK_HI(R, P) (R) |= (P)
  57. #define MASK_LO(R, P) (R) &= ~(P)
  58.  
  59. // HL1606 defines
  60. //Commands for each LED to be ORd together.
  61.  
  62. #define TM_1606 153
  63.  
  64. #define Command     B10000000
  65. #define Commandx2   B11000000   //Use this one to make dimming twice as fast.
  66. #define BlueOff    B00000000  
  67. #define BlueOn     B00010000
  68. #define BlueUp     B00100000
  69. #define BlueDown   B00110000
  70. #define RedOff      B00000000
  71. #define RedOn       B00000100
  72. #define RedUp       B00001000
  73. #define RedDown     B00001100
  74. #define GreenOff     B00000000
  75. #define GreenOn      B00000001
  76. #define GreenUp      B00000010
  77. #define GreenDown    B00000011
  78.  
  79. #define BRIGHT_MAX 256
  80.  
  81. // Some ASM defines
  82. #define NOP __asm__ __volatile__ ("cp r0,r0\n");
  83. #define NOP2 NOP NOP
  84. #define NOP1 NOP
  85. #define NOP3 NOP NOP2
  86. #define NOP4 NOP NOP3
  87. #define NOP5 NOP NOP4
  88. #define NOP6 NOP NOP5
  89. #define NOP7 NOP NOP6
  90. #define NOP8 NOP NOP7
  91. #define NOP9 NOP NOP8
  92. #define NOP10 NOP NOP9
  93. #define NOP11 NOP NOP10
  94. #define NOP12 NOP NOP11
  95. #define NOP13 NOP NOP12
  96. #define NOP14 NOP NOP13
  97. #define NOP16 NOP14 NOP2
  98. #define NOP20 NOP10 NOP10
  99. #define NOP22 NOP20 NOP2
  100.  
  101. #define TM1809_BIT_SET(X,N,_PORT) if( X & (1<<N) ) { MASK_HI(_PORT,PIN); NOP5; MASK_LO(_PORT,PIN); NOP2; } else { MASK_HI(_PORT,PIN); NOP2; MASK_LO(_PORT,PIN); NOP5; }
  102.  
  103. #define TM1809_BIT_ALL(_PORT)   \
  104.                 TM1809_BIT_SET(x,7,_PORT); \
  105.                 TM1809_BIT_SET(x,6,_PORT); \
  106.                 TM1809_BIT_SET(x,5,_PORT); \
  107.                 TM1809_BIT_SET(x,4,_PORT); \
  108.                 TM1809_BIT_SET(x,3,_PORT); \
  109.                 TM1809_BIT_SET(x,2,_PORT); \
  110.                 TM1809_BIT_SET(x,1,_PORT); \
  111.                 TM1809_BIT_SET(x,0,_PORT);
  112.                
  113.  
  114. #define TM1809_ALL(_PORT) \
  115.         while(pData != FastSPI_LED.m_pDataEnd) { register unsigned char x = *pData++;  TM1809_BIT_ALL(_PORT); }
  116. #define TM1809_ALL2(_PORT) \
  117.         while(pData2 != FastSPI_LED.m_pDataEnd2) { register unsigned char x = *pData2++;  TM1809_BIT_ALL(_PORT); }
  118.  
  119. #define TM1809_BIT_ALLD TM1809_BIT_ALL(PORTD);
  120. #define TM1809_BIT_ALLB TM1809_BIT_ALL(PORTB);
  121.  
  122. CFastSPI_LED FastSPI_LED;
  123.  
  124. // local prototyps
  125. extern "C" {
  126. void spi595(void);
  127. void spihl1606(void);
  128. void spilpd6803(void);
  129. };
  130.  
  131. // local variables used for state tracking and pre-computed values
  132. // TODO: move these into the class as necessary
  133. static unsigned char *pData;
  134. static unsigned char *pData2;
  135. static unsigned char nBrightIdx=0;
  136. static unsigned char nBrightMax=0;
  137. static unsigned char nCountBase=0;
  138. static unsigned char nCount=0;
  139. static unsigned char nLedBlocks=0;
  140. unsigned char nChip=0;
  141. //static unsigned long adjustedUSecTime;
  142.  
  143.  
  144. void CFastSPI_LED::setDirty() { m_nDirty = 1; }
  145.  
  146. void CFastSPI_LED::init() {
  147.   // store some static locals (makes lookup faster)
  148.   pData = m_pDataEnd;
  149.   pData2 = m_pDataEnd2;
  150.   nCountBase = m_nLeds / 3;
  151.   // set up the spi timer - also do some initial timing loops to get base adjustments
  152.   // for the timer below  
  153.   setup_hardware_spi();
  154.   delay(10);
  155.   if(m_eChip != SPI_WS2801 && m_eChip != SPI_TM1809) {
  156.     setup_timer1_ovf();
  157.   }
  158. }
  159.  
  160. //
  161. void CFastSPI_LED::start() {
  162.   if(m_eChip != SPI_WS2801 && m_eChip != SPI_TM1809) {
  163.     TCCR1B |= clockSelectBits;                                                     // reset clock select register
  164.   }
  165. }
  166.  
  167. void CFastSPI_LED::stop() {
  168.   if(m_eChip != SPI_WS2801 && m_eChip != SPI_TM1809) {
  169.     // clear the clock select bits
  170.     TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  171.   }
  172. }
  173.  
  174.  
  175. void CFastSPI_LED::setChipset(EChipSet eChip) {
  176.   m_eChip = eChip;
  177.   nChip = eChip;
  178.   switch(eChip) {
  179.     case SPI_595:
  180.       nBrightIdx = 256 / 128;
  181.       nBrightMax = 256 - nBrightIdx;
  182.       // Set some info used for taking advantage of extreme loop unrolling elsewhere
  183.       if(m_nLeds % 24 == 0 ) {
  184.     nLedBlocks = m_nLeds / 24;
  185.     if(nLedBlocks > 4) { nLedBlocks = 0; }
  186.       } else {
  187.     nLedBlocks = 0;
  188.       }
  189.       break;
  190.     case SPI_HL1606:
  191.       // nTimerKick = 153; // shooting for ~ 125,000 rounds/second - 66% cpu
  192.       nBrightIdx = (m_nLeds <= 20) ? (256 / 80) : (256 / 32);
  193.       nBrightMax = 256 - nBrightIdx;
  194.       nCount = nCountBase;
  195.       break;
  196.     case SPI_LPD6803:
  197.       nBrightIdx = 0;
  198.       break;
  199.   }
  200.  
  201.   // set default cpu percentage targets  
  202.   switch(FastSPI_LED.m_eChip) {
  203.     case CFastSPI_LED::SPI_595: m_cpuPercentage = 53; break;
  204.     case CFastSPI_LED::SPI_LPD6803: m_cpuPercentage = 50; break;
  205.     case CFastSPI_LED::SPI_HL1606: m_cpuPercentage = 65; break;
  206.     case CFastSPI_LED::SPI_WS2801: m_cpuPercentage = 25; break;
  207.     case CFastSPI_LED::SPI_TM1809: m_cpuPercentage = 5; break;
  208.   }  
  209.  
  210.   // set default spi rates
  211.   switch(m_eChip) {
  212.     case CFastSPI_LED::SPI_HL1606:
  213.       m_nDataRate = 2;
  214.       if(m_nLeds > 20) {
  215.     m_nDataRate = 3;
  216.       }
  217.       break;
  218.     case CFastSPI_LED::SPI_595:  
  219.     case CFastSPI_LED::SPI_LPD6803:
  220.     case CFastSPI_LED::SPI_WS2801:
  221.     case CFastSPI_LED::SPI_TM1809:
  222.       m_nDataRate = 0;
  223.       break;
  224.   }
  225. }
  226.  
  227. #define SPI_A(data) SPDR=data;
  228. #define SPI_B while(!(SPSR & (1<<SPIF)));
  229. #define SPI_TRANSFER(data) { SPDR=data; while(!(SPSR & (1<<SPIF))); }
  230.  
  231. #if 0
  232. static int in=0;
  233. ISR(SPI_STC_vect) {
  234.        static unsigned char nBrightness = 1;
  235.     if(pData == FastSPI_LED.m_pData)
  236.     {
  237.       BIT_HI(SPI_PORT,SPI_SSN);
  238.  
  239.       pData = FastSPI_LED.m_pDataEnd;
  240.       if(nBrightness > nBrightMax) { nBrightness = 1; }
  241.       else { nBrightness += nBrightIdx; }
  242.       // if( (nBrightness += nBrightIdx) > BRIGHT_MAX) { nBrightness = 1; }  
  243.       // nCount = FastSPI_LED.m_nLeds+1;
  244.       BIT_LO(SPI_PORT,SPI_SSN);
  245.       //return;
  246.     }
  247.     {  
  248.       register unsigned char nCheck = nBrightness;
  249.       register unsigned char aByte = Command;
  250.       if(*(--pData) > nCheck) { aByte |= BlueOn; } if(*(--pData) > nCheck) { aByte |= GreenOn; } if(*(--pData) > nCheck) { aByte |= RedOn; }
  251.       SPI_A(aByte);
  252. #ifdef COUNT_ROUNDS
  253.       FastSPI_LED.m_nCounter++;
  254. #endif
  255.     }
  256. }
  257. #endif
  258.  
  259. // Why not use function pointers?  They're expensive!  Having TIMER1_OVF_vect call a chip
  260. // specific interrupt function through a pointer adds approximately 1.3µs over the if/else blocks
  261. // below per cycle.  That doesn't sound like a lot, though, right?  Wrong.  For the HL-1606, with
  262. // 40 leds, you may want to push up to 125,000 cycles/second.  1.3µs extra per cycle means 162.5
  263. // milliseconds.  Put a different way, you just cost yourself 16.25% of your cpu time.  This is on
  264. // a 16Mhz processor.  On an 8Mhz processor, the hit is even more severe, percentage wise.  1.3µs
  265. // is also, for another point of data, only 20 clocks on a 20Mhz processor.  Every extra register push/pop
  266. // that needs to be added to the function is 4 cycles (2 for push, 2 for pop) - or .25µs.  To call through
  267. // a function pointer requires two pushes and two pops (to save r30/r31) or 8 cycles, plus the actual call
  268. // which is 4 clocks, and then a reti which is another 4 clocks, plus the loading of the function pointer
  269. // which is itself 4 clocks (2 clocks for each of loading the high and low bytes of the function's address)
  270. // The asm below only adds 12 clocks (and did some other tightening in the hl1606 code to get us closer
  271. // to being able to saturate as well) - wouldn't have to worry push/pop'ing r1 if someone out there wasn't
  272. // misbehaving and using r1 for something other than zero!
  273. extern "C"  void TIMER1_OVF_vect(void) __attribute__ ((signal,naked,__INTR_ATTRS));
  274. void TIMER1_OVF_vect(void) {
  275. #if 1
  276.   __asm__ __volatile__ ( "push r1");
  277.   __asm__ __volatile__ ( "lds r1, nChip" );
  278.   __asm__ __volatile__ ( "sbrc r1, 1" );
  279.   __asm__ __volatile__ ( "rjmp do1606" );
  280.   __asm__ __volatile__ ( "sbrs r1, 0" );
  281.   __asm__ __volatile__ ( "rjmp do6803" );
  282.   __asm__ __volatile__ ( "do595: pop r1" );
  283.   __asm__ __volatile__ ( "  jmp spi595" );
  284.   __asm__ __volatile__ ( "do6803: pop r1" );
  285.   __asm__ __volatile__ ( "  jmp spilpd6803" );
  286.   __asm__ __volatile__ ( "do1606: pop r1" );
  287.   __asm__ __volatile__ ( "  jmp spihl1606" );
  288. #else
  289.   __asm__ __volatile__ ( "lds r1, nChip" );
  290.   __asm__ __volatile__ ( "sbrc r1, 1" );
  291.   __asm__ __volatile__ ( "jmp spihl1606" );
  292.   __asm__ __volatile__ ( "sbrc r1, 2" );
  293.   __asm__ __volatile__ ( "jmp spilpd6803");
  294.   __asm__ __volatile__ ( "jmp spi595" );
  295. #endif
  296. //ISR(TIMER1_OVF_vect) {
  297. //#ifdef COUNT_ROUNDS
  298. //  FastSPI_LED.m_nCounter++;
  299. //#endif
  300. }
  301.  
  302. //  if(FastSPI_LED.m_eChip == CFastSPI_LED::SPI_HL1606)
  303.   ISR(spihl1606)
  304.   {
  305.      static unsigned char nBrightness = 1;
  306.      register unsigned char aByte = Command;
  307.    
  308.     //if(pData == FastSPI_LED.m_pData)
  309.     if(nCount != 0)
  310.     {  
  311.       register unsigned char nCheck = nBrightness;
  312.       if(*(--pData) > nCheck) { aByte |= BlueOn; } if(*(--pData) > nCheck) { aByte |= GreenOn; } if(*(--pData) > nCheck) { aByte |= RedOn; }
  313.       // SPI_B;
  314.       SPI_A(aByte);
  315.       nCount--;
  316.       return;
  317.     }
  318.     else
  319.     {
  320.       BIT_HI(SPI_PORT,SPI_SSN);
  321.       pData = FastSPI_LED.m_pDataEnd;
  322.       BIT_LO(SPI_PORT,SPI_SSN);
  323.       if (nBrightness <= nBrightMax) { nBrightness += nBrightIdx; }
  324.       else { nBrightness = 1; }
  325.       BIT_HI(SPI_PORT,SPI_SSN);
  326.       // if( (nBrightness += nBrightIdx) > BRIGHT_MAX) { nBrightness = 1; }  
  327.       nCount = nCountBase;
  328.       BIT_LO(SPI_PORT,SPI_SSN);
  329.       SPI_A(aByte);
  330.       return;
  331.     }
  332.   }
  333.   //else if(FastSPI_LED.m_eChip == CFastSPI_LED::SPI_595)
  334.   ISR(spi595)
  335.   {
  336.     static unsigned char nBrightness = 1;
  337.     if(nBrightness > nBrightMax) { nBrightness = 1; }
  338.     else { nBrightness += nBrightIdx; }
  339.     // register unsigned char nCheck = nBrightness;
  340.     register unsigned char aByte;
  341.     //register unsigned char *
  342.     {
  343.       BIT_LO(SPI_PORT,SPI_SSN);
  344.  
  345. #define BIT_SET(nBit) if(*(--pData) >= nBrightness) { aByte |= nBit; }
  346. #define BLOCK8 aByte=0; BIT_SET(0x80); BIT_SET(0x40); BIT_SET(0x20); BIT_SET(0x10); BIT_SET(0x08); BIT_SET(0x04); BIT_SET(0x02); BIT_SET(0x01);
  347. #define COMMANDA BLOCK8 ; SPI_A(aByte);
  348. #define COMMANDB BLOCK8 ; SPI_B; SPI_A(aByte);
  349. #define COM3A COMMANDA ; COMMANDB ; COMMANDB
  350. #define COM3B COMMANDB ; COMMANDB ; COMMANDB
  351. #define COM12 COM3A ; COM3B ; COM3B ; COM3B
  352.  
  353.       // If we have blocks of 3 8 bit shift registers, that gives us 8 rgb leds, we'll do some aggressive
  354.       // loop unrolling for cases where we have multiples of 3 shift registers - i should expand this out to
  355.       // handle a wider range of cases at some point
  356.       switch(nLedBlocks) {
  357.     case 4: COM12; break;
  358.     case 3: COM3A; COM3B; COM3B; break;
  359.     case 2: COM3A; COM3B; break;
  360.     case 1: COM3A; break;
  361.     default:
  362.       BLOCK8;
  363.       SPI_A(aByte);
  364.       for(register char i = FastSPI_LED.m_nLeds; i > 8; i-= 8) {
  365.         BLOCK8;
  366.         SPI_B;
  367.         SPI_A(aByte);
  368.       }
  369.       }
  370.       BIT_HI(SPI_PORT,SPI_SSN);
  371.       pData = FastSPI_LED.m_pDataEnd;
  372.       return;
  373.     }
  374.   }
  375.   //else // if(FastSPI_LED.m_eChip == CFastSPI_LED::SPI_LPD6803)
  376.   ISR(spilpd6803)
  377.   {
  378.     static unsigned char nState=1;
  379.     if(FastSPI_LED.m_eChip == CFastSPI_LED::SPI_LPD6803)
  380.     {
  381.       if(nState==1)
  382.       {
  383.     SPI_A(0);
  384.     if(FastSPI_LED.m_nDirty==1) {
  385.       nState = 0;
  386.       FastSPI_LED.m_nDirty = 0;
  387.       SPI_B;
  388.       SPI_A(0);
  389.       pData = FastSPI_LED.m_pData;
  390.       return;
  391.     }
  392.     SPI_B;
  393.     SPI_A(0);
  394.     return;
  395.       }
  396.       else
  397.       {
  398.     register unsigned int command;
  399.     command = 0x8000;
  400.     command |= (*(pData++) & 0xF8) << 7; // red is the high 5 bits
  401.     command |= (*(pData++) & 0xF8) << 2; // green is the middle 5 bits
  402.     command |= *(pData++) >> 3 ; // blue is the low 5 bits
  403.     SPI_B;
  404.     SPI_A( (command>>8) &0xFF);
  405.     if(pData == FastSPI_LED.m_pDataEnd) {
  406.       nState = 1;
  407.     }
  408.     SPI_B;
  409.     SPI_A( command & 0xFF);
  410.     return;
  411.       }
  412.     }
  413.   }
  414.  
  415. void CFastSPI_LED::show() {
  416.     setDirty();
  417.     if(FastSPI_LED.m_eChip == CFastSPI_LED::SPI_WS2801)
  418.     {
  419.         cli();
  420.     pData = FastSPI_LED.m_pData;
  421.         while(pData != FastSPI_LED.m_pDataEnd) {
  422.       SPI_B; SPI_A(*pData++);
  423.         }
  424.     m_nDirty = 0;
  425.         sei();
  426.     }
  427.     else if(FastSPI_LED.m_eChip == CFastSPI_LED::SPI_TM1809)
  428.     {
  429.       cli();
  430.       m_nDirty = 0;
  431.       pData = FastSPI_LED.m_pData;
  432.       pData2= FastSPI_LED.m_pData2;
  433.       register unsigned char PIN = digitalPinToBitMask(FastSPI_LED.m_nPin);
  434.       //register unsigned char PIN2 = digitalPinToBitMask(FastSPI_LED.m_nPin2);
  435.      
  436.       register volatile uint8_t *pPort = FastSPI_LED.m_pPort;
  437.       register volatile uint8_t *pPort2 = FastSPI_LED.m_pPort2;
  438.  
  439.       if(m_pPort == NOT_A_PIN) { /* do nothing */ }
  440.       else { TM1809_ALL(*pPort); }
  441.       if(m_pPort2 == NOT_A_PIN) { /* do nothing */ }
  442.       else { TM1809_ALL2(*pPort2); }
  443.       sei();
  444.     }
  445. }
  446.  
  447. void CFastSPI_LED::setDataRate(int datarate) {
  448.   m_nDataRate = datarate;
  449. }
  450.  
  451. void CFastSPI_LED::setPin(int pin) {
  452.   m_nPin = pin;
  453.   m_pPort = (uint8_t*)portOutputRegister(digitalPinToPort(pin));
  454. }
  455.  
  456. void CFastSPI_LED::setPin2(int pin) {
  457.   m_nPin2 = pin;
  458.   m_pPort2 = (uint8_t*)portOutputRegister(digitalPinToPort(pin));
  459. }
  460.  
  461. void CFastSPI_LED::setup_hardware_spi(void) {
  462.   byte clr;
  463.  
  464.   if(m_eChip != SPI_TM1809) {
  465.     pinMode(DATA_PIN,OUTPUT);
  466.     pinMode(LATCH_PIN,OUTPUT);
  467.     pinMode(CLOCK_PIN,OUTPUT);
  468.     pinMode(SLAVE_PIN,OUTPUT);
  469.     digitalWrite(DATA_PIN,LOW);
  470.     digitalWrite(LATCH_PIN,LOW);
  471.     digitalWrite(CLOCK_PIN,LOW);
  472.     digitalWrite(SLAVE_PIN,LOW);
  473.   } else {
  474.     pinMode(m_nPin, OUTPUT);
  475.     digitalWrite(m_nPin,LOW);
  476.   }
  477.  
  478.  
  479.   // spi prescaler:
  480.   // SPI2X SPR1 SPR0
  481.   //   0     0     0    fosc/4
  482.   //   0     0     1    fosc/16
  483.   //   0     1     0    fosc/64
  484.   //   0     1     1    fosc/128
  485.   //   1     0     0    fosc/2
  486.   //   1     0     1    fosc/8
  487.   //   1     1     0    fosc/32
  488.   //   1     1     1    fosc/64
  489.   SPCR |= ( (1<<SPE) | (1<<MSTR) ); // enable SPI as master
  490.   SPCR &= ~ ( (1<<SPR1) | (1<<SPR0) ); // clear prescaler bits
  491.   clr=SPSR; // clear SPI status reg
  492.   clr=SPDR; // clear SPI data reg
  493.  
  494.   // set the prescalar bits based on the chosen data rate values
  495.   bool b2x = false;
  496.   switch(m_nDataRate) {
  497.     /* fosc/2   */ case 0: b2x=true; break;
  498.     /* fosc/4   */ case 1: break;
  499.     /* fosc/8   */ case 2: SPCR |= (1<<SPR0); b2x=true; break;
  500.     /* fosc/16  */ case 3: SPCR |= (1<<SPR0); break;
  501.     /* fosc/32  */ case 4: SPCR |= (1<<SPR1); b2x=true; break;
  502.     /* fosc/64  */ case 5: SPCR |= (1<<SPR1); break;
  503.     /* fosc/64  */ case 6: SPCR |= (1<<SPR1); SPCR |= (1<<SPR0); b2x=true; break;
  504.     /* fosc/128 */ default: SPCR |= (1<<SPR1); SPCR |= (1<<SPR0); break;
  505.   }
  506.   if(b2x) { SPSR |= (1<<SPI2X); }
  507.   else { SPSR &= ~ (1<<SPI2X); }
  508.  
  509.   // dig out some timing info
  510.   SPI_A(0);
  511.   TIMER1_OVF_vect();
  512.  
  513.   // First thing to do is count our cycles to figure out how to line
  514.   // up the desired performance percentages
  515.   unsigned long nRounds=0;
  516.   volatile int x = 0;
  517.   unsigned long mCStart = millis();
  518.   for(volatile int i = 0 ; i < 10000; i++) {
  519.     ;
  520. #ifdef COUNT_ROUNDS
  521.   m_nCounter++;
  522. #endif
  523.   }
  524.   unsigned long mCEnd = millis();
  525.   m_nCounter=0;
  526.   nRounds = 10000;
  527.   DPRINT("10000 round empty loop in ms: "); DPRINTLN(mCEnd - mCStart);
  528.   unsigned long mStart,mStop;
  529.   if(m_eChip == SPI_WS2801 || m_eChip == SPI_TM1809) {
  530. #ifdef DEBUG_SPI
  531.     mStart = millis();
  532.     for(volatile int i = 0; i < 10000; i++) {
  533.       show();
  534.     }
  535.     mStop = millis();
  536. #endif
  537.   } else {
  538.     mStart = millis();
  539.     for(volatile int i = 0; i < 10000; i++) {
  540.       TIMER1_OVF_vect();
  541.     }
  542.     mStop = millis();
  543.   }
  544.   DPRINT(nRounds); DPRINT(" rounds of rgb out in ms: "); DPRINTLN(mStop - mStart);
  545.  
  546.   // This gives us the time for 10 rounds in µs
  547.   m_adjustedUSecTime = (mStop-mStart) - (mCEnd - mCStart);
  548.  
  549. }
  550.  
  551. // Core borrowed and adapted from the Timer1 Arduino library - by Jesse Tane
  552. #define RESOLUTION 65536
  553.  
  554. void CFastSPI_LED::setup_timer1_ovf(void) {
  555.   // Now that we have our per-cycle timing, figure out how to set up the timer to
  556.   // match the desired cpu percentage
  557.   TCCR1A = 0;
  558.   TCCR1B = _BV(WGM13);
  559.  
  560.   unsigned long baseCounts = (((unsigned long)m_cpuPercentage) * 100000) / m_adjustedUSecTime;
  561.   unsigned long us10;
  562.   switch(FastSPI_LED.m_eChip) {
  563.     case CFastSPI_LED::SPI_LPD6803: us10 = (1000000 ) / baseCounts; break;
  564.     case CFastSPI_LED::SPI_HL1606: us10 = (1000000 ) / baseCounts; break;
  565.     case CFastSPI_LED::SPI_595: us10 = (1000000 ) / baseCounts; break;
  566.     case CFastSPI_LED::SPI_WS2801: us10 = (1000000) / baseCounts; break;
  567.   }
  568.  
  569.   DPRINT("bc:"); DPRINTLN(baseCounts);
  570.   DPRINT("us*10:"); DPRINTLN(us10);
  571.  
  572.   long cycles = ( (F_CPU)*us10) / (2000000);                                            // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  573.  
  574.   if(FastSPI_LED.m_eChip == SPI_HL1606) {
  575.     // can't have a cycle at or less than 66 cycles on a 16Mhz system, or 33 cycles on an 8Mhz system
  576.     // with the hl1606's - at least with 40 leds.  Stupid timing constraints.  The chips whig out if you send
  577.     // data at a faster rate.  This rate limit means we don't waste time waiting on SPSR
  578.     if(F_CPU == 16000000 && cycles < 67) { cycles = 67; }
  579.     if(F_CPU == 8000000 && cycles < 34) { cycles = 34; }
  580.   }
  581.   DPRINT("cy:"); DPRINTLN(cycles);
  582.  
  583.   if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal/TCCR
  584.   else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  585.   else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  586.   else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  587.   else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  588.   else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum
  589.   ICR1 = cycles;                                                     // ICR1 is TOP in p & f correct pwm mode
  590.   TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  591.   // call start explicitly TCCR1B |= clockSelectBits;                                                     // reset clock select register
  592.  
  593.   TIMSK1 = _BV(TOIE1);
  594.   sei();
  595. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement