SmartLeds.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. #pragma once
  2. #ifndef SMARTLEDS_H
  3. #define SMARTLEDS_H
  4. /*
  5. * A C++ driver for the WS2812 LEDs using the RMT peripheral on the ESP32.
  6. *
  7. * Jan "yaqwsx" Mrázek <email@honzamrazek.cz>
  8. *
  9. * Based on the work by Martin F. Falatic - https://github.com/FozzTexx/ws2812-demo
  10. */
  11. /*
  12. * Permission is hereby granted, free of charge, to any person obtaining a copy
  13. * of this software and associated documentation files (the "Software"), to deal
  14. * in the Software without restriction, including without limitation the rights
  15. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  16. * copies of the Software, and to permit persons to whom the Software is
  17. * furnished to do so, subject to the following conditions:
  18. *
  19. * The above copyright notice and this permission notice shall be included in
  20. * all copies or substantial portions of the Software.
  21. *
  22. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  25. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  26. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  27. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  28. * THE SOFTWARE.
  29. */
  30. #include <memory>
  31. #include <cassert>
  32. #include <cstring>
  33. #if defined ( ARDUINO )
  34. extern "C" { // ...someone forgot to put in the includes...
  35. #include "esp32-hal.h"
  36. #include "esp_intr_alloc.h"
  37. #include "esp_ipc.h"
  38. #include "driver/gpio.h"
  39. #include "driver/periph_ctrl.h"
  40. #include "freertos/semphr.h"
  41. #include "soc/rmt_struct.h"
  42. #include <driver/spi_master.h>
  43. #include "esp_idf_version.h"
  44. #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
  45. #include "soc/dport_reg.h"
  46. #endif
  47. }
  48. #elif defined ( ESP_PLATFORM )
  49. extern "C" { // ...someone forgot to put in the includes...
  50. #include <esp_intr_alloc.h>
  51. #include <esp_ipc.h>
  52. #include <driver/gpio.h>
  53. #include <freertos/FreeRTOS.h>
  54. #include <freertos/semphr.h>
  55. #include <soc/dport_reg.h>
  56. #include <soc/gpio_sig_map.h>
  57. #include <soc/rmt_struct.h>
  58. #include <driver/spi_master.h>
  59. }
  60. #include <stdio.h>
  61. #endif
  62. #include "Color.h"
  63. namespace detail {
  64. struct TimingParams {
  65. uint32_t T0H;
  66. uint32_t T1H;
  67. uint32_t T0L;
  68. uint32_t T1L;
  69. uint32_t TRS;
  70. };
  71. union RmtPulsePair {
  72. struct {
  73. int duration0:15;
  74. int level0:1;
  75. int duration1:15;
  76. int level1:1;
  77. };
  78. uint32_t value;
  79. };
  80. static const int DIVIDER = 4; // 8 still seems to work, but timings become marginal
  81. static const int MAX_PULSES = 32; // A channel has a 64 "pulse" buffer - we use half per pass
  82. static const double RMT_DURATION_NS = 12.5; // minimum time of a single RMT duration based on clock ns
  83. } // namespace detail
  84. using LedType = detail::TimingParams;
  85. static const LedType LED_WS2812 = { 350, 700, 800, 600, 50000 };
  86. static const LedType LED_WS2812B = { 400, 850, 850, 400, 50100 };
  87. static const LedType LED_SK6812 = { 300, 600, 900, 600, 80000 };
  88. static const LedType LED_WS2813 = { 350, 800, 350, 350, 300000 };
  89. enum BufferType { SingleBuffer = 0, DoubleBuffer };
  90. enum IsrCore { CoreFirst = 0, CoreSecond = 1, CoreCurrent = 2};
  91. class SmartLed {
  92. public:
  93. // The RMT interrupt must not run on the same core as WiFi interrupts, otherwise SmartLeds
  94. // can't fill the RMT buffer fast enough, resulting in rendering artifacts.
  95. // Usually, that means you have to set isrCore == CoreSecond.
  96. //
  97. // If you use anything other than CoreCurrent, the FreeRTOS scheduler MUST be already running,
  98. // so you can't use it if you define SmartLed as global variable.
  99. SmartLed( const LedType& type, int count, int pin, int channel = 0, BufferType doubleBuffer = SingleBuffer, IsrCore isrCore = CoreCurrent)
  100. : _timing( type ),
  101. _channel( channel ),
  102. _count( count ),
  103. _firstBuffer( new Rgb[ count ] ),
  104. _secondBuffer( doubleBuffer ? new Rgb[ count ] : nullptr ),
  105. _finishedFlag( xSemaphoreCreateBinary() )
  106. {
  107. assert( channel >= 0 && channel < 8 );
  108. assert( ledForChannel( channel ) == nullptr );
  109. xSemaphoreGive( _finishedFlag );
  110. DPORT_SET_PERI_REG_MASK( DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN );
  111. DPORT_CLEAR_PERI_REG_MASK( DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST );
  112. PIN_FUNC_SELECT( GPIO_PIN_MUX_REG[ pin ], 2 );
  113. gpio_set_direction( static_cast< gpio_num_t >( pin ), GPIO_MODE_OUTPUT );
  114. gpio_matrix_out( static_cast< gpio_num_t >( pin ), RMT_SIG_OUT0_IDX + _channel, 0, 0 );
  115. initChannel( _channel );
  116. RMT.tx_lim_ch[ _channel ].limit = detail::MAX_PULSES;
  117. RMT.int_ena.val |= 1 << ( 24 + _channel );
  118. RMT.int_ena.val |= 1 << ( 3 * _channel );
  119. _bitToRmt[ 0 ].level0 = 1;
  120. _bitToRmt[ 0 ].level1 = 0;
  121. _bitToRmt[ 0 ].duration0 = _timing.T0H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
  122. _bitToRmt[ 0 ].duration1 = _timing.T0L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
  123. _bitToRmt[ 1 ].level0 = 1;
  124. _bitToRmt[ 1 ].level1 = 0;
  125. _bitToRmt[ 1 ].duration0 = _timing.T1H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
  126. _bitToRmt[ 1 ].duration1 = _timing.T1L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
  127. if ( !anyAlive() ) {
  128. _interruptCore = isrCore;
  129. if(isrCore != CoreCurrent) {
  130. ESP_ERROR_CHECK(esp_ipc_call_blocking(isrCore, registerInterrupt, NULL));
  131. } else {
  132. registerInterrupt(NULL);
  133. }
  134. }
  135. ledForChannel( channel ) = this;
  136. }
  137. ~SmartLed() {
  138. ledForChannel( _channel ) = nullptr;
  139. if ( !anyAlive() ) {
  140. if(_interruptCore != CoreCurrent) {
  141. ESP_ERROR_CHECK(esp_ipc_call_blocking(_interruptCore, unregisterInterrupt, NULL));
  142. } else {
  143. unregisterInterrupt(NULL);
  144. }
  145. }
  146. vSemaphoreDelete( _finishedFlag );
  147. }
  148. Rgb& operator[]( int idx ) {
  149. return _firstBuffer[ idx ];
  150. }
  151. const Rgb& operator[]( int idx ) const {
  152. return _firstBuffer[ idx ];
  153. }
  154. void show() {
  155. _buffer = _firstBuffer.get();
  156. startTransmission();
  157. swapBuffers();
  158. }
  159. bool wait( TickType_t timeout = portMAX_DELAY ) {
  160. if( xSemaphoreTake( _finishedFlag, timeout ) == pdTRUE ) {
  161. xSemaphoreGive( _finishedFlag );
  162. return true;
  163. }
  164. return false;
  165. }
  166. int size() const {
  167. return _count;
  168. }
  169. Rgb *begin() { return _firstBuffer.get(); }
  170. const Rgb *begin() const { return _firstBuffer.get(); }
  171. const Rgb *cbegin() const { return _firstBuffer.get(); }
  172. Rgb *end() { return _firstBuffer.get() + _count; }
  173. const Rgb *end() const { return _firstBuffer.get() + _count; }
  174. const Rgb *cend() const { return _firstBuffer.get() + _count; }
  175. private:
  176. static intr_handle_t _interruptHandle;
  177. static IsrCore _interruptCore;
  178. static void initChannel( int channel ) {
  179. RMT.apb_conf.fifo_mask = 1; //enable memory access, instead of FIFO mode.
  180. RMT.apb_conf.mem_tx_wrap_en = 1; //wrap around when hitting end of buffer
  181. RMT.conf_ch[ channel ].conf0.div_cnt = detail::DIVIDER;
  182. RMT.conf_ch[ channel ].conf0.mem_size = 1;
  183. RMT.conf_ch[ channel ].conf0.carrier_en = 0;
  184. RMT.conf_ch[ channel ].conf0.carrier_out_lv = 1;
  185. RMT.conf_ch[ channel ].conf0.mem_pd = 0;
  186. RMT.conf_ch[ channel ].conf1.rx_en = 0;
  187. RMT.conf_ch[ channel ].conf1.mem_owner = 0;
  188. RMT.conf_ch[ channel ].conf1.tx_conti_mode = 0; //loop back mode.
  189. RMT.conf_ch[ channel ].conf1.ref_always_on = 1; // use apb clock: 80M
  190. RMT.conf_ch[ channel ].conf1.idle_out_en = 1;
  191. RMT.conf_ch[ channel ].conf1.idle_out_lv = 0;
  192. }
  193. static void registerInterrupt(void *) {
  194. ESP_ERROR_CHECK(esp_intr_alloc( ETS_RMT_INTR_SOURCE, 0, interruptHandler, nullptr, &_interruptHandle));
  195. }
  196. static void unregisterInterrupt(void*) {
  197. esp_intr_free( _interruptHandle );
  198. }
  199. static SmartLed*& IRAM_ATTR ledForChannel( int channel );
  200. static void IRAM_ATTR interruptHandler( void* );
  201. void IRAM_ATTR copyRmtHalfBlock();
  202. void swapBuffers() {
  203. if ( _secondBuffer )
  204. _firstBuffer.swap( _secondBuffer );
  205. }
  206. void startTransmission() {
  207. // Invalid use of the library
  208. if( xSemaphoreTake( _finishedFlag, 0 ) != pdTRUE )
  209. abort();
  210. _pixelPosition = _componentPosition = _halfIdx = 0;
  211. copyRmtHalfBlock();
  212. if ( _pixelPosition < _count )
  213. copyRmtHalfBlock();
  214. RMT.conf_ch[ _channel ].conf1.mem_rd_rst = 1;
  215. RMT.conf_ch[ _channel ].conf1.tx_start = 1;
  216. }
  217. static bool anyAlive() {
  218. for ( int i = 0; i != 8; i++ )
  219. if ( ledForChannel( i ) != nullptr ) return true;
  220. return false;
  221. }
  222. const LedType& _timing;
  223. int _channel;
  224. detail::RmtPulsePair _bitToRmt[ 2 ];
  225. int _count;
  226. std::unique_ptr< Rgb[] > _firstBuffer;
  227. std::unique_ptr< Rgb[] > _secondBuffer;
  228. Rgb *_buffer;
  229. xSemaphoreHandle _finishedFlag;
  230. int _pixelPosition;
  231. int _componentPosition;
  232. int _halfIdx;
  233. };
  234. class Apa102 {
  235. public:
  236. struct ApaRgb {
  237. ApaRgb( uint8_t r = 0, uint8_t g = 0, uint32_t b = 0, uint32_t v = 0xFF )
  238. : v( 0xE0 | v ), b( b ), g( g ), r( r )
  239. {}
  240. ApaRgb& operator=( const Rgb& o ) {
  241. r = o.r;
  242. g = o.g;
  243. b = o.b;
  244. return *this;
  245. }
  246. ApaRgb& operator=( const Hsv& o ) {
  247. *this = Rgb{ o };
  248. return *this;
  249. }
  250. uint8_t v, b, g, r;
  251. };
  252. static const int FINAL_FRAME_SIZE = 4;
  253. static const int TRANS_COUNT = 2 + 8;
  254. Apa102( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer )
  255. : _count( count ),
  256. _firstBuffer( new ApaRgb[ count ] ),
  257. _secondBuffer( doubleBuffer ? new ApaRgb[ count ] : nullptr ),
  258. _initFrame( 0 )
  259. {
  260. spi_bus_config_t buscfg;
  261. memset( &buscfg, 0, sizeof( buscfg ) );
  262. buscfg.mosi_io_num = datapin;
  263. buscfg.miso_io_num = -1;
  264. buscfg.sclk_io_num = clkpin;
  265. buscfg.quadwp_io_num = -1;
  266. buscfg.quadhd_io_num = -1;
  267. buscfg.max_transfer_sz = 65535;
  268. spi_device_interface_config_t devcfg;
  269. memset( &devcfg, 0, sizeof( devcfg ) );
  270. devcfg.clock_speed_hz = 1000000;
  271. devcfg.mode = 0;
  272. devcfg.spics_io_num = -1;
  273. devcfg.queue_size = TRANS_COUNT;
  274. devcfg.pre_cb = nullptr;
  275. auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
  276. assert( ret == ESP_OK );
  277. ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
  278. assert( ret == ESP_OK );
  279. std::fill_n( _finalFrame, FINAL_FRAME_SIZE, 0xFFFFFFFF );
  280. }
  281. ~Apa102() {
  282. // ToDo
  283. }
  284. ApaRgb& operator[]( int idx ) {
  285. return _firstBuffer[ idx ];
  286. }
  287. const ApaRgb& operator[]( int idx ) const {
  288. return _firstBuffer[ idx ];
  289. }
  290. void show() {
  291. _buffer = _firstBuffer.get();
  292. startTransmission();
  293. swapBuffers();
  294. }
  295. void wait() {
  296. for ( int i = 0; i != _transCount; i++ ) {
  297. spi_transaction_t *t;
  298. spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
  299. }
  300. }
  301. private:
  302. void swapBuffers() {
  303. if ( _secondBuffer )
  304. _firstBuffer.swap( _secondBuffer );
  305. }
  306. void startTransmission() {
  307. for ( int i = 0; i != TRANS_COUNT; i++ ) {
  308. _transactions[ i ].cmd = 0;
  309. _transactions[ i ].addr = 0;
  310. _transactions[ i ].flags = 0;
  311. _transactions[ i ].rxlength = 0;
  312. _transactions[ i ].rx_buffer = nullptr;
  313. }
  314. // Init frame
  315. _transactions[ 0 ].length = 32;
  316. _transactions[ 0 ].tx_buffer = &_initFrame;
  317. spi_device_queue_trans( _spi, _transactions + 0, portMAX_DELAY );
  318. // Data
  319. _transactions[ 1 ].length = 32 * _count;
  320. _transactions[ 1 ].tx_buffer = _buffer;
  321. spi_device_queue_trans( _spi, _transactions + 1, portMAX_DELAY );
  322. _transCount = 2;
  323. // End frame
  324. for ( int i = 0; i != 1 + _count / 32 / FINAL_FRAME_SIZE; i++ ) {
  325. _transactions[ 2 + i ].length = 32 * FINAL_FRAME_SIZE;
  326. _transactions[ 2 + i ].tx_buffer = _finalFrame;
  327. spi_device_queue_trans( _spi, _transactions + 2 + i, portMAX_DELAY );
  328. _transCount++;
  329. }
  330. }
  331. spi_device_handle_t _spi;
  332. int _count;
  333. std::unique_ptr< ApaRgb[] > _firstBuffer, _secondBuffer;
  334. ApaRgb *_buffer;
  335. spi_transaction_t _transactions[ TRANS_COUNT ];
  336. int _transCount;
  337. uint32_t _initFrame;
  338. uint32_t _finalFrame[ FINAL_FRAME_SIZE ];
  339. };
  340. class LDP8806 {
  341. public:
  342. struct LDP8806_GRB {
  343. LDP8806_GRB( uint8_t g_7bit = 0, uint8_t r_7bit = 0, uint32_t b_7bit = 0 )
  344. : g( g_7bit ), r( r_7bit ), b( b_7bit )
  345. {
  346. }
  347. LDP8806_GRB& operator=( const Rgb& o ) {
  348. //Convert 8->7bit colour
  349. r = ( o.r * 127 / 256 ) | 0x80;
  350. g = ( o.g * 127 / 256 ) | 0x80;
  351. b = ( o.b * 127 / 256 ) | 0x80;
  352. return *this;
  353. }
  354. LDP8806_GRB& operator=( const Hsv& o ) {
  355. *this = Rgb{ o };
  356. return *this;
  357. }
  358. uint8_t g, r, b;
  359. };
  360. static const int LED_FRAME_SIZE_BYTES = sizeof( LDP8806_GRB );
  361. static const int LATCH_FRAME_SIZE_BYTES = 3;
  362. static const int TRANS_COUNT_MAX = 20;//Arbitrary, supports up to 600 LED
  363. LDP8806( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, uint32_t clock_speed_hz = 2000000 )
  364. : _count( count ),
  365. _firstBuffer( new LDP8806_GRB[ count ] ),
  366. _secondBuffer( doubleBuffer ? new LDP8806_GRB[ count ] : nullptr ),
  367. // one 'latch'/start-of-data mark frame for every 32 leds
  368. _latchFrames( ( count + 31 ) / 32 )
  369. {
  370. spi_bus_config_t buscfg;
  371. memset( &buscfg, 0, sizeof( buscfg ) );
  372. buscfg.mosi_io_num = datapin;
  373. buscfg.miso_io_num = -1;
  374. buscfg.sclk_io_num = clkpin;
  375. buscfg.quadwp_io_num = -1;
  376. buscfg.quadhd_io_num = -1;
  377. buscfg.max_transfer_sz = 65535;
  378. spi_device_interface_config_t devcfg;
  379. memset( &devcfg, 0, sizeof( devcfg ) );
  380. devcfg.clock_speed_hz = clock_speed_hz;
  381. devcfg.mode = 0;
  382. devcfg.spics_io_num = -1;
  383. devcfg.queue_size = TRANS_COUNT_MAX;
  384. devcfg.pre_cb = nullptr;
  385. auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
  386. assert( ret == ESP_OK );
  387. ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
  388. assert( ret == ESP_OK );
  389. std::fill_n( _latchBuffer, LATCH_FRAME_SIZE_BYTES, 0x0 );
  390. }
  391. ~LDP8806() {
  392. // noop
  393. }
  394. LDP8806_GRB& operator[]( int idx ) {
  395. return _firstBuffer[ idx ];
  396. }
  397. const LDP8806_GRB& operator[]( int idx ) const {
  398. return _firstBuffer[ idx ];
  399. }
  400. void show() {
  401. _buffer = _firstBuffer.get();
  402. startTransmission();
  403. swapBuffers();
  404. }
  405. void wait() {
  406. while ( _transCount-- ) {
  407. spi_transaction_t *t;
  408. spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
  409. }
  410. }
  411. private:
  412. void swapBuffers() {
  413. if ( _secondBuffer )
  414. _firstBuffer.swap( _secondBuffer );
  415. }
  416. void startTransmission() {
  417. _transCount = 0;
  418. for ( int i = 0; i != TRANS_COUNT_MAX; i++ ) {
  419. _transactions[ i ].cmd = 0;
  420. _transactions[ i ].addr = 0;
  421. _transactions[ i ].flags = 0;
  422. _transactions[ i ].rxlength = 0;
  423. _transactions[ i ].rx_buffer = nullptr;
  424. }
  425. // LED Data
  426. _transactions[ 0 ].length = ( LED_FRAME_SIZE_BYTES * 8 ) * _count;
  427. _transactions[ 0 ].tx_buffer = _buffer;
  428. spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
  429. _transCount++;
  430. // 'latch'/start-of-data marker frames
  431. for ( int i = 0; i < _latchFrames; i++ ) {
  432. _transactions[ _transCount ].length = ( LATCH_FRAME_SIZE_BYTES * 8 );
  433. _transactions[ _transCount ].tx_buffer = _latchBuffer;
  434. spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
  435. _transCount++;
  436. }
  437. }
  438. spi_device_handle_t _spi;
  439. int _count;
  440. std::unique_ptr< LDP8806_GRB[] > _firstBuffer, _secondBuffer;
  441. LDP8806_GRB *_buffer;
  442. spi_transaction_t _transactions[ TRANS_COUNT_MAX ];
  443. int _transCount;
  444. int _latchFrames;
  445. uint8_t _latchBuffer[ LATCH_FRAME_SIZE_BYTES ];
  446. };
  447. #endif //SMARTLEDS_H