NeoEsp8266DmaMethod.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*-------------------------------------------------------------------------
  2. NeoPixel library helper functions for Esp8266.
  3. Written by Michael C. Miller.
  4. Thanks to g3gg0.de for porting the initial DMA support which lead to this.
  5. Thanks to github/cnlohr for the original work on DMA support, which opend
  6. all our minds to a better way (located at https://github.com/cnlohr/esp8266ws2812i2s).
  7. I invest time and resources providing this open source code,
  8. please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
  9. -------------------------------------------------------------------------
  10. This file is part of the Makuna/NeoPixelBus library.
  11. NeoPixelBus is free software: you can redistribute it and/or modify
  12. it under the terms of the GNU Lesser General Public License as
  13. published by the Free Software Foundation, either version 3 of
  14. the License, or (at your option) any later version.
  15. NeoPixelBus is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU Lesser General Public License for more details.
  19. You should have received a copy of the GNU Lesser General Public
  20. License along with NeoPixel. If not, see
  21. <http://www.gnu.org/licenses/>.
  22. -------------------------------------------------------------------------*/
  23. #pragma once
  24. #ifdef ARDUINO_ARCH_ESP8266
  25. extern "C"
  26. {
  27. #include "Arduino.h"
  28. #include "osapi.h"
  29. #include "ets_sys.h"
  30. #include "i2s_reg.h"
  31. #include "i2s.h"
  32. #include "eagle_soc.h"
  33. #include "esp8266_peri.h"
  34. #include "slc_register.h"
  35. #include "osapi.h"
  36. #include "ets_sys.h"
  37. #include "user_interface.h"
  38. void rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id, uint32_t reg_add, uint32_t Msb, uint32_t Lsb, uint32_t indata);
  39. }
  40. struct slc_queue_item
  41. {
  42. uint32 blocksize : 12;
  43. uint32 datalen : 12;
  44. uint32 unused : 5;
  45. uint32 sub_sof : 1;
  46. uint32 eof : 1;
  47. uint32 owner : 1;
  48. uint32 buf_ptr;
  49. uint32 next_link_ptr;
  50. };
  51. class NeoEsp8266DmaSpeedWs2813
  52. {
  53. public:
  54. const static uint32_t I2sClockDivisor = 3;
  55. const static uint32_t I2sBaseClockDivisor = 16;
  56. const static uint32_t ResetTimeUs = 250;
  57. };
  58. class NeoEsp8266DmaSpeed800Kbps
  59. {
  60. public:
  61. const static uint32_t I2sClockDivisor = 3;
  62. const static uint32_t I2sBaseClockDivisor = 16;
  63. const static uint32_t ResetTimeUs = 50;
  64. };
  65. class NeoEsp8266DmaSpeed400Kbps
  66. {
  67. public:
  68. const static uint32_t I2sClockDivisor = 6;
  69. const static uint32_t I2sBaseClockDivisor = 16;
  70. const static uint32_t ResetTimeUs = 50;
  71. };
  72. enum NeoDmaState
  73. {
  74. NeoDmaState_Idle,
  75. NeoDmaState_Pending,
  76. NeoDmaState_Sending,
  77. };
  78. const uint16_t c_maxDmaBlockSize = 4095;
  79. const uint16_t c_dmaBytesPerPixelBytes = 4;
  80. const uint8_t c_I2sPin = 3; // due to I2S hardware, the pin used is restricted to this
  81. template<typename T_SPEED> class NeoEsp8266DmaMethodBase
  82. {
  83. public:
  84. NeoEsp8266DmaMethodBase(uint16_t pixelCount, size_t elementSize)
  85. {
  86. uint16_t dmaPixelSize = c_dmaBytesPerPixelBytes * elementSize;
  87. _pixelsSize = pixelCount * elementSize;
  88. _i2sBufferSize = pixelCount * dmaPixelSize;
  89. _pixels = (uint8_t*)malloc(_pixelsSize);
  90. memset(_pixels, 0x00, _pixelsSize);
  91. _i2sBuffer = (uint8_t*)malloc(_i2sBufferSize);
  92. memset(_i2sBuffer, 0x00, _i2sBufferSize);
  93. memset(_i2sZeroes, 0x00, sizeof(_i2sZeroes));
  94. _is2BufMaxBlockSize = (c_maxDmaBlockSize / dmaPixelSize) * dmaPixelSize;
  95. _i2sBufDescCount = (_i2sBufferSize / _is2BufMaxBlockSize) + 1 + 2; // need two more for state/latch blocks
  96. _i2sBufDesc = (slc_queue_item*)malloc(_i2sBufDescCount * sizeof(slc_queue_item));
  97. s_this = this; // store this for the ISR
  98. }
  99. NeoEsp8266DmaMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize) : NeoEsp8266DmaMethodBase(pixelCount, elementSize)
  100. {
  101. }
  102. ~NeoEsp8266DmaMethodBase()
  103. {
  104. StopDma();
  105. free(_pixels);
  106. free(_i2sBuffer);
  107. free(_i2sBufDesc);
  108. }
  109. bool IsReadyToUpdate() const
  110. {
  111. return (_dmaState == NeoDmaState_Idle);
  112. }
  113. void Initialize()
  114. {
  115. StopDma();
  116. _dmaState = NeoDmaState_Sending; // start off sending empty buffer
  117. uint8_t* is2Buffer = _i2sBuffer;
  118. uint32_t is2BufferSize = _i2sBufferSize;
  119. uint16_t indexDesc;
  120. // prepare main data block decriptors that point into our one static dma buffer
  121. for (indexDesc = 0; indexDesc < (_i2sBufDescCount - 2); indexDesc++)
  122. {
  123. uint32_t blockSize = (is2BufferSize > _is2BufMaxBlockSize) ? _is2BufMaxBlockSize : is2BufferSize;
  124. _i2sBufDesc[indexDesc].owner = 1;
  125. _i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally
  126. _i2sBufDesc[indexDesc].sub_sof = 0;
  127. _i2sBufDesc[indexDesc].datalen = blockSize;
  128. _i2sBufDesc[indexDesc].blocksize = blockSize;
  129. _i2sBufDesc[indexDesc].buf_ptr = (uint32_t)is2Buffer;
  130. _i2sBufDesc[indexDesc].unused = 0;
  131. _i2sBufDesc[indexDesc].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc + 1]);
  132. is2Buffer += blockSize;
  133. is2BufferSize -= blockSize;
  134. }
  135. // prepare the two state/latch descriptors
  136. for (; indexDesc < _i2sBufDescCount; indexDesc++)
  137. {
  138. _i2sBufDesc[indexDesc].owner = 1;
  139. _i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally
  140. _i2sBufDesc[indexDesc].sub_sof = 0;
  141. _i2sBufDesc[indexDesc].datalen = sizeof(_i2sZeroes);
  142. _i2sBufDesc[indexDesc].blocksize = sizeof(_i2sZeroes);
  143. _i2sBufDesc[indexDesc].buf_ptr = (uint32_t)_i2sZeroes;
  144. _i2sBufDesc[indexDesc].unused = 0;
  145. _i2sBufDesc[indexDesc].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc + 1]);
  146. }
  147. // the first state block will trigger the interrupt
  148. _i2sBufDesc[indexDesc - 2].eof = 1;
  149. // the last state block will loop to the first state block by defualt
  150. _i2sBufDesc[indexDesc - 1].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc - 2]);
  151. // setup the rest of i2s DMA
  152. //
  153. ETS_SLC_INTR_DISABLE();
  154. SLCC0 |= SLCRXLR | SLCTXLR;
  155. SLCC0 &= ~(SLCRXLR | SLCTXLR);
  156. SLCIC = 0xFFFFFFFF;
  157. // Configure DMA
  158. SLCC0 &= ~(SLCMM << SLCM); // clear DMA MODE
  159. SLCC0 |= (1 << SLCM); // set DMA MODE to 1
  160. SLCRXDC |= SLCBINR | SLCBTNR; // enable INFOR_NO_REPLACE and TOKEN_NO_REPLACE
  161. SLCRXDC &= ~(SLCBRXFE | SLCBRXEM | SLCBRXFM); // disable RX_FILL, RX_EOF_MODE and RX_FILL_MODE
  162. // Feed DMA the 1st buffer desc addr
  163. // To send data to the I2S subsystem, counter-intuitively we use the RXLINK part, not the TXLINK as you might
  164. // expect. The TXLINK part still needs a valid DMA descriptor, even if it's unused: the DMA engine will throw
  165. // an error at us otherwise. Just feed it any random descriptor.
  166. SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
  167. SLCTXL |= (uint32)&(_i2sBufDesc[_i2sBufDescCount-1]) << SLCTXLA; // set TX descriptor address. any random desc is OK, we don't use TX but it needs to be valid
  168. SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
  169. SLCRXL |= (uint32)_i2sBufDesc << SLCRXLA; // set RX descriptor address
  170. ETS_SLC_INTR_ATTACH(i2s_slc_isr, NULL);
  171. SLCIE = SLCIRXEOF; // Enable only for RX EOF interrupt
  172. ETS_SLC_INTR_ENABLE();
  173. //Start transmission
  174. SLCTXL |= SLCTXLS;
  175. SLCRXL |= SLCRXLS;
  176. pinMode(c_I2sPin, FUNCTION_1); // I2S0_DATA
  177. I2S_CLK_ENABLE();
  178. I2SIC = 0x3F;
  179. I2SIE = 0;
  180. //Reset I2S
  181. I2SC &= ~(I2SRST);
  182. I2SC |= I2SRST;
  183. I2SC &= ~(I2SRST);
  184. I2SFC &= ~(I2SDE | (I2STXFMM << I2STXFM) | (I2SRXFMM << I2SRXFM)); // Set RX/TX FIFO_MOD=0 and disable DMA (FIFO only)
  185. I2SFC |= I2SDE; //Enable DMA
  186. I2SCC &= ~((I2STXCMM << I2STXCM) | (I2SRXCMM << I2SRXCM)); // Set RX/TX CHAN_MOD=0
  187. // set the rate
  188. uint32_t i2s_clock_div = T_SPEED::I2sClockDivisor & I2SCDM;
  189. uint8_t i2s_bck_div = T_SPEED::I2sBaseClockDivisor & I2SBDM;
  190. //!trans master, !bits mod, rece slave mod, rece msb shift, right first, msb right
  191. I2SC &= ~(I2STSM | (I2SBMM << I2SBM) | (I2SBDM << I2SBD) | (I2SCDM << I2SCD));
  192. I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | (i2s_bck_div << I2SBD) | (i2s_clock_div << I2SCD);
  193. I2SC |= I2STXS; // Start transmission
  194. }
  195. void ICACHE_RAM_ATTR Update()
  196. {
  197. // wait for not actively sending data
  198. while (_dmaState != NeoDmaState_Idle)
  199. {
  200. yield();
  201. }
  202. FillBuffers();
  203. // toggle state so the ISR reacts
  204. _dmaState = NeoDmaState_Pending;
  205. }
  206. uint8_t* getPixels() const
  207. {
  208. return _pixels;
  209. };
  210. size_t getPixelsSize() const
  211. {
  212. return _pixelsSize;
  213. }
  214. private:
  215. static NeoEsp8266DmaMethodBase* s_this; // for the ISR
  216. size_t _pixelsSize; // Size of '_pixels' buffer
  217. uint8_t* _pixels; // Holds LED color values
  218. uint32_t _i2sBufferSize; // total size of _i2sBuffer
  219. uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc
  220. // normally 24 bytes creates the minimum 50us latch per spec, but
  221. // with the new logic, this latch is used to space between three states
  222. // buffer size = (24 * (speed / 50)) / 3
  223. uint8_t _i2sZeroes[(24L * (T_SPEED::ResetTimeUs / 50L)) / 3L];
  224. slc_queue_item* _i2sBufDesc; // dma block descriptors
  225. uint16_t _i2sBufDescCount; // count of block descriptors in _i2sBufDesc
  226. uint16_t _is2BufMaxBlockSize; // max size based on size of a pixel of a single block
  227. volatile NeoDmaState _dmaState;
  228. // This routine is called as soon as the DMA routine has something to tell us. All we
  229. // handle here is the RX_EOF_INT status, which indicate the DMA has sent a buffer whose
  230. // descriptor has the 'EOF' field set to 1.
  231. // in the case of this code, the second to last state descriptor
  232. volatile static void ICACHE_RAM_ATTR i2s_slc_isr(void)
  233. {
  234. uint32_t slc_intr_status = SLCIS;
  235. SLCIC = 0xFFFFFFFF;
  236. if (slc_intr_status & SLCIRXEOF)
  237. {
  238. ETS_SLC_INTR_DISABLE();
  239. switch (s_this->_dmaState)
  240. {
  241. case NeoDmaState_Idle:
  242. break;
  243. case NeoDmaState_Pending:
  244. {
  245. slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA;
  246. // data block has pending data waiting to send, prepare it
  247. // point last state block to top
  248. (finished_item + 1)->next_link_ptr = (uint32_t)(s_this->_i2sBufDesc);
  249. s_this->_dmaState = NeoDmaState_Sending;
  250. }
  251. break;
  252. case NeoDmaState_Sending:
  253. {
  254. slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA;
  255. // the data block had actual data sent
  256. // point last state block to first state block thus
  257. // just looping and not sending the data blocks
  258. (finished_item + 1)->next_link_ptr = (uint32_t)(finished_item);
  259. s_this->_dmaState = NeoDmaState_Idle;
  260. }
  261. break;
  262. }
  263. ETS_SLC_INTR_ENABLE();
  264. }
  265. }
  266. void FillBuffers()
  267. {
  268. const uint16_t bitpatterns[16] =
  269. {
  270. 0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
  271. 0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
  272. 0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
  273. 0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
  274. };
  275. uint16_t* pDma = (uint16_t*)_i2sBuffer;
  276. uint8_t* pPixelsEnd = _pixels + _pixelsSize;
  277. for (uint8_t* pPixel = _pixels; pPixel < pPixelsEnd; pPixel++)
  278. {
  279. *(pDma++) = bitpatterns[((*pPixel) & 0x0f)];
  280. *(pDma++) = bitpatterns[((*pPixel) >> 4) & 0x0f];
  281. }
  282. }
  283. void StopDma()
  284. {
  285. ETS_SLC_INTR_DISABLE();
  286. SLCIC = 0xFFFFFFFF;
  287. SLCIE = 0;
  288. SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address
  289. SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address
  290. pinMode(c_I2sPin, INPUT);
  291. }
  292. };
  293. template<typename T_SPEED>
  294. NeoEsp8266DmaMethodBase<T_SPEED>* NeoEsp8266DmaMethodBase<T_SPEED>::s_this;
  295. typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeedWs2813> NeoEsp8266DmaWs2813Method;
  296. typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeed800Kbps> NeoEsp8266Dma800KbpsMethod;
  297. typedef NeoEsp8266DmaMethodBase<NeoEsp8266DmaSpeed400Kbps> NeoEsp8266Dma400KbpsMethod;
  298. // Dma method is the default method for Esp8266
  299. typedef NeoEsp8266DmaWs2813Method NeoWs2813Method;
  300. typedef NeoEsp8266Dma800KbpsMethod Neo800KbpsMethod;
  301. typedef NeoEsp8266Dma400KbpsMethod Neo400KbpsMethod;
  302. #endif