diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..4e42927 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,28 @@ +name: PlatformIO CI + +on: [push] + +jobs: + build-test: + runs-on: ubuntu-22.04 + strategy: + matrix: + example: + - examples/basic + conf: + - esp32-idf4-arduino.ini + - esp32-idf5-idf.ini + - esp32s3-idf4-arduino.ini + - esp32s3-idf5-idf.ini + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + - name: Install dependencies + run: | + python3 -m pip install --upgrade pip + python3 -m pip install platformio + - name: Build examples + run: platformio ci --lib="." --project-conf="./test-inis/${{ matrix.conf }}" + env: + PLATFORMIO_CI_SRC: ${{ matrix.example }} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7caf7f5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0) + +set(SRCS + "src/Color.cpp" + "src/RmtDriver4.cpp" + "src/RmtDriver5.cpp" + "src/SmartLeds.cpp" +) + +idf_component_register( + SRCS ${SRCS} + INCLUDE_DIRS "./src" + REQUIRES driver +) diff --git a/README.md b/README.md index 397edf8..e2daf3a 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,16 @@ Simple & intuitive way to drive various smart LEDs on ESP32. +Requires ESP-IDF >=4.0 + ## Supported LEDs: -- WS2812 (RMT driver) +- WS2812 (RMT driver) - WS2812B (RMT driver) -- SK6812 (RMT driver) -- WS2813 (RMT driver) -- APA102 (SPI driver) -- LPD8806 (SPI driver) +- SK6812 (RMT driver) +- WS2813 (RMT driver) +- APA102 (SPI driver) +- LPD8806 (SPI driver) All the LEDs are driven by hardware peripherals in order to achieve high performance. @@ -28,4 +30,5 @@ performance. - clock at 10 MHz ## Available -[PlatformIO - library 1740 - SmartLeds](https://platformio.org/lib/show/1740/SmartLeds) \ No newline at end of file + +[PlatformIO - library 1740 - SmartLeds](https://platformio.org/lib/show/1740/SmartLeds) diff --git a/examples/basic/main.cpp b/examples/basic/main.cpp new file mode 100644 index 0000000..79e9d6a --- /dev/null +++ b/examples/basic/main.cpp @@ -0,0 +1,62 @@ +#ifdef LX16A_ARDUINO +#include +#else +#include +#include +static void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); } +static uint32_t millis() { return xTaskGetTickCount(); } +#endif + +#include + +const int LED_COUNT = 15; +const int DATA_PIN = 22; +const int CHANNEL = 0; + +// SmartLed -> RMT driver (WS2812/WS2812B/SK6812/WS2813) +SmartLed leds(LED_WS2812B, LED_COUNT, DATA_PIN, CHANNEL, DoubleBuffer); + +const int CLK_PIN = 23; +// APA102 -> SPI driver +//Apa102 leds(LED_COUNT, CLK_PIN, DATA_PIN, DoubleBuffer); + +void setup() {} + +uint8_t hue; +void showGradient() { + hue++; + // Use HSV to create nice gradient + for (int i = 0; i != LED_COUNT; i++) + leds[i] = Hsv { static_cast(hue + 30 * i), 255, 255 }; + leds.show(); + // Show is asynchronous; if we need to wait for the end of transmission, + // we can use leds.wait(); however we use double buffered mode, so we + // can start drawing right after showing. +} + +void showRgb() { + leds[0] = Rgb { 255, 0, 0 }; + leds[1] = Rgb { 0, 255, 0 }; + leds[2] = Rgb { 0, 0, 255 }; + leds[3] = Rgb { 0, 0, 0 }; + leds[4] = Rgb { 255, 255, 255 }; + leds.show(); +} + +void loop() { + if (millis() % 10000 < 5000) + showGradient(); + else + showRgb(); + delay(50); +} + +#ifndef ARDUINO +extern "C" void app_main() { + setup(); + while (true) { + loop(); + vTaskDelay(0); + } +} +#endif diff --git a/examples/basicExample/basicExample.ino b/examples/basicExample/basicExample.ino deleted file mode 100644 index 9ccfbe2..0000000 --- a/examples/basicExample/basicExample.ino +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include - -const int LED_COUNT = 15; -const int DATA_PIN = 22; -const int CHANNEL = 0; - -// SmartLed -> RMT driver (WS2812/WS2812B/SK6812/WS2813) -SmartLed leds( LED_WS2812, LED_COUNT, DATA_PIN, CHANNEL, DoubleBuffer ); - -const int CLK_PIN = 23; -// APA102 -> SPI driver -//Apa102 leds(LED_COUNT, CLK_PIN, DATA_PIN, DoubleBuffer); - -void setup() { - Serial.begin(9600); -} - -uint8_t hue; -void showGradient() { - hue++; - // Use HSV to create nice gradient - for ( int i = 0; i != LED_COUNT; i++ ) - leds[ i ] = Hsv{ static_cast< uint8_t >( hue + 30 * i ), 255, 255 }; - leds.show(); - // Show is asynchronous; if we need to wait for the end of transmission, - // we can use leds.wait(); however we use double buffered mode, so we - // can start drawing right after showing. -} - -void showRgb() { - leds[ 0 ] = Rgb{ 255, 0, 0 }; - leds[ 1 ] = Rgb{ 0, 255, 0 }; - leds[ 2 ] = Rgb{ 0, 0, 255 }; - leds[ 3 ] = Rgb{ 0, 0, 0 }; - leds[ 4 ] = Rgb{ 255, 255, 255 }; - leds.show(); -} - -void loop() { - Serial.println("New loop"); - - if ( millis() % 10000 < 5000 ) - showGradient(); - else - showRgb(); - delay( 50 ); -} diff --git a/src/RmtDriver.h b/src/RmtDriver.h index 69275a9..c71d909 100644 --- a/src/RmtDriver.h +++ b/src/RmtDriver.h @@ -1,13 +1,17 @@ #pragma once -#include +#include #include -#if (defined(ESP_IDF_VERSION) && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) +#if defined(ESP_IDF_VERSION) +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) #define SMARTLEDS_NEW_RMT_DRIVER 1 #else #define SMARTLEDS_NEW_RMT_DRIVER 0 #endif +#else +#define SMARTLEDS_NEW_RMT_DRIVER 0 +#endif namespace detail { diff --git a/src/RmtDriver5.cpp b/src/RmtDriver5.cpp index 15ce973..93e7204 100644 --- a/src/RmtDriver5.cpp +++ b/src/RmtDriver5.cpp @@ -8,7 +8,7 @@ namespace detail { static constexpr const uint32_t RMT_RESOLUTION_HZ = 20 * 1000 * 1000; // 20 MHz -static constexpr const uint32_t RMT_NS_PER_TICK = 1000000000LU / RMT_RESOLUTION_HZ; +static constexpr const uint32_t RMT_NS_PER_TICK = 1000000000LLU / RMT_RESOLUTION_HZ; static RmtEncoderWrapper* IRAM_ATTR encSelf(rmt_encoder_t* encoder) { return (RmtEncoderWrapper*)(((intptr_t)encoder) - offsetof(RmtEncoderWrapper, base)); @@ -124,7 +124,7 @@ esp_err_t RmtDriver::registerIsr(bool isFirstRegisteredChannel) { .gpio_num = _pin, .clk_src = RMT_CLK_SRC_APB, .resolution_hz = RMT_RESOLUTION_HZ, - .mem_block_symbols = 64, + .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, .trans_queue_depth = 1, .flags = {}, }; @@ -151,6 +151,11 @@ esp_err_t RmtDriver::unregisterIsr() { return err; } + err = rmt_disable(_channel); + if (err != ESP_OK) { + return err; + } + return rmt_del_channel(_channel); } diff --git a/src/RmtDriver5.h b/src/RmtDriver5.h index c6b08b6..19a177b 100644 --- a/src/RmtDriver5.h +++ b/src/RmtDriver5.h @@ -29,7 +29,7 @@ struct RmtEncoderWrapper { RmtDriver* driver; rmt_symbol_word_t reset_code; - uint8_t buffer[64 / 8]; // RMT peripherial has buffer for 64 bits + uint8_t buffer[SOC_RMT_MEM_WORDS_PER_CHANNEL / 8]; rmt_encode_state_t last_state; size_t frame_idx; uint8_t component_idx; diff --git a/src/SmartLeds.cpp b/src/SmartLeds.cpp index 20f2e39..601f427 100644 --- a/src/SmartLeds.cpp +++ b/src/SmartLeds.cpp @@ -3,7 +3,7 @@ IsrCore SmartLed::_interruptCore = CoreCurrent; SmartLed*& IRAM_ATTR SmartLed::ledForChannel(int channel) { - static SmartLed* table[detail::CHANNEL_COUNT] = { nullptr }; + static SmartLed* table[detail::CHANNEL_COUNT] = {}; assert(channel < detail::CHANNEL_COUNT); return table[channel]; } diff --git a/src/SmartLeds.h b/src/SmartLeds.h index c1d6d03..935f59b 100644 --- a/src/SmartLeds.h +++ b/src/SmartLeds.h @@ -183,12 +183,10 @@ class SmartLed { std::unique_ptr _secondBuffer; }; -#ifdef CONFIG_IDF_TARGET_ESP32 -#define _SMARTLEDS_SPI_HOST HSPI_HOST -#elif defined(CONFIG_IDF_TARGET_ESP32S3) +#if defined(CONFIG_IDF_TARGET_ESP32S3) #define _SMARTLEDS_SPI_HOST SPI2_HOST #else -#error "SmartLeds SPI host not defined for this chip/esp-idf version." +#define _SMARTLEDS_SPI_HOST HSPI_HOST #endif class Apa102 { diff --git a/test-inis/esp32-idf4-arduino.ini b/test-inis/esp32-idf4-arduino.ini new file mode 100644 index 0000000..daaf145 --- /dev/null +++ b/test-inis/esp32-idf4-arduino.ini @@ -0,0 +1,23 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32@5.3.0 +board = esp32dev +framework = arduino + +upload_speed = 921600 +monitor_speed = 115200 + +build_unflags = -std=gnu++11 +build_flags = + -std=gnu++14 + -fmax-errors=5 + -DLX16A_ARDUINO=1 diff --git a/test-inis/esp32-idf5-idf.ini b/test-inis/esp32-idf5-idf.ini new file mode 100644 index 0000000..1c6f859 --- /dev/null +++ b/test-inis/esp32-idf5-idf.ini @@ -0,0 +1,22 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32@6.3.2 +board = esp32dev +framework = espidf + +upload_speed = 921600 +monitor_speed = 115200 + +build_unflags = -std=gnu++11 +build_flags = + -std=gnu++14 + -fmax-errors=5 diff --git a/test-inis/esp32s3-idf4-arduino.ini b/test-inis/esp32s3-idf4-arduino.ini new file mode 100644 index 0000000..7b0da2f --- /dev/null +++ b/test-inis/esp32s3-idf4-arduino.ini @@ -0,0 +1,23 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32@6.3.2 +board = esp32-s3-devkitc-1 +framework = arduino + +upload_speed = 921600 +monitor_speed = 115200 + +build_unflags = -std=gnu++11 +build_flags = + -std=gnu++14 + -fmax-errors=5 + -DLX16A_ARDUINO=1 diff --git a/test-inis/esp32s3-idf5-idf.ini b/test-inis/esp32s3-idf5-idf.ini new file mode 100644 index 0000000..6b81e68 --- /dev/null +++ b/test-inis/esp32s3-idf5-idf.ini @@ -0,0 +1,22 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32@6.3.2 +board = esp32-s3-devkitc-1 +framework = espidf + +upload_speed = 921600 +monitor_speed = 115200 + +build_unflags = -std=gnu++11 +build_flags = + -std=gnu++14 + -fmax-errors=5