Initial commit of Arduino libraries
This commit is contained in:
65
FastLED/src/third_party/arduinojson/json.h
vendored
Normal file
65
FastLED/src/third_party/arduinojson/json.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
// Arduino JSON may be included by the user, so we need to save the current state
|
||||
// of the macros and restore them after including the library
|
||||
#pragma push_macro("ARDUINO")
|
||||
#pragma push_macro("ARDUINOJSON_ENABLE_STD_STREAM")
|
||||
#pragma push_macro("ARDUINOJSON_ENABLE_STRING_VIEW")
|
||||
#pragma push_macro("ARDUINOJSON_ENABLE_STD_STRING")
|
||||
#pragma push_macro("ARDUINOJSON_ENABLE_ARDUINO_STRING")
|
||||
#pragma push_macro("ARDUINOJSON_ENABLE_ARDUINO_STREAM")
|
||||
#pragma push_macro("ARDUINOJSON_ENABLE_ARDUINO_PRINT")
|
||||
#pragma push_macro("ARDUINOJSON_ENABLE_PROGMEM")
|
||||
|
||||
// Safely undefine FLArduinoJson macros if defined
|
||||
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||
#undef ARDUINOJSON_ENABLE_STD_STREAM
|
||||
#endif
|
||||
#define ARDUINOJSON_ENABLE_STD_STREAM 0
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_STRING_VIEW
|
||||
#undef ARDUINOJSON_ENABLE_STRING_VIEW
|
||||
#endif
|
||||
#define ARDUINOJSON_ENABLE_STRING_VIEW 0
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_STD_STRING
|
||||
#undef ARDUINOJSON_ENABLE_STD_STRING
|
||||
#endif
|
||||
#define ARDUINOJSON_ENABLE_STD_STRING 0
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
#undef ARDUINOJSON_ENABLE_ARDUINO_STRING
|
||||
#endif
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
#undef ARDUINOJSON_ENABLE_ARDUINO_STREAM
|
||||
#endif
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||
#undef ARDUINOJSON_ENABLE_ARDUINO_PRINT
|
||||
#endif
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_PROGMEM
|
||||
#undef ARDUINOJSON_ENABLE_PROGMEM
|
||||
#endif
|
||||
#define ARDUINOJSON_ENABLE_PROGMEM 0
|
||||
|
||||
#ifdef ARDUINO
|
||||
#undef ARDUINO
|
||||
#endif
|
||||
|
||||
#define FASTLED_JSON_GUARD
|
||||
#include "json.hpp"
|
||||
#undef FASTLED_JSON_GUARD
|
||||
|
||||
#pragma pop_macro("ARDUINOJSON_ENABLE_PROGMEM")
|
||||
#pragma pop_macro("ARDUINOJSON_ENABLE_ARDUINO_PRINT")
|
||||
#pragma pop_macro("ARDUINOJSON_ENABLE_ARDUINO_STREAM")
|
||||
#pragma pop_macro("ARDUINOJSON_ENABLE_ARDUINO_STRING")
|
||||
#pragma pop_macro("ARDUINOJSON_ENABLE_STD_STRING")
|
||||
#pragma pop_macro("ARDUINOJSON_ENABLE_STRING_VIEW")
|
||||
#pragma pop_macro("ARDUINOJSON_ENABLE_STD_STREAM")
|
||||
#pragma pop_macro("ARDUINO")
|
||||
8222
FastLED/src/third_party/arduinojson/json.hpp
vendored
Normal file
8222
FastLED/src/third_party/arduinojson/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
12
FastLED/src/third_party/espressif/led_strip/readme
vendored
Normal file
12
FastLED/src/third_party/espressif/led_strip/readme
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
From espressif led_strip component repository.
|
||||
|
||||
Version: 3.0.0
|
||||
|
||||
This library has been lightly modified to support async operations for both spi and rmt strip drivers.
|
||||
|
||||
The following files were added by FastLED:
|
||||
|
||||
strip_spi.h
|
||||
strip_spi.cpp
|
||||
strip_rmt.h
|
||||
strip_rmt.cpp
|
||||
60
FastLED/src/third_party/espressif/led_strip/src/enabled.h
vendored
Normal file
60
FastLED/src/third_party/espressif/led_strip/src/enabled.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "platforms/esp/esp_version.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C2
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 1
|
||||
#define FASTLED_ESP32_HAS_RMT 0
|
||||
#define FASTLED_ESP32_HAS_RMT5 0
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 1
|
||||
#define FASTLED_ESP32_HAS_RMT 1
|
||||
#define FASTLED_ESP32_HAS_RMT5 1
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 1
|
||||
#define FASTLED_ESP32_HAS_RMT 1
|
||||
#define FASTLED_ESP32_HAS_RMT5 1
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 1
|
||||
#define FASTLED_ESP32_HAS_RMT 1
|
||||
#define FASTLED_ESP32_HAS_RMT5 1
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 1
|
||||
#define FASTLED_ESP32_HAS_RMT 1
|
||||
#define FASTLED_ESP32_HAS_RMT5 1
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 1
|
||||
#define FASTLED_ESP32_HAS_RMT 1
|
||||
#define FASTLED_ESP32_HAS_RMT5 1
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 1
|
||||
#define FASTLED_ESP32_HAS_RMT 1
|
||||
#define FASTLED_ESP32_HAS_RMT5 1
|
||||
#elif CONFIG_IDF_TARGET_ESP8266
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 0
|
||||
#define FASTLED_ESP32_HAS_RMT 0
|
||||
#define FASTLED_ESP32_HAS_RMT5 0
|
||||
#elif CONFIG_IDF_TARGET_ESP32 || defined(ARDUINO_ESP32_DEV)
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 0
|
||||
#define FASTLED_ESP32_HAS_RMT 1
|
||||
#define FASTLED_ESP32_HAS_RMT5 1
|
||||
#else
|
||||
#warning "Unknown board, assuming support for clockless RMT5 and SPI chipsets. Please file an bug report with FastLED and tell them about your board type."
|
||||
#endif
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
#undef FASTLED_ESP32_HAS_RMT5
|
||||
#undef FASTLED_ESP32_HAS_CLOCKLESS_SPI
|
||||
#define FASTLED_ESP32_HAS_RMT5 0
|
||||
#define FASTLED_ESP32_HAS_CLOCKLESS_SPI 0
|
||||
#endif
|
||||
|
||||
|
||||
// Note that FASTLED_RMT5 is a legacy name,
|
||||
// so we keep it because "RMT" is specific to ESP32
|
||||
#if FASTLED_ESP32_HAS_RMT5 && !defined(FASTLED_RMT5)
|
||||
#define FASTLED_RMT5 1
|
||||
#else
|
||||
#define FASTLED_RMT5 0
|
||||
#endif
|
||||
112
FastLED/src/third_party/espressif/led_strip/src/led_strip.h
vendored
Normal file
112
FastLED/src/third_party/espressif/led_strip/src/led_strip.h
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "led_strip_rmt.h"
|
||||
#include "led_strip_spi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set RGB for a specific pixel
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param index: index of pixel to set
|
||||
* @param red: red part of color
|
||||
* @param green: green part of color
|
||||
* @param blue: blue part of color
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Set RGB for a specific pixel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
|
||||
* - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
|
||||
*/
|
||||
esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
|
||||
|
||||
/**
|
||||
* @brief Set RGBW for a specific pixel
|
||||
*
|
||||
* @note Only call this function if your led strip does have the white component (e.g. SK6812-RGBW)
|
||||
* @note Also see `led_strip_set_pixel` if you only want to specify the RGB part of the color and bypass the white component
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param index: index of pixel to set
|
||||
* @param red: red part of color
|
||||
* @param green: green part of color
|
||||
* @param blue: blue part of color
|
||||
* @param white: separate white component
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Set RGBW color for a specific pixel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set RGBW color for a specific pixel failed because of an invalid argument
|
||||
* - ESP_FAIL: Set RGBW color for a specific pixel failed because other error occurred
|
||||
*/
|
||||
esp_err_t led_strip_set_pixel_rgbw(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white);
|
||||
|
||||
/**
|
||||
* @brief Set HSV for a specific pixel
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param index: index of pixel to set
|
||||
* @param hue: hue part of color (0 - 360)
|
||||
* @param saturation: saturation part of color (0 - 255, rescaled from 0 - 1. e.g. saturation = 0.5, rescaled to 127)
|
||||
* @param value: value part of color (0 - 255, rescaled from 0 - 1. e.g. value = 0.5, rescaled to 127)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Set HSV color for a specific pixel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set HSV color for a specific pixel failed because of an invalid argument
|
||||
* - ESP_FAIL: Set HSV color for a specific pixel failed because other error occurred
|
||||
*/
|
||||
esp_err_t led_strip_set_pixel_hsv(led_strip_handle_t strip, uint32_t index, uint16_t hue, uint8_t saturation, uint8_t value);
|
||||
|
||||
/**
|
||||
* @brief Refresh memory colors to LEDs
|
||||
*
|
||||
* @param strip: LED strip
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Refresh successfully
|
||||
* - ESP_FAIL: Refresh failed because some other error occurred
|
||||
*
|
||||
* @note:
|
||||
* After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
|
||||
*/
|
||||
esp_err_t led_strip_refresh(led_strip_handle_t strip);
|
||||
|
||||
|
||||
esp_err_t led_strip_refresh_async(led_strip_handle_t strip);
|
||||
|
||||
esp_err_t led_strip_refresh_wait_done(led_strip_handle_t strip);
|
||||
|
||||
/**
|
||||
* @brief Clear LED strip (turn off all LEDs)
|
||||
*
|
||||
* @param strip: LED strip
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Clear LEDs successfully
|
||||
* - ESP_FAIL: Clear LEDs failed because some other error occurred
|
||||
*/
|
||||
esp_err_t led_strip_clear(led_strip_handle_t strip);
|
||||
|
||||
/**
|
||||
* @brief Free LED strip resources
|
||||
*
|
||||
* @param strip: LED strip
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Free resources successfully
|
||||
* - ESP_FAIL: Free resources failed because error occurred
|
||||
*/
|
||||
esp_err_t led_strip_del(led_strip_handle_t strip);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
118
FastLED/src/third_party/espressif/led_strip/src/led_strip_api.c
vendored
Normal file
118
FastLED/src/third_party/espressif/led_strip/src/led_strip_api.c
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
#include "enabled.h"
|
||||
|
||||
#if FASTLED_RMT5 || FASTLED_ESP32_HAS_CLOCKLESS_SPI
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "led_strip.h"
|
||||
#include "led_strip_interface.h"
|
||||
|
||||
static const char *TAG = "led_strip";
|
||||
|
||||
esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return strip->set_pixel(strip, index, red, green, blue);
|
||||
}
|
||||
|
||||
esp_err_t led_strip_set_pixel_hsv(led_strip_handle_t strip, uint32_t index, uint16_t hue, uint8_t saturation, uint8_t value)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
uint32_t red = 0;
|
||||
uint32_t green = 0;
|
||||
uint32_t blue = 0;
|
||||
|
||||
uint32_t rgb_max = value;
|
||||
uint32_t rgb_min = rgb_max * (255 - saturation) / 255.0f;
|
||||
|
||||
uint32_t i = hue / 60;
|
||||
uint32_t diff = hue % 60;
|
||||
|
||||
// RGB adjustment amount by hue
|
||||
uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
red = rgb_max;
|
||||
green = rgb_min + rgb_adj;
|
||||
blue = rgb_min;
|
||||
break;
|
||||
case 1:
|
||||
red = rgb_max - rgb_adj;
|
||||
green = rgb_max;
|
||||
blue = rgb_min;
|
||||
break;
|
||||
case 2:
|
||||
red = rgb_min;
|
||||
green = rgb_max;
|
||||
blue = rgb_min + rgb_adj;
|
||||
break;
|
||||
case 3:
|
||||
red = rgb_min;
|
||||
green = rgb_max - rgb_adj;
|
||||
blue = rgb_max;
|
||||
break;
|
||||
case 4:
|
||||
red = rgb_min + rgb_adj;
|
||||
green = rgb_min;
|
||||
blue = rgb_max;
|
||||
break;
|
||||
default:
|
||||
red = rgb_max;
|
||||
green = rgb_min;
|
||||
blue = rgb_max - rgb_adj;
|
||||
break;
|
||||
}
|
||||
|
||||
return strip->set_pixel(strip, index, red, green, blue);
|
||||
}
|
||||
|
||||
esp_err_t led_strip_refresh_wait_done(led_strip_handle_t strip)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return strip->refresh_wait_done(strip);
|
||||
}
|
||||
|
||||
esp_err_t led_strip_set_pixel_rgbw(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return strip->set_pixel_rgbw(strip, index, red, green, blue, white);
|
||||
}
|
||||
|
||||
esp_err_t led_strip_refresh(led_strip_handle_t strip)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_ERROR(strip->refresh_async(strip), TAG, "refresh failed");
|
||||
ESP_RETURN_ON_ERROR(strip->refresh_wait_done(strip), TAG, "wait for done failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t led_strip_refresh_async(led_strip_handle_t strip)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return strip->refresh_async(strip);
|
||||
}
|
||||
|
||||
esp_err_t led_strip_clear(led_strip_handle_t strip)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return strip->clear(strip);
|
||||
}
|
||||
|
||||
esp_err_t led_strip_del(led_strip_handle_t strip)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return strip->del(strip);
|
||||
}
|
||||
|
||||
#endif // FASTLED_RMT5 || FASTLED_ESP_HAS_CLOCKLESS_SPI
|
||||
|
||||
#endif // ESP32
|
||||
99
FastLED/src/third_party/espressif/led_strip/src/led_strip_interface.h
vendored
Normal file
99
FastLED/src/third_party/espressif/led_strip/src/led_strip_interface.h
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct led_strip_t led_strip_t; /*!< Type of LED strip */
|
||||
|
||||
/**
|
||||
* @brief LED strip interface definition
|
||||
*/
|
||||
struct led_strip_t {
|
||||
/**
|
||||
* @brief Set RGB for a specific pixel
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param index: index of pixel to set
|
||||
* @param red: red part of color
|
||||
* @param green: green part of color
|
||||
* @param blue: blue part of color
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Set RGB for a specific pixel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters
|
||||
* - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred
|
||||
*/
|
||||
esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);
|
||||
|
||||
/**
|
||||
* @brief Set RGBW for a specific pixel. Similar to `set_pixel` but also set the white component
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param index: index of pixel to set
|
||||
* @param red: red part of color
|
||||
* @param green: green part of color
|
||||
* @param blue: blue part of color
|
||||
* @param white: separate white component
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Set RGBW color for a specific pixel successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set RGBW color for a specific pixel failed because of an invalid argument
|
||||
* - ESP_FAIL: Set RGBW color for a specific pixel failed because other error occurred
|
||||
*/
|
||||
esp_err_t (*set_pixel_rgbw)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white);
|
||||
|
||||
/**
|
||||
* @brief Refresh memory colors to LEDs
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param timeout_ms: timeout value for refreshing task
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Refresh successfully
|
||||
* - ESP_FAIL: Refresh failed because some other error occurred
|
||||
*
|
||||
* @note:
|
||||
* After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.
|
||||
*/
|
||||
esp_err_t (*refresh)(led_strip_t *strip);
|
||||
|
||||
|
||||
esp_err_t (*refresh_async)(led_strip_t *strip);
|
||||
esp_err_t (*refresh_wait_done)(led_strip_t *strip);
|
||||
|
||||
/**
|
||||
* @brief Clear LED strip (turn off all LEDs)
|
||||
*
|
||||
* @param strip: LED strip
|
||||
* @param timeout_ms: timeout value for clearing task
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Clear LEDs successfully
|
||||
* - ESP_FAIL: Clear LEDs failed because some other error occurred
|
||||
*/
|
||||
esp_err_t (*clear)(led_strip_t *strip);
|
||||
|
||||
/**
|
||||
* @brief Free LED strip resources
|
||||
*
|
||||
* @param strip: LED strip
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Free resources successfully
|
||||
* - ESP_FAIL: Free resources failed because error occurred
|
||||
*/
|
||||
esp_err_t (*del)(led_strip_t *strip);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
48
FastLED/src/third_party/espressif/led_strip/src/led_strip_rmt.h
vendored
Normal file
48
FastLED/src/third_party/espressif/led_strip/src/led_strip_rmt.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "led_strip_types.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include "driver/rmt_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LED Strip RMT specific configuration
|
||||
*/
|
||||
typedef struct {
|
||||
rmt_clock_source_t clk_src; /*!< RMT clock source */
|
||||
uint32_t resolution_hz; /*!< RMT tick resolution, if set to zero, a default resolution (10MHz) will be applied */
|
||||
size_t mem_block_symbols; /*!< How many RMT symbols can one RMT channel hold at one time. Set to 0 will fallback to use the default size. */
|
||||
/*!< Extra RMT specific driver flags */
|
||||
struct led_strip_rmt_extra_config {
|
||||
uint32_t with_dma: 1; /*!< Use DMA to transmit data */
|
||||
} flags; /*!< Extra driver flags */
|
||||
uint8_t interrupt_priority; /*!< RMT interrupt priority, 0-3 are valid values */
|
||||
} led_strip_rmt_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create LED strip based on RMT TX channel
|
||||
*
|
||||
* @param led_config LED strip configuration
|
||||
* @param rmt_config RMT specific configuration
|
||||
* @param ret_strip Returned LED strip handle
|
||||
* @return
|
||||
* - ESP_OK: create LED strip handle successfully
|
||||
* - ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument
|
||||
* - ESP_ERR_NO_MEM: create LED strip handle failed because of out of memory
|
||||
* - ESP_FAIL: create LED strip handle failed because some other error
|
||||
*/
|
||||
esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
229
FastLED/src/third_party/espressif/led_strip/src/led_strip_rmt_dev.c
vendored
Normal file
229
FastLED/src/third_party/espressif/led_strip/src/led_strip_rmt_dev.c
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
#include "enabled.h"
|
||||
|
||||
#if FASTLED_RMT5
|
||||
|
||||
#include "fl/unused.h"
|
||||
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
#include "led_strip.h"
|
||||
#include "led_strip_interface.h"
|
||||
#include "led_strip_rmt_encoder.h"
|
||||
|
||||
#define LED_STRIP_RMT_DEFAULT_RESOLUTION 10000000 // 10MHz resolution
|
||||
#define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE 4
|
||||
|
||||
#ifndef LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
// Fixes https://github.com/FastLED/FastLED/issues/1846
|
||||
#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER 2
|
||||
#else
|
||||
#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// the memory size of each RMT channel, in words (4 bytes)
|
||||
#ifndef LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS (LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER * 64)
|
||||
#else
|
||||
#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS (LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS_MULTIPLIER * 48)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
static const char *TAG = "led_strip_rmt";
|
||||
|
||||
typedef struct {
|
||||
led_strip_t base;
|
||||
rmt_channel_handle_t rmt_chan;
|
||||
rmt_encoder_handle_t strip_encoder;
|
||||
uint32_t strip_len;
|
||||
uint8_t bytes_per_pixel;
|
||||
led_color_component_format_t component_fmt;
|
||||
uint8_t pixel_buf[];
|
||||
} led_strip_rmt_obj;
|
||||
|
||||
static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
|
||||
|
||||
led_color_component_format_t component_fmt = rmt_strip->component_fmt;
|
||||
uint32_t start = index * rmt_strip->bytes_per_pixel;
|
||||
uint8_t *pixel_buf = rmt_strip->pixel_buf;
|
||||
|
||||
pixel_buf[start + component_fmt.format.r_pos] = red & 0xFF;
|
||||
pixel_buf[start + component_fmt.format.g_pos] = green & 0xFF;
|
||||
pixel_buf[start + component_fmt.format.b_pos] = blue & 0xFF;
|
||||
if (component_fmt.format.num_components > 3) {
|
||||
pixel_buf[start + component_fmt.format.w_pos] = 0;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
led_color_component_format_t component_fmt = rmt_strip->component_fmt;
|
||||
ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
|
||||
ESP_RETURN_ON_FALSE(component_fmt.format.num_components == 4, ESP_ERR_INVALID_ARG, TAG, "led doesn't have 4 components");
|
||||
|
||||
uint32_t start = index * rmt_strip->bytes_per_pixel;
|
||||
uint8_t *pixel_buf = rmt_strip->pixel_buf;
|
||||
|
||||
pixel_buf[start + component_fmt.format.r_pos] = red & 0xFF;
|
||||
pixel_buf[start + component_fmt.format.g_pos] = green & 0xFF;
|
||||
pixel_buf[start + component_fmt.format.b_pos] = blue & 0xFF;
|
||||
pixel_buf[start + component_fmt.format.w_pos] = white & 0xFF;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_refresh_async(led_strip_t *strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
rmt_transmit_config_t tx_conf = {
|
||||
.loop_count = 0,
|
||||
};
|
||||
|
||||
ESP_RETURN_ON_ERROR(rmt_enable(rmt_strip->rmt_chan), TAG, "enable RMT channel failed");
|
||||
ESP_RETURN_ON_ERROR(rmt_transmit(rmt_strip->rmt_chan, rmt_strip->strip_encoder, rmt_strip->pixel_buf,
|
||||
rmt_strip->strip_len * rmt_strip->bytes_per_pixel, &tx_conf), TAG, "transmit pixels by RMT failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_wait_for_done(led_strip_t *strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(rmt_strip->rmt_chan, -1), TAG, "wait for RMT done failed");
|
||||
ESP_RETURN_ON_ERROR(rmt_disable(rmt_strip->rmt_chan), TAG, "disable RMT channel failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_refresh(led_strip_t *strip)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(led_strip_rmt_refresh_async(strip), TAG, "refresh async failed");
|
||||
ESP_RETURN_ON_ERROR(led_strip_rmt_wait_for_done(strip), TAG, "wait for done failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_clear(led_strip_t *strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
// Write zero to turn off all leds
|
||||
memset(rmt_strip->pixel_buf, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel);
|
||||
return led_strip_rmt_refresh(strip);
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_del(led_strip_t *strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
ESP_RETURN_ON_ERROR(rmt_del_channel(rmt_strip->rmt_chan), TAG, "delete RMT channel failed");
|
||||
ESP_RETURN_ON_ERROR(rmt_del_encoder(rmt_strip->strip_encoder), TAG, "delete strip encoder failed");
|
||||
free(rmt_strip);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
FASTLED_UNUSED(ret);
|
||||
ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
led_color_component_format_t component_fmt = led_config->color_component_format;
|
||||
// If R/G/B order is not specified, set default GRB order as fallback
|
||||
if (component_fmt.format_id == 0) {
|
||||
component_fmt = LED_STRIP_COLOR_COMPONENT_FMT_GRB;
|
||||
}
|
||||
// check the validation of the color component format
|
||||
uint8_t mask = 0;
|
||||
if (component_fmt.format.num_components == 3) {
|
||||
mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos);
|
||||
// Check for invalid values
|
||||
ESP_RETURN_ON_FALSE(mask == 0x07, ESP_ERR_INVALID_ARG, TAG, "invalid order argument");
|
||||
} else if (component_fmt.format.num_components == 4) {
|
||||
mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos) | BIT(component_fmt.format.w_pos);
|
||||
// Check for invalid values
|
||||
ESP_RETURN_ON_FALSE(mask == 0x0F, ESP_ERR_INVALID_ARG, TAG, "invalid order argument");
|
||||
} else {
|
||||
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "invalid number of color components: %d", component_fmt.format.num_components);
|
||||
}
|
||||
// TODO: we assume each color component is 8 bits, may need to support other configurations in the future, e.g. 10bits per color component?
|
||||
uint8_t bytes_per_pixel = component_fmt.format.num_components;
|
||||
rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel);
|
||||
ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip");
|
||||
uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION;
|
||||
|
||||
// for backward compatibility, if the user does not set the clk_src, use the default value
|
||||
rmt_clock_source_t clk_src = RMT_CLK_SRC_DEFAULT;
|
||||
if (rmt_config->clk_src) {
|
||||
clk_src = rmt_config->clk_src;
|
||||
}
|
||||
size_t mem_block_symbols = LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS;
|
||||
// override the default value if the user sets it
|
||||
if (rmt_config->mem_block_symbols) {
|
||||
mem_block_symbols = rmt_config->mem_block_symbols;
|
||||
}
|
||||
rmt_tx_channel_config_t rmt_chan_config = {
|
||||
.clk_src = clk_src,
|
||||
.gpio_num = led_config->strip_gpio_num,
|
||||
.mem_block_symbols = mem_block_symbols,
|
||||
.resolution_hz = resolution,
|
||||
.trans_queue_depth = LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE,
|
||||
.flags.with_dma = rmt_config->flags.with_dma,
|
||||
.flags.invert_out = led_config->flags.invert_out,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&rmt_chan_config, &rmt_strip->rmt_chan), err, TAG, "create RMT TX channel failed");
|
||||
|
||||
led_strip_encoder_config_t strip_encoder_conf = {
|
||||
.resolution = resolution,
|
||||
.led_model = led_config->led_model,
|
||||
.timings = led_config->timings,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed");
|
||||
|
||||
rmt_strip->component_fmt = component_fmt;
|
||||
rmt_strip->bytes_per_pixel = bytes_per_pixel;
|
||||
rmt_strip->strip_len = led_config->max_leds;
|
||||
rmt_strip->base.set_pixel = led_strip_rmt_set_pixel;
|
||||
rmt_strip->base.set_pixel_rgbw = led_strip_rmt_set_pixel_rgbw;
|
||||
rmt_strip->base.refresh = led_strip_rmt_refresh;
|
||||
rmt_strip->base.refresh_async = led_strip_rmt_refresh_async;
|
||||
rmt_strip->base.refresh_wait_done = led_strip_rmt_wait_for_done;
|
||||
rmt_strip->base.clear = led_strip_rmt_clear;
|
||||
rmt_strip->base.del = led_strip_rmt_del;
|
||||
|
||||
*ret_strip = &rmt_strip->base;
|
||||
return ESP_OK;
|
||||
err:
|
||||
if (rmt_strip) {
|
||||
if (rmt_strip->rmt_chan) {
|
||||
rmt_del_channel(rmt_strip->rmt_chan);
|
||||
}
|
||||
if (rmt_strip->strip_encoder) {
|
||||
rmt_del_encoder(rmt_strip->strip_encoder);
|
||||
}
|
||||
free(rmt_strip);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // FASTLED_RMT5
|
||||
|
||||
#endif // ESP32
|
||||
195
FastLED/src/third_party/espressif/led_strip/src/led_strip_rmt_encoder.c
vendored
Normal file
195
FastLED/src/third_party/espressif/led_strip/src/led_strip_rmt_encoder.c
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
#include "enabled.h"
|
||||
|
||||
#if FASTLED_RMT5
|
||||
|
||||
#include "fl/unused.h"
|
||||
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "led_strip_rmt_encoder.h"
|
||||
|
||||
static const char *TAG = "led_rmt_encoder";
|
||||
|
||||
typedef struct {
|
||||
rmt_encoder_t base;
|
||||
rmt_encoder_t *bytes_encoder;
|
||||
rmt_encoder_t *copy_encoder;
|
||||
int state;
|
||||
rmt_symbol_word_t reset_code;
|
||||
} rmt_led_strip_encoder_t;
|
||||
|
||||
static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
|
||||
{
|
||||
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
|
||||
rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
|
||||
rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
|
||||
rmt_encode_state_t session_state = 0;
|
||||
rmt_encode_state_t state = 0;
|
||||
size_t encoded_symbols = 0;
|
||||
switch (led_encoder->state) {
|
||||
case 0: // send RGB data
|
||||
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
|
||||
if (session_state & RMT_ENCODING_COMPLETE) {
|
||||
led_encoder->state = 1; // switch to next state when current encoding session finished
|
||||
}
|
||||
if (session_state & RMT_ENCODING_MEM_FULL) {
|
||||
state |= RMT_ENCODING_MEM_FULL;
|
||||
goto out; // yield if there's no free space for encoding artifacts
|
||||
}
|
||||
// fall-through
|
||||
case 1: // send reset code
|
||||
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
|
||||
sizeof(led_encoder->reset_code), &session_state);
|
||||
if (session_state & RMT_ENCODING_COMPLETE) {
|
||||
led_encoder->state = 0; // back to the initial encoding session
|
||||
state |= RMT_ENCODING_COMPLETE;
|
||||
}
|
||||
if (session_state & RMT_ENCODING_MEM_FULL) {
|
||||
state |= RMT_ENCODING_MEM_FULL;
|
||||
goto out; // yield if there's no free space for encoding artifacts
|
||||
}
|
||||
}
|
||||
out:
|
||||
*ret_state = state;
|
||||
return encoded_symbols;
|
||||
}
|
||||
|
||||
static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
|
||||
{
|
||||
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
|
||||
rmt_del_encoder(led_encoder->bytes_encoder);
|
||||
rmt_del_encoder(led_encoder->copy_encoder);
|
||||
free(led_encoder);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
|
||||
{
|
||||
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
|
||||
rmt_encoder_reset(led_encoder->bytes_encoder);
|
||||
rmt_encoder_reset(led_encoder->copy_encoder);
|
||||
led_encoder->state = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
FASTLED_UNUSED(ret);
|
||||
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_GOTO_ON_FALSE(config->led_model < LED_MODEL_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led model");
|
||||
// Create a temporary config with the same base values
|
||||
led_strip_encoder_config_t timing_config = *config;
|
||||
const bool has_encoder_timings = config->timings.t0h || config->timings.t0l || config->timings.t1h || config->timings.t1l || config->timings.reset;
|
||||
|
||||
if (!has_encoder_timings) {
|
||||
// Set the timing values based on LED model
|
||||
if (config->led_model == LED_MODEL_SK6812) {
|
||||
timing_config.timings = (led_strip_encoder_timings_t) {
|
||||
.t0h = 300, // 0.3us = 300ns
|
||||
.t0l = 900, // 0.9us = 900ns
|
||||
.t1h = 600, // 0.6us = 600ns
|
||||
.t1l = 600, // 0.6us = 600ns
|
||||
.reset = 280 // 280us
|
||||
};
|
||||
} else if (config->led_model == LED_MODEL_WS2812) {
|
||||
timing_config.timings = (led_strip_encoder_timings_t) {
|
||||
.t0h = 300, // 0.3us = 300ns
|
||||
.t0l = 900, // 0.9us = 900ns
|
||||
.t1h = 900, // 0.9us = 900ns
|
||||
.t1l = 300, // 0.3us = 300ns
|
||||
.reset = 280 // 280us
|
||||
};
|
||||
} else if (config->led_model == LED_MODEL_WS2811) {
|
||||
timing_config.timings = (led_strip_encoder_timings_t) {
|
||||
.t0h = 500, // 0.5us = 500ns
|
||||
.t0l = 2000, // 2.0us = 2000ns
|
||||
.t1h = 1200, // 1.2us = 1200ns
|
||||
.t1l = 1300, // 1.3us = 1300ns
|
||||
.reset = 50 // 50us
|
||||
};
|
||||
} else {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Delegate to the timing-based encoder creation
|
||||
return rmt_new_led_strip_encoder_with_timings(&timing_config, ret_encoder);
|
||||
|
||||
err:
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t rmt_new_led_strip_encoder_with_timings(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
FASTLED_UNUSED(ret);
|
||||
rmt_led_strip_encoder_t *led_encoder = NULL;
|
||||
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
|
||||
led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t));
|
||||
ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
|
||||
led_encoder->base.encode = rmt_encode_led_strip;
|
||||
led_encoder->base.del = rmt_del_led_strip_encoder;
|
||||
led_encoder->base.reset = rmt_led_strip_encoder_reset;
|
||||
|
||||
// Convert nanosecond timings to ticks using resolution
|
||||
rmt_bytes_encoder_config_t bytes_encoder_config = {
|
||||
.bit0 = {
|
||||
.level0 = 1,
|
||||
.duration0 = (float)config->timings.t0h * config->resolution / 1000000000, // Convert ns to ticks
|
||||
.level1 = 0,
|
||||
.duration1 = (float)config->timings.t0l * config->resolution / 1000000000,
|
||||
},
|
||||
.bit1 = {
|
||||
.level0 = 1,
|
||||
.duration0 = (float)config->timings.t1h * config->resolution / 1000000000,
|
||||
.level1 = 0,
|
||||
.duration1 = (float)config->timings.t1l * config->resolution / 1000000000,
|
||||
},
|
||||
.flags.msb_first = 1
|
||||
};
|
||||
|
||||
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
|
||||
rmt_copy_encoder_config_t copy_encoder_config = {};
|
||||
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
|
||||
|
||||
// Convert reset time from microseconds to ticks
|
||||
uint32_t reset_ticks = config->resolution / 1000000 * config->timings.reset / 2;
|
||||
led_encoder->reset_code = (rmt_symbol_word_t) {
|
||||
.level0 = 0,
|
||||
.duration0 = reset_ticks,
|
||||
.level1 = 0,
|
||||
.duration1 = reset_ticks,
|
||||
};
|
||||
|
||||
*ret_encoder = &led_encoder->base;
|
||||
return ESP_OK;
|
||||
err:
|
||||
if (led_encoder) {
|
||||
if (led_encoder->bytes_encoder) {
|
||||
rmt_del_encoder(led_encoder->bytes_encoder);
|
||||
}
|
||||
if (led_encoder->copy_encoder) {
|
||||
rmt_del_encoder(led_encoder->copy_encoder);
|
||||
}
|
||||
free(led_encoder);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif // FASTLED_RMT5
|
||||
|
||||
#endif // ESP32
|
||||
52
FastLED/src/third_party/espressif/led_strip/src/led_strip_rmt_encoder.h
vendored
Normal file
52
FastLED/src/third_party/espressif/led_strip/src/led_strip_rmt_encoder.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "driver/rmt_encoder.h"
|
||||
#include "led_strip_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type of led strip encoder configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t resolution; /*!< Encoder resolution, in Hz */
|
||||
led_model_t led_model; /*!< LED model */
|
||||
led_strip_encoder_timings_t timings; /*!< Encoder timings */
|
||||
} led_strip_encoder_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create RMT encoder for encoding LED strip pixels into RMT symbols
|
||||
*
|
||||
* @param[in] config Encoder configuration
|
||||
* @param[out] ret_encoder Returned encoder handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG for any invalid arguments
|
||||
* - ESP_ERR_NO_MEM out of memory when creating led strip encoder
|
||||
* - ESP_OK if creating encoder successfully
|
||||
*/
|
||||
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
|
||||
|
||||
/**
|
||||
* @brief Create RMT encoder for encoding LED strip pixels into RMT symbols with custom timings
|
||||
*
|
||||
* @param[in] config Encoder configuration including custom timings
|
||||
* @param[out] ret_encoder Returned encoder handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG for any invalid arguments
|
||||
* - ESP_ERR_NO_MEM out of memory when creating led strip encoder
|
||||
* - ESP_OK if creating encoder successfully
|
||||
*/
|
||||
esp_err_t rmt_new_led_strip_encoder_with_timings(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
47
FastLED/src/third_party/espressif/led_strip/src/led_strip_spi.h
vendored
Normal file
47
FastLED/src/third_party/espressif/led_strip/src/led_strip_spi.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "led_strip_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LED Strip SPI specific configuration
|
||||
*/
|
||||
typedef struct {
|
||||
spi_clock_source_t clk_src; /*!< SPI clock source */
|
||||
spi_host_device_t spi_bus; /*!< SPI bus ID. Which buses are available depends on the specific chip */
|
||||
struct {
|
||||
uint32_t with_dma: 1; /*!< Use DMA to transmit data */
|
||||
} flags; /*!< Extra driver flags */
|
||||
} led_strip_spi_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create LED strip based on SPI MOSI channel
|
||||
*
|
||||
* @note Although only the MOSI line is used for generating the signal, the whole SPI bus can't be used for other purposes.
|
||||
*
|
||||
* @param led_config LED strip configuration
|
||||
* @param spi_config SPI specific configuration
|
||||
* @param ret_strip Returned LED strip handle
|
||||
* @return
|
||||
* - ESP_OK: create LED strip handle successfully
|
||||
* - ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument
|
||||
* - ESP_ERR_NOT_SUPPORTED: create LED strip handle failed because of unsupported configuration
|
||||
* - ESP_ERR_NO_MEM: create LED strip handle failed because of out of memory
|
||||
* - ESP_FAIL: create LED strip handle failed because some other error
|
||||
*/
|
||||
esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const led_strip_spi_config_t *spi_config, led_strip_handle_t *ret_strip);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
261
FastLED/src/third_party/espressif/led_strip/src/led_strip_spi_dev.c
vendored
Normal file
261
FastLED/src/third_party/espressif/led_strip/src/led_strip_spi_dev.c
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
#ifdef ESP32
|
||||
|
||||
#include "enabled.h"
|
||||
|
||||
#if FASTLED_ESP32_HAS_CLOCKLESS_SPI
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "led_strip.h"
|
||||
#include "led_strip_interface.h"
|
||||
#include "fl/unused.h"
|
||||
|
||||
#define LED_STRIP_SPI_DEFAULT_RESOLUTION (2.5 * 1000 * 1000) // 2.5MHz resolution
|
||||
#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4
|
||||
|
||||
#define SPI_BYTES_PER_COLOR_BYTE 3
|
||||
#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8)
|
||||
|
||||
static const char *TAG = "led_strip_spi";
|
||||
|
||||
typedef struct {
|
||||
led_strip_t base;
|
||||
spi_host_device_t spi_host;
|
||||
spi_device_handle_t spi_device;
|
||||
uint32_t strip_len;
|
||||
uint8_t bytes_per_pixel;
|
||||
led_color_component_format_t component_fmt;
|
||||
uint8_t pixel_buf[];
|
||||
} led_strip_spi_obj;
|
||||
|
||||
// please make sure to zero-initialize the buf before calling this function
|
||||
static void __led_strip_spi_bit(uint8_t data, uint8_t *buf)
|
||||
{
|
||||
// Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110
|
||||
// So a color byte occupies 3 bytes of SPI.
|
||||
*(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2);
|
||||
*(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5);
|
||||
*(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00;
|
||||
*(buf + 1) |= BIT(0);
|
||||
*(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3);
|
||||
*(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6);
|
||||
*(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1);
|
||||
*(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4);
|
||||
*(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7);
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_spi_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
|
||||
{
|
||||
led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
|
||||
ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
|
||||
// 3 pixels take 72bits(9bytes)
|
||||
uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
|
||||
uint8_t *pixel_buf = spi_strip->pixel_buf;
|
||||
led_color_component_format_t component_fmt = spi_strip->component_fmt;
|
||||
memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
|
||||
|
||||
__led_strip_spi_bit(red, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.r_pos]);
|
||||
__led_strip_spi_bit(green, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.g_pos]);
|
||||
__led_strip_spi_bit(blue, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.b_pos]);
|
||||
if (component_fmt.format.num_components > 3) {
|
||||
__led_strip_spi_bit(0, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.w_pos]);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_spi_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
|
||||
{
|
||||
led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
|
||||
led_color_component_format_t component_fmt = spi_strip->component_fmt;
|
||||
ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
|
||||
ESP_RETURN_ON_FALSE(component_fmt.format.num_components == 4, ESP_ERR_INVALID_ARG, TAG, "led doesn't have 4 components");
|
||||
|
||||
// LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes)
|
||||
uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
|
||||
uint8_t *pixel_buf = spi_strip->pixel_buf;
|
||||
memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
|
||||
|
||||
__led_strip_spi_bit(red, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.r_pos]);
|
||||
__led_strip_spi_bit(green, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.g_pos]);
|
||||
__led_strip_spi_bit(blue, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.b_pos]);
|
||||
__led_strip_spi_bit(white, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.w_pos]);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t spi_led_strip_refresh_async(led_strip_t *strip)
|
||||
{
|
||||
led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
|
||||
spi_transaction_t tx_conf;
|
||||
memset(&tx_conf, 0, sizeof(tx_conf));
|
||||
|
||||
tx_conf.length = spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE;
|
||||
tx_conf.tx_buffer = spi_strip->pixel_buf;
|
||||
tx_conf.rx_buffer = NULL;
|
||||
spi_device_queue_trans(spi_strip->spi_device, &tx_conf, portMAX_DELAY);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t spi_led_strip_refresh_wait_done(led_strip_t *strip)
|
||||
{
|
||||
led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
|
||||
spi_transaction_t* tx_conf = 0;
|
||||
spi_device_get_trans_result(spi_strip->spi_device, &tx_conf, portMAX_DELAY);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_spi_refresh(led_strip_t *strip)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(spi_led_strip_refresh_async(strip), TAG, "refresh async failed");
|
||||
ESP_RETURN_ON_ERROR(spi_led_strip_refresh_wait_done(strip), TAG, "wait for done failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t led_strip_spi_clear(led_strip_t *strip)
|
||||
{
|
||||
led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
|
||||
//Write zero to turn off all leds
|
||||
memset(spi_strip->pixel_buf, 0, spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
|
||||
uint8_t *buf = spi_strip->pixel_buf;
|
||||
for (int index = 0; index < spi_strip->strip_len * spi_strip->bytes_per_pixel; index++) {
|
||||
__led_strip_spi_bit(0, buf);
|
||||
buf += SPI_BYTES_PER_COLOR_BYTE;
|
||||
}
|
||||
|
||||
return led_strip_spi_refresh(strip);
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_spi_del(led_strip_t *strip)
|
||||
{
|
||||
led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
|
||||
|
||||
ESP_RETURN_ON_ERROR(spi_bus_remove_device(spi_strip->spi_device), TAG, "delete spi device failed");
|
||||
ESP_RETURN_ON_ERROR(spi_bus_free(spi_strip->spi_host), TAG, "free spi bus failed");
|
||||
|
||||
free(spi_strip);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const led_strip_spi_config_t *spi_config, led_strip_handle_t *ret_strip)
|
||||
{
|
||||
led_strip_spi_obj *spi_strip = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
FASTLED_UNUSED(ret);
|
||||
ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
led_color_component_format_t component_fmt = led_config->color_component_format;
|
||||
// If R/G/B order is not specified, set default GRB order as fallback
|
||||
if (component_fmt.format_id == 0) {
|
||||
component_fmt = LED_STRIP_COLOR_COMPONENT_FMT_GRB;
|
||||
}
|
||||
// check the validation of the color component format
|
||||
uint8_t mask = 0;
|
||||
if (component_fmt.format.num_components == 3) {
|
||||
mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos);
|
||||
// Check for invalid values
|
||||
ESP_RETURN_ON_FALSE(mask == 0x07, ESP_ERR_INVALID_ARG, TAG, "invalid order argument");
|
||||
} else if (component_fmt.format.num_components == 4) {
|
||||
mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos) | BIT(component_fmt.format.w_pos);
|
||||
// Check for invalid values
|
||||
ESP_RETURN_ON_FALSE(mask == 0x0F, ESP_ERR_INVALID_ARG, TAG, "invalid order argument");
|
||||
} else {
|
||||
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "invalid number of color components: %d", component_fmt.format.num_components);
|
||||
}
|
||||
// TODO: we assume each color component is 8 bits, may need to support other configurations in the future, e.g. 10bits per color component?
|
||||
uint8_t bytes_per_pixel = component_fmt.format.num_components;
|
||||
uint32_t mem_caps = MALLOC_CAP_DEFAULT;
|
||||
if (spi_config->flags.with_dma) {
|
||||
// DMA buffer must be placed in internal SRAM
|
||||
mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
|
||||
}
|
||||
spi_strip = heap_caps_calloc(1, sizeof(led_strip_spi_obj) + led_config->max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, mem_caps);
|
||||
|
||||
ESP_GOTO_ON_FALSE(spi_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for spi strip");
|
||||
|
||||
spi_strip->spi_host = spi_config->spi_bus;
|
||||
// for backward compatibility, if the user does not set the clk_src, use the default value
|
||||
spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT;
|
||||
if (spi_config->clk_src) {
|
||||
clk_src = spi_config->clk_src;
|
||||
}
|
||||
|
||||
spi_bus_config_t spi_bus_cfg = {
|
||||
.mosi_io_num = led_config->strip_gpio_num,
|
||||
//Only use MOSI to generate the signal, set -1 when other pins are not used.
|
||||
.miso_io_num = -1,
|
||||
.sclk_io_num = -1,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = led_config->max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(spi_bus_initialize(spi_strip->spi_host, &spi_bus_cfg, spi_config->flags.with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED), err, TAG, "create SPI bus failed");
|
||||
|
||||
if (led_config->flags.invert_out == true) {
|
||||
esp_rom_gpio_connect_out_signal(led_config->strip_gpio_num, spi_periph_signal[spi_strip->spi_host].spid_out, true, false);
|
||||
}
|
||||
|
||||
spi_device_interface_config_t spi_dev_cfg = {
|
||||
.clock_source = clk_src,
|
||||
.command_bits = 0,
|
||||
.address_bits = 0,
|
||||
.dummy_bits = 0,
|
||||
.clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION,
|
||||
.mode = 0,
|
||||
//set -1 when CS is not used
|
||||
.spics_io_num = -1,
|
||||
.queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE,
|
||||
};
|
||||
|
||||
ESP_GOTO_ON_ERROR(spi_bus_add_device(spi_strip->spi_host, &spi_dev_cfg, &spi_strip->spi_device), err, TAG, "Failed to add spi device");
|
||||
//ensure the reset time is enough
|
||||
esp_rom_delay_us(10);
|
||||
int clock_resolution_khz = 0;
|
||||
spi_device_get_actual_freq(spi_strip->spi_device, &clock_resolution_khz);
|
||||
// TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution
|
||||
// But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION
|
||||
// clock_resolution between 2.2MHz to 2.8MHz is supported
|
||||
ESP_GOTO_ON_FALSE((clock_resolution_khz < LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000 + 300) && (clock_resolution_khz > LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000 - 300), ESP_ERR_NOT_SUPPORTED, err,
|
||||
TAG, "unsupported clock resolution:%dKHz", clock_resolution_khz);
|
||||
|
||||
spi_strip->component_fmt = component_fmt;
|
||||
spi_strip->bytes_per_pixel = bytes_per_pixel;
|
||||
spi_strip->strip_len = led_config->max_leds;
|
||||
spi_strip->base.set_pixel = led_strip_spi_set_pixel;
|
||||
spi_strip->base.set_pixel_rgbw = led_strip_spi_set_pixel_rgbw;
|
||||
spi_strip->base.refresh = led_strip_spi_refresh;
|
||||
spi_strip->base.refresh_async = spi_led_strip_refresh_async;
|
||||
spi_strip->base.refresh_wait_done = spi_led_strip_refresh_wait_done;
|
||||
spi_strip->base.clear = led_strip_spi_clear;
|
||||
spi_strip->base.del = led_strip_spi_del;
|
||||
|
||||
*ret_strip = &spi_strip->base;
|
||||
return ESP_OK;
|
||||
err:
|
||||
if (spi_strip) {
|
||||
if (spi_strip->spi_device) {
|
||||
spi_bus_remove_device(spi_strip->spi_device);
|
||||
}
|
||||
if (spi_strip->spi_host) {
|
||||
spi_bus_free(spi_strip->spi_host);
|
||||
}
|
||||
free(spi_strip);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif // FASTLED_ESP_HAS_CLOCKLESS_SPI
|
||||
|
||||
#endif // ESP32
|
||||
84
FastLED/src/third_party/espressif/led_strip/src/led_strip_types.h
vendored
Normal file
84
FastLED/src/third_party/espressif/led_strip/src/led_strip_types.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of LED strip handle
|
||||
*/
|
||||
typedef struct led_strip_t *led_strip_handle_t;
|
||||
|
||||
/**
|
||||
* @brief LED strip model
|
||||
* @note Different led model may have different timing parameters, so we need to distinguish them.
|
||||
*/
|
||||
typedef enum {
|
||||
LED_MODEL_WS2812, /*!< LED strip model: WS2812 */
|
||||
LED_MODEL_SK6812, /*!< LED strip model: SK6812 */
|
||||
LED_MODEL_WS2811, /*!< LED strip model: WS2811 */
|
||||
LED_MODEL_INVALID /*!< Invalid LED strip model */
|
||||
} led_model_t;
|
||||
|
||||
/**
|
||||
* @brief LED strip encoder timings.
|
||||
* @note The timings are in nanoseconds. A zero filled structure will represent no timings given.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t t0h; /*!< High time for 0 bit, */
|
||||
uint32_t t1h; /*!< High time for 1 bit */
|
||||
uint32_t t0l; /*!< Low time for 0 bit */
|
||||
uint32_t t1l; /*!< Low time for 1 bit */
|
||||
uint32_t reset; /*!< Reset time, microseconds */
|
||||
} led_strip_encoder_timings_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief LED color component format
|
||||
* @note The format is used to specify the order of color components in each pixel, also the number of color components.
|
||||
*/
|
||||
typedef union {
|
||||
struct format_layout {
|
||||
uint32_t r_pos: 2; /*!< Position of the red channel in the color order: 0~3 */
|
||||
uint32_t g_pos: 2; /*!< Position of the green channel in the color order: 0~3 */
|
||||
uint32_t b_pos: 2; /*!< Position of the blue channel in the color order: 0~3 */
|
||||
uint32_t w_pos: 2; /*!< Position of the white channel in the color order: 0~3 */
|
||||
uint32_t reserved: 21; /*!< Reserved */
|
||||
uint32_t num_components: 3; /*!< Number of color components per pixel: 3 or 4. If set to 0, it will fallback to 3 */
|
||||
} format; /*!< Format layout */
|
||||
uint32_t format_id; /*!< Format ID */
|
||||
} led_color_component_format_t;
|
||||
|
||||
/// Helper macros to set the color component format
|
||||
#define LED_STRIP_COLOR_COMPONENT_FMT_GRB (led_color_component_format_t){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 3}}
|
||||
#define LED_STRIP_COLOR_COMPONENT_FMT_GRBW (led_color_component_format_t){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 4}}
|
||||
#define LED_STRIP_COLOR_COMPONENT_FMT_RGB (led_color_component_format_t){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 3}}
|
||||
#define LED_STRIP_COLOR_COMPONENT_FMT_RGBW (led_color_component_format_t){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 4}}
|
||||
|
||||
/**
|
||||
* @brief LED Strip common configurations
|
||||
* The common configurations are not specific to any backend peripheral.
|
||||
*/
|
||||
typedef struct {
|
||||
int strip_gpio_num; /*!< GPIO number that used by LED strip */
|
||||
uint32_t max_leds; /*!< Maximum number of LEDs that can be controlled in a single strip */
|
||||
led_model_t led_model; /*!< Specifies the LED strip model (e.g., WS2812, SK6812) */
|
||||
led_color_component_format_t color_component_format; /*!< Specifies the order of color components in each pixel.
|
||||
Use helper macros like `LED_STRIP_COLOR_COMPONENT_FMT_GRB` to set the format */
|
||||
/*!< LED strip extra driver flags */
|
||||
struct led_strip_extra_flags {
|
||||
uint32_t invert_out: 1; /*!< Invert output signal */
|
||||
} flags; /*!< Extra driver flags */
|
||||
led_strip_encoder_timings_t timings; /*!< Encoder timings */
|
||||
} led_strip_config_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
6
FastLED/src/third_party/object_fled/readme
vendored
Normal file
6
FastLED/src/third_party/object_fled/readme
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
https://github.com/KurtMF/ObjectFLED
|
||||
|
||||
Version 1.10: https://github.com/KurtMF/ObjectFLED/releases/tag/v1.1.0
|
||||
downloaded date: 2025-Jan. 6th
|
||||
|
||||
Light modifications have been made to this library.
|
||||
206
FastLED/src/third_party/object_fled/src/ObjectFLED.h
vendored
Normal file
206
FastLED/src/third_party/object_fled/src/ObjectFLED.h
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/* ObjectFLED - Teensy 4.x DMA to all pins for independent control of large and
|
||||
multiple LED display objects
|
||||
|
||||
Copyright (c) 2024 Kurt Funderburg
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
OctoWS2811 library code was well-studied and substantial portions of it used
|
||||
to implement high-speed, non-blocking DMA for LED signal output in this library.
|
||||
See ObjectFLED.cpp for a summary of changes made to the original OctoWS2811.
|
||||
|
||||
OctoWS2811 - High Performance WS2811 LED Display Library
|
||||
Copyright (c) 2013 Paul Stoffregen, PJRC.COM, LLC
|
||||
http://www.pjrc.com/teensy/td_libs_OctoWS2811.html
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __IMXRT1062__
|
||||
#error "Sorry, ObjectFLED only works on Teensy 4.x boards."
|
||||
#endif
|
||||
#if TEENSYDUINO < 121
|
||||
#error "Teensyduino version 1.21 or later is required to compile this library."
|
||||
#endif
|
||||
#ifndef ObjectFLED_h
|
||||
#define ObjectFLED_h
|
||||
#include <WProgram.h>
|
||||
#include "DMAChannel.h"
|
||||
|
||||
//Experimentally found DSE=3, SPEED=0 gave best LED overclocking
|
||||
//boot defaults DSE=6, SPEED=2.
|
||||
#define OUTPUT_PAD_DSE 3 //Legal values 0-7
|
||||
#define OUTPUT_PAD_SPEED 0 //Legal values 0-3
|
||||
|
||||
// Ordinary RGB data is converted to GPIO bitmasks on-the-fly using
|
||||
// a transmit buffer sized for 2 DMA transfers. The larger this setting,
|
||||
// the more interrupt latency OctoWS2811 can tolerate, but the transmit
|
||||
// buffer grows in size. For good performance, the buffer should be kept
|
||||
// smaller than the half the Cortex-M7 data cache.
|
||||
//bitdata[B_P_D * 64] buffer holds data (10KB) for 80 LED bytes: 4DW * 8b = 32DW/LEDB = 96DW/LED
|
||||
//framebuffer_index = B_P_D * 2 = pointer to next block for transfer (80 LEDB / bitdata buffer)
|
||||
#define BYTES_PER_DMA 20 //= number of pairs of LEDB (40=80B) bitmasks in bitdata.
|
||||
|
||||
#define CORDER_RGB 0 //* WS2811, YF923
|
||||
#define CORDER_RBG 1
|
||||
#define CORDER_GRB 2 //* WS2811B, Most LED strips are wired this way
|
||||
#define CORDER_GBR 3 //*
|
||||
#define CORDER_BRG 4 //* Adafruit Product ID: 5984 As of November 5, 2024 - this strand has different 'internal' color ordering. It's now BRG not RGB,
|
||||
#define CORDER_BGR 5 //* Adafruit Dotstar LEDs SK9822 uses this CO but they use inverted start/stop bits
|
||||
#define CORDER_RGBW 6 //* Popular
|
||||
#define CORDER_RBGW 7
|
||||
#define CORDER_GRBW 8
|
||||
#define CORDER_GBRW 9
|
||||
#define CORDER_BRGW 10
|
||||
#define CORDER_BGRW 11 // Adafruit Dotstar LEDs SK9822 uses this CO but they use inverted start/stop bits
|
||||
#define CORDER_WRGB 12
|
||||
#define CORDER_WRBG 13
|
||||
#define CORDER_WGRB 14
|
||||
#define CORDER_WGBR 15
|
||||
#define CORDER_WBRG 16
|
||||
#define CORDER_WBGR 17
|
||||
#define CORDER_RWGB 18
|
||||
#define CORDER_RWBG 19
|
||||
#define CORDER_GWRB 20
|
||||
#define CORDER_GWBR 21
|
||||
#define CORDER_BWRG 22
|
||||
#define CORDER_BWGR 23
|
||||
#define CORDER_RGWB 24
|
||||
#define CORDER_RBWG 25
|
||||
#define CORDER_GRWB 26
|
||||
#define CORDER_GBWR 27
|
||||
#define CORDER_BRWG 28
|
||||
#define CORDER_BGWR 29
|
||||
|
||||
namespace fl {
|
||||
|
||||
|
||||
//Usage: ObjectFLED myCube ( Num_LEDs, *drawBuffer, LED_type, numPins, *pinList, serpentineNumber )
|
||||
class ObjectFLED {
|
||||
public:
|
||||
// Usage: ObjectFLED myCube ( Num_LEDs, *drawBuffer, LED_type, numPins, *pinList, serpentineNumber )
|
||||
// Example:
|
||||
// byte pinList[NUM_CHANNELS] = {1, 8, 14, 17, 24, 29, 20, 0, 15, 16, 18, 19, 21, 22, 23, 25};
|
||||
// byte pinListBlank[7] = {1, 8, 14, 17, 24, 29, 20};
|
||||
// CRGB testCube[NUM_PLANES][NUM_ROWS][PIX_PER_ROW];
|
||||
// CRGB blankLeds[7][8][8];
|
||||
// ObjectFLED leds(PIX_PER_ROW * NUM_ROWS * NUM_PLANES, testCube, CORDER_RGB, NUM_CHANNELS, pinList);
|
||||
// void setup() {
|
||||
// leds.begin(1.6, 72); //1.6 ocervlock factor, 72uS LED latch delay
|
||||
// leds.setBrightness(64);
|
||||
// }
|
||||
// void loop() {
|
||||
// leds.show();
|
||||
// delay(100);
|
||||
// }
|
||||
ObjectFLED(uint16_t numLEDs, void* drawBuf, uint8_t config, uint8_t numPins, const uint8_t* pinList, \
|
||||
uint8_t serpentine = 0);
|
||||
|
||||
~ObjectFLED() {
|
||||
// Wait for prior xmission to end, don't need to wait for latch time before deleting buffer
|
||||
while (micros() - update_begin_micros < numbytes * 8 * TH_TL / OC_FACTOR / 1000 + 5);
|
||||
delete frameBuffer;
|
||||
}
|
||||
|
||||
//begin() - Use defalut LED timing: 1.0 OC Factor, 1250 nS CLK (=800 KHz), 300 nS T0H, 750 nS T1H, 300 uS LED Latch Delay.
|
||||
void begin(void);
|
||||
|
||||
//begin(LED_Latch_Delay_uS) - sets the LED Latch Delay.
|
||||
void begin(uint16_t);
|
||||
|
||||
//begin(LED_Overclock_Factor, LED_Latch_Delay_uS) - divides default 1250 nS LED CLK (=800 KHz),
|
||||
// 300 nS T0H, 750 nS T1H; and optionally sets the LED Latch Delay.
|
||||
void begin(double, uint16_t = 300);
|
||||
|
||||
//begin(LED_CLK_nS, LED_T0H_nS, LED_T1H_nS, LED_Latch_Delay_uS) - specifies full LED waveform timing.
|
||||
void begin(uint16_t, uint16_t, uint16_t, uint16_t = 300);
|
||||
|
||||
void show(void);
|
||||
void waitForDmaToFinish() {
|
||||
while (!dma3.complete()) { // wait for dma to complete before reset/re-use
|
||||
delayMicroseconds(10);
|
||||
}
|
||||
}
|
||||
|
||||
int busy(void);
|
||||
|
||||
//Brightness values 0-255
|
||||
void setBrightness(uint8_t);
|
||||
|
||||
//Color Balance is 3-byte number in RGB order. Each byte is a brightness value for that color.
|
||||
void setBalance(uint32_t);
|
||||
|
||||
uint8_t getBrightness() { return brightness; }
|
||||
|
||||
uint32_t getBalance() { return colorBalance; }
|
||||
|
||||
private:
|
||||
static void isr(void);
|
||||
|
||||
void genFrameBuffer(uint32_t);
|
||||
|
||||
static uint8_t* frameBuffer; //isr()
|
||||
static uint32_t numbytes; //isr()
|
||||
static uint8_t numpins; //isr()
|
||||
static uint8_t pin_bitnum[NUM_DIGITAL_PINS]; //isr()
|
||||
static uint8_t pin_offset[NUM_DIGITAL_PINS]; //isr()
|
||||
DMAMEM static uint32_t bitdata[BYTES_PER_DMA * 64] __attribute__((used, aligned(32))); //isr()
|
||||
DMAMEM static uint32_t bitmask[4] __attribute__((used, aligned(32)));
|
||||
static DMAChannel dma1, dma2, dma3;
|
||||
static DMASetting dma2next;
|
||||
|
||||
uint32_t update_begin_micros = 0;
|
||||
uint8_t brightness = 255;
|
||||
uint32_t colorBalance = 0xFFFFFF;
|
||||
uint32_t rLevel = 65025;
|
||||
uint32_t gLevel = 65025;
|
||||
uint32_t bLevel = 65025;
|
||||
void* drawBuffer;
|
||||
uint16_t stripLen;
|
||||
uint8_t params;
|
||||
uint8_t pinlist[NUM_DIGITAL_PINS];
|
||||
uint16_t comp1load[3];
|
||||
uint8_t serpNumber;
|
||||
float OC_FACTOR = 1.0; //used to reduce period of LED output
|
||||
uint16_t TH_TL = 1250; //nS- period of LED output
|
||||
uint16_t T0H = 300; //nS- duration of T0H
|
||||
uint16_t T1H = 750; //nS- duration of T1H
|
||||
uint16_t LATCH_DELAY = 300; //uS time to hold output low for LED latch.
|
||||
|
||||
//for show context switch
|
||||
uint32_t bitmaskLocal[4];
|
||||
uint8_t numpinsLocal;
|
||||
uint8_t* frameBufferLocal;
|
||||
uint32_t numbytesLocal;
|
||||
uint8_t pin_bitnumLocal[NUM_DIGITAL_PINS];
|
||||
uint8_t pin_offsetLocal[NUM_DIGITAL_PINS];
|
||||
}; // class ObjectFLED
|
||||
|
||||
|
||||
//fadeToColorBy(RGB_array, LED_count, Color, FadeAmount)
|
||||
//Fades an RGB array towards the background color by amount.
|
||||
void fadeToColorBy(void*, uint16_t, uint32_t, uint8_t);
|
||||
|
||||
|
||||
//drawSquare(RGB_Array, LED_Rows, LED_Cols, Y_Corner, X_Corner, square_Size)
|
||||
//Draws square in a 2D RGB array with lower left corner at (Y_Corner, X_Corner).
|
||||
//Safe to specify -Y, -X corner, safe to draw a box which partially fits on LED plane.
|
||||
void drawSquare(void*, uint16_t, uint16_t, int, int, uint32_t, uint32_t);
|
||||
|
||||
} // namespace fl
|
||||
|
||||
#endif
|
||||
656
FastLED/src/third_party/object_fled/src/OjectFLED.cpp
vendored
Normal file
656
FastLED/src/third_party/object_fled/src/OjectFLED.cpp
vendored
Normal file
@@ -0,0 +1,656 @@
|
||||
/* ObjectFLED - Teensy 4.x DMA to all pins for independent control of large and
|
||||
multiple LED display objects
|
||||
|
||||
Copyright (c) 2024 Kurt Funderburg
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
OctoWS2811 library code was well-studied and substantial portions of it used
|
||||
to implement high-speed, non-blocking DMA for LED signal output in this library.
|
||||
See below for a summary of changes made to the original OctoWS2811.
|
||||
|
||||
OctoWS2811 - High Performance WS2811 LED Display Library
|
||||
Copyright (c) 2013 Paul Stoffregen, PJRC.COM, LLC
|
||||
http://www.pjrc.com/teensy/td_libs_OctoWS2811.html
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
Teensy 4.0 pin - port assignments
|
||||
GPIO6List = { 0, 1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 } //12 top, 4 bottom
|
||||
GPIO7List = { 6, 7, 8, 9, 10, 11, 12, 13, 32 } //8 top, 1 bottom
|
||||
GPIO8List = { 28, 30, 31, 34, 35, 36, 37, 38, 39 } //0 top, 9 bottom
|
||||
GOIO9List = { 2, 3, 4, 5, 29, 33 } //4 top, 2 bottom
|
||||
Teensy 4.1 pin - port assignments
|
||||
GPIO6List = { 0, 1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 38, 39, 40, 41 } //20 top, 0 bottom
|
||||
GPIO7List = { 6, 7, 8, 9, 10, 11, 12, 13, 32, 34, 35, 36, 37 } //13 top, 0 bottom
|
||||
GPIO8List = { 28, 30, 31, 42, 43, 44, 45, 46, 47 } //3 top, 6 bottom
|
||||
GOIO9List = { 2, 3, 4, 5, 29, 33, 48, 49, 50, 51, 52, 53, 54 } //6 top, 7 bottom
|
||||
* 4 pin groups, 4 timer groups, !4 dma channel groups: only 1 DMA group (4 ch) maps to GPIO (DMAMUX
|
||||
* mapping) Also, only DMA ch0-3 have periodic mode for timer trigger (p77 manual). Separate objects
|
||||
* cannot DMA at once.
|
||||
*
|
||||
* CHANGES:
|
||||
* Moved some variables so class supports multiple instances with separate LED config params
|
||||
* Implemented context switching so multiple instances can show() independently
|
||||
* Re-parameterized TH_TL, T0H, T1H, OC_FACTOR; recalc time for latch at end of show()
|
||||
* Added genFrameBuffer() to implement RGB order, brightness, color balance, and serpentine
|
||||
* Added setBrightness(), setBalance()
|
||||
* FrameBuffer no longer passed in, constructor now creates buffer; destructor added
|
||||
* Added support for per-object setting of OC factor, TH+TL, T0H, T1H, and LATCH_DELAY in begin function
|
||||
* Set DSE=3, SPEED=0, SRE=0 on output pins per experiment & PJRC forum guidance
|
||||
* New default values for TH_TL, T0H, T1H, LATCH_DELAY to work with Audio lib and more LED types
|
||||
* Added wait for prior xmission to complete in destructor
|
||||
*/
|
||||
|
||||
#ifndef __IMXRT1062__
|
||||
// Do nothing for other platforms.
|
||||
#else
|
||||
#include "ObjectFLED.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
namespace fl {
|
||||
|
||||
volatile uint32_t framebuffer_index = 0; //isr()
|
||||
uint8_t* ObjectFLED::frameBuffer; //isr()
|
||||
uint32_t ObjectFLED::numbytes; //isr()
|
||||
uint8_t ObjectFLED::numpins; //isr()
|
||||
uint8_t ObjectFLED::pin_bitnum[NUM_DIGITAL_PINS]; //isr()
|
||||
uint8_t ObjectFLED::pin_offset[NUM_DIGITAL_PINS]; //isr()
|
||||
uint32_t ObjectFLED::bitdata[BYTES_PER_DMA * 64] __attribute__((used, aligned(32))); //isr()
|
||||
uint32_t ObjectFLED::bitmask[4] __attribute__((used, aligned(32)));
|
||||
|
||||
DMASetting ObjectFLED::dma2next;
|
||||
DMAChannel ObjectFLED::dma1;
|
||||
DMAChannel ObjectFLED::dma2;
|
||||
DMAChannel ObjectFLED::dma3;
|
||||
volatile bool dma_first;
|
||||
|
||||
|
||||
ObjectFLED::ObjectFLED(uint16_t numLEDs, void *drawBuf, uint8_t config, uint8_t numPins, \
|
||||
const uint8_t *pinList, uint8_t serpentine) {
|
||||
serpNumber = serpentine;
|
||||
drawBuffer = drawBuf;
|
||||
params = config;
|
||||
if (numPins > NUM_DIGITAL_PINS) numPins = NUM_DIGITAL_PINS;
|
||||
numpins = numPins; //static/isr
|
||||
stripLen = numLEDs / numpins;
|
||||
memcpy(pinlist, pinList, numpins);
|
||||
if ((params & 0x3F) < 6) {
|
||||
frameBuffer = new uint8_t[numLEDs * 3]; //static/isr
|
||||
numbytes = stripLen * 3; // RGB formats //static/isr
|
||||
}
|
||||
else {
|
||||
frameBuffer = new uint8_t[numLEDs * 4]; //static/isr
|
||||
numbytes = stripLen * 4; // RGBW formats //static/isr
|
||||
}
|
||||
|
||||
numpinsLocal = numPins;
|
||||
frameBufferLocal = frameBuffer;
|
||||
numbytesLocal = numbytes;
|
||||
} // ObjectFLED constructor
|
||||
|
||||
|
||||
extern "C" void xbar_connect(unsigned int input, unsigned int output); // in pwm.c
|
||||
static volatile uint32_t *standard_gpio_addr(volatile uint32_t *fastgpio) {
|
||||
return (volatile uint32_t *)((uint32_t)fastgpio - 0x01E48000);
|
||||
}
|
||||
|
||||
|
||||
void ObjectFLED::begin(uint16_t latchDelay) {
|
||||
LATCH_DELAY = latchDelay;
|
||||
begin();
|
||||
}
|
||||
|
||||
|
||||
void ObjectFLED::begin(double OCF, uint16_t latchDelay) {
|
||||
OC_FACTOR = (float)OCF;
|
||||
LATCH_DELAY = latchDelay;
|
||||
begin();
|
||||
}
|
||||
|
||||
|
||||
void ObjectFLED::begin(uint16_t period, uint16_t t0h, uint16_t t1h, uint16_t latchDelay) {
|
||||
TH_TL = period;
|
||||
T0H = t0h;
|
||||
T1H = t1h;
|
||||
LATCH_DELAY = latchDelay;
|
||||
begin();
|
||||
}
|
||||
|
||||
|
||||
// INPUT stripLen, frameBuffer, params, numPins, pinList
|
||||
// GPIOR bits set for pins[i] -> bitmask, pin_bitnum[i], pin_offset[i]
|
||||
// init timers, xbar to DMA, DMA bitdata -> GPIOR; clears frameBuffer (total LEDs * 3 bytes)
|
||||
void ObjectFLED::begin(void) {
|
||||
numpins = numpinsLocal; //needed to compute pin mask/offset & bitmask since static for isr
|
||||
// Set each pin's bitmask bit, store offset & bit# for pin
|
||||
memset(bitmask, 0, sizeof(bitmask));
|
||||
for (uint32_t i=0; i < numpins; i++) {
|
||||
uint8_t pin = pinlist[i];
|
||||
if (pin >= NUM_DIGITAL_PINS) continue; // ignore illegal pins
|
||||
uint8_t bit = digitalPinToBit(pin); // pin's bit index in word port DR
|
||||
// which GPIO R controls this pin: 0-3 map to GPIO6-9 then map to DMA compat GPIO1-4
|
||||
uint8_t offset = ((uint32_t)portOutputRegister(pin) - (uint32_t)&GPIO6_DR) >> 14;
|
||||
if (offset > 3) continue; //ignore unknown pins
|
||||
pin_bitnum[i] = bit; //static/isr
|
||||
pin_offset[i] = offset; //static/isr
|
||||
uint32_t mask = 1 << bit; //mask32 = bit set @position in GPIO DR
|
||||
bitmask[offset] |= mask; //bitmask32[0..3] = collective pin bit masks for each GPIO DR
|
||||
//bit7:6 SPEED; bit 5:3 DSE; bit0 SRE (default SPEED = 0b10; def. DSE = 0b110)
|
||||
*portControlRegister(pin) &= ~0xF9; //clear SPEED, DSE, SRE
|
||||
*portControlRegister(pin) |= ((OUTPUT_PAD_SPEED & 0x3) << 6) | \
|
||||
((OUTPUT_PAD_DSE & 0x7) << 3); //DSE = 0b011 for LED overclock
|
||||
//clear pin bit in IOMUX_GPR26 to map GPIO6-9 to GPIO1-4 for DMA
|
||||
*(&IOMUXC_GPR_GPR26 + offset) &= ~mask;
|
||||
*standard_gpio_addr(portModeRegister(pin)) |= mask; //GDIR? bit flag set output mode
|
||||
}
|
||||
//stash context for multi-show
|
||||
memcpy(bitmaskLocal, bitmask, 16);
|
||||
memcpy(pin_bitnumLocal, pin_bitnum, numpins);
|
||||
memcpy(pin_offsetLocal, pin_offset, numpins);
|
||||
|
||||
arm_dcache_flush_delete(bitmask, sizeof(bitmask)); //can't DMA from cached memory
|
||||
|
||||
// Set up 3 timers to create waveform timing events
|
||||
comp1load[0] = (uint16_t)((float)F_BUS_ACTUAL / 1000000000.0 * (float)TH_TL / OC_FACTOR );
|
||||
comp1load[1] = (uint16_t)((float)F_BUS_ACTUAL / 1000000000.0 * (float)T0H / OC_FACTOR );
|
||||
comp1load[2] = (uint16_t)((float)F_BUS_ACTUAL / 1000000000.0 * (float)T1H / (1.0 + ((OC_FACTOR - 1.0)/3)) );
|
||||
TMR4_ENBL &= ~7;
|
||||
TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE | TMR_SCTRL_MSTR;
|
||||
TMR4_CSCTRL0 = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_TCF1EN;
|
||||
TMR4_CNTR0 = 0;
|
||||
TMR4_LOAD0 = 0;
|
||||
TMR4_COMP10 = comp1load[0];
|
||||
TMR4_CMPLD10 = comp1load[0];
|
||||
TMR4_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(3);
|
||||
TMR4_SCTRL1 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
|
||||
TMR4_CNTR1 = 0;
|
||||
TMR4_LOAD1 = 0;
|
||||
TMR4_COMP11 = comp1load[1]; // T0H
|
||||
TMR4_CMPLD11 = comp1load[1];
|
||||
TMR4_CTRL1 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_COINIT | TMR_CTRL_OUTMODE(3);
|
||||
TMR4_SCTRL2 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
|
||||
TMR4_CNTR2 = 0;
|
||||
TMR4_LOAD2 = 0;
|
||||
TMR4_COMP12 = comp1load[2]; // T1H
|
||||
TMR4_CMPLD12 = comp1load[2];
|
||||
TMR4_CTRL2 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_COINIT | TMR_CTRL_OUTMODE(3);
|
||||
|
||||
// route the timer outputs through XBAR to edge trigger DMA request: only 4 mappings avail.
|
||||
CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
|
||||
xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_DMA_CH_MUX_REQ30);
|
||||
xbar_connect(XBARA1_IN_QTIMER4_TIMER1, XBARA1_OUT_DMA_CH_MUX_REQ31);
|
||||
xbar_connect(XBARA1_IN_QTIMER4_TIMER2, XBARA1_OUT_DMA_CH_MUX_REQ94);
|
||||
XBARA1_CTRL0 = XBARA_CTRL_STS1 | XBARA_CTRL_EDGE1(3) | XBARA_CTRL_DEN1 |
|
||||
XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
|
||||
XBARA1_CTRL1 = XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
|
||||
|
||||
// configure DMA channels
|
||||
dma1.begin();
|
||||
dma1.TCD->SADDR = bitmask; // source 4*32b GPIO pin mask
|
||||
dma1.TCD->SOFF = 8; // bytes offset added to SADDR after each transfer
|
||||
// SMOD(4) low bits of SADDR to update with adds of SOFF
|
||||
// SSIZE(3) code for 64 bit transfer size DSIZE(2) code for 32 bit transfer size
|
||||
dma1.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_SMOD(4) | DMA_TCD_ATTR_DSIZE(2);
|
||||
dma1.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE | // Dest minor loop offsetting enable
|
||||
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
|
||||
DMA_TCD_NBYTES_MLOFFYES_NBYTES(16); // #bytes to tansfer, offsetting enabled
|
||||
dma1.TCD->SLAST = 0; // add to SADDR after xfer
|
||||
dma1.TCD->DADDR = &GPIO1_DR_SET;
|
||||
dma1.TCD->DOFF = 16384; //&GPIO1_DR_SET + DOFF = next &GPIO2_DR_SET
|
||||
dma1.TCD->CITER_ELINKNO = numbytes * 8; // CITER outer loop count (linking disabled) = # LED bits to write
|
||||
dma1.TCD->DLASTSGA = -65536; // add to DADDR after xfer
|
||||
dma1.TCD->BITER_ELINKNO = numbytes * 8; // Beginning CITER (not decremented by transfer)
|
||||
dma1.TCD->CSR = DMA_TCD_CSR_DREQ; // channel ERQ field cleared when minor loop completed
|
||||
dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_0); // only 4 XBAR1 triggers (DMA MUX mapping)
|
||||
|
||||
dma2next.TCD->SADDR = bitdata; //uint32_t bitdata[BYTES_PER_DMA*64]
|
||||
dma2next.TCD->SOFF = 8;
|
||||
dma2next.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_DSIZE(2);
|
||||
dma2next.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
|
||||
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
|
||||
DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
|
||||
dma2next.TCD->SLAST = 0;
|
||||
dma2next.TCD->DADDR = &GPIO1_DR_CLEAR;
|
||||
dma2next.TCD->DOFF = 16384;
|
||||
dma2next.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
|
||||
dma2next.TCD->DLASTSGA = (int32_t)(dma2next.TCD);
|
||||
dma2next.TCD->BITER_ELINKNO = BYTES_PER_DMA * 8;
|
||||
dma2next.TCD->CSR = 0;
|
||||
|
||||
dma2.begin();
|
||||
dma2 = dma2next; // copies TCD
|
||||
dma2.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_1);
|
||||
dma2.attachInterrupt(isr);
|
||||
|
||||
dma3.begin();
|
||||
dma3.TCD->SADDR = bitmask;
|
||||
dma3.TCD->SOFF = 8;
|
||||
dma3.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_SMOD(4) | DMA_TCD_ATTR_DSIZE(2);
|
||||
dma3.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
|
||||
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
|
||||
DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
|
||||
dma3.TCD->SLAST = 0;
|
||||
dma3.TCD->DADDR = &GPIO1_DR_CLEAR;
|
||||
dma3.TCD->DOFF = 16384;
|
||||
dma3.TCD->CITER_ELINKNO = numbytes * 8;
|
||||
dma3.TCD->DLASTSGA = -65536;
|
||||
dma3.TCD->BITER_ELINKNO = numbytes * 8;
|
||||
dma3.TCD->CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_DONE;
|
||||
dma3.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_2);
|
||||
} // begin()
|
||||
|
||||
|
||||
//*dest = *bitdata + pin offset
|
||||
//*pixels = pin's block in frameBuffer
|
||||
//mask = pin's bit position in GPIOR
|
||||
//set a pin's mask32 for each color bit=0 at every 4*words32 in bitdata+offset
|
||||
void fillbits(uint32_t *dest, const uint8_t *pixels, int n, uint32_t mask) {
|
||||
do {
|
||||
uint8_t pix = *pixels++;
|
||||
if (!(pix & 0x80)) *dest |= mask;
|
||||
dest += 4;
|
||||
if (!(pix & 0x40)) *dest |= mask;
|
||||
dest += 4;
|
||||
if (!(pix & 0x20)) *dest |= mask;
|
||||
dest += 4;
|
||||
if (!(pix & 0x10)) *dest |= mask;
|
||||
dest += 4;
|
||||
if (!(pix & 0x08)) *dest |= mask;
|
||||
dest += 4;
|
||||
if (!(pix & 0x04)) *dest |= mask;
|
||||
dest += 4;
|
||||
if (!(pix & 0x02)) *dest |= mask;
|
||||
dest += 4;
|
||||
if (!(pix & 0x01)) *dest |= mask;
|
||||
dest += 4;
|
||||
} while (--n > 0);
|
||||
}
|
||||
|
||||
|
||||
void ObjectFLED::genFrameBuffer(uint32_t serp) {
|
||||
uint32_t j = 0;
|
||||
int jChange = -3;
|
||||
if (serp == 0) { // use faster loops if no serp
|
||||
switch (params & 0x3F) {
|
||||
case CORDER_RGBW: // R,G,B = R,G,B - MIN(R,G,B); W = MIN(R,G,B)
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 4) {
|
||||
uint8_t minRGB = MIN(*((uint8_t*)drawBuffer + j) * rLevel / 65025, \
|
||||
*((uint8_t*)drawBuffer + j + 1) * rLevel / 65025);
|
||||
minRGB = MIN(minRGB, *((uint8_t*)drawBuffer + j + 2) * rLevel / 65025);
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j) * rLevel / 65025 - minRGB;
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025 - minRGB;
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025 - minRGB;
|
||||
*(frameBuffer + i + 3) = minRGB;
|
||||
j += 3;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_GBR:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += 3;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_BGR:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += 3;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_BRG:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += 3;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_GRB:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += 3;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_RGB:
|
||||
default:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += 3;
|
||||
} //for(leds in drawbuffer)
|
||||
} // switch()
|
||||
} else { //serpentine
|
||||
switch (params & 0x3F) {
|
||||
case CORDER_RGBW: // R,G,B = R,G,B - MIN(R,G,B); W = MIN(R,G,B)
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 4) {
|
||||
uint8_t minRGB = MIN(*((uint8_t*)drawBuffer + j) * rLevel / 65025, \
|
||||
* ((uint8_t*)drawBuffer + j + 1) * rLevel / 65025);
|
||||
minRGB = MIN(minRGB, *((uint8_t*)drawBuffer + j + 2) * rLevel / 65025);
|
||||
if (i % (serp * 4) == 0) {
|
||||
if (jChange < 0) { j = i / 4 * 3; jChange = 3; }
|
||||
else { j = (i / 4 + serp - 1) * 3; jChange = -3; }
|
||||
}
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j) * rLevel / 65025 - minRGB;
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025 - minRGB;
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025 - minRGB;
|
||||
*(frameBuffer + i + 3) = minRGB;
|
||||
j += jChange;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_GBR:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
if (i % (serp * 3) == 0) {
|
||||
if (jChange < 0) { j = i; jChange = 3; }
|
||||
else { j = i + (serp - 1) * 3; jChange = -3; }
|
||||
}
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += 3;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_BGR:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
if (i % (serp * 3) == 0) {
|
||||
if (jChange < 0) { j = i; jChange = 3; }
|
||||
else { j = i + (serp - 1) * 3; jChange = -3; }
|
||||
}
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += 3;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_BRG:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
if (i % (serp * 3) == 0) {
|
||||
if (jChange < 0) { j = i; jChange = 3; }
|
||||
else { j = i + (serp - 1) * 3; jChange = -3; }
|
||||
}
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += jChange;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_GRB:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
if (i % (serp * 3) == 0) {
|
||||
if (jChange < 0) { j = i; jChange = 3; }
|
||||
else { j = i + (serp - 1) * 3; jChange = -3; }
|
||||
}
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += jChange;
|
||||
} //for(leds in drawbuffer)
|
||||
break;
|
||||
case CORDER_RGB:
|
||||
default:
|
||||
for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
|
||||
if (i % (serp * 3) == 0) {
|
||||
if (jChange < 0) { j = i; jChange = 3; }
|
||||
else { j = i + (serp - 1) * 3; jChange = -3; }
|
||||
}
|
||||
*(frameBuffer + i) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
|
||||
*(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
|
||||
*(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
|
||||
j += jChange;
|
||||
} //for(leds in drawbuffer)
|
||||
} // switch()
|
||||
} // else serpentine
|
||||
} //genFrameBuffer()
|
||||
|
||||
|
||||
// pre-show prior transfer wait, copies drawBuffer -> frameBuffer
|
||||
// resets timers, clears pending DMA reqs
|
||||
// fills bitdata[BYTES_PER_DMA * 64 * 4 bytes] from frameBuffer with 4-block bitmasks for 0's in led data
|
||||
// 4 word32s for each bit in (led data)/pin = 16 * 8 = 96 bitdata bytes for each LED byte: 288 bytes / LED
|
||||
// launches DMA with IRQ activation to reload bitdata from frameBuffer
|
||||
void ObjectFLED::show(void) {
|
||||
waitForDmaToFinish(); //wait for prior DMA to finish
|
||||
|
||||
//Restore context if needed
|
||||
if (frameBuffer != frameBufferLocal) {
|
||||
numpins = numpinsLocal;
|
||||
frameBuffer = frameBufferLocal;
|
||||
numbytes = numbytesLocal;
|
||||
memcpy(bitmask, bitmaskLocal, 16);
|
||||
memcpy(pin_bitnum, pin_bitnumLocal, numpins);
|
||||
memcpy(pin_offset, pin_offsetLocal, numpins);
|
||||
arm_dcache_flush_delete(bitmask, sizeof(bitmask)); //can't DMA from cached memory
|
||||
// Restore 3 timers to create waveform timing events
|
||||
TMR4_COMP10 = comp1load[0];
|
||||
TMR4_CMPLD10 = comp1load[0];
|
||||
TMR4_COMP11 = comp1load[1]; // T0H
|
||||
TMR4_CMPLD11 = comp1load[1];
|
||||
TMR4_COMP12 = comp1load[2]; // T1H
|
||||
TMR4_CMPLD12 = comp1load[2];
|
||||
//restore DMA loop control
|
||||
dma1.TCD->CITER_ELINKNO = numbytes * 8; // CITER outer loop count (linking disabled) = # LED bits to write
|
||||
dma1.TCD->BITER_ELINKNO = numbytes * 8; // Beginning CITER (not decremented by transfer)
|
||||
dma3.TCD->CITER_ELINKNO = numbytes * 8;
|
||||
dma3.TCD->BITER_ELINKNO = numbytes * 8;
|
||||
} //done restoring context
|
||||
|
||||
genFrameBuffer(serpNumber);
|
||||
|
||||
// disable timers
|
||||
uint16_t enable = TMR4_ENBL;
|
||||
TMR4_ENBL = enable & ~7;
|
||||
|
||||
// force all timer outputs to logic low
|
||||
TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE | TMR_SCTRL_MSTR;
|
||||
TMR4_SCTRL1 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
|
||||
TMR4_SCTRL2 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
|
||||
|
||||
// clear any prior pending DMA requests
|
||||
XBARA1_CTRL0 |= XBARA_CTRL_STS1 | XBARA_CTRL_STS0;
|
||||
XBARA1_CTRL1 |= XBARA_CTRL_STS0;
|
||||
|
||||
// fill the DMA transmit buffer
|
||||
memset(bitdata, 0, sizeof(bitdata)); //BYTES_PER_DMA * 64 words32
|
||||
uint32_t count = numbytes; //bytes per strip
|
||||
if (count > BYTES_PER_DMA*2) count = BYTES_PER_DMA*2;
|
||||
framebuffer_index = count; //ptr to framebuffer last byte output
|
||||
|
||||
//Sets each pin mask in bitdata32[BYTES_PER_DMA*64] for every 0 bit of pin's frameBuffer block bytes
|
||||
for (uint32_t i=0; i < numpins; i++) { //for each pin
|
||||
fillbits(bitdata + pin_offset[i], (uint8_t *)frameBuffer + i*numbytes,
|
||||
count, 1<<pin_bitnum[i]);
|
||||
}
|
||||
arm_dcache_flush_delete(bitdata, count * 128); // don't need bitdata in cache for DMA
|
||||
|
||||
// set up DMA transfers
|
||||
if (numbytes <= BYTES_PER_DMA*2) {
|
||||
dma2.TCD->SADDR = bitdata;
|
||||
dma2.TCD->DADDR = &GPIO1_DR_CLEAR;
|
||||
dma2.TCD->CITER_ELINKNO = count * 8;
|
||||
dma2.TCD->CSR = DMA_TCD_CSR_DREQ;
|
||||
} else {
|
||||
dma2.TCD->SADDR = bitdata;
|
||||
dma2.TCD->DADDR = &GPIO1_DR_CLEAR;
|
||||
dma2.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
|
||||
dma2.TCD->CSR = 0;
|
||||
dma2.TCD->CSR = DMA_TCD_CSR_INTMAJOR | DMA_TCD_CSR_ESG;
|
||||
dma2next.TCD->SADDR = bitdata + BYTES_PER_DMA*32;
|
||||
dma2next.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
|
||||
if (numbytes <= BYTES_PER_DMA*3) {
|
||||
dma2next.TCD->CSR = DMA_TCD_CSR_ESG;
|
||||
} else {
|
||||
dma2next.TCD->CSR = DMA_TCD_CSR_ESG | DMA_TCD_CSR_INTMAJOR;
|
||||
}
|
||||
dma_first = true;
|
||||
}
|
||||
dma3.clearComplete();
|
||||
dma1.enable();
|
||||
dma2.enable();
|
||||
dma3.enable();
|
||||
|
||||
// initialize timers
|
||||
TMR4_CNTR0 = 0;
|
||||
TMR4_CNTR1 = comp1load[0] + 1;
|
||||
TMR4_CNTR2 = comp1load[0] + 1;
|
||||
|
||||
// wait for last LED reset to finish
|
||||
while (micros() - update_begin_micros < numbytes * 8 * TH_TL / OC_FACTOR / 1000 + LATCH_DELAY);
|
||||
|
||||
// start everything running!
|
||||
TMR4_ENBL = enable | 7;
|
||||
update_begin_micros = micros();
|
||||
} // show()
|
||||
|
||||
|
||||
//INPUT: dma2, dma2next, bitdata, framebuffer_inedex, numpins, numbytes, pin_offset[], pin_bitnum[]
|
||||
//Reads next block of framebuffer -> fillbits() -> bitdata
|
||||
//Checks for last block to transfer, next to last, or not to update dma2next major loop
|
||||
void ObjectFLED::isr(void)
|
||||
{
|
||||
// first ack the interrupt
|
||||
dma2.clearInterrupt();
|
||||
|
||||
// fill (up to) half the transmit buffer with new fillbits(frameBuffer data)
|
||||
//digitalWriteFast(12, HIGH);
|
||||
uint32_t *dest;
|
||||
if (dma_first) {
|
||||
dma_first = false;
|
||||
dest = bitdata;
|
||||
} else {
|
||||
dma_first = true;
|
||||
dest = bitdata + BYTES_PER_DMA*32;
|
||||
}
|
||||
memset(dest, 0, sizeof(bitdata)/2);
|
||||
uint32_t index = framebuffer_index;
|
||||
uint32_t count = numbytes - framebuffer_index;
|
||||
if (count > BYTES_PER_DMA) count = BYTES_PER_DMA;
|
||||
framebuffer_index = index + count;
|
||||
for (int i=0; i < numpins; i++) {
|
||||
fillbits(dest + pin_offset[i], (uint8_t *)frameBuffer + index + i*numbytes,
|
||||
count, 1<<pin_bitnum[i]);
|
||||
}
|
||||
arm_dcache_flush_delete(dest, count * 128);
|
||||
//digitalWriteFast(12, LOW);
|
||||
|
||||
// queue it for the next DMA transfer
|
||||
dma2next.TCD->SADDR = dest;
|
||||
dma2next.TCD->CITER_ELINKNO = count * 8;
|
||||
uint32_t remain = numbytes - (index + count);
|
||||
if (remain == 0) {
|
||||
dma2next.TCD->CSR = DMA_TCD_CSR_DREQ;
|
||||
} else if (remain <= BYTES_PER_DMA) {
|
||||
dma2next.TCD->CSR = DMA_TCD_CSR_ESG;
|
||||
} else {
|
||||
dma2next.TCD->CSR = DMA_TCD_CSR_ESG | DMA_TCD_CSR_INTMAJOR;
|
||||
}
|
||||
} // isr()
|
||||
|
||||
|
||||
int ObjectFLED::busy(void)
|
||||
{
|
||||
if (micros() - update_begin_micros < numbytes * TH_TL / OC_FACTOR / 1000 * 8 + LATCH_DELAY) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ObjectFLED::setBrightness(uint8_t brightLevel) {
|
||||
brightness = brightLevel;
|
||||
rLevel = brightness * (colorBalance >> 16);
|
||||
gLevel = brightness * ((colorBalance >> 8) & 0xFF);
|
||||
bLevel = brightness * (colorBalance & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
void ObjectFLED::setBalance(uint32_t balMask) {
|
||||
colorBalance = balMask & 0xFFFFFF;
|
||||
rLevel = brightness * (colorBalance >> 16);
|
||||
gLevel = brightness * ((colorBalance >> 8) & 0xFF);
|
||||
bLevel = brightness * (colorBalance & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
//Fades CRGB array towards the background color by amount.
|
||||
void fadeToColorBy(void* leds, uint16_t count, uint32_t color, uint8_t fadeAmt) {
|
||||
for (uint32_t x = 0; x < count * 3; x += 3) {
|
||||
//fade red
|
||||
*((uint8_t*)leds + x) = (( *((uint8_t*)leds + x) * (1 + (255 - fadeAmt))) >> 8) + \
|
||||
(( ((color >> 16) & 0xFF) * (1 + fadeAmt)) >> 8);
|
||||
//fade green
|
||||
*((uint8_t*)leds + x + 1) = (( *((uint8_t*)leds + x + 1) * (1 + (255 - fadeAmt))) >> 8) + \
|
||||
(( ((color >> 8) & 0xFF) * (1 + fadeAmt)) >> 8);
|
||||
//fade blue
|
||||
*((uint8_t*)leds + x + 2) = (( *((uint8_t*)leds + x + 2) * (1 + (255 - fadeAmt))) >> 8) + \
|
||||
(( (color & 0xFF) * (1 + fadeAmt)) >> 8);
|
||||
}
|
||||
} //fadeToColorBy()
|
||||
|
||||
|
||||
// Safely draws box even if partially offscreen on 2D CRGB array
|
||||
void drawSquare(void* leds, uint16_t planeY, uint16_t planeX, int yCorner, int xCorner, uint32_t size, uint32_t color) {
|
||||
if (size != 0) { size--; }
|
||||
else { return; }
|
||||
for (int x = xCorner; x <= xCorner + (int)size; x++) {
|
||||
// if validX { if validY+S {draw Y+S,X}; if validY {draw Y, X} }
|
||||
if ((x >= 0) && (x < planeX)) { //valid X
|
||||
if ((yCorner >= 0) && (yCorner < planeY)) {
|
||||
*((uint8_t*)leds + (yCorner * planeX + x) * 3) = ((color >> 16) & 0xFF);
|
||||
*((uint8_t*)leds + (yCorner * planeX + x) * 3 + 1) = ((color >> 8) & 0xFF);
|
||||
*((uint8_t*)leds + (yCorner * planeX + x) * 3 + 2) = (color & 0xFF);
|
||||
}
|
||||
if ((yCorner + size >= 0) && (yCorner + size < planeY)) {
|
||||
*((uint8_t*)leds + ((yCorner + size) * planeX + x) * 3) = ((color >> 16) & 0xFF);
|
||||
*((uint8_t*)leds + ((yCorner + size) * planeX + x) * 3 + 1) = ((color >> 8) & 0xFF);
|
||||
*((uint8_t*)leds + ((yCorner + size) * planeX + x) * 3 + 2) = (color & 0xFF);
|
||||
}
|
||||
} //if valid x
|
||||
} //for x
|
||||
for (int y = yCorner; y <= yCorner + (int)size; y++) {
|
||||
if ((y >= 0) && (y < planeY)) { //valid y
|
||||
if ((xCorner >= 0) && (xCorner < planeX)) {
|
||||
*((uint8_t*)leds + (xCorner + y * planeX) * 3) = ((color >> 16) & 0xFF);
|
||||
*((uint8_t*)leds + (xCorner + y * planeX) * 3 + 1) = ((color >> 8) & 0xFF);
|
||||
*((uint8_t*)leds + (xCorner + y * planeX) * 3 + 2) = (color & 0xFF);
|
||||
}
|
||||
if ((xCorner + size >= 0) && (xCorner + size < planeX)) {
|
||||
*((uint8_t*)leds + (xCorner + size + y * planeX) * 3) = ((color >> 16) & 0xFF);
|
||||
*((uint8_t*)leds + (xCorner + size + y * planeX) * 3 + 1) = ((color >> 8) & 0xFF);
|
||||
*((uint8_t*)leds + (xCorner + size + y * planeX) * 3 + 2) = (color & 0xFF);
|
||||
}
|
||||
} //if valid y
|
||||
} //for y
|
||||
} // drawSquare()
|
||||
|
||||
} // namespace fl
|
||||
|
||||
|
||||
#endif // __IMXRT1062__
|
||||
3
FastLED/src/third_party/yves/I2SClockLessLedDriveresp32s3/_readme
vendored
Normal file
3
FastLED/src/third_party/yves/I2SClockLessLedDriveresp32s3/_readme
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
Repo: https://github.com/hpwit/I2SClockLessLedDriveresp32s3
|
||||
commit: 48e9cb6d3db0e902703b0325bfaa153074f071d8
|
||||
11
FastLED/src/third_party/yves/I2SClockLessLedDriveresp32s3/driver.h
vendored
Normal file
11
FastLED/src/third_party/yves/I2SClockLessLedDriveresp32s3/driver.h
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef USE_FASTLED
|
||||
#define USE_FASTLED
|
||||
#endif // USE_FASTLED
|
||||
|
||||
#define COLOR_ORDER_RBG
|
||||
|
||||
#include "src/I2SClockLessLedDriveresp32s3.h"
|
||||
|
||||
|
||||
506
FastLED/src/third_party/yves/I2SClockLessLedDriveresp32s3/src/I2SClockLessLedDriveresp32s3.h
vendored
Normal file
506
FastLED/src/third_party/yves/I2SClockLessLedDriveresp32s3/src/I2SClockLessLedDriveresp32s3.h
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
|
||||
#if !__has_include("esp_memory_utils.h")
|
||||
#error \
|
||||
"esp_memory_utils.h is not available, are you using esp-idf 4.4 or earlier?"
|
||||
#else
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wattributes"
|
||||
#pragma GCC diagnostic ignored "-Wvolatile"
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_pm.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h> // ok include
|
||||
#include <string.h>
|
||||
// #include "esp_lcd_panel_io_interface.h"
|
||||
// #include "esp_lcd_panel_io.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#include "esp_private/gdma.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "hal/dma_types.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "soc/rtc.h" // for `rtc_clk_xtal_freq_get()`
|
||||
#include "soc/soc_caps.h"
|
||||
// #include "esp_private/periph_ctrl.h"
|
||||
|
||||
// #include "esp_lcd_common.h"
|
||||
#include "hal/lcd_hal.h"
|
||||
#include "hal/lcd_ll.h"
|
||||
#include "soc/lcd_periph.h"
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_io_interface.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "soc/gdma_reg.h"
|
||||
#include "platforms/esp/esp_version.h"
|
||||
|
||||
#define IDF_5_3_OR_EARLIER (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0))
|
||||
|
||||
// According to bug reports, this driver does not work well with the new WS2812-v5b. This is
|
||||
// probably due to the extrrra long reset time requirements of this chipset. so we put in
|
||||
// a hack that will always add 300 uS to the reset time.
|
||||
#define FASTLED_EXPERIMENTAL_YVES_EXTRA_WAIT_MICROS 300
|
||||
|
||||
#ifndef NUMSTRIPS
|
||||
#define NUMSTRIPS 16
|
||||
#endif
|
||||
|
||||
#ifndef SNAKEPATTERN
|
||||
#define SNAKEPATTERN 1
|
||||
#endif
|
||||
|
||||
#ifndef ALTERNATEPATTERN
|
||||
#define ALTERNATEPATTERN 1
|
||||
#endif
|
||||
|
||||
#define I2S_DEVICE 0
|
||||
|
||||
#define AA (0x00AA00AAL)
|
||||
#define CC (0x0000CCCCL)
|
||||
#define FF (0xF0F0F0F0L)
|
||||
#define FF2 (0x0F0F0F0FL)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define __OFFSET 0 // (24*3*2*2*2+2)
|
||||
|
||||
#define __OFFSET_END (24 * 3 * 2 * 2 * 2 + 2)
|
||||
#ifndef HARDWARESPRITES
|
||||
#define HARDWARESPRITES 0
|
||||
#endif
|
||||
|
||||
#if HARDWARESPRITES == 1
|
||||
#include "hardwareSprite.h"
|
||||
#endif
|
||||
|
||||
#ifdef COLOR_ORDER_GRBW
|
||||
#define _p_r 1
|
||||
#define _p_g 0
|
||||
#define _p_b 2
|
||||
#define _nb_components 4
|
||||
#else
|
||||
#ifdef COLOR_ORDER_RGB
|
||||
#define _p_r 0
|
||||
#define _p_g 1
|
||||
#define _p_b 2
|
||||
#define _nb_components 3
|
||||
#else
|
||||
#ifdef COLOR_ORDER_RBG
|
||||
#define _p_r 0
|
||||
#define _p_g 2
|
||||
#define _p_b 1
|
||||
#define _nb_components 3
|
||||
#else
|
||||
#ifdef COLOR_ORDER_GBR
|
||||
#define _p_r 2
|
||||
#define _p_g 0
|
||||
#define _p_b 1
|
||||
#define _nb_components 3
|
||||
#else
|
||||
#ifdef COLOR_ORDER_BGR
|
||||
#define _p_r 2
|
||||
#define _p_g 1
|
||||
#define _p_b 0
|
||||
#define _nb_components 3
|
||||
#else
|
||||
#ifdef COLOR_ORDER_BRG
|
||||
#define _p_r 1
|
||||
#define _p_g 2
|
||||
#define _p_b 0
|
||||
#define _nb_components 3
|
||||
#else
|
||||
#ifdef COLOR_ORDER_GRB
|
||||
#define _p_r 1
|
||||
#define _p_g 0
|
||||
#define _p_b 2
|
||||
#define _nb_components 3
|
||||
#else
|
||||
|
||||
#define _p_r 1
|
||||
#define _p_g 0
|
||||
#define _p_b 2
|
||||
#define _nb_components 3
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_PIXELSLIB
|
||||
// #include "pixelslib.h"
|
||||
#else
|
||||
#include "___pixeltypes.h"
|
||||
#endif
|
||||
|
||||
#define LCD_DRIVER_PSRAM_DATA_ALIGNMENT 64
|
||||
#define CLOCKLESS_PIXEL_CLOCK_HZ (24 * 100 * 1000)
|
||||
|
||||
namespace fl {
|
||||
|
||||
static bool IRAM_ATTR flush_ready(esp_lcd_panel_io_handle_t panel_io,
|
||||
esp_lcd_panel_io_event_data_t *edata,
|
||||
void *user_ctx);
|
||||
|
||||
typedef union {
|
||||
uint8_t bytes[16];
|
||||
uint32_t shorts[8];
|
||||
uint32_t raw[2];
|
||||
} Lines;
|
||||
|
||||
enum colorarrangment {
|
||||
ORDER_GRBW,
|
||||
ORDER_RGB,
|
||||
ORDER_RBG,
|
||||
ORDER_GRB,
|
||||
ORDER_GBR,
|
||||
ORDER_BRG,
|
||||
ORDER_BGR,
|
||||
};
|
||||
|
||||
enum displayMode {
|
||||
NO_WAIT,
|
||||
WAIT,
|
||||
LOOP,
|
||||
LOOP_INTERUPT,
|
||||
};
|
||||
|
||||
bool DRIVER_READY = true;
|
||||
|
||||
typedef struct led_driver_t led_driver_t;
|
||||
|
||||
struct led_driver_t {
|
||||
size_t (*init)();
|
||||
void (*update)(uint8_t *colors, size_t len);
|
||||
};
|
||||
volatile xSemaphoreHandle I2SClocklessLedDriverS3_sem = NULL;
|
||||
volatile bool isDisplaying = false;
|
||||
volatile bool iswaiting = false;
|
||||
|
||||
static void IRAM_ATTR transpose16x1_noinline2(unsigned char *A, uint16_t *B) {
|
||||
|
||||
uint32_t x, y, x1, y1, t;
|
||||
|
||||
y = *(unsigned int *)(A);
|
||||
#if NUMSTRIPS > 4
|
||||
x = *(unsigned int *)(A + 4);
|
||||
#else
|
||||
x = 0;
|
||||
#endif
|
||||
|
||||
#if NUMSTRIPS > 8
|
||||
y1 = *(unsigned int *)(A + 8);
|
||||
#else
|
||||
y1 = 0;
|
||||
#endif
|
||||
#if NUMSTRIPS > 12
|
||||
x1 = *(unsigned int *)(A + 12);
|
||||
#else
|
||||
x1 = 0;
|
||||
#endif
|
||||
|
||||
// pre-transform x
|
||||
#if NUMSTRIPS > 4
|
||||
t = (x ^ (x >> 7)) & AA;
|
||||
x = x ^ t ^ (t << 7);
|
||||
t = (x ^ (x >> 14)) & CC;
|
||||
x = x ^ t ^ (t << 14);
|
||||
#endif
|
||||
#if NUMSTRIPS > 12
|
||||
t = (x1 ^ (x1 >> 7)) & AA;
|
||||
x1 = x1 ^ t ^ (t << 7);
|
||||
t = (x1 ^ (x1 >> 14)) & CC;
|
||||
x1 = x1 ^ t ^ (t << 14);
|
||||
#endif
|
||||
// pre-transform y
|
||||
t = (y ^ (y >> 7)) & AA;
|
||||
y = y ^ t ^ (t << 7);
|
||||
t = (y ^ (y >> 14)) & CC;
|
||||
y = y ^ t ^ (t << 14);
|
||||
#if NUMSTRIPS > 8
|
||||
t = (y1 ^ (y1 >> 7)) & AA;
|
||||
y1 = y1 ^ t ^ (t << 7);
|
||||
t = (y1 ^ (y1 >> 14)) & CC;
|
||||
y1 = y1 ^ t ^ (t << 14);
|
||||
#endif
|
||||
// final transform
|
||||
t = (x & FF) | ((y >> 4) & FF2);
|
||||
y = ((x << 4) & FF) | (y & FF2);
|
||||
x = t;
|
||||
|
||||
t = (x1 & FF) | ((y1 >> 4) & FF2);
|
||||
y1 = ((x1 << 4) & FF) | (y1 & FF2);
|
||||
x1 = t;
|
||||
|
||||
*((uint16_t *)(B)) =
|
||||
(uint16_t)(((x & 0xff000000) >> 8 | ((x1 & 0xff000000))) >> 16);
|
||||
*((uint16_t *)(B + 3)) =
|
||||
(uint16_t)(((x & 0xff0000) >> 16 | ((x1 & 0xff0000) >> 8)));
|
||||
*((uint16_t *)(B + 6)) =
|
||||
(uint16_t)(((x & 0xff00) | ((x1 & 0xff00) << 8)) >> 8);
|
||||
*((uint16_t *)(B + 9)) = (uint16_t)((x & 0xff) | ((x1 & 0xff) << 8));
|
||||
*((uint16_t *)(B + 12)) =
|
||||
(uint16_t)(((y & 0xff000000) >> 8 | ((y1 & 0xff000000))) >> 16);
|
||||
*((uint16_t *)(B + 15)) =
|
||||
(uint16_t)(((y & 0xff0000) | ((y1 & 0xff0000) << 8)) >> 16);
|
||||
*((uint16_t *)(B + 18)) =
|
||||
(uint16_t)(((y & 0xff00) | ((y1 & 0xff00) << 8)) >> 8);
|
||||
*((uint16_t *)(B + 21)) = (uint16_t)((y & 0xff) | ((y1 & 0xff) << 8));
|
||||
}
|
||||
|
||||
esp_lcd_panel_io_handle_t led_io_handle = NULL;
|
||||
|
||||
class I2SClocklessLedDriveresp32S3 {
|
||||
|
||||
public:
|
||||
int testcount;
|
||||
uint16_t *buffers[2];
|
||||
uint16_t *led_output = NULL;
|
||||
uint16_t *led_output2 = NULL;
|
||||
uint8_t *ledsbuff = NULL;
|
||||
int num_leds_per_strip;
|
||||
int _numstrips;
|
||||
int currentframe;
|
||||
|
||||
uint8_t __green_map[256];
|
||||
uint8_t __blue_map[256];
|
||||
uint8_t __red_map[256];
|
||||
uint8_t __white_map[256];
|
||||
uint8_t _brightness;
|
||||
float _gammar, _gammab, _gammag, _gammaw;
|
||||
|
||||
void setBrightness(int brightness) {
|
||||
_brightness = brightness;
|
||||
float tmp;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
tmp = powf((float)i / 255, 1 / _gammag);
|
||||
__green_map[i] = (uint8_t)(tmp * brightness);
|
||||
tmp = powf((float)i / 255, 1 / _gammag);
|
||||
__blue_map[i] = (uint8_t)(tmp * brightness);
|
||||
tmp = powf((float)i / 255, 1 / _gammag);
|
||||
__red_map[i] = (uint8_t)(tmp * brightness);
|
||||
tmp = powf((float)i / 255, 1 / _gammag);
|
||||
__white_map[i] = (uint8_t)(tmp * brightness);
|
||||
}
|
||||
}
|
||||
|
||||
void setGamma(float gammar, float gammab, float gammag, float gammaw) {
|
||||
_gammag = gammag;
|
||||
_gammar = gammar;
|
||||
_gammaw = gammaw;
|
||||
_gammab = gammab;
|
||||
setBrightness(_brightness);
|
||||
}
|
||||
|
||||
void setGamma(float gammar, float gammab, float gammag) {
|
||||
_gammag = gammag;
|
||||
_gammar = gammar;
|
||||
_gammab = gammab;
|
||||
setBrightness(_brightness);
|
||||
}
|
||||
|
||||
void _initled(uint8_t *leds, const int *pins, int numstrip,
|
||||
int NUM_LED_PER_STRIP) {
|
||||
|
||||
// esp_lcd_panel_io_handle_t init_lcd_driver(unsigned int
|
||||
// CLOCKLESS_PIXEL_CLOCK_HZ, size_t _nb_components) {
|
||||
|
||||
esp_lcd_i80_bus_handle_t i80_bus = NULL;
|
||||
|
||||
esp_lcd_i80_bus_config_t bus_config;
|
||||
|
||||
bus_config.clk_src = LCD_CLK_SRC_PLL160M;
|
||||
bus_config.dc_gpio_num = 0;
|
||||
bus_config.wr_gpio_num = 0;
|
||||
// bus_config.data_gpio_nums = (int*)malloc(16*sizeof(int));
|
||||
for (int i = 0; i < numstrip; i++) {
|
||||
bus_config.data_gpio_nums[i] = pins[i];
|
||||
}
|
||||
if (numstrip < 16) {
|
||||
for (int i = numstrip; i < 16; i++) {
|
||||
bus_config.data_gpio_nums[i] = 0;
|
||||
}
|
||||
}
|
||||
bus_config.bus_width = 16;
|
||||
bus_config.max_transfer_bytes =
|
||||
_nb_components * NUM_LED_PER_STRIP * 8 * 3 * 2 + __OFFSET + __OFFSET_END;
|
||||
#if IDF_5_3_OR_EARLIER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
// In IDF 5.3, psram_trans_align became deprecated. We kick the can down
|
||||
// the road a little bit and suppress the warning until idf 5.4 arrives.
|
||||
bus_config.psram_trans_align = LCD_DRIVER_PSRAM_DATA_ALIGNMENT;
|
||||
bus_config.sram_trans_align = 4;
|
||||
#if IDF_5_3_OR_EARLIER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
|
||||
|
||||
esp_lcd_panel_io_i80_config_t io_config;
|
||||
|
||||
io_config.cs_gpio_num = -1;
|
||||
io_config.pclk_hz = CLOCKLESS_PIXEL_CLOCK_HZ;
|
||||
io_config.trans_queue_depth = 1;
|
||||
io_config.dc_levels = {
|
||||
.dc_idle_level = 0,
|
||||
.dc_cmd_level = 0,
|
||||
.dc_dummy_level = 0,
|
||||
.dc_data_level = 1,
|
||||
};
|
||||
//.on_color_trans_done = flush_ready,
|
||||
// .user_ctx = nullptr,
|
||||
io_config.lcd_cmd_bits = 0;
|
||||
io_config.lcd_param_bits = 0;
|
||||
io_config.user_ctx = this;
|
||||
|
||||
io_config.on_color_trans_done = flush_ready;
|
||||
ESP_ERROR_CHECK(
|
||||
esp_lcd_new_panel_io_i80(i80_bus, &io_config, &led_io_handle));
|
||||
}
|
||||
|
||||
void initled(uint8_t *leds, const int *pins, int numstrip,
|
||||
int NUM_LED_PER_STRIP) {
|
||||
currentframe = 0;
|
||||
_gammab = 1;
|
||||
_gammar = 1;
|
||||
_gammag = 1;
|
||||
_gammaw = 1;
|
||||
setBrightness(255);
|
||||
if (I2SClocklessLedDriverS3_sem == NULL) {
|
||||
I2SClocklessLedDriverS3_sem = xSemaphoreCreateBinary();
|
||||
}
|
||||
// esp_lcd_panel_io_handle_t init_lcd_driver(unsigned int
|
||||
// CLOCKLESS_PIXEL_CLOCK_HZ, size_t _nb_components) {
|
||||
led_output = (uint16_t *)heap_caps_aligned_alloc(
|
||||
LCD_DRIVER_PSRAM_DATA_ALIGNMENT,
|
||||
8 * _nb_components * NUM_LED_PER_STRIP * 3 * 2 + __OFFSET +
|
||||
__OFFSET_END,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
memset(led_output, 0,
|
||||
8 * _nb_components * NUM_LED_PER_STRIP * 3 * 2 + __OFFSET +
|
||||
__OFFSET_END);
|
||||
|
||||
led_output2 = (uint16_t *)heap_caps_aligned_alloc(
|
||||
LCD_DRIVER_PSRAM_DATA_ALIGNMENT,
|
||||
8 * _nb_components * NUM_LED_PER_STRIP * 3 * 2 + __OFFSET +
|
||||
__OFFSET_END,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
memset(led_output2, 0,
|
||||
8 * _nb_components * NUM_LED_PER_STRIP * 3 * 2 + __OFFSET +
|
||||
__OFFSET_END);
|
||||
buffers[0] = led_output;
|
||||
buffers[1] = led_output2;
|
||||
// led_output[0] = 0xFFFF; //the +1 because it's like the first value
|
||||
// doesnt get pushed do not ask me why for now
|
||||
// led_output2[0] = 0xFFFF;
|
||||
led_output2 += __OFFSET / 2;
|
||||
led_output += __OFFSET / 2;
|
||||
|
||||
for (int i = 0; i < NUM_LED_PER_STRIP * _nb_components * 8; i++) {
|
||||
led_output[3 * i + 1] =
|
||||
0xFFFF; // the +1 because it's like the first value doesnt get
|
||||
// pushed do not ask me why for now
|
||||
led_output2[3 * i + 1] = 0xFFFF;
|
||||
}
|
||||
ledsbuff = leds;
|
||||
_numstrips = numstrip;
|
||||
num_leds_per_strip = NUM_LED_PER_STRIP;
|
||||
_initled(leds, pins, numstrip, NUM_LED_PER_STRIP);
|
||||
}
|
||||
|
||||
void transposeAll(uint16_t *ledoutput) {
|
||||
|
||||
uint16_t ledToDisplay = 0;
|
||||
Lines secondPixel[_nb_components];
|
||||
uint16_t *buff =
|
||||
ledoutput + 2; //+1 pour le premier empty +1 pour le 1 systématique
|
||||
uint16_t jump = num_leds_per_strip * _nb_components;
|
||||
for (int j = 0; j < num_leds_per_strip; j++) {
|
||||
uint8_t *poli = ledsbuff + ledToDisplay * _nb_components;
|
||||
for (int i = 0; i < _numstrips; i++) {
|
||||
|
||||
secondPixel[_p_g].bytes[i] = __green_map[*(poli + 1)];
|
||||
secondPixel[_p_r].bytes[i] = __red_map[*(poli + 0)];
|
||||
secondPixel[_p_b].bytes[i] = __blue_map[*(poli + 2)];
|
||||
if (_nb_components > 3)
|
||||
secondPixel[3].bytes[i] = __white_map[*(poli + 3)];
|
||||
// #endif
|
||||
poli += jump;
|
||||
}
|
||||
ledToDisplay++;
|
||||
transpose16x1_noinline2(secondPixel[0].bytes, buff);
|
||||
buff += 24;
|
||||
transpose16x1_noinline2(secondPixel[1].bytes, buff);
|
||||
buff += 24;
|
||||
transpose16x1_noinline2(secondPixel[2].bytes, buff);
|
||||
buff += 24;
|
||||
if (_nb_components > 3) {
|
||||
transpose16x1_noinline2(secondPixel[3].bytes, buff);
|
||||
buff += 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show() {
|
||||
transposeAll(buffers[currentframe]);
|
||||
if (isDisplaying) {
|
||||
// Serial.println("on display dejà");
|
||||
iswaiting = true;
|
||||
if (I2SClocklessLedDriverS3_sem == NULL)
|
||||
I2SClocklessLedDriverS3_sem = xSemaphoreCreateBinary();
|
||||
xSemaphoreTake(I2SClocklessLedDriverS3_sem, portMAX_DELAY);
|
||||
}
|
||||
isDisplaying = true;
|
||||
|
||||
if (FASTLED_EXPERIMENTAL_YVES_EXTRA_WAIT_MICROS) {
|
||||
delayMicroseconds(FASTLED_EXPERIMENTAL_YVES_EXTRA_WAIT_MICROS);
|
||||
}
|
||||
|
||||
led_io_handle->tx_color(led_io_handle, 0x2C, buffers[currentframe],
|
||||
_nb_components * num_leds_per_strip * 8 * 3 *
|
||||
2 +
|
||||
__OFFSET + __OFFSET_END);
|
||||
|
||||
currentframe = (currentframe + 1) % 2;
|
||||
}
|
||||
};
|
||||
|
||||
static bool IRAM_ATTR flush_ready(esp_lcd_panel_io_handle_t panel_io,
|
||||
esp_lcd_panel_io_event_data_t *edata,
|
||||
void *user_ctx) {
|
||||
// printf("we're here");
|
||||
DRIVER_READY = true;
|
||||
isDisplaying = false;
|
||||
I2SClocklessLedDriveresp32S3 *cont =
|
||||
(I2SClocklessLedDriveresp32S3 *)user_ctx;
|
||||
cont->testcount++;
|
||||
if (iswaiting) {
|
||||
portBASE_TYPE HPTaskAwoken = 0;
|
||||
iswaiting = false;
|
||||
xSemaphoreGiveFromISR(I2SClocklessLedDriverS3_sem, &HPTaskAwoken);
|
||||
if (HPTaskAwoken == pdTRUE)
|
||||
portYIELD_FROM_ISR(HPTaskAwoken);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
} // namespace fl
|
||||
|
||||
#endif // __has_include("esp_memory_utils.h")
|
||||
334
FastLED/src/third_party/yves/I2SClockLessLedDriveresp32s3/src/___pixeltypes.h
vendored
Normal file
334
FastLED/src/third_party/yves/I2SClockLessLedDriveresp32s3/src/___pixeltypes.h
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_FASTLED
|
||||
#include "FastLED.h"
|
||||
#endif
|
||||
// #include "Arduino.h"
|
||||
|
||||
#define _OUT_OF_BOUND -12
|
||||
|
||||
namespace fl {
|
||||
|
||||
#ifdef COLOR_RGBW
|
||||
|
||||
struct Pixel {
|
||||
union {
|
||||
uint8_t raw[4];
|
||||
struct {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
uint8_t white;
|
||||
};
|
||||
};
|
||||
|
||||
inline Pixel(uint8_t r, uint8_t g, uint8_t b, uint8_t w)
|
||||
__attribute__((always_inline))
|
||||
: red(r), green(g), blue(b), white(w) {
|
||||
// brigthness =0xE0 |(br&31);
|
||||
}
|
||||
|
||||
inline Pixel(uint8_t r, uint8_t g, uint8_t b) __attribute__((always_inline))
|
||||
: red(r), green(g), blue(b) {
|
||||
white = MIN(red, green);
|
||||
white = MIN(white, blue);
|
||||
red = red - white;
|
||||
green = green - white;
|
||||
blue = blue - white;
|
||||
}
|
||||
|
||||
inline Pixel() __attribute__((always_inline)) {}
|
||||
|
||||
#ifdef USE_FASTLED
|
||||
inline Pixel &operator=(const CRGB &rhs) __attribute__((always_inline)) {
|
||||
|
||||
red = rhs.r;
|
||||
green = rhs.g;
|
||||
blue = rhs.b;
|
||||
white = MIN(red, green);
|
||||
white = MIN(white, blue);
|
||||
red = red - white;
|
||||
green = green - white;
|
||||
blue = blue - white;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Pixel(const Pixel &rhs) __attribute__((always_inline)) {
|
||||
// brigthness=rhs.brigthness;
|
||||
red = rhs.red;
|
||||
green = rhs.green;
|
||||
blue = rhs.blue;
|
||||
white = rhs.white;
|
||||
}
|
||||
inline Pixel &operator=(const uint32_t colorcode)
|
||||
__attribute__((always_inline)) {
|
||||
// rgb colorg;
|
||||
red = (colorcode >> 24) & 0xFF;
|
||||
green = (colorcode >> 16) & 0xFF;
|
||||
blue = (colorcode >> 8) & 0xFF;
|
||||
white = colorcode & 0xFF;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
#else
|
||||
|
||||
struct Pixel {
|
||||
union {
|
||||
uint8_t raw[3];
|
||||
struct {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
};
|
||||
};
|
||||
|
||||
inline Pixel(uint8_t r, uint8_t g, uint8_t b) __attribute__((always_inline))
|
||||
: red(r), green(g), blue(b) {
|
||||
// brigthness =0xE0 |(br&31);
|
||||
}
|
||||
|
||||
inline Pixel() __attribute__((always_inline)) {}
|
||||
|
||||
#ifdef USE_FASTLED
|
||||
inline Pixel &operator=(const CRGB &rhs) __attribute__((always_inline)) {
|
||||
red = rhs.r;
|
||||
green = rhs.g;
|
||||
blue = rhs.b;
|
||||
return *this;
|
||||
}
|
||||
inline Pixel &operator=(CRGB &rhs) __attribute__((always_inline)) {
|
||||
red = rhs.r;
|
||||
green = rhs.g;
|
||||
blue = rhs.b;
|
||||
return *this;
|
||||
}
|
||||
inline Pixel(const CRGB &rhs) __attribute__((always_inline)) {
|
||||
red = rhs.r;
|
||||
green = rhs.g;
|
||||
blue = rhs.b;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Pixel(const Pixel &rhs) __attribute__((always_inline)) {
|
||||
// brigthness=rhs.brigthness;
|
||||
red = rhs.red;
|
||||
green = rhs.green;
|
||||
blue = rhs.blue;
|
||||
}
|
||||
inline Pixel &operator=(const uint32_t colorcode)
|
||||
__attribute__((always_inline)) {
|
||||
// rgb colorg;
|
||||
red = (colorcode >> 16) & 0xFF;
|
||||
green = (colorcode >> 8) & 0xFF;
|
||||
blue = (colorcode >> 0) & 0xFF;
|
||||
return *this;
|
||||
}
|
||||
inline __attribute__((always_inline)) bool operator==(const Pixel &rhs) {
|
||||
return (red == rhs.red) && (green == rhs.green) && (blue == rhs.blue);
|
||||
}
|
||||
inline __attribute__((always_inline)) bool operator!=(const Pixel &rhs) {
|
||||
return !((red == rhs.red) && (green == rhs.green) &&
|
||||
(blue == rhs.blue));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
enum class leddirection { FORWARD, BACKWARD, MAP };
|
||||
|
||||
class Pixels {
|
||||
public:
|
||||
inline Pixels() __attribute__((always_inline)) {}
|
||||
inline Pixels(const Pixels &rhs) __attribute__((always_inline)) {
|
||||
_size = rhs._size;
|
||||
_direction = rhs._direction;
|
||||
_num_strips = rhs._num_strips;
|
||||
for (int i = 0; i < _num_strips; i++) {
|
||||
_sizes[i] = rhs._sizes[i];
|
||||
}
|
||||
ledpointer = rhs.ledpointer;
|
||||
mapFunction = rhs.mapFunction;
|
||||
|
||||
// parent=rhs.parent;
|
||||
}
|
||||
Pixels(int size, Pixel *ledpoi) {
|
||||
Pixels(size, ledpoi, leddirection::FORWARD);
|
||||
}
|
||||
|
||||
Pixels(int size, Pixel *ledpoi, leddirection direction) {
|
||||
__Pixels(size, ledpoi, direction, this);
|
||||
}
|
||||
|
||||
void __Pixels(int size, Pixel *ledpoi, leddirection direction,
|
||||
Pixels *pib) {
|
||||
pib->_size = size;
|
||||
pib->ledpointer = ledpoi;
|
||||
pib->_num_strips = 0;
|
||||
pib->_direction = direction;
|
||||
// pib->nb_child=0;
|
||||
}
|
||||
|
||||
Pixels(int num_led_per_strip, int num_strips) {
|
||||
int sizes[16];
|
||||
for (int i = 0; i < num_strips; i++) {
|
||||
sizes[i] = num_led_per_strip;
|
||||
}
|
||||
__Pixels(sizes, num_strips, leddirection::FORWARD, this);
|
||||
}
|
||||
|
||||
Pixels(int *sizes, int num_strips) {
|
||||
__Pixels(sizes, num_strips, leddirection::FORWARD, this);
|
||||
}
|
||||
|
||||
Pixels(int *sizes, int num_strips, leddirection direction) {
|
||||
__Pixels(sizes, num_strips, direction, this);
|
||||
}
|
||||
void __Pixels(int *sizes, int num_strips, leddirection direction,
|
||||
Pixels *pib) {
|
||||
int size = 0;
|
||||
for (int i = 0; i < num_strips; i++) {
|
||||
size += sizes[i];
|
||||
pib->_sizes[i] = sizes[i];
|
||||
}
|
||||
|
||||
pib->_num_strips = num_strips;
|
||||
|
||||
ledpointer = (Pixel *)calloc(size, sizeof(Pixel));
|
||||
if (ledpointer == NULL) {
|
||||
pib->_size = 0;
|
||||
} else {
|
||||
pib->_size = size;
|
||||
}
|
||||
pib->_direction = direction;
|
||||
}
|
||||
Pixel &operator[](int i) {
|
||||
switch (_direction) {
|
||||
|
||||
case (leddirection::FORWARD):
|
||||
|
||||
return *(ledpointer + i % _size);
|
||||
break;
|
||||
|
||||
case (leddirection::BACKWARD):
|
||||
|
||||
return *(ledpointer + (_size - i % (_size)-1));
|
||||
break;
|
||||
|
||||
case (leddirection::MAP):
|
||||
if (mapFunction) {
|
||||
int offset = mapFunction(i, arguments);
|
||||
// printf("%d %d\n",i,offset);
|
||||
if (offset == _OUT_OF_BOUND) {
|
||||
return offPixel;
|
||||
} else
|
||||
return *(ledpointer + (mapFunction(i, arguments) % _size));
|
||||
}
|
||||
|
||||
else
|
||||
return *(ledpointer);
|
||||
break;
|
||||
default:
|
||||
return *(ledpointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void copy(Pixels ori) { copy(ori, leddirection::FORWARD); }
|
||||
|
||||
void copy(Pixels ori, leddirection dir) {
|
||||
leddirection ledd = _direction;
|
||||
if (_direction == leddirection::MAP)
|
||||
ledd = leddirection::FORWARD;
|
||||
for (int i = 0; i < ori._size; i++) {
|
||||
if (ledd == dir) {
|
||||
(*this)[i] = ori[i];
|
||||
} else {
|
||||
(*this)[i] = ori[ori._size - i % (ori._size) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pixels getStrip(int num_strip, leddirection direction) {
|
||||
if (_num_strips == 0 or _num_strips < num_strip) {
|
||||
|
||||
int d[0];
|
||||
return Pixels(d, 1, direction);
|
||||
} else {
|
||||
uint32_t off = 0;
|
||||
for (int i = 0; i < num_strip % _num_strips; i++) {
|
||||
off += _sizes[i];
|
||||
}
|
||||
|
||||
return Pixels(_sizes[num_strip], ledpointer + off, direction);
|
||||
}
|
||||
}
|
||||
|
||||
Pixels getStrip(int num_strip) {
|
||||
return getStrip(num_strip, leddirection::FORWARD);
|
||||
}
|
||||
|
||||
int *getLengths() { return _sizes; }
|
||||
|
||||
int getNumStrip() { return _num_strips; }
|
||||
uint8_t *getPixels() { return (uint8_t *)ledpointer; }
|
||||
void clear() {
|
||||
// memset(ledpointer,0,_size*sizeof(Pixel));
|
||||
}
|
||||
|
||||
Pixels createSubset(int start, int length) {
|
||||
return createSubset(start, length, leddirection::FORWARD);
|
||||
}
|
||||
|
||||
Pixels createSubset(int start, leddirection direction) {
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
return Pixels(_size, ledpointer + start, direction);
|
||||
}
|
||||
|
||||
Pixels createSubset(int start, int length, leddirection direction) {
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (length <= 0)
|
||||
length = 1;
|
||||
return Pixels(length, ledpointer + start, direction);
|
||||
}
|
||||
/*
|
||||
Pixels getParent()
|
||||
{
|
||||
return *parent;
|
||||
}
|
||||
|
||||
Pixels * getChild(int i)
|
||||
{
|
||||
|
||||
return children[i%nb_child];
|
||||
}
|
||||
*/
|
||||
inline void setMapFunction(int (*fptr)(int i, void *args), void *args,
|
||||
int size) {
|
||||
mapFunction = fptr;
|
||||
if (arguments == NULL)
|
||||
arguments = (void *)malloc(sizeof(size));
|
||||
memcpy(arguments, args, size);
|
||||
}
|
||||
|
||||
private:
|
||||
Pixel *ledpointer;
|
||||
size_t _size = 0;
|
||||
int _sizes[16];
|
||||
int _num_strips = 0;
|
||||
leddirection _direction;
|
||||
// int nb_child;
|
||||
// Pixels *parent;
|
||||
void *arguments;
|
||||
// Pixels **children;
|
||||
int (*mapFunction)(int i, void *args);
|
||||
/*
|
||||
* this is the pixel to retuen when out of bound
|
||||
*/
|
||||
Pixel offPixel;
|
||||
};
|
||||
|
||||
} // namespace fl
|
||||
Reference in New Issue
Block a user