Skip to content

Commit

Permalink
Speed improvements (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
awawa-dev authored Dec 13, 2022
1 parent 1399cf6 commit 2634681
Show file tree
Hide file tree
Showing 13 changed files with 1,436 additions and 613 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020,2021 awawa-dev
Copyright (c) 2020,2021,2022 awawa-dev

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
36 changes: 25 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ WLED is a brilliant app and it's preffered solution in most cases. But sometimes

**Arduino: 250 RGB leds, 500000 baud, 100 Hz output from HyperHDR, real output for the LED strip is around 20Hz.**
**With such slow hardware driver you don't even need 30FPS from the grabber really:**
<img src='https://i.postimg.cc/1PD541LP/p100.jpg' border='0' alt='p100' width="320"/>

<img src='https://user-images.githubusercontent.com/69086569/207443059-0ef8bc71-0a5d-4faa-bab7-f313d1cb6ed6.png' border='0' alt='p100' width="320"/>


With HyperSerialEsp8266 you can have over 100Hz refresh rate for 250 RGB and over 80HZ for 250 RGBW LED strips.
Expand Down Expand Up @@ -61,25 +62,38 @@ Using esphome-flasher:

# Usage in HyperHDR

Make sure you set "Refresh time" to zero, "Baudrate" to 2000000 and enabled HyperHDR's AWA protocol.
Enabling "White channel calibration" is optional, if you want to fine tune the white channel balance of your sk6812 RGBW LED strip.

![obraz](https://user-images.githubusercontent.com/69086569/192894824-7c58b497-480d-468a-8014-fb03859e3977.png)

# Result
Set `Refresh time` to zero, `Baudrate` to 2000000 and you enabled `HyperHDR's AWA protocol`.
Enabling `White channel calibration` is optional, if you want to fine tune the white channel balance of your sk6812 RGBW LED strip.
`ESP8266/ESP32 handshake` could help you to properly initialize the ESP device and enables statistics available in the logs (you must stop the LED device first to get them).

![obraz](https://user-images.githubusercontent.com/69086569/207109594-0493fe58-3530-46bb-a0a3-31a110475ed6.png)

RGB (250 leds, 100Hz)
# Benchmarks


**Refresh rate depending on requested refresh rate/LED strip length**:
| RGBW LED strip / Device | WeMos D1 Mini Pro (CP2104)<br>HyperSerialEsp8266 v8 |
|------------------------------------------------|-----------------------------------------|
| 300LEDs<br>Refresh rate/continues output=100Hz | 71-75 |
| 600LEDs<br>Refresh rate/continues output=60Hz | 34-35 |
| 900LEDs<br>Refresh rate/continues output=40Hz | 23 |


**Logic level analyzer, RGB (250 leds, 100Hz)**
<img src="https://i.postimg.cc/sjrQQ11Y/250-rgb-setup.jpg" width="640"/>

RGBW (250 leds, 100Hz)


**Logic level analyzer, RGBW (250 leds, 100Hz)**
<img src="https://i.postimg.cc/KZL38tcc/250-rgbw-setup.jpg" width="640"/>

# Compiling

Currently we use PlatformIO to compile the project. Install [Visual Studio Code](https://code.visualstudio.com/) and add [PlatformIO plugin](https://platformio.org/).
This environment will take care of everything and compile the firmware for you.

But there is also an alternative and an easier way. Just fork the project and enable its Github Action. Use the online editor to make changes to the ```platformio.ini``` file, for example, and save it. Github Action will compile new firmware automatically in the Artifacts archive. It has never been so easy!
But there is also an alternative and an easier way. Just fork the project and enable its Github Action. Use the online editor to make changes to the ```platformio.ini``` file, for example change default pin-outs/speed or enable multi-segments support, and save it. Github Action will compile new firmware automatically in the Artifacts archive. It has never been so easy!

Tutorial: https://github.com/awawa-dev/HyperSerialEsp8266/wiki

# Pinout

Expand Down
39 changes: 0 additions & 39 deletions include/README

This file was deleted.

113 changes: 113 additions & 0 deletions include/base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/* base.h
*
* MIT License
*
* Copyright (c) 2022 awawa-dev
*
* https://github.com/awawa-dev/HyperSerialEsp8266
*
* 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.
* 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 BASE_H
#define BASE_H

class Base
{
// LED strip number
int ledsNumber = 0;
// NeoPixelBusLibrary primary object
LED_DRIVER* ledStrip1 = nullptr;
// frame is set and ready to render
bool readyToRender = false;

public:
// static data buffer for the loop
uint8_t buffer[MAX_BUFFER];
// current queue position
uint16_t queueCurrent = 0;
// queue end position
volatile uint16_t queueEnd = 0;

inline int getLedsNumber()
{
return ledsNumber;
}

inline LED_DRIVER* getLedStrip1()
{
return ledStrip1;
}

void initLedStrip(int count)
{
if (ledStrip1 != nullptr)
{
delete ledStrip1;
ledStrip1 = nullptr;
}

ledsNumber = count;

if (ledStrip1 == nullptr)
{
ledStrip1 = new LED_DRIVER(ledsNumber);
ledStrip1->Begin();
}
}

/**
* @brief Check if there is already prepared frame to display
*
* @return true
* @return false
*/
inline bool hasLateFrameToRender()
{
return readyToRender;
}

inline void renderLeds(bool newFrame)
{
if (newFrame)
readyToRender = true;

if (readyToRender &&
(ledStrip1 != nullptr && ledStrip1->CanShow()))
{
statistics.increaseShow();
readyToRender = false;

// display segments
ledStrip1->Show(false);
}
}

inline bool setStripPixel(uint16_t pix, ColorDefinition &inputColor)
{
if (pix < ledsNumber)
{
ledStrip1->SetPixelColor(pix, inputColor);
}

return (pix + 1 < ledsNumber);
}
} base;

#endif
105 changes: 79 additions & 26 deletions include/calibration.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,48 +25,48 @@
* SOFTWARE.
*/

#ifndef CALIBRATION_H
#ifdef NEOPIXEL_RGBW
typedef RgbwColor ColorDefinition;
#else
typedef RgbColor ColorDefinition;
#endif


#if !defined(CALIBRATION_H) && (defined(NEOPIXEL_RGBW) || defined(HYPERSERIAL_TESTING))
#define CALIBRATION_H

#include <stdint.h>
#include <algorithm>

#define ROUND_DIVIDE(numer, denom) (((numer) + (denom) / 2) / (denom))

struct {
uint8_t white[256];
uint8_t red[256];
uint8_t green[256];
uint8_t blue[256];
struct
{
uint8_t white[256];
uint8_t red[256];
uint8_t green[256];
uint8_t blue[256];
} channelCorrection;

struct {
uint8_t gain = 0xFF;
#ifdef COLD_WHITE
uint8_t red = 0xA0; // adjust red -> white in 0-0xFF range
uint8_t green = 0xA0; // adjust green -> white in 0-0xFF range
uint8_t blue = 0xA0; // adjust blue -> white in 0-0xFF range
#else
uint8_t red = 0xB0; // adjust red -> white in 0-0xFF range
uint8_t green = 0xB0; // adjust green -> white in 0-0xFF range
uint8_t blue = 0x70; // adjust blue -> white in 0-0xFF range
#endif

void setParams(uint8_t _gain, uint8_t _red, uint8_t _green, uint8_t _blue)
{
gain = _gain;
red = _red;
green = _green;
blue = _blue;
}
class CalibrationConfig
{
// calibration parameters
uint8_t gain = 0xFF;
uint8_t red = 0xA0;
uint8_t green = 0xA0;
uint8_t blue = 0xA0;

/**
* @brief Build the LUT table using provided parameters
*
*/
void prepareCalibration()
{
// prepare LUT calibration table, cold white is much better than "neutral" white
for (uint32_t i = 0; i < 256; i++)
{
// color calibration
uint32_t _gain = uint32_t(gain) * i; // adjust gain
uint32_t _gain = gain * i; // adjust gain
uint32_t _red = red * i; // adjust red
uint32_t _green = green * i; // adjust green
uint32_t _blue = blue * i; // adjust blue
Expand All @@ -77,6 +77,59 @@ struct {
channelCorrection.blue[i] = (uint8_t)std::min(ROUND_DIVIDE(_blue, 0xFF), (uint32_t)0xFF);
}
}

public:
CalibrationConfig()
{
prepareCalibration();
}

/**
* @brief Compare base calibration settings
*
*/
bool compareCalibrationSettings(uint8_t _gain, uint8_t _red, uint8_t _green, uint8_t _blue)
{
return _gain == gain && _red == red && _green == green && _blue == blue;
}

/**
* @brief Set the parameters that define RGB to RGBW transformation
*
* @param _gain
* @param _red
* @param _green
* @param _blue
*/
void setParamsAndPrepareCalibration(uint8_t _gain, uint8_t _red, uint8_t _green, uint8_t _blue)
{
if (gain != _gain || red != _red || green != _green || blue != _blue)
{
gain = _gain;
red = _red;
green = _green;
blue = _blue;
prepareCalibration();
}
}

/**
* @brief print RGBW calibration parameters when no data is received
*
*/
void printCalibration()
{
#ifdef SerialPort
SerialPort.write("\r\nRGBW => Gain: ");
SerialPort.print(gain);
SerialPort.write("/255, red: ");
SerialPort.print(red);
SerialPort.write(" , green: ");
SerialPort.print(green);
SerialPort.write(" , blue: ");
SerialPort.print(blue);
#endif
}
} calibrationConfig;
#endif

Loading

0 comments on commit 2634681

Please sign in to comment.