PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

vor 3 Jahren
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. #ifndef __INC_FASTSPI_AVR_H
  2. #define __INC_FASTSPI_AVR_H
  3. FASTLED_NAMESPACE_BEGIN
  4. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  5. //
  6. // Hardware SPI support using USART registers and friends
  7. //
  8. // TODO: Complete/test implementation - right now this doesn't work
  9. //
  10. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. // uno/mini/duemilanove
  12. #if defined(AVR_HARDWARE_SPI)
  13. #if defined(UBRR1)
  14. #ifndef UCPHA1
  15. #define UCPHA1 1
  16. #endif
  17. template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
  18. class AVRUSART1SPIOutput {
  19. Selectable *m_pSelect;
  20. public:
  21. AVRUSART1SPIOutput() { m_pSelect = NULL; }
  22. AVRUSART1SPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
  23. void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
  24. void init() {
  25. UBRR1 = 0;
  26. /* Set MSPI mode of operation and SPI data mode 0. */
  27. UCSR1C = (1<<UMSEL11)|(1<<UMSEL10)|(0<<UCPHA1)|(0<<UCPOL1);
  28. /* Enable receiver and transmitter. */
  29. UCSR1B = (1<<RXEN1)|(1<<TXEN1);
  30. FastPin<_CLOCK_PIN>::setOutput();
  31. FastPin<_DATA_PIN>::setOutput();
  32. // must be done last, see page 206
  33. setSPIRate();
  34. }
  35. void setSPIRate() {
  36. if(_SPI_CLOCK_DIVIDER > 2) {
  37. UBRR1 = (_SPI_CLOCK_DIVIDER/2)-1;
  38. } else {
  39. UBRR1 = 0;
  40. }
  41. }
  42. static void stop() {
  43. // TODO: stop the uart spi output
  44. }
  45. static bool shouldWait(bool wait = false) __attribute__((always_inline)) {
  46. static bool sWait=false;
  47. if(sWait) {
  48. sWait = wait; return true;
  49. } else {
  50. sWait = wait; return false;
  51. }
  52. // return true;
  53. }
  54. static void wait() __attribute__((always_inline)) {
  55. if(shouldWait()) {
  56. while(!(UCSR1A & (1<<UDRE1)));
  57. }
  58. }
  59. static void waitFully() __attribute__((always_inline)) { wait(); }
  60. static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); }
  61. static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); UDR1=b; shouldWait(true); }
  62. static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { UDR1=b; shouldWait(true); wait(); }
  63. static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { UDR1=b; shouldWait(true); }
  64. template <uint8_t BIT> inline static void writeBit(uint8_t b) {
  65. if(b && (1 << BIT)) {
  66. FastPin<_DATA_PIN>::hi();
  67. } else {
  68. FastPin<_DATA_PIN>::lo();
  69. }
  70. FastPin<_CLOCK_PIN>::hi();
  71. FastPin<_CLOCK_PIN>::lo();
  72. }
  73. void enable_pins() { }
  74. void disable_pins() { }
  75. void select() {
  76. if(m_pSelect != NULL) {
  77. m_pSelect->select();
  78. }
  79. enable_pins();
  80. setSPIRate();
  81. }
  82. void release() {
  83. if(m_pSelect != NULL) {
  84. m_pSelect->release();
  85. }
  86. disable_pins();
  87. }
  88. static void writeBytesValueRaw(uint8_t value, int len) {
  89. while(len--) {
  90. writeByte(value);
  91. }
  92. }
  93. void writeBytesValue(uint8_t value, int len) {
  94. //setSPIRate();
  95. select();
  96. while(len--) {
  97. writeByte(value);
  98. }
  99. release();
  100. }
  101. // Write a block of n uint8_ts out
  102. template <class D> void writeBytes(register uint8_t *data, int len) {
  103. //setSPIRate();
  104. uint8_t *end = data + len;
  105. select();
  106. while(data != end) {
  107. // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM)
  108. writeByte(D::adjust(*data++)); delaycycles<3>();
  109. }
  110. release();
  111. }
  112. void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
  113. // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
  114. // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
  115. template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
  116. //setSPIRate();
  117. int len = pixels.mLen;
  118. select();
  119. while(pixels.has(1)) {
  120. if(FLAGS & FLAG_START_BIT) {
  121. writeBit<0>(1);
  122. writeBytePostWait(D::adjust(pixels.loadAndScale0()));
  123. writeBytePostWait(D::adjust(pixels.loadAndScale1()));
  124. writeBytePostWait(D::adjust(pixels.loadAndScale2()));
  125. } else {
  126. writeByte(D::adjust(pixels.loadAndScale0()));
  127. writeByte(D::adjust(pixels.loadAndScale1()));
  128. writeByte(D::adjust(pixels.loadAndScale2()));
  129. }
  130. pixels.advanceData();
  131. pixels.stepDithering();
  132. }
  133. D::postBlock(len);
  134. release();
  135. }
  136. };
  137. #endif
  138. #if defined(UBRR0)
  139. template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
  140. class AVRUSART0SPIOutput {
  141. Selectable *m_pSelect;
  142. public:
  143. AVRUSART0SPIOutput() { m_pSelect = NULL; }
  144. AVRUSART0SPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
  145. void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
  146. void init() {
  147. UBRR0 = 0;
  148. /* Set MSPI mode of operation and SPI data mode 0. */
  149. UCSR0C = (1<<UMSEL01)|(1<<UMSEL00)/*|(0<<UCPHA0)*/|(0<<UCPOL0);
  150. /* Enable receiver and transmitter. */
  151. UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  152. FastPin<_CLOCK_PIN>::setOutput();
  153. FastPin<_DATA_PIN>::setOutput();
  154. // must be done last, see page 206
  155. setSPIRate();
  156. }
  157. void setSPIRate() {
  158. if(_SPI_CLOCK_DIVIDER > 2) {
  159. UBRR0 = (_SPI_CLOCK_DIVIDER/2)-1;
  160. } else {
  161. UBRR0 = 0;
  162. }
  163. }
  164. static void stop() {
  165. // TODO: stop the uart spi output
  166. }
  167. static bool shouldWait(bool wait = false) __attribute__((always_inline)) {
  168. static bool sWait=false;
  169. if(sWait) {
  170. sWait = wait; return true;
  171. } else {
  172. sWait = wait; return false;
  173. }
  174. // return true;
  175. }
  176. static void wait() __attribute__((always_inline)) {
  177. if(shouldWait()) {
  178. while(!(UCSR0A & (1<<UDRE0)));
  179. }
  180. }
  181. static void waitFully() __attribute__((always_inline)) { wait(); }
  182. static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); }
  183. static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); UDR0=b; shouldWait(true); }
  184. static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { UDR0=b; shouldWait(true); wait(); }
  185. static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { UDR0=b; shouldWait(true); }
  186. template <uint8_t BIT> inline static void writeBit(uint8_t b) {
  187. if(b && (1 << BIT)) {
  188. FastPin<_DATA_PIN>::hi();
  189. } else {
  190. FastPin<_DATA_PIN>::lo();
  191. }
  192. FastPin<_CLOCK_PIN>::hi();
  193. FastPin<_CLOCK_PIN>::lo();
  194. }
  195. void enable_pins() { }
  196. void disable_pins() { }
  197. void select() {
  198. if(m_pSelect != NULL) {
  199. m_pSelect->select();
  200. }
  201. enable_pins();
  202. setSPIRate();
  203. }
  204. void release() {
  205. if(m_pSelect != NULL) {
  206. m_pSelect->release();
  207. }
  208. disable_pins();
  209. }
  210. static void writeBytesValueRaw(uint8_t value, int len) {
  211. while(len--) {
  212. writeByte(value);
  213. }
  214. }
  215. void writeBytesValue(uint8_t value, int len) {
  216. //setSPIRate();
  217. select();
  218. while(len--) {
  219. writeByte(value);
  220. }
  221. release();
  222. }
  223. // Write a block of n uint8_ts out
  224. template <class D> void writeBytes(register uint8_t *data, int len) {
  225. //setSPIRate();
  226. uint8_t *end = data + len;
  227. select();
  228. while(data != end) {
  229. // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM)
  230. writeByte(D::adjust(*data++)); delaycycles<3>();
  231. }
  232. release();
  233. }
  234. void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
  235. // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
  236. // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
  237. template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
  238. //setSPIRate();
  239. int len = pixels.mLen;
  240. select();
  241. while(pixels.has(1)) {
  242. if(FLAGS & FLAG_START_BIT) {
  243. writeBit<0>(1);
  244. writeBytePostWait(D::adjust(pixels.loadAndScale0()));
  245. writeBytePostWait(D::adjust(pixels.loadAndScale1()));
  246. writeBytePostWait(D::adjust(pixels.loadAndScale2()));
  247. } else {
  248. writeByte(D::adjust(pixels.loadAndScale0()));
  249. writeByte(D::adjust(pixels.loadAndScale1()));
  250. writeByte(D::adjust(pixels.loadAndScale2()));
  251. }
  252. pixels.advanceData();
  253. pixels.stepDithering();
  254. }
  255. D::postBlock(len);
  256. waitFully();
  257. release();
  258. }
  259. };
  260. #endif
  261. #if defined(SPSR)
  262. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  263. //
  264. // Hardware SPI support using SPDR registers and friends
  265. //
  266. // Technically speaking, this uses the AVR SPI registers. This will work on the Teensy 3.0 because Paul made a set of compatability
  267. // classes that map the AVR SPI registers to ARM's, however this caps the performance of output.
  268. //
  269. // TODO: implement ARMHardwareSPIOutput
  270. //
  271. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
  273. class AVRHardwareSPIOutput {
  274. Selectable *m_pSelect;
  275. bool mWait;
  276. public:
  277. AVRHardwareSPIOutput() { m_pSelect = NULL; mWait = false;}
  278. AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
  279. void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
  280. void setSPIRate() {
  281. SPCR &= ~ ( (1<<SPR1) | (1<<SPR0) ); // clear out the prescalar bits
  282. bool b2x = false;
  283. if(_SPI_CLOCK_DIVIDER >= 128) { SPCR |= (1<<SPR1); SPCR |= (1<<SPR0); }
  284. else if(_SPI_CLOCK_DIVIDER >= 64) { SPCR |= (1<<SPR1);}
  285. else if(_SPI_CLOCK_DIVIDER >= 32) { SPCR |= (1<<SPR1); b2x = true; }
  286. else if(_SPI_CLOCK_DIVIDER >= 16) { SPCR |= (1<<SPR0); }
  287. else if(_SPI_CLOCK_DIVIDER >= 8) { SPCR |= (1<<SPR0); b2x = true; }
  288. else if(_SPI_CLOCK_DIVIDER >= 4) { /* do nothing - default rate */ }
  289. else { b2x = true; }
  290. if(b2x) { SPSR |= (1<<SPI2X); }
  291. else { SPSR &= ~ (1<<SPI2X); }
  292. }
  293. void init() {
  294. volatile uint8_t clr;
  295. // set the pins to output
  296. FastPin<_DATA_PIN>::setOutput();
  297. FastPin<_CLOCK_PIN>::setOutput();
  298. #ifdef SPI_SELECT
  299. // Make sure the slave select line is set to output, or arduino will block us
  300. FastPin<SPI_SELECT>::setOutput();
  301. FastPin<SPI_SELECT>::lo();
  302. #endif
  303. SPCR |= ((1<<SPE) | (1<<MSTR) ); // enable SPI as master
  304. SPCR &= ~ ( (1<<SPR1) | (1<<SPR0) ); // clear out the prescalar bits
  305. clr = SPSR; // clear SPI status register
  306. clr = SPDR; // clear SPI data register
  307. clr;
  308. bool b2x = false;
  309. if(_SPI_CLOCK_DIVIDER >= 128) { SPCR |= (1<<SPR1); SPCR |= (1<<SPR0); }
  310. else if(_SPI_CLOCK_DIVIDER >= 64) { SPCR |= (1<<SPR1);}
  311. else if(_SPI_CLOCK_DIVIDER >= 32) { SPCR |= (1<<SPR1); b2x = true; }
  312. else if(_SPI_CLOCK_DIVIDER >= 16) { SPCR |= (1<<SPR0); }
  313. else if(_SPI_CLOCK_DIVIDER >= 8) { SPCR |= (1<<SPR0); b2x = true; }
  314. else if(_SPI_CLOCK_DIVIDER >= 4) { /* do nothing - default rate */ }
  315. else { b2x = true; }
  316. if(b2x) { SPSR |= (1<<SPI2X); }
  317. else { SPSR &= ~ (1<<SPI2X); }
  318. SPDR=0;
  319. shouldWait(false);
  320. release();
  321. }
  322. static bool shouldWait(bool wait = false) __attribute__((always_inline)) {
  323. static bool sWait=false;
  324. if(sWait) { sWait = wait; return true; } else { sWait = wait; return false; }
  325. // return true;
  326. }
  327. static void wait() __attribute__((always_inline)) { if(shouldWait()) { while(!(SPSR & (1<<SPIF))); } }
  328. static void waitFully() __attribute__((always_inline)) { wait(); }
  329. static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); }
  330. static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPDR=b; shouldWait(true); }
  331. static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPDR=b; shouldWait(true); wait(); }
  332. static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPDR=b; shouldWait(true); }
  333. template <uint8_t BIT> inline static void writeBit(uint8_t b) {
  334. SPCR &= ~(1 << SPE);
  335. if(b & (1 << BIT)) {
  336. FastPin<_DATA_PIN>::hi();
  337. } else {
  338. FastPin<_DATA_PIN>::lo();
  339. }
  340. FastPin<_CLOCK_PIN>::hi();
  341. FastPin<_CLOCK_PIN>::lo();
  342. SPCR |= 1 << SPE;
  343. shouldWait(false);
  344. }
  345. void enable_pins() {
  346. SPCR |= ((1<<SPE) | (1<<MSTR) ); // enable SPI as master
  347. }
  348. void disable_pins() {
  349. SPCR &= ~(((1<<SPE) | (1<<MSTR) )); // disable SPI
  350. }
  351. void select() {
  352. if(m_pSelect != NULL) { m_pSelect->select(); }
  353. enable_pins();
  354. setSPIRate();
  355. }
  356. void release() {
  357. if(m_pSelect != NULL) { m_pSelect->release(); }
  358. disable_pins();
  359. }
  360. static void writeBytesValueRaw(uint8_t value, int len) {
  361. while(len--) { writeByte(value); }
  362. }
  363. void writeBytesValue(uint8_t value, int len) {
  364. //setSPIRate();
  365. select();
  366. while(len--) {
  367. writeByte(value);
  368. }
  369. release();
  370. }
  371. // Write a block of n uint8_ts out
  372. template <class D> void writeBytes(register uint8_t *data, int len) {
  373. //setSPIRate();
  374. uint8_t *end = data + len;
  375. select();
  376. while(data != end) {
  377. // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM)
  378. writeByte(D::adjust(*data++)); delaycycles<3>();
  379. }
  380. release();
  381. }
  382. void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
  383. // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
  384. // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
  385. template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
  386. //setSPIRate();
  387. int len = pixels.mLen;
  388. select();
  389. while(pixels.has(1)) {
  390. if(FLAGS & FLAG_START_BIT) {
  391. writeBit<0>(1);
  392. writeBytePostWait(D::adjust(pixels.loadAndScale0()));
  393. writeBytePostWait(D::adjust(pixels.loadAndScale1()));
  394. writeBytePostWait(D::adjust(pixels.loadAndScale2()));
  395. } else {
  396. writeByte(D::adjust(pixels.loadAndScale0()));
  397. writeByte(D::adjust(pixels.loadAndScale1()));
  398. writeByte(D::adjust(pixels.loadAndScale2()));
  399. }
  400. pixels.advanceData();
  401. pixels.stepDithering();
  402. }
  403. D::postBlock(len);
  404. waitFully();
  405. release();
  406. }
  407. };
  408. #elif defined(SPSR0)
  409. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  410. //
  411. // Hardware SPI support using SPDR0 registers and friends
  412. //
  413. // Technically speaking, this uses the AVR SPI registers. This will work on the Teensy 3.0 because Paul made a set of compatability
  414. // classes that map the AVR SPI registers to ARM's, however this caps the performance of output.
  415. //
  416. // TODO: implement ARMHardwareSPIOutput
  417. //
  418. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  419. template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
  420. class AVRHardwareSPIOutput {
  421. Selectable *m_pSelect;
  422. bool mWait;
  423. public:
  424. AVRHardwareSPIOutput() { m_pSelect = NULL; mWait = false;}
  425. AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
  426. void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
  427. void setSPIRate() {
  428. SPCR0 &= ~ ( (1<<SPR10) | (1<<SPR0) ); // clear out the prescalar bits
  429. bool b2x = false;
  430. if(_SPI_CLOCK_DIVIDER >= 128) { SPCR0 |= (1<<SPR1); SPCR0 |= (1<<SPR0); }
  431. else if(_SPI_CLOCK_DIVIDER >= 64) { SPCR0 |= (1<<SPR1);}
  432. else if(_SPI_CLOCK_DIVIDER >= 32) { SPCR0 |= (1<<SPR1); b2x = true; }
  433. else if(_SPI_CLOCK_DIVIDER >= 16) { SPCR0 |= (1<<SPR0); }
  434. else if(_SPI_CLOCK_DIVIDER >= 8) { SPCR0 |= (1<<SPR0); b2x = true; }
  435. else if(_SPI_CLOCK_DIVIDER >= 4) { /* do nothing - default rate */ }
  436. else { b2x = true; }
  437. if(b2x) { SPSR0 |= (1<<SPI2X); }
  438. else { SPSR0 &= ~ (1<<SPI2X); }
  439. }
  440. void init() {
  441. volatile uint8_t clr;
  442. // set the pins to output
  443. FastPin<_DATA_PIN>::setOutput();
  444. FastPin<_CLOCK_PIN>::setOutput();
  445. #ifdef SPI_SELECT
  446. // Make sure the slave select line is set to output, or arduino will block us
  447. FastPin<SPI_SELECT>::setOutput();
  448. FastPin<SPI_SELECT>::lo();
  449. #endif
  450. SPCR0 |= ((1<<SPE) | (1<<MSTR) ); // enable SPI as master
  451. SPCR0 &= ~ ( (1<<SPR1) | (1<<SPR0) ); // clear out the prescalar bits
  452. clr = SPSR0; // clear SPI status register
  453. clr = SPDR0; // clear SPI data register
  454. clr;
  455. bool b2x = false;
  456. if(_SPI_CLOCK_DIVIDER >= 128) { SPCR0 |= (1<<SPR1); SPCR0 |= (1<<SPR0); }
  457. else if(_SPI_CLOCK_DIVIDER >= 64) { SPCR0 |= (1<<SPR1);}
  458. else if(_SPI_CLOCK_DIVIDER >= 32) { SPCR0 |= (1<<SPR1); b2x = true; }
  459. else if(_SPI_CLOCK_DIVIDER >= 16) { SPCR0 |= (1<<SPR0); }
  460. else if(_SPI_CLOCK_DIVIDER >= 8) { SPCR0 |= (1<<SPR0); b2x = true; }
  461. else if(_SPI_CLOCK_DIVIDER >= 4) { /* do nothing - default rate */ }
  462. else { b2x = true; }
  463. if(b2x) { SPSR0 |= (1<<SPI2X); }
  464. else { SPSR0 &= ~ (1<<SPI2X); }
  465. SPDR0=0;
  466. shouldWait(false);
  467. release();
  468. }
  469. static bool shouldWait(bool wait = false) __attribute__((always_inline)) {
  470. static bool sWait=false;
  471. if(sWait) { sWait = wait; return true; } else { sWait = wait; return false; }
  472. // return true;
  473. }
  474. static void wait() __attribute__((always_inline)) { if(shouldWait()) { while(!(SPSR0 & (1<<SPIF))); } }
  475. static void waitFully() __attribute__((always_inline)) { wait(); }
  476. static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); }
  477. static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPDR0=b; shouldWait(true); }
  478. static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPDR0=b; shouldWait(true); wait(); }
  479. static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPDR0=b; shouldWait(true); }
  480. template <uint8_t BIT> inline static void writeBit(uint8_t b) {
  481. SPCR0 &= ~(1 << SPE);
  482. if(b & (1 << BIT)) {
  483. FastPin<_DATA_PIN>::hi();
  484. } else {
  485. FastPin<_DATA_PIN>::lo();
  486. }
  487. FastPin<_CLOCK_PIN>::hi();
  488. FastPin<_CLOCK_PIN>::lo();
  489. SPCR0 |= 1 << SPE;
  490. shouldWait(false);
  491. }
  492. void enable_pins() {
  493. SPCR0 |= ((1<<SPE) | (1<<MSTR) ); // enable SPI as master
  494. }
  495. void disable_pins() {
  496. SPCR0 &= ~(((1<<SPE) | (1<<MSTR) )); // disable SPI
  497. }
  498. void select() {
  499. if(m_pSelect != NULL) { m_pSelect->select(); }
  500. enable_pins();
  501. setSPIRate();
  502. }
  503. void release() {
  504. if(m_pSelect != NULL) { m_pSelect->release(); }
  505. disable_pins();
  506. }
  507. static void writeBytesValueRaw(uint8_t value, int len) {
  508. while(len--) { writeByte(value); }
  509. }
  510. void writeBytesValue(uint8_t value, int len) {
  511. //setSPIRate();
  512. select();
  513. while(len--) {
  514. writeByte(value);
  515. }
  516. release();
  517. }
  518. // Write a block of n uint8_ts out
  519. template <class D> void writeBytes(register uint8_t *data, int len) {
  520. //setSPIRate();
  521. uint8_t *end = data + len;
  522. select();
  523. while(data != end) {
  524. // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM)
  525. writeByte(D::adjust(*data++)); delaycycles<3>();
  526. }
  527. release();
  528. }
  529. void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
  530. // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
  531. // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
  532. template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
  533. //setSPIRate();
  534. int len = pixels.mLen;
  535. select();
  536. while(pixels.has(1)) {
  537. if(FLAGS & FLAG_START_BIT) {
  538. writeBit<0>(1);
  539. writeBytePostWait(D::adjust(pixels.loadAndScale0()));
  540. writeBytePostWait(D::adjust(pixels.loadAndScale1()));
  541. writeBytePostWait(D::adjust(pixels.loadAndScale2()));
  542. } else {
  543. writeByte(D::adjust(pixels.loadAndScale0()));
  544. writeByte(D::adjust(pixels.loadAndScale1()));
  545. writeByte(D::adjust(pixels.loadAndScale2()));
  546. }
  547. pixels.advanceData();
  548. pixels.stepDithering();
  549. }
  550. D::postBlock(len);
  551. waitFully();
  552. release();
  553. }
  554. };
  555. #endif
  556. #else
  557. // #define FASTLED_FORCE_SOFTWARE_SPI
  558. #endif
  559. FASTLED_NAMESPACE_END;
  560. #endif