PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CShiftPWM.cpp 19KB

3 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. /*
  2. CShiftPWM.cpp - ShiftPWM.h - Library for Arduino to PWM many outputs using shift registers
  3. Copyright (c) 2011-2012 Elco Jacobs, www.elcojacobs.com
  4. All right reserved.
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. /* workaround for a bug in WString.h */
  18. #define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
  19. #include "CShiftPWM.h"
  20. #include <Arduino.h>
  21. CShiftPWM::CShiftPWM(int timerInUse, bool noSPI, int latchPin, int dataPin, int clockPin) : // Constants are set in initializer list
  22. m_timer(timerInUse), m_noSPI(noSPI), m_latchPin(latchPin), m_dataPin(dataPin), m_clockPin(clockPin){
  23. m_ledFrequency = 0;
  24. m_maxBrightness = 0;
  25. m_amountOfRegisters = 0;
  26. m_amountOfOutputs = 0;
  27. m_counter = 0;
  28. m_pinGrouping = 1; // Default = RGBRGBRGB... PinGrouping = 3 means: RRRGGGBBBRRRGGGBBB...
  29. m_PWMValues=0;
  30. }
  31. CShiftPWM::~CShiftPWM() {
  32. if(m_PWMValues>0){
  33. free( m_PWMValues );
  34. }
  35. }
  36. bool CShiftPWM::IsValidPin(int pin){
  37. if(pin<m_amountOfOutputs){
  38. return 1;
  39. }
  40. else{
  41. Serial.print(F("Error: Trying to write duty cycle of pin "));
  42. Serial.print(pin);
  43. Serial.print(F(" , while number of outputs is "));
  44. Serial.print(m_amountOfOutputs);
  45. Serial.print(F(" , numbered 0-"));
  46. Serial.println(m_amountOfOutputs-1);
  47. delay(1000);
  48. return 0;
  49. }
  50. }
  51. void CShiftPWM::SetOne(int pin, unsigned char value){
  52. if(IsValidPin(pin) ){
  53. m_PWMValues[pin]=value;
  54. }
  55. }
  56. void CShiftPWM::SetAll(unsigned char value){
  57. for(int k=0 ; k<(m_amountOfOutputs);k++){
  58. m_PWMValues[k]=value;
  59. }
  60. }
  61. void CShiftPWM::SetGroupOf2(int group, unsigned char v0,unsigned char v1, int offset){
  62. int skip = m_pinGrouping*(group/m_pinGrouping); // is not equal to 2*group. Division is rounded down first.
  63. if(IsValidPin(group+skip+offset+m_pinGrouping) ){
  64. m_PWMValues[group+skip+offset] =v0;
  65. m_PWMValues[group+skip+offset+m_pinGrouping] =v1;
  66. }
  67. }
  68. void CShiftPWM::SetGroupOf3(int group, unsigned char v0,unsigned char v1,unsigned char v2, int offset){
  69. int skip = 2*m_pinGrouping*(group/m_pinGrouping); // is not equal to 2*group. Division is rounded down first.
  70. if(IsValidPin(group+skip+offset+2*m_pinGrouping) ){
  71. m_PWMValues[group+skip+offset] =v0;
  72. m_PWMValues[group+skip+offset+m_pinGrouping] =v1;
  73. m_PWMValues[group+skip+offset+m_pinGrouping*2] =v2;
  74. }
  75. }
  76. void CShiftPWM::SetGroupOf4(int group, unsigned char v0,unsigned char v1,unsigned char v2,unsigned char v3, int offset){
  77. int skip = 3*m_pinGrouping*(group/m_pinGrouping); // is not equal to 2*group. Division is rounded down first.
  78. if(IsValidPin(group+skip+offset+3*m_pinGrouping) ){
  79. m_PWMValues[group+skip+offset] =v0;
  80. m_PWMValues[group+skip+offset+m_pinGrouping] =v1;
  81. m_PWMValues[group+skip+offset+m_pinGrouping*2] =v2;
  82. m_PWMValues[group+skip+offset+m_pinGrouping*3] =v3;
  83. }
  84. }
  85. void CShiftPWM::SetGroupOf5(int group, unsigned char v0,unsigned char v1,unsigned char v2,unsigned char v3,unsigned char v4, int offset){
  86. int skip = 4*m_pinGrouping*(group/m_pinGrouping); // is not equal to 2*group. Division is rounded down first.
  87. if(IsValidPin(group+skip+offset+4*m_pinGrouping) ){
  88. m_PWMValues[group+skip+offset] =v0;
  89. m_PWMValues[group+skip+offset+m_pinGrouping] =v1;
  90. m_PWMValues[group+skip+offset+m_pinGrouping*2] =v2;
  91. m_PWMValues[group+skip+offset+m_pinGrouping*3] =v3;
  92. m_PWMValues[group+skip+offset+m_pinGrouping*4] =v4;
  93. }
  94. }
  95. void CShiftPWM::SetRGB(int led, unsigned char r,unsigned char g,unsigned char b, int offset){
  96. int skip = 2*m_pinGrouping*(led/m_pinGrouping); // is not equal to 2*led. Division is rounded down first.
  97. if(IsValidPin(led+skip+offset+2*m_pinGrouping) ){
  98. m_PWMValues[led+skip+offset] =( (unsigned int) r * m_maxBrightness)>>8;
  99. m_PWMValues[led+skip+offset+m_pinGrouping] =( (unsigned int) g * m_maxBrightness)>>8;
  100. m_PWMValues[led+skip+offset+2*m_pinGrouping] =( (unsigned int) b * m_maxBrightness)>>8;
  101. }
  102. }
  103. void CShiftPWM::SetAllRGB(unsigned char r,unsigned char g,unsigned char b){
  104. for(int k=0 ; (k+3*m_pinGrouping-1) < m_amountOfOutputs; k+=3*m_pinGrouping){
  105. for(int l=0; l<m_pinGrouping;l++){
  106. m_PWMValues[k+l] = ( (unsigned int) r * m_maxBrightness)>>8;
  107. m_PWMValues[k+l+m_pinGrouping] = ( (unsigned int) g * m_maxBrightness)>>8;
  108. m_PWMValues[k+l+m_pinGrouping*2] = ( (unsigned int) b * m_maxBrightness)>>8;
  109. }
  110. }
  111. }
  112. void CShiftPWM::SetHSV(int led, unsigned int hue, unsigned int sat, unsigned int val, int offset){
  113. unsigned char r=0,g=0,b=0;
  114. unsigned int H_accent = hue/60;
  115. unsigned int bottom = ((255 - sat) * val)>>8;
  116. unsigned int top = val;
  117. unsigned char rising = ((top-bottom) *(hue%60 ) ) / 60 + bottom;
  118. unsigned char falling = ((top-bottom) *(60-hue%60) ) / 60 + bottom;
  119. switch(H_accent) {
  120. case 0:
  121. r = top;
  122. g = rising;
  123. b = bottom;
  124. break;
  125. case 1:
  126. r = falling;
  127. g = top;
  128. b = bottom;
  129. break;
  130. case 2:
  131. r = bottom;
  132. g = top;
  133. b = rising;
  134. break;
  135. case 3:
  136. r = bottom;
  137. g = falling;
  138. b = top;
  139. break;
  140. case 4:
  141. r = rising;
  142. g = bottom;
  143. b = top;
  144. break;
  145. case 5:
  146. r = top;
  147. g = bottom;
  148. b = falling;
  149. break;
  150. }
  151. SetRGB(led,r,g,b,offset);
  152. }
  153. void CShiftPWM::SetAllHSV(unsigned int hue, unsigned int sat, unsigned int val){
  154. // Set the first LED
  155. SetHSV(0, hue, sat, val);
  156. // Copy RGB values all LED's.
  157. SetAllRGB(m_PWMValues[0],m_PWMValues[m_pinGrouping],m_PWMValues[2*m_pinGrouping]);
  158. }
  159. // OneByOne functions are usefull for testing all your outputs
  160. void CShiftPWM::OneByOneSlow(void){
  161. OneByOne_core(1024/m_maxBrightness);
  162. }
  163. void CShiftPWM::OneByOneFast(void){
  164. OneByOne_core(1);
  165. }
  166. void CShiftPWM::OneByOne_core(int delaytime){
  167. int pin,brightness;
  168. SetAll(0);
  169. for(pin=0;pin<m_amountOfOutputs;pin++){
  170. for(brightness=0;brightness<m_maxBrightness;brightness++){
  171. m_PWMValues[pin]=brightness;
  172. delay(delaytime);
  173. }
  174. for(brightness=m_maxBrightness;brightness>=0;brightness--){
  175. m_PWMValues[pin]=brightness;
  176. delay(delaytime);
  177. }
  178. }
  179. }
  180. void CShiftPWM::SetAmountOfRegisters(unsigned char newAmount){
  181. cli(); // Disable interrupt
  182. unsigned char oldAmount = m_amountOfRegisters;
  183. m_amountOfRegisters = newAmount;
  184. m_amountOfOutputs=m_amountOfRegisters*8;
  185. if(LoadNotTooHigh() ){ //Check if new amount will not result in deadlock
  186. m_PWMValues = (unsigned char *) realloc(m_PWMValues, newAmount*8); //resize array for PWMValues
  187. for(int k=oldAmount; k<(newAmount*8);k++){
  188. m_PWMValues[k]=0; //set new values to zero
  189. }
  190. sei(); //Re-enable interrupt
  191. }
  192. else{
  193. // New value would result in deadlock, keep old values and print an error message
  194. m_amountOfRegisters = oldAmount;
  195. m_amountOfOutputs=m_amountOfRegisters*8;
  196. Serial.println(F("Amount of registers is not increased, because load would become too high"));
  197. sei();
  198. }
  199. }
  200. void CShiftPWM::SetPinGrouping(int grouping){
  201. // Sets the number of pins per color that are used after eachother. RRRRGGGGBBBBRRRRGGGGBBBB would be a grouping of 4.
  202. m_pinGrouping = grouping;
  203. }
  204. bool CShiftPWM::LoadNotTooHigh(void){
  205. // This function calculates if the interrupt load would become higher than 0.9 and prints an error if it would.
  206. // This is with inverted outputs, which is worst case. Without inverting, it would be 42 per register.
  207. float interruptDuration;
  208. if(m_noSPI){
  209. #if defined(__AVR__)
  210. interruptDuration = 96+108*(float) m_amountOfRegisters;
  211. #else
  212. // TODO: perhaps this is too pessimistic? Best to err on the
  213. // side of caution to avoid overcommitting the CPU...
  214. interruptDuration = 96+193*(float) m_amountOfRegisters;
  215. #endif
  216. }
  217. else{
  218. interruptDuration = 97+43* (float) m_amountOfRegisters;
  219. }
  220. float interruptFrequency = (float) m_ledFrequency* ((float) m_maxBrightness + 1);
  221. float load = interruptDuration*interruptFrequency/F_CPU;
  222. if(load > 0.9){
  223. Serial.print(F("New interrupt duration =")); Serial.print(interruptDuration); Serial.println(F("clock cycles"));
  224. Serial.print(F("New interrupt frequency =")); Serial.print(interruptFrequency); Serial.println(F("Hz"));
  225. Serial.print(F("New interrupt load would be "));
  226. Serial.print(load);
  227. Serial.println(F(" , which is too high."));
  228. return 0;
  229. }
  230. else{
  231. return 1;
  232. }
  233. }
  234. void CShiftPWM::Start(int ledFrequency, unsigned char maxBrightness){
  235. // Configure and enable timer1 or timer 2 for a compare and match A interrupt.
  236. m_ledFrequency = ledFrequency;
  237. m_maxBrightness = maxBrightness;
  238. pinMode(m_dataPin, OUTPUT);
  239. pinMode(m_clockPin, OUTPUT);
  240. pinMode(m_latchPin, OUTPUT);
  241. digitalWrite(m_clockPin, LOW);
  242. digitalWrite(m_dataPin, LOW);
  243. if(!m_noSPI){ // initialize SPI when used
  244. // The least significant bit shoult be sent out by the SPI port first.
  245. // equals SPI.setBitOrder(LSBFIRST);
  246. SPCR |= _BV(DORD);
  247. // Here you can set the clock speed of the SPI port. Default is DIV4, which is 4MHz with a 16Mhz system clock.
  248. // If you encounter problems due to long wires or capacitive loads, try lowering the SPI clock.
  249. // equals SPI.setClockDivider(SPI_CLOCK_DIV4);
  250. SPCR = (SPCR & 0b11111000);
  251. SPSR = (SPSR & 0b11111110);
  252. // Set clock polarity and phase for shift registers (Mode 3)
  253. SPCR |= _BV(CPOL);
  254. SPCR |= _BV(CPHA);
  255. // When the SS pin is set as OUTPUT, it can be used as
  256. // a general purpose output port (it doesn't influence
  257. // SPI operations).
  258. pinMode(SS, OUTPUT);
  259. digitalWrite(SS, HIGH);
  260. // Warning: if the SS pin ever becomes a LOW INPUT then SPI
  261. // automatically switches to Slave, so the data direction of
  262. // the SS pin MUST be kept as OUTPUT.
  263. SPCR |= _BV(MSTR);
  264. SPCR |= _BV(SPE);
  265. }
  266. if(LoadNotTooHigh() ){
  267. switch (m_timer) {
  268. #if defined(__AVR__) && defined(OCR1A)
  269. case 1:
  270. InitTimer1();
  271. break;
  272. #endif
  273. #if defined(__AVR__) && defined(OCR2A)
  274. case 2:
  275. InitTimer2();
  276. break;
  277. #endif
  278. #if defined(__AVR__) && defined(OCR3A)
  279. case 3:
  280. InitTimer3();
  281. break;
  282. #endif
  283. #if defined(__arm__) && defined(CORE_TEENSY)
  284. default:
  285. InitTimer1();
  286. break;
  287. #endif
  288. }
  289. }
  290. else{
  291. Serial.println(F("Interrupts are disabled because load is too high."));
  292. cli(); //Disable interrupts
  293. }
  294. }
  295. #if defined(__AVR__) && defined(OCR1A)
  296. void CShiftPWM::InitTimer1(void){
  297. /* Configure timer1 in CTC mode: clear the timer on compare match
  298. * See the Atmega328 Datasheet 15.9.2 for an explanation on CTC mode.
  299. * See table 15-4 in the datasheet. */
  300. bitSet(TCCR1B,WGM12);
  301. bitClear(TCCR1B,WGM13);
  302. bitClear(TCCR1A,WGM11);
  303. bitClear(TCCR1A,WGM10);
  304. /* Select clock source: internal I/O clock, without a prescaler
  305. * This is the fastest possible clock source for the highest accuracy.
  306. * See table 15-5 in the datasheet. */
  307. bitSet(TCCR1B,CS10);
  308. bitClear(TCCR1B,CS11);
  309. bitClear(TCCR1B,CS12);
  310. /* The timer will generate an interrupt when the value we load in OCR1A matches the timer value.
  311. * One period of the timer, from 0 to OCR1A will therefore be (OCR1A+1)/(timer clock frequency).
  312. * We want the frequency of the timer to be (LED frequency)*(number of brightness levels)
  313. * So the value we want for OCR1A is: timer clock frequency/(LED frequency * number of bightness levels)-1 */
  314. m_prescaler = 1;
  315. OCR1A = round((float) F_CPU/((float) m_ledFrequency*((float) m_maxBrightness+1)))-1;
  316. /* Finally enable the timer interrupt, see datasheet 15.11.8) */
  317. bitSet(TIMSK1,OCIE1A);
  318. }
  319. #endif
  320. #if defined(__arm__) && defined(CORE_TEENSY)
  321. static IntervalTimer itimer;
  322. extern void ShiftPWM_handleInterrupt(void);
  323. void CShiftPWM::InitTimer1(void){
  324. itimer.begin(ShiftPWM_handleInterrupt,
  325. 1000000.0 / (m_ledFrequency * (m_maxBrightness+1)));
  326. }
  327. #endif
  328. #if defined(__AVR__) && defined(OCR2A)
  329. void CShiftPWM::InitTimer2(void){
  330. /* Configure timer2 in CTC mode: clear the timer on compare match
  331. * See the Atmega328 Datasheet 15.9.2 for an explanation on CTC mode.
  332. * See table 17-8 in the datasheet. */
  333. bitClear(TCCR2B,WGM22);
  334. bitSet(TCCR2A,WGM21);
  335. bitClear(TCCR2A,WGM20);
  336. /* Select clock source: internal I/O clock, calculate most suitable prescaler
  337. * This is only an 8 bit timer, so choose the prescaler so that OCR2A fits in 8 bits.
  338. * See table 15-5 in the datasheet. */
  339. int compare_value = round((float) F_CPU/((float) m_ledFrequency*((float) m_maxBrightness+1))-1);
  340. if(compare_value <= 255){
  341. m_prescaler = 1;
  342. bitClear(TCCR2B,CS22); bitClear(TCCR2B,CS21); bitClear(TCCR2B,CS20);
  343. }
  344. else if(compare_value/8 <=255){
  345. m_prescaler = 8;
  346. bitClear(TCCR2B,CS22); bitSet(TCCR2B,CS21); bitClear(TCCR2B,CS20);
  347. }
  348. else
  349. if(compare_value/32 <=255){
  350. m_prescaler = 32;
  351. bitClear(TCCR2B,CS22); bitSet(TCCR2B,CS21); bitSet(TCCR2B,CS20);
  352. }
  353. else if(compare_value/64 <= 255){
  354. m_prescaler = 64;
  355. bitSet(TCCR2B,CS22); bitClear(TCCR2B,CS21); bitClear(TCCR2B,CS20);
  356. }
  357. else if(compare_value/128 <= 255){
  358. m_prescaler = 128;
  359. bitSet(TCCR2B,CS22); bitClear(TCCR2B,CS21); bitSet(TCCR2B,CS20);
  360. }
  361. else if(compare_value/256 <= 255){
  362. m_prescaler = 256;
  363. bitSet(TCCR2B,CS22); bitSet(TCCR2B,CS21); bitClear(TCCR2B,CS20);
  364. }
  365. /* The timer will generate an interrupt when the value we load in OCR2A matches the timer value.
  366. * One period of the timer, from 0 to OCR2A will therefore be (OCR2A+1)/(timer clock frequency).
  367. * We want the frequency of the timer to be (LED frequency)*(number of brightness levels)
  368. * So the value we want for OCR2A is: timer clock frequency/(LED frequency * number of bightness levels)-1 */
  369. OCR2A = round( ( (float) F_CPU / (float) m_prescaler ) / ( (float) m_ledFrequency*( (float) m_maxBrightness+1) ) -1);
  370. /* Finally enable the timer interrupt, see datasheet 15.11.8) */
  371. bitSet(TIMSK2,OCIE2A);
  372. }
  373. #endif
  374. #if defined(__AVR__) && defined(OCR3A)
  375. // Arduino Leonardo or Micro
  376. void CShiftPWM::InitTimer3(void){
  377. /*
  378. * Only available on Leonardo and micro.
  379. * Configure timer3 in CTC mode: clear the timer on compare match
  380. * See the Atmega32u4 Datasheet 15.10.2 for an explanation on CTC mode.
  381. * See table 14-5 in the datasheet. */
  382. bitSet(TCCR3B,WGM32);
  383. bitClear(TCCR3B,WGM33);
  384. bitClear(TCCR3A,WGM31);
  385. bitClear(TCCR3A,WGM30);
  386. /* Select clock source: internal I/O clock, without a prescaler
  387. * This is the fastest possible clock source for the highest accuracy.
  388. * See table 15-5 in the datasheet. */
  389. bitSet(TCCR3B,CS30);
  390. bitClear(TCCR3B,CS31);
  391. bitClear(TCCR3B,CS32);
  392. /* The timer will generate an interrupt when the value we load in OCR1A matches the timer value.
  393. * One period of the timer, from 0 to OCR1A will therefore be (OCR1A+1)/(timer clock frequency).
  394. * We want the frequency of the timer to be (LED frequency)*(number of brightness levels)
  395. * So the value we want for OCR1A is: timer clock frequency/(LED frequency * number of bightness levels)-1 */
  396. m_prescaler = 1;
  397. OCR3A = round((float) F_CPU/((float) m_ledFrequency*((float) m_maxBrightness+1)))-1;
  398. /* Finally enable the timer interrupt, see datasheet 15.11.8) */
  399. bitSet(TIMSK3,OCIE3A);
  400. }
  401. #endif
  402. void CShiftPWM::PrintInterruptLoad(void){
  403. //This function prints information on the interrupt settings for ShiftPWM
  404. //It runs a delay loop 2 times: once with interrupts enabled, once disabled.
  405. //From the difference in duration, it can calculate the load of the interrupt on the program.
  406. unsigned long start1,end1,time1,start2,end2,time2,k;
  407. double load, cycles_per_int, interrupt_frequency;
  408. switch (m_timer) {
  409. #if defined(__AVR__) && defined(OCR1A)
  410. case 1:
  411. if(TIMSK1 & (1<<OCIE1A)){
  412. // interrupt is enabled, continue
  413. }
  414. else{
  415. // interrupt is disabled
  416. Serial.println(F("Interrupt is disabled."));
  417. return;
  418. }
  419. break;
  420. #endif
  421. #if defined(__AVR__) && defined(OCR2A)
  422. case 2:
  423. if(TIMSK2 & (1<<OCIE2A)){
  424. // interrupt is enabled, continue
  425. }
  426. else{
  427. // interrupt is disabled
  428. Serial.println(F("Interrupt is disabled."));
  429. return;
  430. }
  431. break;
  432. #endif
  433. #if defined(__AVR__) && defined(OCR3A)
  434. case 3:
  435. if(TIMSK3 & (1<<OCIE3A)){
  436. // interrupt is enabled, continue
  437. }
  438. else{
  439. // interrupt is disabled
  440. Serial.println(F("Interrupt is disabled."));
  441. return;
  442. }
  443. break;
  444. #endif
  445. }
  446. //run with interrupt enabled
  447. start1 = micros();
  448. for(k=0; k<100000; k++){
  449. delayMicroseconds(1);
  450. }
  451. end1 = micros();
  452. time1 = end1-start1;
  453. //Disable Interrupt
  454. switch (m_timer) {
  455. #if defined(__AVR__) && defined(OCR1A)
  456. case 1:
  457. bitClear(TIMSK1,OCIE1A);
  458. break;
  459. #endif
  460. #if defined(__AVR__) && defined(OCR2A)
  461. case 2:
  462. bitClear(TIMSK2,OCIE2A);
  463. break;
  464. #endif
  465. #if defined(__AVR__) && defined(OCR3A)
  466. case 3:
  467. bitClear(TIMSK3,OCIE3A);
  468. break;
  469. #endif
  470. #if defined(__arm__) && defined(CORE_TEENSY)
  471. default:
  472. itimer.end();
  473. #endif
  474. }
  475. // run with interrupt disabled
  476. start2 = micros();
  477. for(k=0; k<100000; k++){
  478. delayMicroseconds(1);
  479. }
  480. end2 = micros();
  481. time2 = end2-start2;
  482. // ready for calculations
  483. load = (double)(time1-time2)/(double)(time1);
  484. switch (m_timer) {
  485. #if defined(__AVR__) && defined(OCR1A)
  486. case 1:
  487. interrupt_frequency = (F_CPU/m_prescaler)/(OCR1A+1);
  488. break;
  489. #endif
  490. #if defined(__AVR__) && defined(OCR2A)
  491. case 2:
  492. interrupt_frequency = (F_CPU/m_prescaler)/(OCR2A+1);
  493. break;
  494. #endif
  495. #if defined(__AVR__) && defined(OCR3A)
  496. case 3:
  497. interrupt_frequency = (F_CPU/m_prescaler)/(OCR3A+1);
  498. break;
  499. #endif
  500. #if defined(__arm__) && defined(CORE_TEENSY)
  501. default:
  502. interrupt_frequency = m_ledFrequency * (m_maxBrightness+1);
  503. #endif
  504. }
  505. cycles_per_int = load*(F_CPU/interrupt_frequency);
  506. //Ready to print information
  507. Serial.print(F("Load of interrupt: ")); Serial.println(load,10);
  508. Serial.print(F("Clock cycles per interrupt: ")); Serial.println(cycles_per_int);
  509. Serial.print(F("Interrupt frequency: ")); Serial.print(interrupt_frequency); Serial.println(F(" Hz"));
  510. Serial.print(F("PWM frequency: ")); Serial.print(interrupt_frequency/(m_maxBrightness+1)); Serial.println(F(" Hz"));
  511. #if defined(__AVR__)
  512. #if defined(USBCON)
  513. if(m_timer==1){
  514. Serial.println(F("Timer1 in use."));
  515. Serial.println(F("add '#define SHIFTPWM_USE_TIMER3' before '#include <ShiftPWM.h>' to switch to timer 3."));
  516. Serial.print(F("OCR1A: ")); Serial.println(OCR1A, DEC);
  517. Serial.print(F("Prescaler: ")); Serial.println(m_prescaler);
  518. //Re-enable Interrupt
  519. bitSet(TIMSK1,OCIE1A);
  520. }
  521. else if(m_timer==3){
  522. Serial.println(F("Timer3 in use."));
  523. Serial.print(F("OCR3A: ")); Serial.println(OCR3A, DEC);
  524. Serial.print(F("Presclaler: ")); Serial.println(m_prescaler);
  525. //Re-enable Interrupt
  526. bitSet(TIMSK3,OCIE3A);
  527. }
  528. #else
  529. if(m_timer==1){
  530. Serial.println(F("Timer1 in use for highest precision."));
  531. Serial.println(F("add '#define SHIFTPWM_USE_TIMER2' before '#include <ShiftPWM.h>' to switch to timer 2."));
  532. Serial.print(F("OCR1A: ")); Serial.println(OCR1A, DEC);
  533. Serial.print(F("Prescaler: ")); Serial.println(m_prescaler);
  534. //Re-enable Interrupt
  535. bitSet(TIMSK1,OCIE1A);
  536. }
  537. else if(m_timer==2){
  538. Serial.println(F("Timer2 in use."));
  539. Serial.print(F("OCR2A: ")); Serial.println(OCR2A, DEC);
  540. Serial.print(F("Presclaler: ")); Serial.println(m_prescaler);
  541. //Re-enable Interrupt
  542. bitSet(TIMSK2,OCIE2A);
  543. }
  544. #endif
  545. #elif defined(__arm__) && defined(CORE_TEENSY)
  546. itimer.begin(ShiftPWM_handleInterrupt,
  547. 1000000.0 / (m_ledFrequency * (m_maxBrightness+1)));
  548. #endif
  549. }