├── .github ├── dependabot.yml └── workflows │ ├── esp-idf-with-gfx.yml │ ├── esp-idf-without-gfx.yml │ └── pio_arduino_build.yml ├── CMakeLists.txt ├── Kconfig.projbuild ├── LICENSE.txt ├── README.md ├── component.mk ├── doc ├── BuildOptions.md ├── Panel_Chaining_Types.ods ├── ScanRateGraphic.jpg ├── ScanRateGraphic.odp ├── VirtualMatrixPanel.odp ├── VirtualMatrixPanel.pdf ├── fillrate.md ├── memcalc.jpg ├── memcalc.md └── memcalc.xlsm ├── examples ├── 1_SimpleTestShapes │ └── 1_SimpleTestShapes.ino ├── 2_PatternPlasma │ ├── 2_PatternPlasma.ino │ ├── PatternWave.jpg │ └── README.md ├── 3_DoubleBuffer │ └── 3_DoubleBuffer.ino ├── 4_OtherShiftDriverPanel │ ├── 4_OtherShiftDriverPanel.ino │ ├── FM6126A.md │ └── README.md ├── AnimatedGIFPanel_LittleFS │ ├── AnimatedGIFPanel_LittleFS.ino │ ├── README.md │ └── data │ │ └── gifs │ │ ├── cartoon.gif │ │ ├── ezgif.com-pacmn.gif │ │ ├── loading.io-64x32px.gif │ │ ├── matrix-spin.gif │ │ ├── parasite1.gif │ │ ├── parasite2.gif │ │ └── shock-gs.gif ├── AnimatedGIFPanel_SD │ ├── AnimatedGIFPanel_SD.ino │ ├── Readme.md │ ├── esp32_sdcard.jpg │ ├── gif_functions.hpp │ ├── gifs │ │ ├── cartoon.gif │ │ ├── ezgif.com-pacmn.gif │ │ ├── loading.io-64x32px.gif │ │ ├── matrix-spin.gif │ │ ├── parasite1.gif │ │ ├── parasite2.gif │ │ └── shock-gs.gif │ └── sdcard_functions.hpp ├── AuroraDemo │ ├── Attractor.hpp │ ├── AuroraDemo.ino │ ├── Boid.hpp │ ├── Drawable.hpp │ ├── EffectsLayer.hpp │ ├── Geometry.hpp │ ├── PatternAttract.hpp │ ├── PatternBounce.hpp │ ├── PatternCube.hpp │ ├── PatternElectricMandala.hpp │ ├── PatternFireKoz.hpp │ ├── PatternFireworks.hpp │ ├── PatternFlock.hpp │ ├── PatternFlowField.hpp │ ├── PatternGreenScroll.hpp │ ├── PatternIncrementalDrift.hpp │ ├── PatternIncrementalDrift2.hpp │ ├── PatternInfinity.hpp │ ├── PatternJuliaSetFractal.hpp │ ├── PatternMaze.hpp │ ├── PatternMunch.hpp │ ├── PatternNoiseSmearing.hpp │ ├── PatternPendulumWave.hpp │ ├── PatternPlasma.hpp │ ├── PatternRadar.hpp │ ├── PatternRain.hpp │ ├── PatternSimplexNoise.hpp │ ├── PatternSnake.hpp │ ├── PatternSpin.hpp │ ├── PatternSpiral.hpp │ ├── PatternSpiro.hpp │ ├── PatternStarfield.hpp │ ├── PatternTest.hpp │ ├── PatternWave.hpp │ ├── Patterns.hpp │ ├── README.md │ └── Vector2.hpp ├── BitmapIcons │ ├── BitmapIcons.ino │ ├── Dhole_weather_icons32px.h │ ├── README.md │ ├── WiFi1bit.bmp │ ├── bmp2hex.py │ └── screenshot.jpg ├── HueValueSpectrum │ └── HueValueSpectrum.ino ├── PIO_TestPatterns │ ├── README.md │ ├── platformio.ini │ ├── sdkconfig.defaults │ └── src │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ └── main.h ├── Pixel_Mapping_Test │ ├── Pixel_Mapping_Test.ino │ └── README.md ├── README.md ├── ScrollingTextLayer │ └── ScrollingTextLayer.ino ├── VirtualMatrixPanel │ ├── README.md │ └── VirtualMatrixPanel.ino └── esp-idf │ ├── .gitignore │ ├── with-gfx │ ├── CMakeLists.txt │ ├── README.md │ ├── components │ │ └── .gitignore │ ├── main │ │ ├── CMakeLists.txt │ │ └── main.cpp │ └── sdkconfig.defaults │ └── without-gfx │ ├── CMakeLists.txt │ ├── README.md │ ├── components │ └── .gitignore │ ├── main │ ├── CMakeLists.txt │ └── main.cpp │ └── sdkconfig.defaults ├── image.jpg ├── keywords.txt ├── library.json ├── library.properties ├── src ├── ESP32-HUB75-MatrixPanel-I2S-DMA.cpp ├── ESP32-HUB75-MatrixPanel-I2S-DMA.h ├── ESP32-HUB75-MatrixPanel-leddrivers.cpp ├── ESP32-HUB75-VirtualMatrixPanel_T.hpp ├── ESP32-VirtualMatrixPanel-I2S-DMA.h └── platforms │ ├── esp32 │ ├── RGB_HUB75_PINS.png │ ├── esp32-default-pins.hpp │ ├── esp32_i2s_parallel_dma.cpp │ └── esp32_i2s_parallel_dma.hpp │ ├── esp32c6 │ ├── dma_parallel_io.cpp.notused │ ├── dma_parallel_io.hpp.notused │ └── esp32c6-default-pins.hpp.notused │ ├── esp32s2 │ └── esp32s2-default-pins.hpp │ ├── esp32s3 │ ├── ESP32-S3-DevKitC-1-pin-layout.png │ ├── Readme.md │ ├── ReservedPinsForPSRAM.PNG │ ├── esp32s3-default-pins.hpp │ ├── gdma_lcd_parallel16.cpp │ └── gdma_lcd_parallel16.hpp │ └── platform_detect.hpp └── testing ├── README.md ├── baseline.hpp ├── four_scan_40_80px_hfarcan.cpp └── virtual.cpp /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/esp-idf-with-gfx.yml: -------------------------------------------------------------------------------- 1 | name: esp-idf with Adafruit GFX Library 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - '**.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | build: 15 | name: esp-idf v5.3.2 with Adafruit GFX 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout repo 21 | uses: actions/checkout@v4 22 | with: 23 | submodules: 'recursive' 24 | - name: Checkout ESP32-HUB75-MatrixPanel-I2S-DMA component 25 | uses: actions/checkout@v4 26 | with: 27 | path: 'examples/esp-idf/with-gfx/components/ESP32-HUB75-MatrixPanel-I2S-DMA' 28 | - name: Checkout Adafruit-GFX-Library repo 29 | uses: actions/checkout@v4 30 | with: 31 | repository: 'adafruit/Adafruit-GFX-Library' 32 | path: 'examples/esp-idf/with-gfx/components/Adafruit-GFX-Library' 33 | - name: Checkout Adafruit_BusIO repo 34 | uses: actions/checkout@v4 35 | with: 36 | repository: 'adafruit/Adafruit_BusIO' 37 | path: 'examples/esp-idf/with-gfx/components/Adafruit_BusIO' 38 | - name: Checkout arduino-esp32 repo 39 | uses: actions/checkout@v4 40 | with: 41 | repository: 'espressif/arduino-esp32' 42 | ref: 3.1.3 43 | path: 'examples/esp-idf/with-gfx/components/arduino' 44 | - name: Edit Adafruit_BusIO CMakeLists.txt 45 | run: sed -i 's/arduino-esp32)/arduino)/g' examples/esp-idf/with-gfx/components/Adafruit_BusIO/CMakeLists.txt 46 | - name: esp-idf build 47 | uses: espressif/esp-idf-ci-action@v1 48 | with: 49 | esp_idf_version: v5.3.2 50 | target: esp32 51 | path: 'examples/esp-idf/with-gfx' 52 | -------------------------------------------------------------------------------- /.github/workflows/esp-idf-without-gfx.yml: -------------------------------------------------------------------------------- 1 | name: esp-idf without Adafruit GFX Library 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - 'doc/**' 8 | pull_request: 9 | paths-ignore: 10 | - '**.md' 11 | - 'doc/**' 12 | 13 | jobs: 14 | build: 15 | name: esp-idf 5.1.4 without Adafruit GFX 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout repo 21 | uses: actions/checkout@v4 22 | with: 23 | submodules: 'recursive' 24 | - name: Checkout ESP32-HUB75-MatrixPanel-I2S-DMA component 25 | uses: actions/checkout@v4 26 | with: 27 | path: 'examples/esp-idf/without-gfx/components/ESP32-HUB75-MatrixPanel-I2S-DMA' 28 | - name: esp-idf build 29 | uses: espressif/esp-idf-ci-action@v1 30 | with: 31 | esp_idf_version: v5.1.4 32 | target: esp32 33 | path: 'examples/esp-idf/without-gfx' 34 | -------------------------------------------------------------------------------- /.github/workflows/pio_arduino_build.yml: -------------------------------------------------------------------------------- 1 | # Build examples with Platformio 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | # https://docs.platformio.org/en/latest/integration/ci/github-actions.html 4 | 5 | name: PlatformIO 6.1.17 Arduino CI 6 | 7 | on: 8 | push: 9 | branches: [ master, dev ] 10 | paths-ignore: 11 | - '**.md' 12 | - 'doc/**' 13 | pull_request: 14 | branches: [ master, dev ] 15 | paths-ignore: 16 | - '**.md' 17 | - 'doc/**' 18 | 19 | jobs: 20 | build: 21 | 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | framework: ["Arduino", "IDF"] 26 | no_gfx: ["", -DNO_GFX] 27 | # no_fast_functions: ["", -DNO_FAST_FUNCTIONS] 28 | # no_cie1931: ["", -DNO_CIE1931] 29 | # virtual_panel: ["", -DVIRTUAL_PANE] 30 | example: 31 | - "examples/PIO_TestPatterns" 32 | # exclude: 33 | # - no_fast_functions: "" 34 | # virtual_panel: -DVIRTUAL_PANE 35 | 36 | steps: 37 | - name: Checkout 38 | uses: actions/checkout@v4 39 | - name: Cache pip and platformio 40 | uses: actions/cache@v4 41 | with: 42 | path: | 43 | ~/.cache/pip 44 | ~/.platformio/.cache 45 | key: ${{ runner.os }}-pio 46 | - name: Set up Python 3.x 47 | uses: actions/setup-python@v5 48 | with: 49 | python-version: '3.x' 50 | - name: Install Platformio 51 | run: pip install --upgrade platformio==6.1.17 52 | - name: Run PlatformIO CI (Arduino) 53 | if: ${{ matrix.framework == 'Arduino'}} 54 | env: 55 | PLATFORMIO_BUILD_FLAGS: ${{ matrix.no_gfx }} ${{ matrix.no_fast_functions }} ${{ matrix.no_cie1931 }} ${{ matrix.virtual_panel }} 56 | PLATFORMIO_CI_SRC: ${{ matrix.example }} 57 | run: pio ci -e esp32 -c ${{ matrix.example }}/platformio.ini 58 | - name: Run PlatformIO CI (ESP-IDF) 59 | if: ${{ matrix.framework == 'IDF'}} 60 | env: 61 | PLATFORMIO_BUILD_FLAGS: -DIDF_BUILD ${{ matrix.no_gfx }} ${{ matrix.no_fast_functions }} ${{ matrix.no_cie1931 }} ${{ matrix.virtual_panel }} 62 | # pio ci doesn't use our sdkconfig, so we have to use pio run 63 | #run: pio run -d ${{ matrix.example }} -e esp32idf -c ${{ matrix.example }}/platformio.ini 64 | run: pio run -d ${{ matrix.example }} 65 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # HUB75 RGB LED matrix library utilizing ESP32 DMA Engine 2 | # https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA 3 | # MIT License 4 | 5 | cmake_minimum_required(VERSION 3.5) 6 | idf_build_get_property(target IDF_TARGET) 7 | 8 | if(ARDUINO_ARCH_ESP32 OR CONFIG_ESP32_HUB75_USE_GFX) 9 | list(APPEND build_dependencies arduino Adafruit-GFX-Library) 10 | else() 11 | list(APPEND build_dependencies esp_lcd driver) 12 | endif() 13 | 14 | if(${target} STREQUAL "esp32s3") 15 | list(APPEND extra_srcs src/platforms/${target}/gdma_lcd_parallel16.cpp) 16 | 17 | # Required by gdma_lcd_parallel16.cpp 18 | if (NOT esp_lcd IN_LIST build_dependencies) 19 | list(APPEND build_dependencies esp_lcd) 20 | endif() 21 | endif() 22 | 23 | idf_component_register(SRCS "src/platforms/esp32/esp32_i2s_parallel_dma.cpp" "src/ESP32-HUB75-MatrixPanel-I2S-DMA.cpp" "src/ESP32-HUB75-MatrixPanel-leddrivers.cpp" ${extra_srcs} 24 | INCLUDE_DIRS "./src" 25 | ) 26 | 27 | # Dependencies cannot be added to the REQUIRES argument of `idf_component_register` because (according to the build process 28 | # listed at https://docs.espressif.com/projects/esp-idf/en/v4.2/esp32/api-guides/build-system.html#build-process) 29 | # `idf_component_register` is processed during the "Enumeration" stage which happens before the sdkconfig file is loaded 30 | # in the "Processing" stage. So if dependencies are going to be loaded based on certain CONFIG_* variables we must 31 | # use `target_link_libraries` instead. This is the method used by Arduino's CMakeLists.txt file. 32 | idf_build_get_property(components BUILD_COMPONENTS) 33 | foreach(component_name IN LISTS build_dependencies) 34 | if (NOT ${component_name} IN_LIST components) 35 | message(FATAL_ERROR "Missing component: ${component_name}") 36 | endif() 37 | idf_component_get_property(lib_name ${component_name} COMPONENT_LIB) 38 | target_link_libraries(${COMPONENT_LIB} PUBLIC ${lib_name}) 39 | endforeach() 40 | 41 | # In case you are running into issues with "missing" header files from 3rd party libraries 42 | # you can add them to the REQUIRES section above. If you use some of the build options below 43 | # you probably want to remove (NO_GFX) or replace Adafruit-GFX-Library (USE_GFX_ROOT) 44 | 45 | # Example to build with USE_GFX_ROOT or NO_GFX / just uncomment the appropriate line 46 | # target_compile_options(${COMPONENT_TARGET} PUBLIC -DUSE_GFX_ROOT) 47 | # target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX) 48 | 49 | # esp-idf does not have any GFX library support yet, so we need to define NO_GFX 50 | if(ARDUINO_ARCH_ESP32 OR CONFIG_ESP32_HUB75_USE_GFX) 51 | else() 52 | target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX) 53 | if(${target} STREQUAL "esp32s3") 54 | # Don't enable PSRAM based framebuffer just because it's an S3. 55 | # This is an advanced option and should only be used with an S3 with Octal-SPI RAM. 56 | # target_compile_options(${COMPONENT_TARGET} PUBLIC -DSPIRAM_FRAMEBUFFER) 57 | target_compile_options(${COMPONENT_TARGET} PUBLIC) 58 | endif() 59 | endif() 60 | 61 | # You can also use multiple options like this 62 | # target_compile_options(${COMPONENT_TARGET} PUBLIC -DNO_GFX -DNO_FAST_FUNCTIONS) 63 | 64 | # All options can be found here: 65 | # https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/blob/master/doc/BuildOptions.md 66 | 67 | project(ESP32-HUB75-MatrixPanel-I2S-DMA) 68 | -------------------------------------------------------------------------------- /Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "ESP32 HUB75 Configuration" 2 | 3 | config ESP32_HUB75_USE_GFX 4 | bool "Use Adafruit GFX library." 5 | default y 6 | help 7 | This option enables use of the Adafruit GFX library using the `Adafruit-GFX-Library` component. 8 | 9 | endmenu 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2032 Faptastic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /component.mk: -------------------------------------------------------------------------------- 1 | COMPONENT_ADD_INCLUDEDIRS = . 2 | -------------------------------------------------------------------------------- /doc/BuildOptions.md: -------------------------------------------------------------------------------- 1 | ### Build Options and flags 2 | 3 | This library supports build-time defines to modify its features or enable greater debugging information. Please use the debugging capabilities before raising any issues. 4 | 5 | For example build flags could be set using PlatformIO's .ini file like this 6 | 7 | ``` 8 | [env] 9 | framework = arduino 10 | platform = espressif32 11 | lib_deps = 12 | ESP32 HUB75 LED MATRIX PANEL DMA Display 13 | build_flags = 14 | -DCORE_DEBUG_LEVEL=3 15 | -DNO_GFX=1 16 | (etc.....) 17 | ``` 18 | Or if using Arduino: 'Tools' menu > 'Core Debug Level' > Select 'Debug' 19 | 20 | ... and use the Serial output to see the debug information. 21 | 22 | ## Build flags 23 | 24 | | Flag | Description | Note | 25 | | :------------ |---------------|-----| 26 | | **CORE_DEBUG_LEVEL** |Adjust the espressif ESP32 IDF debug level, for which this library leverages to output information on what is going on when allocating memory etc. This will provide detailed information about memory allocations, DMA descriptors setup and color depth [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm) |Set value to at least 3 [(Info)](https://iotespresso.com/core-debug-level-in-esp32/) 27 | | **USE_GFX_ROOT** | Use [lightweight](https://github.com/mrfaptastic/Adafruit_GFX_Lite) version of AdafuitGFX, without Adafruit BusIO extensions | You **must** install [Adafruit_GFX_Lite](https://github.com/mrfaptastic/Adafruit_GFX_Lite) library instead of original AdafruitGFX| 28 | | **NO_GFX** | Build without AdafuitGFX API, only native methods supported based on manipulating DMA buffer. I.e. no methods of drawing circles/shapes, typing text or using fonts!!! This might save some resources for applications using it's own internal graphics buffer or working solely with per-pixel manipulation. | Use this if you rely on FastLED, Neomatrix or any other API. For example [Aurora](/examples/AuroraDemo/) effects can work fine w/o AdafruitGFX. | 29 | | **NO_FAST_FUNCTIONS** | Do not build auxiliary speed-optimized functions. Those are used to speed-up operations like drawing straight lines or rectangles. Otherwise lines/shapes are drawn using drawPixel() method. The trade-off for speed is RAM/code-size, take it or leave it ;) | If you are not using AdafruitGFX than you probably do not need this either| 30 | |**NO_CIE1931**|Do not use LED brightness [compensation](https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/) described in [CIE 1931](https://en.wikipedia.org/wiki/CIE_1931_color_space). Normally library would adjust every pixel's RGB888 so that luminance (or brightness control) for the corresponding LED's would appear 'linear' to the human's eye. I.e. a white dot with rgb(128,128,128) would seem to be at 50% brightness between rgb(0,0,0) and rgb(255,255,255). Normally you would like to keep this enabled by default. Not only it makes brightness control "linear", it also makes colours more vivid, otherwise it looks brighter but 'bleached'.|You might want to turn it off in some special cases like: | 31 | | **FORCE_COLOR_DEPTH** |In some cases the library may reduce colour fidelity to increase the refresh rate (i.e. reduce visible flicker). This is most likely to occur with a large chain of panels. However, if you want to force pure 24bpp colour, at the expense of likely noticeable flicker, then set this defined. |Not required in 99% of cases. 32 | | **SPIRAM_FRAMEBUFFER** |Use SPIRAM/PSRAM for the HUB75 DMA buffer and not internal SRAM. ONLY SUPPORTED ON ESP32-S3 VARIANTS WITH OCTAL (not quad!) SPIRAM/PSRAM, as ony OCTAL PSRAM an provide the required data rate / bandwidth to drive the panels adequately.|ONLY SUPPORTED ON ESP32-S3 VARIANTS WITH OCTAL (not quad) SPIRAM/PSRAM 33 | 34 | ## Build-time variables 35 | 36 | | Flag | Description | Note | 37 | | :------------ |---------------|-----| 38 | | **PIXEL_COLOR_DEPTH_BITS=8** | Colour depth per pixel in range 2-8. More bit's - more natural colour. But on the other hand every additional bit: | For large chains of panels (i.e. 6 x 64x64 panels) you WILL need to reduce the colour depth, or likely run out of memory. Default is 8 bits per colour per pixel, i.e. True colour 24 bit RGB.

For higher resolutions, from 64x64 and above it is not possible to provide full 24 bits colour without significant flickering OR reducing dynamic range in shadows. In that case using 5-6 bits at high res make very small difference to the human’s eye actually. Refer to the [I2S memcalc](i2s_memcalc.md) for more details. 39 | -------------------------------------------------------------------------------- /doc/Panel_Chaining_Types.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/doc/Panel_Chaining_Types.ods -------------------------------------------------------------------------------- /doc/ScanRateGraphic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/doc/ScanRateGraphic.jpg -------------------------------------------------------------------------------- /doc/ScanRateGraphic.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/doc/ScanRateGraphic.odp -------------------------------------------------------------------------------- /doc/VirtualMatrixPanel.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/doc/VirtualMatrixPanel.odp -------------------------------------------------------------------------------- /doc/VirtualMatrixPanel.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/doc/VirtualMatrixPanel.pdf -------------------------------------------------------------------------------- /doc/fillrate.md: -------------------------------------------------------------------------------- 1 | ## Estimating fillrate 2 | 3 | Here are some results of simple tests on filling DMA buffer with data. 4 | Filling DMA buffer requires lots of memory operations on a bit level rather than doing simple byte/word wide store and copy. And it looks like it's quite a task both for esp32 core and compiler. 5 | I've done this while optimizing loops and bit logic along with testing compiler results. 6 | 7 | So the testbed is: 8 | - Matrix modules: 4 x FM6126A based 64x64 modules chained in 256x64 9 | 10 | A testpatterns sketch: 11 | - allocating single DMA buffs for 256x64 12 | - allocating (NUM_LEDS*3) bytes for CRGB buffer 13 | - measuring microseconds for the following calls: 14 | - clearScreen() - full blanking 15 | - fillScreenRGB888() with monochrome/gray colors 16 | - fill screen using drawPixel() 17 | - filling some gradient into CRGB buff 18 | - painting CRGB buff into DMA buff with looped drawPixelRGB888() 19 | - drawing lines 20 | 21 | 22 | ||clearScreen()|drawPixelRGB888(), ticks|fillScreen()|fillScreen with a drawPixel()|fillRect() over Matrix|V-line with drawPixel|fast-V-line|H-line with drawPixel|fast-H-line| 23 | |--|--|--|--|--|--|--|--|--|--| 24 | |v1.2.4|1503113 ticks|9244 non-cached, 675 cached|1719 us, 412272 t|47149 us, 11315418 ticks|-|24505 us, 5880209 ticks|-|24200 us|-| 25 | |FastLines|1503113 ticks|1350 non-cached, 405 cached|1677 us, 401198 t|28511 us, 6841440 ticks|10395 us|14462 us, 3469605 ticks|10391 us, 2492743 ticks|14575 us|5180 us, 1242041 ticks| 26 | 27 | to be continued... -------------------------------------------------------------------------------- /doc/memcalc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/doc/memcalc.jpg -------------------------------------------------------------------------------- /doc/memcalc.md: -------------------------------------------------------------------------------- 1 | ### Memory Calculator 2 | 3 | I've made this [spreadsheet](memcalc.xlsm) to estimate all of the main parameters for ESP32-HUB75-MatrixPanel-DMA lib driving any combination of matrices/chains so that I do not need to reflash it hundreds of times just to check for the debug info about memory. 4 | Be sure to enable embedded macro's to allow refresh rate calculations. 5 | 6 | ![](i2scalc.png) 7 | Just fill-in all of the INPUT fields and get the OUTPUTs. 8 | 9 | So there are two main resources used to drive LED matrix 10 | - Memory 11 | - Bus clock speed (resulting in available bandwidth to pump pixel color data) 12 | 13 | And there are lot's of hogs for those: 14 | - matrix resolution (number of pixels) 15 | - number of modules in chain 16 | - pixel color depth 17 | - [BCM](http://www.batsocks.co.uk/readme/art_bcm_5.htm) LSB to MSB transition 18 | - double buffering 19 | 20 | Equalising ones with the others results in **Refresh rate**, 21 | 22 | or (rough approximation) 23 | 24 | 25 | [//]: # (github markdown does not like LaTex formulas) 26 | [//]: # ($$RefreshRate=\frac{resolution \times chain \times (ColorDepth-LSB2MSB)}{ I ^2S _ {clock} }$$) 27 | 28 | So, how to find optimum balance for all of these? Obviously you can't change *resolution* and *chain length*, it is physical characteristics and there is not much you can do about it except cutting off your chain or pushing it to the memory limits. 29 | 30 | There are 3 parameters you can choose from (actually two:) 31 | - **Color Depth** - predefined at [build-time](/doc/BuildOptions.md) option 32 | 33 | - I2S clock speed - run-time tunable with a very limited options 34 | 35 | - **LSB-to-MSB** transition - it can't be controlled in any way, library uses it internally trying to balance all of the above 36 | 37 | Using provided table it is possible to estimate all of the parameters before running the library. Besides calculating memory requirements it could help to find **optimum color depth** for your matrix configuration. For higher resolutions default 8 bits could be too much to sustain minimal refresh rate and avoid annoying flickering. So the library would increase MSB transition to keep the balance, thus reducing dynamic range in shadows and dark colors. As a result it is nearly almost the same as just reducing overall color depth. **But** reducing global color depth would also save lot's of precious RAM! 38 | Now it's all up to you to decide :) 39 | 40 | /Vortigont/ 41 | -------------------------------------------------------------------------------- /doc/memcalc.xlsm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/doc/memcalc.xlsm -------------------------------------------------------------------------------- /examples/1_SimpleTestShapes/1_SimpleTestShapes.ino: -------------------------------------------------------------------------------- 1 | 2 | // Example sketch which shows how to display some patterns 3 | // on a 64x32 LED matrix 4 | // 5 | 6 | #include 7 | 8 | 9 | #define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module. 10 | #define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module. 11 | #define PANEL_CHAIN 1 // Total number of panels chained one to another 12 | 13 | //MatrixPanel_I2S_DMA dma_display; 14 | MatrixPanel_I2S_DMA *dma_display = nullptr; 15 | 16 | uint16_t myBLACK, myWHITE, myRED, myGREEN, myBLUE; 17 | 18 | // Input a value 0 to 255 to get a color value. 19 | // The colours are a transition r - g - b - back to r. 20 | // From: https://gist.github.com/davidegironi/3144efdc6d67e5df55438cc3cba613c8 21 | uint16_t colorWheel(uint8_t pos) { 22 | if(pos < 85) { 23 | return dma_display->color565(pos * 3, 255 - pos * 3, 0); 24 | } else if(pos < 170) { 25 | pos -= 85; 26 | return dma_display->color565(255 - pos * 3, 0, pos * 3); 27 | } else { 28 | pos -= 170; 29 | return dma_display->color565(0, pos * 3, 255 - pos * 3); 30 | } 31 | } 32 | 33 | void drawText(int colorWheelOffset) 34 | { 35 | 36 | // draw text with a rotating colour 37 | dma_display->setTextSize(1); // size 1 == 8 pixels high 38 | dma_display->setTextWrap(false); // Don't wrap at end of line - will do ourselves 39 | 40 | dma_display->setCursor(5, 0); // start at top left, with 8 pixel of spacing 41 | uint8_t w = 0; 42 | const char *str = "ESP32 DMA"; 43 | for (w=0; wsetTextColor(colorWheel((w*32)+colorWheelOffset)); 45 | dma_display->print(str[w]); 46 | } 47 | 48 | dma_display->println(); 49 | dma_display->print(" "); 50 | for (w=9; w<18; w++) { 51 | dma_display->setTextColor(colorWheel((w*32)+colorWheelOffset)); 52 | dma_display->print("*"); 53 | } 54 | 55 | dma_display->println(); 56 | 57 | dma_display->setTextColor(dma_display->color444(15,15,15)); 58 | dma_display->println("LED MATRIX!"); 59 | 60 | // print each letter with a fixed rainbow color 61 | dma_display->setTextColor(dma_display->color444(0,8,15)); 62 | dma_display->print('3'); 63 | dma_display->setTextColor(dma_display->color444(15,4,0)); 64 | dma_display->print('2'); 65 | dma_display->setTextColor(dma_display->color444(15,15,0)); 66 | dma_display->print('x'); 67 | dma_display->setTextColor(dma_display->color444(8,15,0)); 68 | dma_display->print('6'); 69 | dma_display->setTextColor(dma_display->color444(8,0,15)); 70 | dma_display->print('4'); 71 | 72 | // Jump a half character 73 | dma_display->setCursor(34, 24); 74 | dma_display->setTextColor(dma_display->color444(0,15,15)); 75 | dma_display->print("*"); 76 | dma_display->setTextColor(dma_display->color444(15,0,0)); 77 | dma_display->print('R'); 78 | dma_display->setTextColor(dma_display->color444(0,15,0)); 79 | dma_display->print('G'); 80 | dma_display->setTextColor(dma_display->color444(0,0,15)); 81 | dma_display->print("B"); 82 | dma_display->setTextColor(dma_display->color444(15,0,8)); 83 | dma_display->println("*"); 84 | 85 | } 86 | 87 | 88 | void setup() { 89 | 90 | // Module configuration 91 | HUB75_I2S_CFG mxconfig( 92 | PANEL_RES_X, // module width 93 | PANEL_RES_Y, // module height 94 | PANEL_CHAIN // Chain length 95 | ); 96 | 97 | //mxconfig.gpio.e = 18; 98 | //mxconfig.clkphase = false; 99 | //mxconfig.driver = HUB75_I2S_CFG::FM6126A; 100 | 101 | // Display Setup 102 | dma_display = new MatrixPanel_I2S_DMA(mxconfig); 103 | dma_display->begin(); 104 | dma_display->setBrightness8(90); //0-255 105 | dma_display->clearScreen(); 106 | 107 | myBLACK = dma_display->color565(0, 0, 0); 108 | myWHITE = dma_display->color565(255, 255, 255); 109 | myRED = dma_display->color565(255, 0, 0); 110 | myGREEN = dma_display->color565(0, 255, 0); 111 | myBLUE = dma_display->color565(0, 0, 255); 112 | 113 | 114 | dma_display->fillScreen(myWHITE); 115 | 116 | // fix the screen with green 117 | dma_display->fillRect(0, 0, dma_display->width(), dma_display->height(), dma_display->color444(0, 15, 0)); 118 | delay(500); 119 | 120 | // draw a box in yellow 121 | dma_display->drawRect(0, 0, dma_display->width(), dma_display->height(), dma_display->color444(15, 15, 0)); 122 | delay(500); 123 | 124 | // draw an 'X' in red 125 | dma_display->drawLine(0, 0, dma_display->width()-1, dma_display->height()-1, dma_display->color444(15, 0, 0)); 126 | dma_display->drawLine(dma_display->width()-1, 0, 0, dma_display->height()-1, dma_display->color444(15, 0, 0)); 127 | delay(500); 128 | 129 | // draw a blue circle 130 | dma_display->drawCircle(10, 10, 10, dma_display->color444(0, 0, 15)); 131 | delay(500); 132 | 133 | // fill a violet circle 134 | dma_display->fillCircle(40, 21, 10, dma_display->color444(15, 0, 15)); 135 | delay(500); 136 | 137 | // fill the screen with 'black' 138 | dma_display->fillScreen(dma_display->color444(0, 0, 0)); 139 | 140 | //drawText(0); 141 | 142 | } 143 | 144 | uint8_t wheelval = 0; 145 | void loop() { 146 | 147 | // animate by going through the colour wheel for the first two lines 148 | drawText(wheelval); 149 | wheelval +=1; 150 | 151 | delay(20); 152 | /* 153 | drawText(0); 154 | delay(2000); 155 | dma_display->clearScreen(); 156 | dma_display->fillScreen(myBLACK); 157 | delay(2000); 158 | dma_display->fillScreen(myBLUE); 159 | delay(2000); 160 | dma_display->fillScreen(myRED); 161 | delay(2000); 162 | dma_display->fillScreen(myGREEN); 163 | delay(2000); 164 | dma_display->fillScreen(myWHITE); 165 | dma_display->clearScreen(); 166 | */ 167 | 168 | } 169 | -------------------------------------------------------------------------------- /examples/2_PatternPlasma/PatternWave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/2_PatternPlasma/PatternWave.jpg -------------------------------------------------------------------------------- /examples/2_PatternPlasma/README.md: -------------------------------------------------------------------------------- 1 | # Wave Pattern 2 | 3 | Demo of the colours, and the little flicker. 4 | 5 | ![It's better in real life](PatternWave.jpg) 6 | -------------------------------------------------------------------------------- /examples/3_DoubleBuffer/3_DoubleBuffer.ino: -------------------------------------------------------------------------------- 1 | /** 2 | Example uses the following configuration: mxconfig.double_buff = true; 3 | to enable double buffering, which means display->flipDMABuffer(); is required. 4 | 5 | Bounce squares around the screen, doing the re-drawing in the background back-buffer. 6 | 7 | Double buffering is not usually required. It is only useful when you have a long (in duration) 8 | drawing routine that you want to 'flip to' once complete without the drawing being visible to 9 | the naked eye when looking at the HUB75 panel. 10 | 11 | Please note that double buffering isn't a silver bullet, and may still result in flickering 12 | if you end up 'flipping' the buffer quicker than the physical HUB75 refresh output rate. 13 | 14 | Refer to the runtime debug output to see, i.e: 15 | 16 | [ 2103][I][ESP32-HUB75-MatrixPanel-I2S-DMA.cpp:85] setupDMA(): [I2S-DMA] Minimum visual refresh rate (scan rate from panel top to bottom) requested: 60 Hz 17 | [ 2116][W][ESP32-HUB75-MatrixPanel-I2S-DMA.cpp:105] setupDMA(): [I2S-DMA] lsbMsbTransitionBit of 0 gives 57 Hz refresh rate. 18 | [ 2128][W][ESP32-HUB75-MatrixPanel-I2S-DMA.cpp:105] setupDMA(): [I2S-DMA] lsbMsbTransitionBit of 1 gives 110 Hz refresh rate. 19 | [ 2139][W][ESP32-HUB75-MatrixPanel-I2S-DMA.cpp:118] setupDMA(): [I2S-DMA] lsbMsbTransitionBit of 1 used to achieve refresh rate of 60 Hz. 20 | 21 | **/ 22 | 23 | 24 | #include 25 | #include 26 | 27 | MatrixPanel_I2S_DMA *display = nullptr; 28 | 29 | constexpr std::size_t color_num = 5; 30 | using colour_arr_t = std::array; 31 | 32 | uint16_t myDARK, myWHITE, myRED, myGREEN, myBLUE; 33 | colour_arr_t colours; 34 | 35 | struct Square 36 | { 37 | float xpos, ypos; 38 | float velocityx; 39 | float velocityy; 40 | boolean xdir, ydir; 41 | uint16_t square_size; 42 | uint16_t colour; 43 | }; 44 | 45 | const int numSquares = 25; 46 | Square Squares[numSquares]; 47 | 48 | void setup() 49 | { 50 | // put your setup code here, to run once: 51 | delay(1000); 52 | Serial.begin(115200); 53 | delay(200); 54 | 55 | Serial.println("...Starting Display"); 56 | HUB75_I2S_CFG mxconfig; 57 | mxconfig.double_buff = true; // <------------- Turn on double buffer 58 | //mxconfig.clkphase = false; // <------------- Turn off double buffer and it'll look flickery 59 | 60 | // OK, now we can create our matrix object 61 | display = new MatrixPanel_I2S_DMA(mxconfig); 62 | display->begin(); // setup display with pins as pre-defined in the library 63 | 64 | myDARK = display->color565(64, 64, 64); 65 | myWHITE = display->color565(192, 192, 192); 66 | myRED = display->color565(255, 0, 0); 67 | myGREEN = display->color565(0, 255, 0); 68 | myBLUE = display->color565(0, 0, 255); 69 | 70 | colours = {{ myDARK, myWHITE, myRED, myGREEN, myBLUE }}; 71 | 72 | // Create some random squares 73 | for (int i = 0; i < numSquares; i++) 74 | { 75 | Squares[i].square_size = random(2,10); 76 | Squares[i].xpos = random(0, display->width() - Squares[i].square_size); 77 | Squares[i].ypos = random(0, display->height() - Squares[i].square_size); 78 | Squares[i].velocityx = static_cast (rand()) / static_cast (RAND_MAX); 79 | Squares[i].velocityy = static_cast (rand()) / static_cast (RAND_MAX); 80 | 81 | int random_num = random(6); 82 | Squares[i].colour = colours[random_num]; 83 | } 84 | } 85 | 86 | void loop() 87 | { 88 | 89 | // Flip all future drawPixel calls to write to the back buffer which is NOT being displayed. 90 | display->flipDMABuffer(); 91 | 92 | // SUPER IMPORTANT: Wait at least long enough to ensure that a "frame" has been displayed on the LED Matrix Panel before the next flip! 93 | delay(1000/display->calculated_refresh_rate); 94 | 95 | // Now clear the back-buffer we are drawing to. 96 | display->clearScreen(); 97 | 98 | // This is here to demonstrate flicker if double buffering is disabled. Emulates a long draw routine that would typically occur after a 'clearscreen'. 99 | delay(25); 100 | 101 | 102 | for (int i = 0; i < numSquares; i++) 103 | { 104 | // Draw rect and then calculate 105 | display->fillRect(Squares[i].xpos, Squares[i].ypos, Squares[i].square_size, Squares[i].square_size, Squares[i].colour); 106 | 107 | if (Squares[i].square_size + Squares[i].xpos >= display->width()) { 108 | Squares[i].velocityx *= -1; 109 | } else if (Squares[i].xpos <= 0) { 110 | Squares[i].velocityx = abs (Squares[i].velocityx); 111 | } 112 | 113 | if (Squares[i].square_size + Squares[i].ypos >= display->height()) { 114 | Squares[i].velocityy *= -1; 115 | } else if (Squares[i].ypos <= 0) { 116 | Squares[i].velocityy = abs (Squares[i].velocityy); 117 | } 118 | 119 | Squares[i].xpos += Squares[i].velocityx; 120 | Squares[i].ypos += Squares[i].velocityy; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /examples/4_OtherShiftDriverPanel/4_OtherShiftDriverPanel.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * The library by default supports simple 'shift register' based panels 3 | * with A,B,C,D,E lines to select a specific row, but there are plenty 4 | * of examples of new chips coming on the market that work different. 5 | * 6 | * Please search through the project's issues. For some of these chips 7 | * (you will need to look at the back of your panel to identify), this 8 | * library has workarounds. This can be configured through using one of: 9 | 10 | // mxconfig.driver = HUB75_I2S_CFG::FM6126A; 11 | //mxconfig.driver = HUB75_I2S_CFG::ICN2038S; 12 | //mxconfig.driver = HUB75_I2S_CFG::FM6124; 13 | //mxconfig.driver = HUB75_I2S_CFG::MBI5124; 14 | */ 15 | 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | //////////////////////////////////////////////////////////////////// 22 | 23 | // Output resolution and panel chain length configuration 24 | #define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module. 25 | #define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module. 26 | #define PANEL_CHAIN 1 // Total number of panels chained one to another 27 | 28 | // placeholder for the matrix object 29 | MatrixPanel_I2S_DMA *dma_display = nullptr; 30 | 31 | /////////////////////////////////////////////////////////////// 32 | 33 | // FastLED variables for pattern output 34 | uint16_t time_counter = 0, cycles = 0, fps = 0; 35 | unsigned long fps_timer; 36 | 37 | CRGB currentColor; 38 | CRGBPalette16 palettes[] = {HeatColors_p, LavaColors_p, RainbowColors_p, RainbowStripeColors_p, CloudColors_p}; 39 | CRGBPalette16 currentPalette = palettes[0]; 40 | 41 | 42 | CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) { 43 | return ColorFromPalette(currentPalette, index, brightness, blendType); 44 | } 45 | 46 | void setup(){ 47 | 48 | HUB75_I2S_CFG mxconfig( 49 | PANEL_RES_X, // module width 50 | PANEL_RES_Y, // module height 51 | PANEL_CHAIN // Chain length 52 | ); 53 | 54 | // in case that we use panels based on FM6126A chip, we can set it here before creating MatrixPanel_I2S_DMA object 55 | mxconfig.driver = HUB75_I2S_CFG::FM6126A; 56 | //mxconfig.driver = HUB75_I2S_CFG::ICN2038S; 57 | //mxconfig.driver = HUB75_I2S_CFG::FM6124; 58 | //mxconfig.driver = HUB75_I2S_CFG::MBI5124; 59 | 60 | 61 | // OK, now we can create our matrix object 62 | dma_display = new MatrixPanel_I2S_DMA(mxconfig); 63 | 64 | // If you experience ghosting, you will need to reduce the brightness level, not all RGB Matrix 65 | // Panels are the same - some seem to display ghosting artefacts at lower brightness levels. 66 | // In the setup() function do something like: 67 | 68 | // let's adjust default brightness to about 75% 69 | dma_display->setBrightness8(192); // range is 0-255, 0 - 0%, 255 - 100% 70 | 71 | // Allocate memory and start DMA display 72 | if( not dma_display->begin() ) 73 | Serial.println("****** !KABOOM! Insufficient memory - allocation failed ***********"); 74 | 75 | fps_timer = millis(); 76 | 77 | } 78 | 79 | void loop(){ 80 | for (int x = 0; x < dma_display->width(); x++) { 81 | for (int y = 0; y < dma_display->height(); y++) { 82 | int16_t v = 0; 83 | uint8_t wibble = sin8(time_counter); 84 | v += sin16(x * wibble * 3 + time_counter); 85 | v += cos16(y * (128 - wibble) + time_counter); 86 | v += sin16(y * x * cos8(-time_counter) / 8); 87 | 88 | currentColor = ColorFromPalette(currentPalette, (v >> 8) + 127); //, brightness, currentBlendType); 89 | dma_display->drawPixelRGB888(x, y, currentColor.r, currentColor.g, currentColor.b); 90 | } 91 | } 92 | 93 | ++time_counter; 94 | ++cycles; 95 | ++fps; 96 | 97 | if (cycles >= 1024) { 98 | time_counter = 0; 99 | cycles = 0; 100 | currentPalette = palettes[random(0,sizeof(palettes)/sizeof(palettes[0]))]; 101 | } 102 | 103 | // print FPS rate every 5 seconds 104 | // Note: this is NOT a matrix refresh rate, it's the number of data frames being drawn to the DMA buffer per second 105 | if (fps_timer + 5000 < millis()){ 106 | Serial.printf_P(PSTR("Effect fps: %d\n"), fps/5); 107 | fps_timer = millis(); 108 | fps = 0; 109 | } 110 | } 111 | 112 | 113 | // FM6126 panel , thanks goes to: 114 | // https://github.com/hzeller/rpi-rgb-led-matrix/issues/746 115 | -------------------------------------------------------------------------------- /examples/4_OtherShiftDriverPanel/FM6126A.md: -------------------------------------------------------------------------------- 1 | ## The mystery of control registers for FM6126A chips 2 | 3 | 4 | The only available Datasheet for this chips is in Chinese and does not shed a light on what those two control regs are. 5 | 6 | An excellent insight could be found here https://github.com/hzeller/rpi-rgb-led-matrix/issues/746#issuecomment-453860510 7 | 8 | 9 | 10 | So there are two regs in this chip - **REG1** and **REG2**, 11 | one could be written with 12 clock pulses (and usually called reg12, dunno why :)) 12 | the other one could be written with 13 clock pulses (and usually called reg13, dunno why :)) 13 | 14 | 15 | I've done some measurements on power consumption while toggling bits of **REG1** and it looks that it could provide a fine grained brightness control over the entire matrix with no need for bitbanging over RGB or EO pins. 16 | There are 6 bits (6 to 11) giving an increased brightness (compared to all-zeroes) and 4 bits (2-5) giving decreased brightness!!! 17 | Still unclear if FM6112A brightness control is internally PWMed or current limited, might require some poking with oscilloscope. 18 | 19 | So it seems that the most bright (and hungry for power) value is bool REG1[16] = {0,0,0,0,0, 1,1,1,1,1,1, 0,0,0,0,0}; and not {0,1,1,1,1, 1,1,1,1,1,1, 1,1,1,1,1} as it is usually used. 20 | I'm not sure about bit 1 - it is either not used or I was unable to measure it's influence to brightness/power. 21 | 22 | Giving at least 10 bits of hardware brightness control opens pretty nice options for offloading and simplifying matrix output. Should dig into this more deeper. 23 | 24 | Here are some of the measurements I've took for 2 64x64 panels filled with white color - reg value and corresponding current drain in amps. 25 | 26 | 27 | |REG1 |bit value|Current, amps | 28 | |--|--|--| 29 | |REG1| 0111111 00000| >5 amps| 30 | |REG1| 0100010 00000| 3.890 amp| 31 | |REG1| 0100000 00000| 3.885 amp| 32 | |REG1| 0011110 00000| 3.640 amp| 33 | |REG1| 0011100 00000| 3.620 amp| 34 | |REG1| 0011000 00000| 3.240 amp| 35 | |REG1| 0010010 00000| 2.520 amp| 36 | |REG1| 0010001 00000| 2.518 amp| 37 | |REG1| 0010001 10000| 2.493 amp| 38 | |REG1| 0010000 00000| 2.490 amp| 39 | |REG1| 0010000 11110| 2.214 amp| 40 | |REG1| 0001100 00000| 2.120 amp| 41 | |REG1| 0001000 00000| 1.750 amp| 42 | |REG1| 0000100 00000| 1.375 amp| 43 | |REG1| 0000010 00000| 1.000 amp| 44 | |REG1| **0000000 00000**| 0.995 amp| 45 | |REG1| 0000001 11111| 0.700 amp| 46 | |REG1| 0000000 01111| 0.690 amp| 47 | |REG1| 0000000 10000| 0.690 amp| 48 | |REG1| 0000000 11110| 0.686 amp| 49 | 50 | 51 | /Vortigont/ -------------------------------------------------------------------------------- /examples/4_OtherShiftDriverPanel/README.md: -------------------------------------------------------------------------------- 1 | ## Other driver based LED Matrix Panels ## 2 | 3 | Limited support for other panels exists, but requires this to be passed as a configuration option when using the library. 4 | 5 | These panels require a special reset sequence before they can be used, check your panel chipset if you have issues. Refer to the example. 6 | 7 | 8 | ``` 9 | mxconfig.driver = HUB75_I2S_CFG::FM6126A; 10 | mxconfig.driver = HUB75_I2S_CFG::ICN2038S; 11 | mxconfig.driver = HUB75_I2S_CFG::FM6124; 12 | mxconfig.driver = HUB75_I2S_CFG::MBI5124; 13 | ``` 14 | -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_LittleFS/README.md: -------------------------------------------------------------------------------- 1 | ## Animated GIF Decoding Example 2 | 3 | ### Prerequisites 4 | 1. The excellent 'AnimatedGIF' library by Larry Bank needs to be installed: https://github.com/bitbank2/AnimatedGIF 5 | 6 | 2. The files in the 'data' folder are written to the ESP32's SPIFFS file system. In order to be able to do this using the Arduino 2.0 IDE, you need to install the ESP32 LittleFS plugin: https://github.com/lorol/arduino-esp32littlefs-plugin 7 | 8 | Follow the instructions in the link to install the plugin: https://randomnerdtutorials.com/arduino-ide-2-install-esp32-littlefs/ 9 | 10 | 11 | ## Credits 12 | 13 | https://github.com/bitbank2/AnimatedGIF 14 | -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_LittleFS/data/gifs/cartoon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_LittleFS/data/gifs/cartoon.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_LittleFS/data/gifs/ezgif.com-pacmn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_LittleFS/data/gifs/ezgif.com-pacmn.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_LittleFS/data/gifs/loading.io-64x32px.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_LittleFS/data/gifs/loading.io-64x32px.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_LittleFS/data/gifs/matrix-spin.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_LittleFS/data/gifs/matrix-spin.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_LittleFS/data/gifs/parasite1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_LittleFS/data/gifs/parasite1.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_LittleFS/data/gifs/parasite2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_LittleFS/data/gifs/parasite2.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_LittleFS/data/gifs/shock-gs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_LittleFS/data/gifs/shock-gs.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/Readme.md: -------------------------------------------------------------------------------- 1 | # ESP32-HUB75-MatrixPanel-DMA SDCard example 2 | 3 | A very basic example using the 'Animated GIF' library by Larry Bank + the SD / File system library provided for Arduino by Espressif. 4 | 5 | Some default HUB75 pins need to be remapped to accomodate for the SD Card. 6 | 7 | ![image](esp32_sdcard.jpg) 8 | 9 | ## How to use it? 10 | 11 | 1. Format a SD Card with FAT32 file system (default setting) 12 | 2. Create a directory called 'gifs' 13 | 3. Drop your gifs in there. The resolution of the GIFS must match that of the display. 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/esp32_sdcard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_SD/esp32_sdcard.jpg -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/gif_functions.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Code copied from AnimatedGIF examples 3 | 4 | #ifndef M5STACK_SD 5 | // for custom ESP32 builds 6 | #define M5STACK_SD SD 7 | #endif 8 | 9 | 10 | static void * GIFOpenFile(const char *fname, int32_t *pSize) 11 | { 12 | //log_d("GIFOpenFile( %s )\n", fname ); 13 | FSGifFile = M5STACK_SD.open(fname); 14 | if (FSGifFile) { 15 | *pSize = FSGifFile.size(); 16 | return (void *)&FSGifFile; 17 | } 18 | return NULL; 19 | } 20 | 21 | 22 | static void GIFCloseFile(void *pHandle) 23 | { 24 | File *f = static_cast(pHandle); 25 | if (f != NULL) 26 | f->close(); 27 | } 28 | 29 | 30 | static int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen) 31 | { 32 | int32_t iBytesRead; 33 | iBytesRead = iLen; 34 | File *f = static_cast(pFile->fHandle); 35 | // Note: If you read a file all the way to the last byte, seek() stops working 36 | if ((pFile->iSize - pFile->iPos) < iLen) 37 | iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around 38 | if (iBytesRead <= 0) 39 | return 0; 40 | iBytesRead = (int32_t)f->read(pBuf, iBytesRead); 41 | pFile->iPos = f->position(); 42 | return iBytesRead; 43 | } 44 | 45 | 46 | static int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition) 47 | { 48 | int i = micros(); 49 | File *f = static_cast(pFile->fHandle); 50 | f->seek(iPosition); 51 | pFile->iPos = (int32_t)f->position(); 52 | i = micros() - i; 53 | //log_d("Seek time = %d us\n", i); 54 | return pFile->iPos; 55 | } 56 | 57 | 58 | // Draw a line of image directly on the LCD 59 | void GIFDraw(GIFDRAW *pDraw) 60 | { 61 | uint8_t *s; 62 | uint16_t *d, *usPalette, usTemp[320]; 63 | int x, y, iWidth; 64 | 65 | iWidth = pDraw->iWidth; 66 | if (iWidth > PANEL_RES_X) 67 | iWidth = PANEL_RES_X; 68 | usPalette = pDraw->pPalette; 69 | y = pDraw->iY + pDraw->y; // current line 70 | 71 | s = pDraw->pPixels; 72 | if (pDraw->ucDisposalMethod == 2) {// restore to background color 73 | for (x=0; xucTransparent) 75 | s[x] = pDraw->ucBackground; 76 | } 77 | pDraw->ucHasTransparency = 0; 78 | } 79 | // Apply the new pixels to the main image 80 | if (pDraw->ucHasTransparency) { // if transparency used 81 | uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent; 82 | int x, iCount; 83 | pEnd = s + iWidth; 84 | x = 0; 85 | iCount = 0; // count non-transparent pixels 86 | while(x < iWidth) { 87 | c = ucTransparent-1; 88 | d = usTemp; 89 | while (c != ucTransparent && s < pEnd) { 90 | c = *s++; 91 | if (c == ucTransparent) { // done, stop 92 | s--; // back up to treat it like transparent 93 | } else { // opaque 94 | *d++ = usPalette[c]; 95 | iCount++; 96 | } 97 | } // while looking for opaque pixels 98 | if (iCount) { // any opaque pixels? 99 | for(int xOffset = 0; xOffset < iCount; xOffset++ ){ 100 | dma_display->drawPixel(x + xOffset, y, usTemp[xOffset]); // 565 Color Format 101 | } 102 | x += iCount; 103 | iCount = 0; 104 | } 105 | // no, look for a run of transparent pixels 106 | c = ucTransparent; 107 | while (c == ucTransparent && s < pEnd) { 108 | c = *s++; 109 | if (c == ucTransparent) 110 | iCount++; 111 | else 112 | s--; 113 | } 114 | if (iCount) { 115 | x += iCount; // skip these 116 | iCount = 0; 117 | } 118 | } 119 | } else { 120 | s = pDraw->pPixels; 121 | // Translate the 8-bit pixels through the RGB565 palette (already byte reversed) 122 | for (x=0; xdrawPixel(x, y, usPalette[*s++]); // color 565 124 | /* 125 | usTemp[x] = usPalette[*s++]; 126 | 127 | for (x=0; xiWidth; x++) { 128 | dma_display->drawPixel(x, y, usTemp[*s++]); // color 565 129 | } */ 130 | 131 | } 132 | } /* GIFDraw() */ 133 | -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/gifs/cartoon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_SD/gifs/cartoon.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/gifs/ezgif.com-pacmn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_SD/gifs/ezgif.com-pacmn.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/gifs/loading.io-64x32px.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_SD/gifs/loading.io-64x32px.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/gifs/matrix-spin.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_SD/gifs/matrix-spin.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/gifs/parasite1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_SD/gifs/parasite1.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/gifs/parasite2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_SD/gifs/parasite2.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/gifs/shock-gs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/AnimatedGIFPanel_SD/gifs/shock-gs.gif -------------------------------------------------------------------------------- /examples/AnimatedGIFPanel_SD/sdcard_functions.hpp: -------------------------------------------------------------------------------- 1 | /************************ SD Card Code ************************/ 2 | // As per: https://github.com/espressif/arduino-esp32/tree/master/libraries/SD/examples/SD_Test 3 | 4 | 5 | 6 | void listDir(fs::FS &fs, const char * dirname, uint8_t levels, bool add_to_gif_list = false){ 7 | Serial.printf("Listing directory: %s\n", dirname); 8 | 9 | File root = fs.open(dirname); 10 | if(!root){ 11 | Serial.println("Failed to open directory"); 12 | return; 13 | } 14 | if(!root.isDirectory()){ 15 | Serial.println("Not a directory"); 16 | return; 17 | } 18 | 19 | File file = root.openNextFile(); 20 | while(file){ 21 | if(file.isDirectory()){ 22 | Serial.print(" DIR : "); 23 | Serial.println(file.name()); 24 | if(levels){ 25 | listDir(fs, file.path(), levels -1, false); 26 | } 27 | } else { 28 | Serial.print(" FILE: "); 29 | Serial.print(file.name()); 30 | Serial.print(" SIZE: "); 31 | Serial.println(file.size()); 32 | 33 | if (add_to_gif_list && levels == 0) 34 | { 35 | GifFiles.push_back( std::string(dirname) + file.name() ); 36 | Serial.println("Adding to gif list:" + String(dirname) +"/" + file.name()); 37 | totalFiles++; 38 | } 39 | } 40 | file = root.openNextFile(); 41 | } 42 | 43 | file.close(); 44 | } 45 | 46 | void readFile(fs::FS &fs, const char * path){ 47 | Serial.printf("Reading file: %s\n", path); 48 | 49 | File file = fs.open(path); 50 | if(!file){ 51 | Serial.println("Failed to open file for reading"); 52 | return; 53 | } 54 | 55 | Serial.print("Read from file: "); 56 | while(file.available()){ 57 | Serial.write(file.read()); 58 | } 59 | file.close(); 60 | } 61 | 62 | void testFileIO(fs::FS &fs, const char * path){ 63 | File file = fs.open(path); 64 | static uint8_t buf[512]; 65 | size_t len = 0; 66 | uint32_t start = millis(); 67 | uint32_t end = start; 68 | if(file){ 69 | len = file.size(); 70 | size_t flen = len; 71 | start = millis(); 72 | while(len){ 73 | size_t toRead = len; 74 | if(toRead > 512){ 75 | toRead = 512; 76 | } 77 | file.read(buf, toRead); 78 | len -= toRead; 79 | } 80 | end = millis() - start; 81 | Serial.printf("%u bytes read for %u ms\n", flen, end); 82 | file.close(); 83 | } else { 84 | Serial.println("Failed to open file for reading"); 85 | } 86 | 87 | 88 | file = fs.open(path, FILE_WRITE); 89 | if(!file){ 90 | Serial.println("Failed to open file for writing"); 91 | return; 92 | } 93 | 94 | size_t i; 95 | start = millis(); 96 | for(i=0; i<2048; i++){ 97 | file.write(buf, 512); 98 | } 99 | end = millis() - start; 100 | Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end); 101 | file.close(); 102 | } -------------------------------------------------------------------------------- /examples/AuroraDemo/Attractor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Attractor" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/ 6 | * Copyright (c) 2014 Daniel Shiffman 7 | * http://www.shiffman.net 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | #include "Vector2.hpp" 28 | 29 | class Attractor { 30 | public: 31 | float mass; // Mass, tied to size 32 | float G; // Gravitational Constant 33 | PVector location; // Location 34 | 35 | Attractor() { 36 | location = PVector(effects.getCenterX(), effects.getCenterY()); 37 | mass = 10; 38 | G = .5; 39 | } 40 | 41 | PVector attract(Boid m) { 42 | PVector force = location - m.location; // Calculate direction of force 43 | float d = force.mag(); // Distance between objects 44 | d = constrain(d, 5.0, 32.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects 45 | force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) 46 | float strength = (G * mass * m.mass) / (d * d); // Calculate gravitational force magnitude 47 | force *= strength; // Get force vector --> magnitude * direction 48 | return force; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /examples/AuroraDemo/Drawable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Drawable_H 24 | #define Drawable_H 25 | 26 | class Drawable{ 27 | public: 28 | char* name; 29 | 30 | virtual bool isRunnable() { 31 | return false; 32 | } 33 | 34 | virtual bool isPlaylist() { 35 | return false; 36 | } 37 | 38 | // a single frame should be drawn as fast as possible, without any delay or blocking 39 | // return how many millisecond delay is requested before the next call to drawFrame() 40 | virtual unsigned int drawFrame() { 41 | matrix->fillScreen(0); 42 | //backgroundLayer.fillScreen({ 0, 0, 0 }); 43 | return 0; 44 | }; 45 | 46 | virtual void printTesting() 47 | { 48 | Serial.println("Testing..."); 49 | } 50 | 51 | virtual void start() {}; 52 | virtual void stop() {}; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /examples/AuroraDemo/Geometry.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from Noel Bundy's work: https://github.com/TwystNeko/Object3d 6 | * Copyright (c) 2014 Noel Bundy 7 | * 8 | * Portions of this code are adapted from the Petty library: https://code.google.com/p/peggy/ 9 | * Copyright (c) 2008 Windell H Oskay. All right reserved. 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 12 | * this software and associated documentation files (the "Software"), to deal in 13 | * the Software without restriction, including without limitation the rights to 14 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15 | * the Software, and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 24 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 25 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #ifndef Geometry_H 30 | #define Geometry_H 31 | 32 | struct Vertex 33 | { 34 | float x, y, z; 35 | Vertex() 36 | { 37 | this->set(0, 0, 0); 38 | } 39 | 40 | Vertex(float x, float y, float z) 41 | { 42 | this->set(x, y, z); 43 | } 44 | 45 | void set(float x, float y, float z) 46 | { 47 | this->x = x; 48 | this->y = y; 49 | this->z = z; 50 | } 51 | }; 52 | 53 | struct EdgePoint 54 | { 55 | int x, y; 56 | boolean visible; 57 | 58 | EdgePoint() 59 | { 60 | this->set(0, 0); 61 | this->visible = false; 62 | } 63 | 64 | void set(int a, int b) 65 | { 66 | this->x = a; 67 | this->y = b; 68 | } 69 | }; 70 | 71 | struct Point 72 | { 73 | float x, y; 74 | 75 | Point() 76 | { 77 | set(0, 0); 78 | } 79 | 80 | Point(float x, float y) 81 | { 82 | set(x, y); 83 | } 84 | 85 | void set(float x, float y) 86 | { 87 | this->x = x; 88 | this->y = y; 89 | } 90 | 91 | }; 92 | 93 | struct squareFace 94 | { 95 | int length; 96 | int sommets[4]; 97 | int ed[4]; 98 | 99 | squareFace() 100 | { 101 | set(-1, -1, -1, -1); 102 | } 103 | 104 | squareFace(int a, int b, int c, int d) 105 | { 106 | this->length = 4; 107 | this->sommets[0] = a; 108 | this->sommets[1] = b; 109 | this->sommets[2] = c; 110 | this->sommets[3] = d; 111 | } 112 | 113 | void set(int a, int b, int c, int d) 114 | { 115 | this->length = 4; 116 | this->sommets[0] = a; 117 | this->sommets[1] = b; 118 | this->sommets[2] = c; 119 | this->sommets[3] = d; 120 | } 121 | 122 | }; 123 | 124 | struct triFace 125 | { 126 | int length; 127 | int sommets[3]; 128 | int ed[3]; 129 | 130 | triFace() 131 | { 132 | set(-1,-1,-1); 133 | } 134 | triFace(int a, int b, int c) 135 | { 136 | this->length =3; 137 | this->sommets[0]=a; 138 | this->sommets[1]=b; 139 | this->sommets[2]=c; 140 | } 141 | void set(int a, int b, int c) 142 | { 143 | this->length =3; 144 | this->sommets[0]=a; 145 | this->sommets[1]=b; 146 | this->sommets[2]=c; 147 | } 148 | }; 149 | 150 | #endif -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternAttract.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternAttract_H 24 | 25 | class PatternAttract : public Drawable { 26 | private: 27 | const int count = AVAILABLE_BOID_COUNT-1; 28 | Attractor attractor; 29 | 30 | public: 31 | PatternAttract() { 32 | name = (char *)"Attract"; 33 | } 34 | 35 | void start() { 36 | int direction = random(0, 2); 37 | if (direction == 0) 38 | direction = -1; 39 | 40 | for (int i = 0; i < count; i++) { 41 | Boid boid = Boid(VPANEL_W/2, VPANEL_H - i); 42 | boid.mass = 1; // random(0.1, 2); 43 | boid.velocity.x = ((float) random(40, 50)) / 100.0; 44 | boid.velocity.x *= direction; 45 | boid.velocity.y = 0; 46 | boid.colorIndex = i * 32; 47 | boids[i] = boid; 48 | //dim = random(170, 250); 49 | } 50 | } 51 | 52 | unsigned int drawFrame() { 53 | // dim all pixels on the display 54 | uint8_t dim = beatsin8(2, 170, 250); 55 | effects.DimAll(dim); 56 | 57 | for (int i = 0; i < count; i++) { 58 | Boid boid = boids[i]; 59 | 60 | PVector force = attractor.attract(boid); 61 | boid.applyForce(force); 62 | 63 | boid.update(); 64 | effects.setPixel(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex)); 65 | 66 | boids[i] = boid; 67 | } 68 | 69 | effects.ShowFrame(); 70 | return 0; 71 | } 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternBounce.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternBounce_H 24 | 25 | class PatternBounce : public Drawable { 26 | private: 27 | static const int count = VPANEL_W-1; 28 | PVector gravity = PVector(0, 0.0125); 29 | 30 | public: 31 | PatternBounce() { 32 | name = (char *)"Bounce"; 33 | } 34 | 35 | void start() { 36 | unsigned int colorWidth = 256 / count; 37 | for (int i = 0; i < count; i++) { 38 | Boid boid = Boid(i, 0); 39 | boid.velocity.x = 0; 40 | boid.velocity.y = i * -0.01; 41 | boid.colorIndex = colorWidth * i; 42 | boid.maxforce = 10; 43 | boid.maxspeed = 10; 44 | boids[i] = boid; 45 | } 46 | } 47 | 48 | unsigned int drawFrame() { 49 | // dim all pixels on the display 50 | effects.DimAll(170); effects.ShowFrame(); 51 | 52 | for (int i = 0; i < count; i++) { 53 | Boid boid = boids[i]; 54 | 55 | boid.applyForce(gravity); 56 | 57 | boid.update(); 58 | 59 | effects.setPixel(boid.location.x, boid.location.y, effects.ColorFromCurrentPalette(boid.colorIndex)); 60 | 61 | if (boid.location.y >= VPANEL_H - 1) { 62 | boid.location.y = VPANEL_H - 1; 63 | boid.velocity.y *= -1.0; 64 | } 65 | 66 | boids[i] = boid; 67 | } 68 | 69 | return 15; 70 | } 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternCube.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from Noel Bundy's work: https://github.com/TwystNeko/Object3d 6 | * Copyright (c) 2014 Noel Bundy 7 | * 8 | * Portions of this code are adapted from the Petty library: https://code.google.com/p/peggy/ 9 | * Copyright (c) 2008 Windell H Oskay. All right reserved. 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 12 | * this software and associated documentation files (the "Software"), to deal in 13 | * the Software without restriction, including without limitation the rights to 14 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 15 | * the Software, and to permit persons to whom the Software is furnished to do so, 16 | * subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 24 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 25 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #ifndef PatternCube_H 30 | #define PatternCube_H 31 | 32 | class PatternCube : public Drawable { 33 | private: 34 | float focal = 30; // Focal of the camera 35 | int cubeWidth = 28; // Cube size 36 | float Angx = 20.0, AngxSpeed = 0.05; // rotation (angle+speed) around X-axis 37 | float Angy = 10.0, AngySpeed = 0.05; // rotation (angle+speed) around Y-axis 38 | float Ox = VPANEL_W/2, Oy = VPANEL_H/2; // position (x,y) of the frame center 39 | int zCamera = 110; // distance from cube to the eye of the camera 40 | 41 | // Local vertices 42 | Vertex local[8]; 43 | // Camera aligned vertices 44 | Vertex aligned[8]; 45 | // On-screen projected vertices 46 | Point screen[8]; 47 | // Faces 48 | squareFace face[6]; 49 | // Edges 50 | EdgePoint edge[12]; 51 | int nbEdges; 52 | // ModelView matrix 53 | float m00, m01, m02, m10, m11, m12, m20, m21, m22; 54 | 55 | // constructs the cube 56 | void make(int w) 57 | { 58 | nbEdges = 0; 59 | 60 | local[0].set(-w, w, w); 61 | local[1].set(w, w, w); 62 | local[2].set(w, -w, w); 63 | local[3].set(-w, -w, w); 64 | local[4].set(-w, w, -w); 65 | local[5].set(w, w, -w); 66 | local[6].set(w, -w, -w); 67 | local[7].set(-w, -w, -w); 68 | 69 | face[0].set(1, 0, 3, 2); 70 | face[1].set(0, 4, 7, 3); 71 | face[2].set(4, 0, 1, 5); 72 | face[3].set(4, 5, 6, 7); 73 | face[4].set(1, 2, 6, 5); 74 | face[5].set(2, 3, 7, 6); 75 | 76 | int f, i; 77 | for (f = 0; f < 6; f++) 78 | { 79 | for (i = 0; i < face[f].length; i++) 80 | { 81 | face[f].ed[i] = this->findEdge(face[f].sommets[i], face[f].sommets[i ? i - 1 : face[f].length - 1]); 82 | } 83 | } 84 | } 85 | 86 | // finds edges from faces 87 | int findEdge(int a, int b) 88 | { 89 | int i; 90 | for (i = 0; i < nbEdges; i++) 91 | if ((edge[i].x == a && edge[i].y == b) || (edge[i].x == b && edge[i].y == a)) 92 | return i; 93 | edge[nbEdges++].set(a, b); 94 | return i; 95 | } 96 | 97 | // rotates according to angle x&y 98 | void rotate(float angx, float angy) 99 | { 100 | int i; 101 | float cx = cos(angx); 102 | float sx = sin(angx); 103 | float cy = cos(angy); 104 | float sy = sin(angy); 105 | 106 | m00 = cy; 107 | m01 = 0; 108 | m02 = -sy; 109 | m10 = sx * sy; 110 | m11 = cx; 111 | m12 = sx * cy; 112 | m20 = cx * sy; 113 | m21 = -sx; 114 | m22 = cx * cy; 115 | 116 | for (i = 0; i < 8; i++) 117 | { 118 | aligned[i].x = m00 * local[i].x + m01 * local[i].y + m02 * local[i].z; 119 | aligned[i].y = m10 * local[i].x + m11 * local[i].y + m12 * local[i].z; 120 | aligned[i].z = m20 * local[i].x + m21 * local[i].y + m22 * local[i].z + zCamera; 121 | 122 | screen[i].x = floor((Ox + focal * aligned[i].x / aligned[i].z)); 123 | screen[i].y = floor((Oy - focal * aligned[i].y / aligned[i].z)); 124 | } 125 | 126 | for (i = 0; i < 12; i++) 127 | edge[i].visible = false; 128 | 129 | Point *pa, *pb, *pc; 130 | for (i = 0; i < 6; i++) 131 | { 132 | pa = screen + face[i].sommets[0]; 133 | pb = screen + face[i].sommets[1]; 134 | pc = screen + face[i].sommets[2]; 135 | 136 | boolean back = ((pb->x - pa->x) * (pc->y - pa->y) - (pb->y - pa->y) * (pc->x - pa->x)) < 0; 137 | if (!back) 138 | { 139 | int j; 140 | for (j = 0; j < 4; j++) 141 | { 142 | edge[face[i].ed[j]].visible = true; 143 | } 144 | } 145 | } 146 | } 147 | 148 | byte hue = 0; 149 | int step = 0; 150 | 151 | public: 152 | PatternCube() { 153 | name = (char *)"Cube"; 154 | make(VPANEL_W); 155 | } 156 | 157 | unsigned int drawFrame() { 158 | uint8_t blurAmount = beatsin8(2, 10, 128); 159 | 160 | #if FASTLED_VERSION >= 3001000 161 | blur2d(effects.leds, VPANEL_W, VPANEL_H, blurAmount); 162 | #else 163 | effects.DimAll(blurAmount); effects.ShowFrame(); 164 | #endif 165 | 166 | zCamera = beatsin8(2, 100, 140); 167 | AngxSpeed = beatsin8(3, 1, 6) / 100.0f; 168 | AngySpeed = effects.beatcos8(5, 1, 6) / 100.0f; 169 | 170 | // Update values 171 | Angx += AngxSpeed; 172 | Angy += AngySpeed; 173 | if (Angx >= TWO_PI) 174 | Angx -= TWO_PI; 175 | if (Angy >= TWO_PI) 176 | Angy -= TWO_PI; 177 | 178 | rotate(Angx, Angy); 179 | 180 | // Draw cube 181 | int i; 182 | 183 | CRGB color = effects.ColorFromCurrentPalette(hue, 128); 184 | 185 | // Backface 186 | EdgePoint *e; 187 | for (i = 0; i < 12; i++) 188 | { 189 | e = edge + i; 190 | if (!e->visible) { 191 | effects.drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color); 192 | } 193 | } 194 | 195 | color = effects.ColorFromCurrentPalette(hue, 255); 196 | 197 | // Frontface 198 | for (i = 0; i < 12; i++) 199 | { 200 | e = edge + i; 201 | if (e->visible) 202 | { 203 | effects.drawLine(screen[e->x].x, screen[e->x].y, screen[e->y].x, screen[e->y].y, color); 204 | } 205 | } 206 | 207 | step++; 208 | if (step == 8) { 209 | step = 0; 210 | hue++; 211 | } 212 | 213 | effects.ShowFrame(); 214 | 215 | return 20; 216 | } 217 | }; 218 | 219 | #endif 220 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternElectricMandala.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Funky Noise" by Stefan Petrick: https://github.com/StefanPetrick/FunkyNoise 6 | * Copyright (c) 2014 Stefan Petrick 7 | * http://www.stefan-petrick.de/wordpress_beta 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | #ifndef PatternElectricMandala_H 28 | 29 | class PatternElectricMandala : public Drawable { 30 | private: 31 | 32 | // The coordinates for 16-bit noise spaces. 33 | #define NUM_LAYERS 1 34 | 35 | // used for the random based animations 36 | int16_t dx; 37 | int16_t dy; 38 | int16_t dz; 39 | int16_t dsx; 40 | int16_t dsy; 41 | 42 | 43 | unsigned int last_parameter_change_ms = 0; 44 | 45 | public: 46 | PatternElectricMandala() { 47 | name = (char *)"ElectricMandala"; 48 | } 49 | 50 | void start() { 51 | // set to reasonable values to avoid a black out 52 | effects.noisesmoothing = 200; 53 | 54 | // just any free input pin 55 | //random16_add_entropy(analogRead(18)); 56 | 57 | // fill coordinates with random values 58 | // set zoom levels 59 | effects.noise_x = random16(); 60 | effects.noise_y = random16(); 61 | effects.noise_z = random16(); 62 | effects.noise_scale_x = 6000; 63 | effects.noise_scale_y = 6000; 64 | 65 | // for the random movement 66 | dx = random8(); 67 | dy = random8(); 68 | dz = random8(); 69 | dsx = random8(); 70 | dsy = random8(); 71 | } 72 | 73 | unsigned int drawFrame() { 74 | #if FASTLED_VERSION >= 3001000 75 | // a new parameter set every 15 seconds 76 | if(millis() - last_parameter_change_ms > 15000) { 77 | last_parameter_change_ms = millis(); 78 | //SetupRandomPalette3(); 79 | dy = random16(500) - 250; // random16(2000) - 1000 is pretty fast but works fine, too 80 | dx = random16(500) - 250; 81 | dz = random16(500) - 250; 82 | effects.noise_scale_x = random16(10000) + 2000; 83 | effects.noise_scale_y = random16(10000) + 2000; 84 | } 85 | #endif 86 | 87 | effects.noise_y += dy; 88 | effects.noise_x += dx; 89 | effects.noise_z += dz; 90 | 91 | effects.FillNoise(); 92 | ShowNoiseLayer(0, 1, 0); 93 | 94 | effects.Caleidoscope3(); 95 | effects.Caleidoscope1(); 96 | 97 | effects.ShowFrame(); 98 | 99 | return 30; 100 | } 101 | 102 | // show just one layer 103 | void ShowNoiseLayer(byte layer, byte colorrepeat, byte colorshift) { 104 | for (uint16_t i = 0; i < VPANEL_W; i++) { 105 | for (uint16_t j = 0; j < VPANEL_H; j++) { 106 | 107 | uint8_t color = effects.noise[i][j]; 108 | 109 | uint8_t bri = color; 110 | 111 | // assign a color depending on the actual palette 112 | CRGB pixel = ColorFromPalette(effects.currentPalette, colorrepeat * (color + colorshift), bri); 113 | 114 | effects.leds[XY16(i, j)] = pixel; 115 | } 116 | } 117 | } 118 | }; 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternFlock.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from "Flocking" in "The Nature of Code" by Daniel Shiffman: http://natureofcode.com/ 6 | * Copyright (c) 2014 Daniel Shiffman 7 | * http://www.shiffman.net 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | // Flocking 28 | // Daniel Shiffman 29 | // The Nature of Code, Spring 2009 30 | 31 | // Demonstration of Craig Reynolds' "Flocking" behavior 32 | // See: http://www.red3d.com/cwr/ 33 | // Rules: Cohesion, Separation, Alignment 34 | 35 | #ifndef PatternFlock_H 36 | #define PatternFlock_H 37 | 38 | class PatternFlock : public Drawable { 39 | 40 | private: 41 | unsigned long last_update_hue_ms = 0; 42 | unsigned long last_update_predator_ms = 0; 43 | 44 | public: 45 | PatternFlock() { 46 | name = (char *)"Flock"; 47 | } 48 | 49 | static const int boidCount = VPANEL_W-1; 50 | Boid predator; 51 | 52 | PVector wind; 53 | byte hue = 0; 54 | bool predatorPresent = true; 55 | 56 | void start() { 57 | for (int i = 0; i < boidCount; i++) { 58 | boids[i] = Boid(15, 15); 59 | boids[i].maxspeed = 0.380; 60 | boids[i].maxforce = 0.015; 61 | } 62 | 63 | predatorPresent = random(0, 2) >= 1; 64 | if (predatorPresent) { 65 | predator = Boid(31, 31); 66 | predatorPresent = true; 67 | predator.maxspeed = 0.385; 68 | predator.maxforce = 0.020; 69 | predator.neighbordist = 16.0; 70 | predator.desiredseparation = 0.0; 71 | } 72 | } 73 | 74 | unsigned int drawFrame() { 75 | effects.DimAll(230); effects.ShowFrame(); 76 | 77 | bool applyWind = random(0, 255) > 250; 78 | if (applyWind) { 79 | wind.x = Boid::randomf() * .015; 80 | wind.y = Boid::randomf() * .015; 81 | } 82 | 83 | CRGB color = effects.ColorFromCurrentPalette(hue); 84 | 85 | for (int i = 0; i < boidCount; i++) { 86 | Boid * boid = &boids[i]; 87 | 88 | if (predatorPresent) { 89 | // flee from predator 90 | boid->repelForce(predator.location, 10); 91 | } 92 | 93 | boid->run(boids, boidCount); 94 | boid->wrapAroundBorders(); 95 | PVector location = boid->location; 96 | // PVector velocity = boid->velocity; 97 | // backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color); 98 | // effects.leds[XY16(location.x, location.y)] += color; 99 | effects.setPixel(location.x, location.y, color); 100 | 101 | if (applyWind) { 102 | boid->applyForce(wind); 103 | applyWind = false; 104 | } 105 | } 106 | 107 | if (predatorPresent) { 108 | predator.run(boids, boidCount); 109 | predator.wrapAroundBorders(); 110 | color = effects.ColorFromCurrentPalette(hue + 128); 111 | PVector location = predator.location; 112 | // PVector velocity = predator.velocity; 113 | // backgroundLayer.drawLine(location.x, location.y, location.x - velocity.x, location.y - velocity.y, color); 114 | // effects.leds[XY16(location.x, location.y)] += color; 115 | effects.setPixel(location.x, location.y, color); 116 | } 117 | 118 | if (millis() - last_update_hue_ms > 200) { 119 | last_update_hue_ms = millis(); 120 | hue++; 121 | } 122 | 123 | if (millis() - last_update_predator_ms > 30000) { 124 | last_update_predator_ms = millis(); 125 | predatorPresent = !predatorPresent; 126 | } 127 | 128 | return 0; 129 | } 130 | }; 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternFlowField.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternFlowField_H 24 | 25 | class PatternFlowField : public Drawable { 26 | public: 27 | PatternFlowField() { 28 | name = (char *)"FlowField"; 29 | } 30 | 31 | uint16_t x; 32 | uint16_t y; 33 | uint16_t z; 34 | 35 | uint16_t speed = 1; 36 | uint16_t scale = 26; 37 | 38 | static const int count = 40; 39 | 40 | unsigned long last_update_hue_ms = 0; 41 | byte hue = 0; 42 | 43 | void start() { 44 | x = random16(); 45 | y = random16(); 46 | z = random16(); 47 | 48 | for (int i = 0; i < count; i++) { 49 | boids[i] = Boid(random(VPANEL_W), 0); 50 | } 51 | } 52 | 53 | unsigned int drawFrame() { 54 | effects.DimAll(240); 55 | 56 | // CRGB color = effects.ColorFromCurrentPalette(hue); 57 | 58 | for (int i = 0; i < count; i++) { 59 | Boid * boid = &boids[i]; 60 | 61 | int ioffset = scale * boid->location.x; 62 | int joffset = scale * boid->location.y; 63 | 64 | byte angle = inoise8(x + ioffset, y + joffset, z); 65 | 66 | boid->velocity.x = (float) sin8(angle) * 0.0078125 - 1.0; 67 | boid->velocity.y = -((float)cos8(angle) * 0.0078125 - 1.0); 68 | boid->update(); 69 | 70 | effects.setPixel(boid->location.x, boid->location.y, effects.ColorFromCurrentPalette(angle + hue)); // color 71 | 72 | if (boid->location.x < 0 || boid->location.x >= VPANEL_W || 73 | boid->location.y < 0 || boid->location.y >= VPANEL_H) { 74 | boid->location.x = random(VPANEL_W); 75 | boid->location.y = 0; 76 | } 77 | } 78 | 79 | if (millis() - last_update_hue_ms > 200) { 80 | last_update_hue_ms = millis(); 81 | hue++; 82 | } 83 | 84 | x += speed; 85 | y += speed; 86 | z += speed; 87 | 88 | effects.ShowFrame(); 89 | 90 | return 50; 91 | } 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternGreenScroll.hpp: -------------------------------------------------------------------------------- 1 | // Codetastic 2024 2 | // ChatGPT was used to create this. 3 | // It sucks. 4 | 5 | #ifndef PatternTheMatrix_H 6 | #define PatternTheMatrix_H 7 | 8 | // Function to generate a random greenish color for the digital rain 9 | CRGB generateRainColor() { 10 | return CHSV(96 + random(64), 255, 255); // Greenish colors 11 | } 12 | 13 | 14 | class PatternTheMatrix : public Drawable { 15 | 16 | public: 17 | PatternTheMatrix() { 18 | name = (char *)"The Matrix"; 19 | } 20 | 21 | 22 | // Function to draw the digital rain effect 23 | void drawDigitalRain() { 24 | // Shift all the LEDs down by one row 25 | for (int x = 0; x < VPANEL_W ; x++) { 26 | for (int y = VPANEL_H - 1; y > 0; y--) { 27 | effects.leds[XY(x, y)] = effects.leds[XY(x, y - 1)]; 28 | } 29 | // Add a new drop at the top of the column randomly 30 | if (random(10) > 7) { // Adjust the probability to control density of rain 31 | effects.leds[XY(x, 0)] = generateRainColor(); 32 | } else { 33 | effects.leds[XY(x, 0)] = CRGB::Black; 34 | } 35 | } 36 | } 37 | 38 | 39 | void start() 40 | { 41 | 42 | }; 43 | 44 | unsigned int drawFrame() { 45 | 46 | effects.DimAll(250); 47 | 48 | drawDigitalRain(); 49 | 50 | effects.ShowFrame(); 51 | return 0; 52 | } 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternIncrementalDrift.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Aurora: https://github.com/pixelmatix/aurora 4 | * Copyright (c) 2014 Jason Coon 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef PatternIncrementalDrift_H 25 | #define PatternIncrementalDrift_H 26 | 27 | class PatternIncrementalDrift : public Drawable { 28 | public: 29 | PatternIncrementalDrift() { 30 | name = (char *)"Incremental Drift"; 31 | } 32 | 33 | unsigned int drawFrame() { 34 | //uint8_t dim = beatsin8(2, 230, 250); 35 | effects.DimAll(250); 36 | 37 | for (int i = 2; i <= VPANEL_W / 2; i++) 38 | { 39 | CRGB color = effects.ColorFromCurrentPalette((i - 2) * (240 / (VPANEL_W / 2))); 40 | 41 | uint8_t x = effects.beatcos8((17 - i) * 2, effects.getCenterX() - i, effects.getCenterX() + i); 42 | uint8_t y = beatsin8((17 - i) * 2, effects.getCenterY() - i, effects.getCenterY() + i); 43 | 44 | effects.setPixel(x, y, color); 45 | } 46 | 47 | effects.ShowFrame(); 48 | 49 | return 0; 50 | } 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternIncrementalDrift2.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Aurora: https://github.com/pixelmatix/aurora 4 | * Copyright (c) 2014 Jason Coon 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifndef PatternIncrementalDrift2_H 25 | #define PatternIncrementalDrift2_H 26 | 27 | class PatternIncrementalDrift2 : public Drawable { 28 | public: 29 | PatternIncrementalDrift2() { 30 | name = (char *)"Incremental Drift Rose"; 31 | } 32 | 33 | unsigned int drawFrame() { 34 | uint8_t dim = beatsin8(2, 170, 250); 35 | effects.DimAll(dim); effects.ShowFrame(); 36 | 37 | for (int i = 2; i < VPANEL_H / 2; ++i) 38 | //for (uint8_t i = 0; i < 32; i++) 39 | { 40 | CRGB color; 41 | 42 | uint8_t x = 0; 43 | uint8_t y = 0; 44 | 45 | if (i < 16) { 46 | x = effects.beatcos8((i + 1) * 2, i, VPANEL_W - i); 47 | y = beatsin8((i + 1) * 2, i, VPANEL_H - i); 48 | color = effects.ColorFromCurrentPalette(i * 14); 49 | } 50 | else 51 | { 52 | x = beatsin8((32 - i) * 2, VPANEL_W - i, i + 1); 53 | y = effects.beatcos8((32 - i) * 2, VPANEL_H - i, i + 1); 54 | color = effects.ColorFromCurrentPalette((31 - i) * 14); 55 | } 56 | 57 | effects.setPixel(x, y, color); 58 | } 59 | 60 | return 0; 61 | } 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternInfinity.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternInfinity_H 24 | 25 | class PatternInfinity : public Drawable { 26 | public: 27 | PatternInfinity() { 28 | name = (char *)"Infinity"; 29 | } 30 | 31 | void start() { 32 | effects.ClearFrame(); 33 | } 34 | 35 | unsigned int drawFrame() { 36 | // dim all pixels on the display slightly 37 | // to 250/255 (98%) of their current brightness 38 | //blur2d(effects.leds, VPANEL_W > 255 ? 255 : VPANEL_W, VPANEL_H > 255 ? 255 : VPANEL_H, 250); 39 | // effects.DimAll(250); effects.ShowFrame(); 40 | 41 | 42 | // the EffectsLayer class has some sample oscillators 43 | // that move from 0 to 255 at different speeds 44 | effects.MoveOscillators(); 45 | 46 | // the horizontal position of the head of the infinity sign 47 | // oscillates from 0 to the maximum horizontal and back 48 | int x = (VPANEL_W - 4) - effects.p[1]; 49 | 50 | // the vertical position of the head oscillates 51 | // from 8 to 23 and back (hard-coded for a 32x32 matrix) 52 | int y = map8(sin8(effects.osci[3]), 8, VPANEL_H - 8); 53 | 54 | // the hue oscillates from 0 to 255, overflowing back to 0 55 | byte hue = sin8(effects.osci[5]); 56 | 57 | // draw a pixel at x,y using a color from the current palette 58 | effects.drawTriangle(x,y,x+1,y+1,x+2,y+2,effects.ColorFromCurrentPalette(hue)); 59 | ////effects.setPixelFromPaletteIndex(x, y, hue); 60 | 61 | effects.ShowFrame(); 62 | return 30; 63 | } 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternJuliaSetFractal.hpp: -------------------------------------------------------------------------------- 1 | #ifndef JuliaSet_H 2 | #define JuliaSet_H 3 | 4 | // Codetastic 2024 5 | 6 | #define USE_FLOATHACK // To boost float performance, comment if this doesn't work. 7 | 8 | // inspired by 9 | // https://en.wikipedia.org/wiki/Fast_inverse_square_root 10 | #ifdef USE_FLOATHACK 11 | // cast float as int32_t 12 | int32_t intfloat(float n){ return *(int32_t *)&n; } 13 | // cast int32_t as float 14 | float floatint(int32_t n){ return *(float *)&n; } 15 | // fast approx sqrt(x) 16 | float floatsqrt(float n){ return floatint(0x1fbb4000+(intfloat(n)>>1)); } 17 | // fast approx 1/x 18 | float floatinv(float n){ return floatint(0x7f000000-intfloat(n)); } 19 | // fast approx log2(x) 20 | float floatlog2(float n){ return (float)((intfloat(n)<<1)-0x7f000000)*5.9604645e-08f; } 21 | #else 22 | float floatinv(float n){ return 1.f/n;} 23 | float floatsqrt(float n){ return std::sqrt(n); } 24 | float floatlog2(float n){ return std::log2f(n); } 25 | #endif 26 | 27 | //////////////////////////////////////// 28 | // Escape time mandelbrot set function, 29 | // with arbitrary start point zx, zy 30 | // and arbitrary seed point ax, ay 31 | // 32 | // For julia set 33 | // zx = pos_x, zy = pos_y; 34 | // ax = seed_x, ay = seed_y; 35 | // 36 | // For mandelbrot set 37 | // zx = 0, zy = 0; 38 | // ax = pos_x, ay = pos_y; 39 | // 40 | const float bailOut = 4; // Escape radius 41 | const int32_t itmult = 1<<10; // Color speed 42 | // 43 | // https://en.wikipedia.org/wiki/Mandelbrot_set 44 | int32_t iteratefloat(float ax, float ay, float zx, float zy, uint16_t mxIT) { 45 | float zzl = 0; 46 | for (int it = 0; it=bailOut){ 51 | if(it>0){ 52 | // calculate smooth coloring 53 | float zza = floatlog2(zzl); 54 | float zzb = floatlog2(zzx+zzy); 55 | float zzc = floatlog2(bailOut); 56 | float zzd = (zzc-zza)*floatinv(zzb-zza); 57 | return it*itmult+zzd*itmult; 58 | } 59 | }; 60 | // z -> z*z + c 61 | zy = 2.f*zx*zy+ay; 62 | zx = zzx-zzy+ax; 63 | zzl = zzx+zzy; 64 | } 65 | return 0; 66 | } 67 | 68 | class PatternJuliaSet : public Drawable { 69 | 70 | private: 71 | 72 | float sint[256]; // precalculated sin table, for performance reasons 73 | 74 | public: 75 | PatternJuliaSet() { 76 | name = (char *)"Julia Set"; 77 | } 78 | 79 | void start() { 80 | 81 | for(int i=0;i<256;i++){ 82 | sint[i] = sinf(i/256.f*2.f*PI); 83 | } 84 | } 85 | 86 | 87 | // Palette color taken from: 88 | // https://editor.p5js.org/Kouzerumatsukite/sketches/DwTiq9D01 89 | // color palette originally made by piano_miles, written in p5js 90 | // hsv2rgb(IT, cos(4096*it)/2+0.5, 1-sin(2048*it)/2-0.5) 91 | void drawPixelPalette(int x, int y, uint32_t m){ 92 | float r = 0.f, g = 0.f, b = 0.f; 93 | if(m){ 94 | char n = m>> 4 ; 95 | float l =abs(sint[m>> 2&255] )*255.f ; 96 | float s = (sint[m &255]+ 1.f)*0.5f ; 97 | r = (max(min(sint[n &255]+0.5f,1.f),0.f)*s+(1-s))*l; 98 | g = (max(min(sint[n+ 85&255]+0.5f,1.f),0.f)*s+(1-s))*l; 99 | b = (max(min(sint[n+170&255]+0.5f,1.f),0.f)*s+(1-s))*l; 100 | } 101 | effects.setPixel(x,y,CRGB(r,g,b)); 102 | 103 | } 104 | 105 | unsigned int drawFrame() { 106 | uint32_t lastMicros = micros(); 107 | double t = (double)lastMicros/8000000; 108 | double k = sin(t*3.212/2)*sin(t*3.212/2)/16+1; 109 | float cosk = (k-cos(t))/2; 110 | float xoff = (cos(t)*cosk+k/2-0.25); 111 | float yoff = (sin(t)*cosk ); 112 | for(uint8_t y=0;y= VPANEL_W) { 55 | dir = -dir; 56 | } 57 | 58 | if (count <= 0) { 59 | if (flip == 0) 60 | flip = VPANEL_W-1; 61 | else 62 | flip = 0; 63 | } 64 | 65 | generation++; 66 | 67 | // show it ffs! 68 | effects.ShowFrame(); 69 | return 60; 70 | } 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternPendulumWave.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Inspired by and based on a loading animation for Prismata by Lunarch Studios: 4 | * http://www.reddit.com/r/gifs/comments/2on8si/connecting_to_server_so_mesmerizing/cmow0sz 5 | * 6 | * Lunarch Studios Inc. hereby publishes the Actionscript 3 source code pasted in this 7 | * comment under the Creative Commons CC0 1.0 Universal Public Domain Dedication. 8 | * Lunarch Studios Inc. waives all rights to the work worldwide under copyright law, 9 | * including all related and neighboring rights, to the extent allowed by law. 10 | * You can copy, modify, distribute and perform the work, even for commercial purposes, 11 | * all without asking permission. 12 | * 13 | * Aurora: https://github.com/pixelmatix/aurora 14 | * Copyright (c) 2014 Jason Coon 15 | * 16 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 17 | * this software and associated documentation files (the "Software"), to deal in 18 | * the Software without restriction, including without limitation the rights to 19 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 20 | * the Software, and to permit persons to whom the Software is furnished to do so, 21 | * subject to the following conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be included in all 24 | * copies or substantial portions of the Software. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 28 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 29 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 30 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | */ 33 | 34 | #ifndef PatternPendulumWave_H 35 | #define PatternPendulumWave_H 36 | 37 | #define WAVE_BPM 25 38 | #define AMP_BPM 2 39 | #define SKEW_BPM 4 40 | #define WAVE_TIMEMINSKEW VPANEL_W/8 41 | #define WAVE_TIMEMAXSKEW effects.getCenterX() 42 | 43 | class PatternPendulumWave : public Drawable { 44 | public: 45 | PatternPendulumWave() { 46 | name = (char *)"Pendulum Wave"; 47 | } 48 | 49 | unsigned int drawFrame() 50 | { 51 | effects.DimAll(192); 52 | 53 | for (int x = 0; x < VPANEL_W; ++x) 54 | { 55 | uint16_t amp = beatsin16(AMP_BPM, VPANEL_H/8, VPANEL_H-1); 56 | uint16_t offset = (VPANEL_H - beatsin16(AMP_BPM, 0, VPANEL_H))/2; 57 | 58 | uint8_t y = beatsin16(WAVE_BPM, 0, amp, x*beatsin16(SKEW_BPM, WAVE_TIMEMINSKEW, WAVE_TIMEMAXSKEW)) + offset; 59 | 60 | effects.setPixel(x, y, effects.ColorFromCurrentPalette(x * 7)); 61 | } 62 | effects.ShowFrame(); 63 | return 20; 64 | } 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternPlasma.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from LedEffects Plasma by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Plasma.cpp?at=default 6 | * Copyright (c) 2013 Robert Atkins 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternPlasma_H 27 | #define PatternPlasma_H 28 | 29 | class PatternPlasma : public Drawable { 30 | private: 31 | int time = 0; 32 | int cycles = 0; 33 | 34 | public: 35 | PatternPlasma() { 36 | name = (char *)"Plasma"; 37 | } 38 | 39 | unsigned int drawFrame() { 40 | for (int x = 0; x < VPANEL_W; x++) { 41 | for (int y = 0; y < VPANEL_H; y++) { 42 | int16_t v = 0; 43 | uint8_t wibble = sin8(time); 44 | v += sin16(x * wibble * 6 + time); 45 | v += cos16(y * (128 - wibble) * 6 + time); 46 | v += sin16(y * x * cos8(-time) / 8); 47 | 48 | effects.setPixelFromPaletteIndex(x, y, (v >> 8) + 127); 49 | } 50 | } 51 | 52 | time += 1; 53 | cycles++; 54 | 55 | if (cycles >= 2048) { 56 | time = 0; 57 | cycles = 0; 58 | } 59 | 60 | effects.ShowFrame(); 61 | 62 | return 30; 63 | } 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternRadar.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternRadar_H 24 | 25 | class PatternRadar : public Drawable { 26 | private: 27 | byte theta = 0; 28 | byte hueoffset = 0; 29 | unsigned long last_update_hue_ms = 0; 30 | 31 | public: 32 | PatternRadar() { 33 | name = (char *)"Radar"; 34 | } 35 | 36 | unsigned int drawFrame() { 37 | effects.DimAll(254); effects.ShowFrame(); 38 | 39 | for (int offset = 0; offset < effects.getCenterX(); offset++) { 40 | byte hue = 255 - (offset * 16 + hueoffset); 41 | CRGB color = effects.ColorFromCurrentPalette(hue); 42 | uint8_t x = effects.mapcos8(theta, offset, (VPANEL_W - 1) - offset); 43 | uint8_t y = effects.mapsin8(theta, offset, (VPANEL_H - 1) - offset); 44 | uint16_t xy = XY16(x, y); 45 | effects.leds[xy] = color; 46 | 47 | if (millis() - last_update_hue_ms > 25) { 48 | last_update_hue_ms = millis(); 49 | theta += 2; 50 | hueoffset += 1; 51 | } 52 | } 53 | 54 | return 0; 55 | } 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternRain.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PatternRain_H 2 | #define PatternRain_H 3 | 4 | // Codetastic 2024 5 | 6 | struct rainDrop { 7 | uint8_t x; 8 | uint8_t y; 9 | CRGB colour; 10 | }; 11 | 12 | #define MAX_RAINDROPS 128 13 | 14 | class PatternRain : public Drawable { 15 | 16 | public: 17 | PatternRain() 18 | { 19 | name = (char *)"PatternRain"; 20 | } 21 | 22 | void start() { 23 | 24 | buffer = (uint16_t *) malloc(((VPANEL_W*VPANEL_H)+1)*sizeof(uint16_t)); // always alloc an extra amount for XY 25 | } 26 | 27 | void stop() { 28 | 29 | free(buffer); 30 | 31 | } 32 | 33 | 34 | unsigned int drawFrame() 35 | { 36 | rain(32, 255, 224, 240, CRGB::Green); 37 | 38 | effects.ShowFrame(); 39 | 40 | return 45; // 1000/45 frames per secton 41 | 42 | } 43 | 44 | 45 | 46 | private: 47 | 48 | struct rainDrop rainDrops[MAX_RAINDROPS]; 49 | int rainDropPos = 0; 50 | 51 | uint16_t* buffer = NULL; // buffer of number 52 | 53 | void rain(byte backgroundDepth, byte maxBrightness, byte spawnFreq, byte tailLength, CRGB rainColor) 54 | { 55 | CRGBPalette16 rain_p( CRGB::Black, rainColor ); 56 | 57 | // Dim routine 58 | for (int16_t i = 0; i < VPANEL_W; i++) { 59 | for (int16_t j = 0; j < VPANEL_H; j++) { 60 | uint16_t xy = XY16(i, j); 61 | effects.leds[xy].nscale8(tailLength); 62 | } 63 | } 64 | 65 | // Genrate a new raindrop if the randomness says we should 66 | if (random(255) < spawnFreq) { 67 | 68 | // Find a spare raindrop slot 69 | for (int d = 0; d < MAX_RAINDROPS; d++) { 70 | 71 | // This raindrop is done with, it has... dropped 72 | if (rainDrops[d].y >= VPANEL_H ) // not currently in use 73 | { 74 | rainDrops[d].colour = ColorFromPalette(rain_p, random(backgroundDepth, maxBrightness)); 75 | rainDrops[d].x = random(VPANEL_W-1); 76 | rainDrops[d].y = 0; 77 | 78 | break; // exit until next time. 79 | } 80 | } 81 | } // end random spawn 82 | 83 | // Iterate through all the rainDrops, draw the drop pixel on the layer 84 | for (int d = 0; d < MAX_RAINDROPS; d++) { 85 | effects.setPixel(rainDrops[d].x, rainDrops[d].y++, rainDrops[d].colour); 86 | } 87 | 88 | } 89 | 90 | 91 | }; 92 | 93 | #endif -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternSimplexNoise.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from FastLED Fire2012 example by Mark Kriegsman: https://github.com/FastLED/FastLED/blob/master/examples/Noise/Noise.ino 6 | * Copyright (c) 2013 FastLED 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSimplexNoise_H 27 | #define PatternSimplexNoise_H 28 | 29 | class PatternSimplexNoise : public Drawable { 30 | 31 | private: 32 | 33 | unsigned int last_update_ms = 0; 34 | public: 35 | PatternSimplexNoise() { 36 | name = (char *)"Noise"; 37 | } 38 | 39 | void start() { 40 | // Initialize our coordinates to some random values 41 | effects.noise_x = random16(); 42 | effects.noise_y = random16(); 43 | effects.noise_z = random16(); 44 | } 45 | 46 | unsigned int drawFrame() { 47 | #if FASTLED_VERSION >= 3001000 48 | // a new parameter set every 15 seconds 49 | if(millis() - last_update_ms > 15000) { 50 | last_update_ms = millis(); 51 | effects.noise_x = random16(); 52 | effects.noise_y = random16(); 53 | effects.noise_z = random16(); 54 | } 55 | #endif 56 | 57 | uint32_t speed = 100; 58 | 59 | effects.FillNoise(); 60 | ShowNoiseLayer(0, 1, 0); 61 | 62 | // noise_x += speed; 63 | effects.noise_y += speed; 64 | effects.noise_z += speed; 65 | 66 | effects.ShowFrame(); 67 | 68 | return 30; 69 | } 70 | 71 | // show just one layer 72 | void ShowNoiseLayer(byte layer, byte colorrepeat, byte colorshift) { 73 | for (uint16_t i = 0; i < VPANEL_W; i++) { 74 | for (uint16_t j = 0; j < VPANEL_H; j++) { 75 | uint8_t pixel = effects.noise[i][j]; 76 | 77 | // assign a color depending on the actual palette 78 | effects.leds[XY16(i, j)] = effects.ColorFromCurrentPalette(colorrepeat * (pixel + colorshift), pixel); 79 | } 80 | } 81 | } 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternSnake.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Portions of this code are adapted from LedEffects Snake by Robert Atkins: https://bitbucket.org/ratkins/ledeffects/src/26ed3c51912af6fac5f1304629c7b4ab7ac8ca4b/Snake.cpp?at=default 6 | * Copyright (c) 2013 Robert Atkins 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSnake_H 27 | #define PatternSnake_H 28 | 29 | class PatternSnake : public Drawable { 30 | private: 31 | static const byte SNAKE_LENGTH = 8; 32 | 33 | CRGB colors[SNAKE_LENGTH]; 34 | uint8_t initialHue; 35 | 36 | enum Direction { 37 | UP, DOWN, LEFT, RIGHT 38 | }; 39 | 40 | struct Pixel { 41 | uint8_t x; 42 | uint8_t y; 43 | }; 44 | 45 | struct Snake { 46 | Pixel pixels[SNAKE_LENGTH]; 47 | 48 | Direction direction; 49 | 50 | void newDirection() { 51 | switch (direction) { 52 | case UP: 53 | case DOWN: 54 | direction = random(0, 2) == 1 ? RIGHT : LEFT; 55 | break; 56 | 57 | case LEFT: 58 | case RIGHT: 59 | direction = random(0, 2) == 1 ? DOWN : UP; 60 | 61 | default: 62 | break; 63 | } 64 | } 65 | 66 | void shuffleDown() { 67 | for (byte i = SNAKE_LENGTH - 1; i > 0; i--) { 68 | pixels[i] = pixels[i - 1]; 69 | } 70 | } 71 | 72 | void reset() { 73 | direction = UP; 74 | for (int i = 0; i < SNAKE_LENGTH; i++) { 75 | pixels[i].x = 0; 76 | pixels[i].y = 0; 77 | } 78 | } 79 | 80 | void move() { 81 | switch (direction) { 82 | case UP: 83 | pixels[0].y = (pixels[0].y + 1) % VPANEL_H; 84 | break; 85 | case LEFT: 86 | pixels[0].x = (pixels[0].x + 1) % VPANEL_W; 87 | break; 88 | case DOWN: 89 | pixels[0].y = pixels[0].y == 0 ? VPANEL_H - 1 : pixels[0].y - 1; 90 | break; 91 | case RIGHT: 92 | pixels[0].x = pixels[0].x == 0 ? VPANEL_W - 1 : pixels[0].x - 1; 93 | break; 94 | } 95 | } 96 | 97 | void draw(CRGB colors[SNAKE_LENGTH]) { 98 | for (byte i = 0; i < SNAKE_LENGTH; i++) { 99 | effects.leds[XY16(pixels[i].x, pixels[i].y)] = colors[i] %= (255 - i * (255 / SNAKE_LENGTH)); 100 | } 101 | } 102 | }; 103 | 104 | static const int snakeCount = 6; 105 | Snake snakes[snakeCount]; 106 | 107 | public: 108 | PatternSnake() { 109 | name = (char *)"Snake"; 110 | for (int i = 0; i < snakeCount; i++) { 111 | Snake* snake = &snakes[i]; 112 | snake->reset(); 113 | } 114 | } 115 | 116 | void start() 117 | { 118 | effects.ClearFrame(); 119 | } 120 | 121 | unsigned int drawFrame() { 122 | 123 | 124 | fill_palette(colors, SNAKE_LENGTH, initialHue++, 5, effects.currentPalette, 255, LINEARBLEND); 125 | 126 | for (int i = 0; i < snakeCount; i++) { 127 | Snake* snake = &snakes[i]; 128 | 129 | snake->shuffleDown(); 130 | 131 | if (random(10) > 7) { 132 | snake->newDirection(); 133 | } 134 | 135 | snake->move(); 136 | snake->draw(colors); 137 | } 138 | 139 | effects.ShowFrame(); 140 | 141 | return 30; 142 | } 143 | }; 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternSpin.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternSpin_H 24 | 25 | 26 | 27 | class PatternSpin : public Drawable { 28 | public: 29 | PatternSpin() { 30 | name = (char *)"Spin"; 31 | } 32 | 33 | float degrees = 0; 34 | float radius = 16; 35 | 36 | float speedStart = 1; 37 | float velocityStart = 0.6; 38 | 39 | float maxSpeed = 30; 40 | 41 | float speed = speedStart; 42 | float velocity = velocityStart; 43 | 44 | void start() { 45 | speed = speedStart; 46 | velocity = velocityStart; 47 | degrees = 0; 48 | } 49 | 50 | unsigned int drawFrame() { 51 | 52 | 53 | CRGB color = effects.ColorFromCurrentPalette(speed * 8); 54 | 55 | // start position 56 | int x; 57 | int y; 58 | 59 | // target position 60 | float targetDegrees = degrees + speed; 61 | float targetRadians = radians(targetDegrees); 62 | int targetX = (int) (effects.getCenterX() + radius * cos(targetRadians)); 63 | int targetY = (int) (effects.getCenterY() - radius * sin(targetRadians)); 64 | 65 | float tempDegrees = degrees; 66 | 67 | for (int i =0; i < 16; i++) 68 | { 69 | float radians = radians(tempDegrees); 70 | x = (int) (effects.getCenterX() + radius * cos(radians)); 71 | y = (int) (effects.getCenterY() - radius * sin(radians)); 72 | 73 | effects.setPixel(x, y, color); 74 | effects.setPixel(y, x, color); 75 | 76 | tempDegrees += 1; 77 | if (tempDegrees >= 360) 78 | tempDegrees = 0; 79 | 80 | } 81 | 82 | 83 | degrees += speed; 84 | 85 | // add velocity to the particle each pass around the accelerator 86 | if (degrees >= 360) { 87 | degrees = 0; 88 | speed += velocity; 89 | if (speed <= speedStart) { 90 | speed = speedStart; 91 | velocity *= -1; 92 | } 93 | else if (speed > maxSpeed){ 94 | speed = maxSpeed - velocity; 95 | velocity *= -1; 96 | } 97 | } 98 | 99 | effects.ShowFrame(); 100 | 101 | return 0; 102 | } 103 | }; 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternSpiral.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Portions of this code are adapted from "Funky Clouds" by Stefan Petrick: 3 | * https://gist.github.com/anonymous/876f908333cd95315c35 4 | * 5 | * Copyright (c) 2014 Stefan Petrick 6 | * http://www.stefan-petrick.de/wordpress_beta 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | 26 | #ifndef PatternSpiral_H 27 | #define PatternSpiral_H 28 | 29 | class PatternSpiral : public Drawable { 30 | private: 31 | // Timer stuff (Oscillators) 32 | struct timer { 33 | unsigned long takt; 34 | unsigned long lastMillis; 35 | unsigned long count; 36 | int delta; 37 | byte up; 38 | byte down; 39 | }; 40 | timer multiTimer[5]; 41 | 42 | int timers = sizeof(multiTimer) / sizeof(multiTimer[0]); 43 | 44 | // counts all variables with different speeds linear up and down 45 | void UpdateTimers() 46 | { 47 | unsigned long now = millis(); 48 | for (int i = 0; i < timers; i++) 49 | { 50 | while (now - multiTimer[i].lastMillis >= multiTimer[i].takt) 51 | { 52 | multiTimer[i].lastMillis += multiTimer[i].takt; 53 | multiTimer[i].count = multiTimer[i].count + multiTimer[i].delta; 54 | if ((multiTimer[i].count == multiTimer[i].up) || (multiTimer[i].count == multiTimer[i].down)) 55 | { 56 | multiTimer[i].delta = -multiTimer[i].delta; 57 | } 58 | } 59 | } 60 | } 61 | 62 | public: 63 | PatternSpiral() { 64 | name = (char *)"Spiral"; 65 | } 66 | 67 | void start() { 68 | // set all counting directions positive for the beginning 69 | for (int i = 0; i < timers; i++) multiTimer[i].delta = 1; 70 | 71 | // set range (up/down), speed (takt=ms between steps) and starting point of all oscillators 72 | 73 | unsigned long now = millis(); 74 | 75 | multiTimer[0].lastMillis = now; 76 | multiTimer[0].takt = 42; //x1 77 | multiTimer[0].up = VPANEL_W - 1; 78 | multiTimer[0].down = 0; 79 | multiTimer[0].count = 0; 80 | 81 | multiTimer[1].lastMillis = now; 82 | multiTimer[1].takt = 55; //y1 83 | multiTimer[1].up = VPANEL_H - 1; 84 | multiTimer[1].down = 0; 85 | multiTimer[1].count = 0; 86 | 87 | multiTimer[2].lastMillis = now; 88 | multiTimer[2].takt = 3; //color 89 | multiTimer[2].up = 255; 90 | multiTimer[2].down = 0; 91 | multiTimer[2].count = 0; 92 | 93 | multiTimer[3].lastMillis = now; 94 | multiTimer[3].takt = 71; //x2 95 | multiTimer[3].up = VPANEL_W - 1; 96 | multiTimer[3].down = 0; 97 | multiTimer[3].count = 0; 98 | 99 | multiTimer[4].lastMillis = now; 100 | multiTimer[4].takt = 89; //y2 101 | multiTimer[4].up = VPANEL_H - 1; 102 | multiTimer[4].down = 0; 103 | multiTimer[4].count = 0; 104 | } 105 | 106 | unsigned int drawFrame() { 107 | // manage the Oscillators 108 | UpdateTimers(); 109 | 110 | // draw just a line defined by 5 oscillators 111 | effects.BresenhamLine( 112 | multiTimer[3].count, // x1 113 | multiTimer[4].count, // y1 114 | multiTimer[0].count, // x2 115 | multiTimer[1].count, // y2 116 | multiTimer[2].count); // color 117 | 118 | // manipulate the screen buffer 119 | // with fixed parameters (could be oscillators too) 120 | // Params: center x, y, radius, scale color down 121 | // --> NOTE: Affects always a SQUARE with an odd length 122 | // effects.SpiralStream(15, 15, 10, 128); 123 | 124 | effects.SpiralStream(31, 15, 64, 128); // for 64 pixel wide matrix! 125 | // effects.SpiralStream(47, 15, 10, 128); // for 64 pixel wide matrix! 126 | 127 | // why not several times?! 128 | // effects.SpiralStream(16, 6, 6, 128); 129 | // effects.SpiralStream(10, 24, 10, 128); 130 | 131 | // increase the contrast 132 | effects.DimAll(250); effects.ShowFrame(); 133 | 134 | return 0; 135 | } 136 | }; 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternSpiro.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternSpiro_H 24 | 25 | class PatternSpiro : public Drawable { 26 | private: 27 | byte theta1 = 0; 28 | byte theta2 = 0; 29 | byte hueoffset = 0; 30 | 31 | uint8_t radiusx = VPANEL_W / 4; 32 | uint8_t radiusy = VPANEL_H / 4; 33 | uint8_t minx = effects.getCenterX() - radiusx; 34 | uint8_t maxx = effects.getCenterX() + radiusx + 1; 35 | uint8_t miny = effects.getCenterY() - radiusy; 36 | uint8_t maxy = effects.getCenterY() + radiusy + 1; 37 | 38 | uint8_t spirocount = 64; 39 | uint8_t spirooffset = 256 / spirocount; 40 | boolean spiroincrement = true; 41 | 42 | boolean handledChange = false; 43 | 44 | unsigned long last_update_theta1_ms = 0; 45 | unsigned long last_update_hue_ms = 0; 46 | unsigned long last_update_frame_ms = 0; 47 | 48 | public: 49 | PatternSpiro() { 50 | name = (char *)"Spiro"; 51 | } 52 | 53 | void start(){ 54 | effects.ClearFrame(); 55 | }; 56 | 57 | unsigned int drawFrame() { 58 | blur2d(effects.leds, VPANEL_W > 255 ? 255 : VPANEL_W, VPANEL_H > 255 ? 255 : VPANEL_H, 64); 59 | 60 | boolean change = false; 61 | 62 | for (int i = 0; i < spirocount; i++) { 63 | uint8_t x = effects.mapsin8(theta1 + i * spirooffset, minx, maxx); 64 | uint8_t y = effects.mapcos8(theta1 + i * spirooffset, miny, maxy); 65 | 66 | uint8_t x2 = effects.mapsin8(theta2 + i * spirooffset, x - radiusx, x + radiusx); 67 | uint8_t y2 = effects.mapcos8(theta2 + i * spirooffset, y - radiusy, y + radiusy); 68 | 69 | CRGB color = effects.ColorFromCurrentPalette(hueoffset + i * spirooffset, 128); 70 | effects.leds[XY16(x2, y2)] += color; 71 | 72 | if((x2 == effects.getCenterX() && y2 == effects.getCenterY()) || 73 | (x2 == effects.getCenterX() && y2 == effects.getCenterY())) change = true; 74 | } 75 | 76 | theta2 += 1; 77 | 78 | if (millis() - last_update_theta1_ms > 25) { 79 | last_update_theta1_ms = millis(); 80 | theta1 += 1; 81 | } 82 | 83 | if (millis() - last_update_frame_ms > 100) { 84 | last_update_frame_ms = millis(); 85 | 86 | if (change && !handledChange) { 87 | handledChange = true; 88 | 89 | if (spirocount >= VPANEL_W || spirocount == 1) spiroincrement = !spiroincrement; 90 | 91 | if (spiroincrement) { 92 | if(spirocount >= 4) 93 | spirocount *= 2; 94 | else 95 | spirocount += 1; 96 | } 97 | else { 98 | if(spirocount > 4) 99 | spirocount /= 2; 100 | else 101 | spirocount -= 1; 102 | } 103 | 104 | spirooffset = 256 / spirocount; 105 | } 106 | 107 | if(!change) handledChange = false; 108 | } 109 | 110 | if (millis() - last_update_hue_ms > 33) { 111 | last_update_hue_ms = millis(); 112 | hueoffset += 1; 113 | } 114 | 115 | effects.ShowFrame(); 116 | return 0; 117 | } 118 | }; 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternStarfield.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PatternStarfield_H 2 | #define PatternStarfield_H 3 | 4 | struct Star 5 | { 6 | Star() { 7 | x = y = z = 0; 8 | colour = CRGB::White; 9 | } 10 | 11 | float x; 12 | float y; 13 | float z; 14 | CRGB colour; 15 | }; 16 | 17 | 18 | // Based on https://github.com/sinoia/oled-starfield/blob/master/src/starfield.cpp 19 | class PatternStarfield : public Drawable { 20 | 21 | private: 22 | 23 | const int starCount = 100; // number of stars in the star field 24 | const int maxDepth = 32; // maximum distance away for a star 25 | 26 | // the star field - starCount stars represented as x, y and z co-ordinates 27 | // https://www.cplusplus.com/doc/tutorial/dynamic/ 28 | Star * stars; 29 | //CRGBPalette16 currentPalette; 30 | 31 | unsigned int drawFrame() { // aka drawStars 32 | 33 | // Dim routine 34 | 35 | for (int16_t i = 0; i < VPANEL_W; i++) { 36 | for (int16_t j = 0; j < VPANEL_H; j++) { 37 | 38 | uint16_t xy = XY16(i, j); 39 | effects.leds[xy].nscale8(250); 40 | } 41 | } 42 | 43 | int origin_x = VPANEL_W / 2; 44 | int origin_y = VPANEL_H / 2; 45 | 46 | // Iterate through the stars reducing the z co-ordinate in order to move the 47 | // star closer. 48 | for (int i = 0; i < starCount; ++i) { 49 | stars[i].z -= 0.1; 50 | // if the star has moved past the screen (z < 0) reposition it far away 51 | // with random x and y positions. 52 | if (stars[i].z <= 0) 53 | { 54 | stars[i].x = getRandom(-25, 25); 55 | stars[i].y = getRandom(-25, 25); 56 | stars[i].z = maxDepth; 57 | } 58 | 59 | // Convert the 3D coordinates to 2D using perspective projection. 60 | float k = VPANEL_W / stars[i].z; 61 | int x = static_cast(stars[i].x * k + origin_x); 62 | int y = static_cast(stars[i].y * k + origin_y); 63 | 64 | // Draw the star (if it is visible in the screen). 65 | // Distant stars are smaller than closer stars. 66 | if ((0 <= x and x < VPANEL_H) 67 | and (0 <= y and y < VPANEL_H)) { 68 | 69 | CRGB tmp = stars[i].colour; 70 | //CRGB tmp = CRGB::White; 71 | byte scale = 255 -(stars[i].z*7); 72 | tmp.nscale8(scale); 73 | 74 | effects.setPixel(x,y, CRGB(tmp.r,tmp.g,tmp.b)); 75 | } 76 | else 77 | { 78 | stars[i].z = -1; // set to -1 so it gets re-popualted 79 | } 80 | } 81 | 82 | effects.ShowFrame(); 83 | 84 | return 5; 85 | } 86 | 87 | int getRandom(int lower, int upper) { 88 | /* Generate and return a random number between lower and upper bound */ 89 | return lower + static_cast(rand() % (upper - lower + 1)); 90 | } 91 | 92 | /* 93 | CRGB ColorFromCurrentPalette(uint8_t index = 0, uint8_t brightness = 255, TBlendType blendType = LINEARBLEND) { 94 | return ColorFromPalette(currentPalette, index, brightness, blendType); 95 | } 96 | */ 97 | 98 | public: 99 | PatternStarfield() 100 | { 101 | name = (char *)"PatternStarfield"; 102 | } 103 | 104 | void start() { 105 | 106 | //currentPalette = RainbowColors_p; 107 | //currentPalette = CloudColors_p; 108 | 109 | // Allocate memory 110 | stars = new Star[starCount]; 111 | 112 | // Initialise the star field with random stars 113 | for (int i = 0; i < starCount; i++) { 114 | stars[i].x = getRandom(-25, 25); 115 | stars[i].y = getRandom(-25, 25); 116 | stars[i].z = getRandom(0, maxDepth); 117 | //stars[i].colour = ColorFromCurrentPalette(random(0, 128)); 118 | stars[i].colour = effects.ColorFromCurrentPalette(random(0, 128)); 119 | } 120 | } // end start 121 | 122 | void stop() { 123 | delete[] stars; 124 | } 125 | 126 | 127 | 128 | }; 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternTest.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef PatternTest_H 3 | #define PatternTest_H 4 | 5 | class PatternTest : public Drawable { 6 | private: 7 | 8 | public: 9 | PatternTest() { 10 | name = (char *)"Test Pattern"; 11 | } 12 | 13 | unsigned int drawFrame() { 14 | 15 | matrix->fillScreen(matrix->color565(128, 0, 0)); 16 | return 1000; 17 | } 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /examples/AuroraDemo/PatternWave.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef PatternWave_H 24 | #define PatternWave_H 25 | 26 | class PatternWave : public Drawable { 27 | private: 28 | byte thetaUpdate = 0; 29 | byte thetaUpdateFrequency = 0; 30 | byte theta = 0; 31 | 32 | byte hueUpdate = 0; 33 | byte hueUpdateFrequency = 0; 34 | byte hue = 0; 35 | 36 | byte rotation = 0; 37 | 38 | uint8_t scale = 256 / VPANEL_W; 39 | 40 | uint8_t maxX = VPANEL_W - 1; 41 | uint8_t maxY = VPANEL_H - 1; 42 | 43 | uint8_t waveCount = 1; 44 | 45 | public: 46 | PatternWave() { 47 | name = (char *)"Wave"; 48 | } 49 | 50 | void start() { 51 | rotation = random(0, 4); 52 | waveCount = random(1, 3); 53 | 54 | } 55 | 56 | unsigned int drawFrame() { 57 | int n = 0; 58 | 59 | switch (rotation) { 60 | case 0: 61 | for (int x = 0; x < VPANEL_W; x++) { 62 | n = quadwave8(x * 2 + theta) / scale; 63 | effects.setPixel(x, n, effects.ColorFromCurrentPalette(x + hue)); 64 | if (waveCount == 2) 65 | effects.setPixel(x, maxY - n, effects.ColorFromCurrentPalette(x + hue)); 66 | } 67 | break; 68 | 69 | case 1: 70 | for (int y = 0; y < VPANEL_H; y++) { 71 | n = quadwave8(y * 2 + theta) / scale; 72 | effects.setPixel(n, y, effects.ColorFromCurrentPalette(y + hue)); 73 | if (waveCount == 2) 74 | effects.setPixel(maxX - n, y, effects.ColorFromCurrentPalette(y + hue)); 75 | } 76 | break; 77 | 78 | case 2: 79 | for (int x = 0; x < VPANEL_W; x++) { 80 | n = quadwave8(x * 2 - theta) / scale; 81 | effects.setPixel(x, n, effects.ColorFromCurrentPalette(x + hue)); 82 | if (waveCount == 2) 83 | effects.setPixel(x, maxY - n, effects.ColorFromCurrentPalette(x + hue)); 84 | } 85 | break; 86 | 87 | case 3: 88 | for (int y = 0; y < VPANEL_H; y++) { 89 | n = quadwave8(y * 2 - theta) / scale; 90 | effects.setPixel(n, y, effects.ColorFromCurrentPalette(y + hue)); 91 | if (waveCount == 2) 92 | effects.setPixel(maxX - n, y, effects.ColorFromCurrentPalette(y + hue)); 93 | } 94 | break; 95 | } 96 | 97 | effects.DimAll(220); 98 | 99 | 100 | if (thetaUpdate >= thetaUpdateFrequency) { 101 | thetaUpdate = 0; 102 | theta++; 103 | } 104 | else { 105 | thetaUpdate++; 106 | } 107 | 108 | if (hueUpdate >= hueUpdateFrequency) { 109 | hueUpdate = 0; 110 | hue++; 111 | } 112 | else { 113 | hueUpdate++; 114 | } 115 | 116 | effects.ShowFrame(); 117 | 118 | return 0; 119 | } 120 | }; 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /examples/AuroraDemo/Patterns.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Original Copyright (c) 2014 Jason Coon 4 | * 5 | * Modified by Codetastic 2024 6 | * 7 | */ 8 | 9 | #ifndef Patterns_H 10 | #define Patterns_H 11 | 12 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 13 | 14 | #include "Vector2.hpp" 15 | #include "Boid.hpp" 16 | #include "Attractor.hpp" 17 | 18 | /* 19 | * Note from mrfaptastic: 20 | * 21 | * Commented out patterns are due to the fact they either didn't work properly with a non-square display, 22 | * or from my personal opinion, are crap. 23 | */ 24 | #include "PatternStarfield.hpp" // new 2024 25 | #include "PatternAttract.hpp" 26 | #include "PatternBounce.hpp" // Doesn't seem to work, omitting. 27 | #include "PatternCube.hpp" // Doesn't seem to work, omitting. 28 | #include "PatternElectricMandala.hpp" 29 | #include "PatternFireKoz.hpp" // Doesn't seem to work, omitting. 30 | #include "PatternFlock.hpp" 31 | #include "PatternFlowField.hpp" 32 | #include "PatternIncrementalDrift.hpp" 33 | #include "PatternIncrementalDrift2.hpp" // Doesn't seem to work, omitting. 34 | #include "PatternInfinity.hpp" 35 | #include "PatternMaze.hpp" // ?? 36 | #include "PatternMunch.hpp" 37 | //#include "PatternNoiseSmearing.hpp" 38 | #include "PatternPendulumWave.hpp" 39 | #include "PatternPlasma.hpp" 40 | #include "PatternRadar.hpp" 41 | #include "PatternSimplexNoise.hpp" 42 | #include "PatternSnake.hpp" 43 | #include "PatternSpiral.hpp" 44 | #include "PatternSpiro.hpp" 45 | #include "PatternWave.hpp" 46 | #include "PatternRain.hpp" 47 | #include "PatternJuliaSetFractal.hpp" 48 | #include "PatternRain.hpp" 49 | #include "PatternFireworks.hpp" 50 | 51 | 52 | 53 | class Patterns { 54 | private: 55 | 56 | PatternStarfield starfield; 57 | PatternAttract attract; 58 | PatternBounce bounce; 59 | PatternCube cube; 60 | PatternElectricMandala electricMandala; 61 | PatternFireKoz fire; 62 | PatternFlock flock; 63 | PatternFlowField flowField; 64 | PatternIncrementalDrift incrementalDrift; 65 | PatternIncrementalDrift2 incrementalDrift2; 66 | PatternInfinity infinity; 67 | PatternMaze maze; 68 | PatternMunch munch; 69 | PatternPendulumWave pendwave; 70 | PatternPlasma plasma; 71 | PatternRadar radar; 72 | PatternSimplexNoise simpnoise; 73 | PatternSnake snake; 74 | PatternSpiral spiral; 75 | PatternSpiro spiro; 76 | PatternWave wave; 77 | PatternJuliaSet juliaSet; 78 | 79 | PatternRain rain; 80 | PatternFirework fireworks; 81 | 82 | 83 | std::vector availablePatterns = { 84 | &juliaSet, 85 | &starfield, 86 | &attract, 87 | &bounce, 88 | &cube, 89 | &electricMandala, 90 | &fire, 91 | &flock, 92 | &spiro, 93 | &radar, 94 | &flowField, 95 | &incrementalDrift, 96 | &incrementalDrift2, 97 | &infinity, 98 | &maze, 99 | &munch, 100 | &pendwave, 101 | &plasma, 102 | &radar, 103 | &simpnoise, 104 | &spiro, 105 | &wave, 106 | &rain, 107 | &fireworks 108 | }; 109 | 110 | int currentIndex = 0; 111 | Drawable* currentItem; 112 | 113 | int getCurrentIndex() { 114 | return currentIndex; 115 | } 116 | 117 | 118 | public: 119 | Patterns() { 120 | this->currentItem = availablePatterns[0]; 121 | this->currentItem->start(); 122 | } 123 | 124 | void stop() { 125 | if (currentItem) 126 | currentItem->stop(); 127 | } 128 | 129 | void start() { 130 | if (currentItem) 131 | currentItem->start(); 132 | } 133 | 134 | void moveTo(int index) 135 | { 136 | index = ((index >= availablePatterns.size()) || (index < 0)) ? 0 : index; 137 | 138 | if (currentItem) 139 | currentItem->stop(); 140 | 141 | currentIndex = index; 142 | currentItem = availablePatterns[currentIndex]; 143 | 144 | Serial.print("Changing pattern to: "); 145 | Serial.println(getCurrentPatternName()); 146 | 147 | if (currentItem) 148 | currentItem->start(); 149 | 150 | } // index 151 | 152 | 153 | void move(int step) { 154 | 155 | currentIndex += step; 156 | 157 | if (currentIndex >= availablePatterns.size()) currentIndex = 0; 158 | else if (currentIndex < 0) currentIndex = 0; 159 | 160 | moveTo(currentIndex); 161 | } 162 | 163 | void moveRandom(int step) { 164 | int rand_index = random(0, availablePatterns.size()-1); 165 | moveTo(rand_index); 166 | } 167 | 168 | unsigned int drawFrame() { 169 | return currentItem->drawFrame(); 170 | } 171 | 172 | void listPatterns() { 173 | Serial.println(F("{")); 174 | Serial.print(F(" \"count\": ")); 175 | Serial.print(availablePatterns.size()); 176 | Serial.println(","); 177 | Serial.println(F(" \"results\": [")); 178 | 179 | for (size_t i = 0; i < availablePatterns.size(); i++) { 180 | Serial.print(F(" \"")); 181 | Serial.print(i, DEC); 182 | Serial.print(F(": ")); 183 | Serial.print(availablePatterns[i]->name); 184 | if (i == availablePatterns.size() - 1) 185 | Serial.println(F("\"")); 186 | else 187 | Serial.println(F("\",")); 188 | } 189 | 190 | Serial.println(" ]"); 191 | Serial.println("}"); 192 | } 193 | 194 | char * getCurrentPatternName() 195 | { 196 | return currentItem->name; 197 | } 198 | /* 199 | bool setPattern(String name) { 200 | 201 | for (size_t i = 0; i < availablePatterns.size(); i++) { 202 | if (name.compareTo(availablePatterns[i]->name) == 0) { 203 | moveTo(i); 204 | return true; 205 | } 206 | } 207 | 208 | return false; 209 | } 210 | 211 | */ 212 | bool setPattern(int index) { 213 | if (index >= availablePatterns.size() || index < 0) 214 | return false; 215 | 216 | moveTo(index); 217 | 218 | return true; 219 | } 220 | }; 221 | 222 | #endif -------------------------------------------------------------------------------- /examples/AuroraDemo/README.md: -------------------------------------------------------------------------------- 1 | ## Aurora Demo 2 | * This demonstrates a combination of the following libraries: 3 | - "ESP32-HUB75-MatrixPanel-DMA" to send pixel data to the physical panels in combination with its in-built "VirtualMatrix" class to create a virtual display of chained panels, so the graphical effects of the Aurora demonstrations can be shown over a 'bigger' grid of physical panels acting as one big display. 4 | - "GFX_Lite" to provide a simple graphics library for drawing on the virtual display. 5 | - Note: GFX_Lite is a fork of AdaFruitGFX and FastLED library combined together, with a focus on simplicity and ease of use. 6 | 7 | ## Instructions 8 | * Use the serial input to advance through the patterns, or to toggle auto advance. 9 | * Sending 'n' will advance to the next pattern, 'p' will go to the previous pattern. Sending 'a' will toggle auto advance on and off. 10 | -------------------------------------------------------------------------------- /examples/AuroraDemo/Vector2.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Aurora: https://github.com/pixelmatix/aurora 3 | * Copyright (c) 2014 Jason Coon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | * this software and associated documentation files (the "Software"), to deal in 7 | * the Software without restriction, including without limitation the rights to 8 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | * the Software, and to permit persons to whom the Software is furnished to do so, 10 | * subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef Vector_H 24 | #define Vector_H 25 | 26 | template 27 | class Vector2 { 28 | public: 29 | T x, y; 30 | 31 | Vector2() :x(0), y(0) {} 32 | Vector2(T x, T y) : x(x), y(y) {} 33 | Vector2(const Vector2& v) : x(v.x), y(v.y) {} 34 | 35 | Vector2& operator=(const Vector2& v) { 36 | x = v.x; 37 | y = v.y; 38 | return *this; 39 | } 40 | 41 | bool isEmpty() { 42 | return x == 0 && y == 0; 43 | } 44 | 45 | bool operator==(Vector2& v) { 46 | return x == v.x && y == v.y; 47 | } 48 | 49 | bool operator!=(Vector2& v) { 50 | return !(x == y); 51 | } 52 | 53 | Vector2 operator+(Vector2& v) { 54 | return Vector2(x + v.x, y + v.y); 55 | } 56 | Vector2 operator-(Vector2& v) { 57 | return Vector2(x - v.x, y - v.y); 58 | } 59 | 60 | Vector2& operator+=(Vector2& v) { 61 | x += v.x; 62 | y += v.y; 63 | return *this; 64 | } 65 | Vector2& operator-=(Vector2& v) { 66 | x -= v.x; 67 | y -= v.y; 68 | return *this; 69 | } 70 | 71 | Vector2 operator+(double s) { 72 | return Vector2(x + s, y + s); 73 | } 74 | Vector2 operator-(double s) { 75 | return Vector2(x - s, y - s); 76 | } 77 | Vector2 operator*(double s) { 78 | return Vector2(x * s, y * s); 79 | } 80 | Vector2 operator/(double s) { 81 | return Vector2(x / s, y / s); 82 | } 83 | 84 | Vector2& operator+=(double s) { 85 | x += s; 86 | y += s; 87 | return *this; 88 | } 89 | Vector2& operator-=(double s) { 90 | x -= s; 91 | y -= s; 92 | return *this; 93 | } 94 | Vector2& operator*=(double s) { 95 | x *= s; 96 | y *= s; 97 | return *this; 98 | } 99 | Vector2& operator/=(double s) { 100 | x /= s; 101 | y /= s; 102 | return *this; 103 | } 104 | 105 | void set(T x, T y) { 106 | this->x = x; 107 | this->y = y; 108 | } 109 | 110 | void rotate(double deg) { 111 | double theta = deg / 180.0 * M_PI; 112 | double c = cos(theta); 113 | double s = sin(theta); 114 | double tx = x * c - y * s; 115 | double ty = x * s + y * c; 116 | x = tx; 117 | y = ty; 118 | } 119 | 120 | Vector2& normalize() { 121 | if (length() == 0) return *this; 122 | *this *= (1.0 / length()); 123 | return *this; 124 | } 125 | 126 | float dist(Vector2 v) const { 127 | Vector2 d(v.x - x, v.y - y); 128 | return d.length(); 129 | } 130 | float length() const { 131 | return sqrt(x * x + y * y); 132 | } 133 | 134 | float mag() const { 135 | return length(); 136 | } 137 | 138 | float magSq() { 139 | return (x * x + y * y); 140 | } 141 | 142 | void truncate(double length) { 143 | double angle = atan2f(y, x); 144 | x = length * cos(angle); 145 | y = length * sin(angle); 146 | } 147 | 148 | Vector2 ortho() const { 149 | return Vector2(y, -x); 150 | } 151 | 152 | static float dot(Vector2 v1, Vector2 v2) { 153 | return v1.x * v2.x + v1.y * v2.y; 154 | } 155 | static float cross(Vector2 v1, Vector2 v2) { 156 | return (v1.x * v2.y) - (v1.y * v2.x); 157 | } 158 | 159 | void limit(float max) { 160 | if (magSq() > max*max) { 161 | normalize(); 162 | *this *= max; 163 | } 164 | } 165 | }; 166 | 167 | typedef Vector2 PVector; 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /examples/BitmapIcons/BitmapIcons.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Dhole_weather_icons32px.h" 4 | 5 | /*--------------------- DEBUG -------------------------*/ 6 | #define Sprintln(a) (Serial.println(a)) 7 | #define SprintlnDEC(a, x) (Serial.println(a, x)) 8 | 9 | #define Sprint(a) (Serial.print(a)) 10 | #define SprintDEC(a, x) (Serial.print(a, x)) 11 | 12 | 13 | /*--------------------- RGB DISPLAY PINS -------------------------*/ 14 | #define R1_PIN 25 15 | #define G1_PIN 26 16 | #define B1_PIN 27 17 | #define R2_PIN 14 18 | #define G2_PIN 12 19 | #define B2_PIN 13 20 | #define A_PIN 23 21 | #define B_PIN 19 // Changed from library default 22 | #define C_PIN 5 23 | #define D_PIN 17 24 | #define E_PIN -1 25 | #define LAT_PIN 4 26 | #define OE_PIN 15 27 | #define CLK_PIN 16 28 | 29 | 30 | /*--------------------- MATRIX LILBRARY CONFIG -------------------------*/ 31 | #define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module. 32 | #define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module. 33 | #define PANEL_CHAIN 1 // Total number of panels chained one to another 34 | 35 | MatrixPanel_I2S_DMA *dma_display = nullptr; 36 | 37 | // Module configuration 38 | HUB75_I2S_CFG mxconfig( 39 | PANEL_RES_X, // module width 40 | PANEL_RES_Y, // module height 41 | PANEL_CHAIN // Chain length 42 | ); 43 | 44 | /* 45 | //Another way of creating config structure 46 | //Custom pin mapping for all pins 47 | HUB75_I2S_CFG::i2s_pins _pins={R1, G1, BL1, R2, G2, BL2, CH_A, CH_B, CH_C, CH_D, CH_E, LAT, OE, CLK}; 48 | HUB75_I2S_CFG mxconfig( 49 | 64, // width 50 | 64, // height 51 | 4, // chain length 52 | _pins, // pin mapping 53 | HUB75_I2S_CFG::FM6126A // driver chip 54 | ); 55 | 56 | */ 57 | 58 | 59 | //mxconfig.gpio.e = -1; // Assign a pin if you have a 64x64 panel 60 | //mxconfig.clkphase = false; // Change this if you have issues with ghosting. 61 | //mxconfig.driver = HUB75_I2S_CFG::FM6126A; // Change this according to your pane. 62 | 63 | 64 | /* 65 | * Wifi Logo, generated with the following steps: 66 | * 67 | * Python and Paint.Net needs to be installed. 68 | * 69 | * 1. SAVE BITMAP AS 1BIT COLOUR in paint.net 70 | * 2. Run: bmp2hex.py -i -x 71 | * 3. Copy paste output into sketch. 72 | * 73 | */ 74 | 75 | const char wifi_image1bit[] PROGMEM = { 76 | 0x00,0x00,0x00,0xf8,0x1f,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0xff,0x01,0x00, 77 | 0x00,0x00,0x00,0xf0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0xfc,0xff,0xff,0x1f, 78 | 0x00,0x00,0x00,0x00,0xfe,0x07,0xe0,0x7f,0x00,0x00,0x00,0x80,0xff,0x00,0x00, 79 | 0xff,0x01,0x00,0x00,0xc0,0x1f,0x00,0x00,0xf8,0x03,0x00,0x00,0xe0,0x0f,0x00, 80 | 0x00,0xf0,0x07,0x00,0x00,0xf0,0x03,0xf0,0x0f,0xc0,0x0f,0x00,0x00,0xe0,0x01, 81 | 0xff,0xff,0x80,0x07,0x00,0x00,0xc0,0xc0,0xff,0xff,0x03,0x03,0x00,0x00,0x00, 82 | 0xe0,0xff,0xff,0x07,0x00,0x00,0x00,0x00,0xf8,0x0f,0xf0,0x1f,0x00,0x00,0x00, 83 | 0x00,0xfc,0x01,0x80,0x3f,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x3e,0x00,0x00, 84 | 0x00,0x00,0x38,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x10,0xe0,0x07,0x08,0x00, 85 | 0x00,0x00,0x00,0x00,0xfc,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x7f,0x00, 86 | 0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xf8, 87 | 0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 88 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 89 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00, 90 | 0x00,0xc0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x07,0x00,0x00,0x00,0x00, 91 | 0x00,0x00,0xe0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x03,0x00,0x00,0x00, 92 | 0x00,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 93 | 0x00 }; 94 | 95 | 96 | void drawXbm565(int x, int y, int width, int height, const char *xbm, uint16_t color = 0xffff) 97 | { 98 | if (width % 8 != 0) { 99 | width = ((width / 8) + 1) * 8; 100 | } 101 | for (int i = 0; i < width * height / 8; i++ ) { 102 | unsigned char charColumn = pgm_read_byte(xbm + i); 103 | for (int j = 0; j < 8; j++) { 104 | int targetX = (i * 8 + j) % width + x; 105 | int targetY = (8 * i / (width)) + y; 106 | if (bitRead(charColumn, j)) { 107 | dma_display->drawPixel(targetX, targetY, color); 108 | } 109 | } 110 | } 111 | } 112 | 113 | /* Bitmaps */ 114 | int current_icon = 0; 115 | static int num_icons = 22; 116 | 117 | static char icon_name[22][30] = { 118 | "cloud_moon_bits", 119 | "cloud_sun_bits", 120 | "clouds_bits", 121 | "cloud_wind_moon_bits", 122 | "cloud_wind_sun_bits", 123 | "cloud_wind_bits", 124 | "cloud_bits", 125 | "lightning_bits", 126 | "moon_bits", 127 | "rain0_sun_bits", 128 | "rain0_bits", 129 | "rain1_moon_bits", 130 | "rain1_sun_bits", 131 | "rain1_bits", 132 | "rain2_bits", 133 | "rain_lightning_bits", 134 | "rain_snow_bits", 135 | "snow_moon_bits", 136 | "snow_sun_bits", 137 | "snow_bits", 138 | "sun_bits", 139 | "wind_bits" }; 140 | 141 | static char *icon_bits[22] = { cloud_moon_bits, 142 | cloud_sun_bits, 143 | clouds_bits, 144 | cloud_wind_moon_bits, 145 | cloud_wind_sun_bits, 146 | cloud_wind_bits, 147 | cloud_bits, 148 | lightning_bits, 149 | moon_bits, 150 | rain0_sun_bits, 151 | rain0_bits, 152 | rain1_moon_bits, 153 | rain1_sun_bits, 154 | rain1_bits, 155 | rain2_bits, 156 | rain_lightning_bits, 157 | rain_snow_bits, 158 | snow_moon_bits, 159 | snow_sun_bits, 160 | snow_bits, 161 | sun_bits, 162 | wind_bits}; 163 | 164 | 165 | 166 | void setup() { 167 | 168 | // put your setup code here, to run once: 169 | delay(1000); Serial.begin(115200); delay(200); 170 | 171 | 172 | /************** DISPLAY **************/ 173 | Sprintln("...Starting Display"); 174 | dma_display = new MatrixPanel_I2S_DMA(mxconfig); 175 | dma_display->begin(); 176 | dma_display->setBrightness8(90); //0-255 177 | dma_display->clearScreen(); 178 | 179 | dma_display->fillScreen(dma_display->color444(0, 1, 0)); 180 | 181 | // Fade a Red Wifi Logo In 182 | for (int r=0; r < 255; r++ ) 183 | { 184 | drawXbm565(0,0,64,32, wifi_image1bit, dma_display->color565(r,0,0)); 185 | delay(10); 186 | } 187 | 188 | delay(2000); 189 | dma_display->clearScreen(); 190 | } 191 | 192 | 193 | void loop() { 194 | 195 | // Loop through Weather Icons 196 | Serial.print("Showing icon "); 197 | Serial.println(icon_name[current_icon]); 198 | drawXbm565(0,0, 32, 32, icon_bits[current_icon]); 199 | 200 | current_icon = (current_icon +1 ) % num_icons; 201 | delay(2000); 202 | dma_display->clearScreen(); 203 | 204 | } -------------------------------------------------------------------------------- /examples/BitmapIcons/README.md: -------------------------------------------------------------------------------- 1 | # Xbm Bitmap example 2 | ## Requirements 3 | * To generate the required Xbm data to be copied into the Sketch. Have python and [paint.net](https://www.getpaint.net/) installed. 4 | * Bitmap should match the resolution of your display configuration. 5 | 6 | ## Instructions 7 | 1. SAVE BITMAP AS 1BIT COLOUR in paint.net 8 | 1. Run: bmp2hex.py -i -x (e.g. "bmp2hex.py -i -x WiFi1bit.bmp") 9 | 1. Copy paste output into sketch. 10 | 11 | ![bmp2hex usage screenshot](screenshot.jpg) 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/BitmapIcons/WiFi1bit.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/BitmapIcons/WiFi1bit.bmp -------------------------------------------------------------------------------- /examples/BitmapIcons/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/examples/BitmapIcons/screenshot.jpg -------------------------------------------------------------------------------- /examples/HueValueSpectrum/HueValueSpectrum.ino: -------------------------------------------------------------------------------- 1 | #define PANEL_RES_X 64 // Number of pixels wide of each INDIVIDUAL panel module. 2 | #define PANEL_RES_Y 32 // Number of pixels tall of each INDIVIDUAL panel module. 3 | #define PANEL_CHAIN 1 // Total number of panels chained one to another 4 | 5 | #include 6 | 7 | MatrixPanel_I2S_DMA *dma_display = nullptr; 8 | 9 | void setup() { 10 | 11 | Serial.begin(112500); 12 | 13 | 14 | HUB75_I2S_CFG::i2s_pins _pins={ 15 | 25, //R1_PIN, 16 | 26, //G1_PIN, 17 | 27, //B1_PIN, 18 | 14, //R2_PIN, 19 | 12, //G2_PIN, 20 | 13, //B2_PIN, 21 | 23, //A_PIN, 22 | 19, //B_PIN, 23 | 5, //C_PIN, 24 | 17, //D_PIN, 25 | 18, //E_PIN, 26 | 4, //LAT_PIN, 27 | 15, //OE_PIN, 28 | 16, //CLK_PIN 29 | }; 30 | HUB75_I2S_CFG mxconfig( 31 | PANEL_RES_X, // Module width 32 | PANEL_RES_Y, // Module height 33 | PANEL_CHAIN // // chain length 34 | //,_pins // pin mapping -- uncomment if providing own custom pin mapping as per above. 35 | ); 36 | //mxconfig.clkphase = false; 37 | //mxconfig.driver = HUB75_I2S_CFG::FM6126A; 38 | 39 | // Display Setup 40 | dma_display = new MatrixPanel_I2S_DMA(mxconfig); 41 | dma_display->begin(); 42 | dma_display->clearScreen(); 43 | } 44 | 45 | void loop() { 46 | // Canvas loop 47 | float t = (float) ((millis()%4000)/4000.f); 48 | float tt = (float) ((millis()%16000)/16000.f); 49 | 50 | for(int x = 0; x < (PANEL_RES_X*PANEL_CHAIN); x++) 51 | { 52 | // calculate the overal shade 53 | float f = (((sin(tt-(float)x/PANEL_RES_Y/32.)*2.f*PI)+1)/2)*255; 54 | // calculate hue spectrum into rgb 55 | float r = max(min(cosf(2.f*PI*(t+((float)x/PANEL_RES_Y+0.f)/3.f))+0.5f,1.f),0.f); 56 | float g = max(min(cosf(2.f*PI*(t+((float)x/PANEL_RES_Y+1.f)/3.f))+0.5f,1.f),0.f); 57 | float b = max(min(cosf(2.f*PI*(t+((float)x/PANEL_RES_Y+2.f)/3.f))+0.5f,1.f),0.f); 58 | 59 | // iterate pixels for every row 60 | for(int y = 0; y < PANEL_RES_Y; y++){ 61 | if(y*2 < PANEL_RES_Y){ 62 | // top-middle part of screen, transition of value 63 | float t = (2.f*y+1)/PANEL_RES_Y; 64 | dma_display->drawPixelRGB888(x,y, 65 | (r*t)*f, 66 | (g*t)*f, 67 | (b*t)*f 68 | ); 69 | }else{ 70 | // middle to bottom of screen, transition of saturation 71 | float t = (2.f*(PANEL_RES_Y-y)-1)/PANEL_RES_Y; 72 | dma_display->drawPixelRGB888(x,y, 73 | (r*t+1-t)*f, 74 | (g*t+1-t)*f, 75 | (b*t+1-t)*f 76 | ); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/PIO_TestPatterns/README.md: -------------------------------------------------------------------------------- 1 | # Test Patterns 2 | 3 | Simple solid colors, gradients and test line patterns, could be used to test matrices for proper operation, flickering and estimate fillrate timings. 4 | 5 | It is also used in CI test builds to check different build flags scenarios. 6 | 7 | Should be build and uploaded as a [platformio](https://platformio.org/) project 8 | 9 | 10 | To build with Arduino's framework use 11 | ``` 12 | pio run -t upload 13 | ``` 14 | 15 | To build using ESP32 IDF with arduino's component use 16 | ``` 17 | pio run -t upload -e idfarduino 18 | ``` 19 | -------------------------------------------------------------------------------- /examples/PIO_TestPatterns/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | default_envs = esp32 3 | description = HUB75 ESP32 I2S DMA test patterns example 4 | ;src_dir = src 5 | 6 | [env] 7 | platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip 8 | board = wemos_d1_mini32 9 | lib_deps = 10 | fastled/FastLED 11 | Wire 12 | adafruit/Adafruit BusIO 13 | adafruit/Adafruit GFX Library 14 | https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA.git 15 | upload_speed = 460800 16 | monitor_speed = 115200 17 | monitor_filters = esp32_exception_decoder 18 | 19 | [env:esp32] 20 | framework = arduino 21 | 22 | [env:esp32idf] 23 | framework = arduino, espidf 24 | -------------------------------------------------------------------------------- /examples/PIO_TestPatterns/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # Override some defaults to enable Arduino framework 2 | CONFIG_ENABLE_ARDUINO_DEPENDS=y 3 | CONFIG_AUTOSTART_ARDUINO=y 4 | CONFIG_ARDUINO_RUN_CORE1=y 5 | CONFIG_ARDUINO_RUNNING_CORE=1 6 | CONFIG_ARDUINO_EVENT_RUN_CORE1=y 7 | CONFIG_ARDUINO_EVENT_RUNNING_CORE=1 8 | CONFIG_ARDUINO_UDP_RUN_CORE1=y 9 | CONFIG_ARDUINO_UDP_RUNNING_CORE=1 10 | CONFIG_DISABLE_HAL_LOCKS=y 11 | CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_ERROR=y 12 | CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL=1 13 | CONFIG_ARDUHAL_PARTITION_SCHEME_DEFAULT=y 14 | CONFIG_ARDUHAL_PARTITION_SCHEME="default" 15 | CONFIG_AUTOCONNECT_WIFI=y 16 | CONFIG_ARDUINO_SELECTIVE_WiFi=y 17 | CONFIG_MBEDTLS_PSK_MODES=y 18 | CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y 19 | CONFIG_FREERTOS_HZ=1000 -------------------------------------------------------------------------------- /examples/PIO_TestPatterns/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file was automatically generated for projects 2 | # without default 'CMakeLists.txt' file. 3 | 4 | FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*) 5 | 6 | idf_component_register(SRCS ${app_sources}) 7 | -------------------------------------------------------------------------------- /examples/PIO_TestPatterns/src/main.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #define BAUD_RATE 115200 // serial debug port baud rate 5 | 6 | void buffclear(CRGB *buf); 7 | uint16_t XY16( uint16_t x, uint16_t y); 8 | void mxfill(CRGB *leds); 9 | uint16_t colorWheel(uint8_t pos); 10 | void drawText(int colorWheelOffset); -------------------------------------------------------------------------------- /examples/Pixel_Mapping_Test/Pixel_Mapping_Test.ino: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | Description: 3 | 4 | The underlying implementation of the ESP32-HUB75-MatrixPanel-I2S-DMA only 5 | supports output to HALF scan panels - which means outputting 6 | two lines at the same time, 16 or 32 rows apart if a 32px or 64px high panel 7 | respectively. 8 | This cannot be changed at the DMA layer as it would require a messy and complex 9 | rebuild of the library's internals. 10 | 11 | However, it is possible to connect QUARTER (i.e. FOUR lines updated in parallel) 12 | scan panels to this same library and 13 | 'trick' the output to work correctly on these panels by way of adjusting the 14 | pixel co-ordinates that are 'sent' to the ESP32-HUB75-MatrixPanel-I2S-DMA 15 | library. 16 | 17 | **************************************************************************/ 18 | 19 | /* Use the Virtual Display class to re-map co-ordinates such that they draw 20 | correctly on a 32x16 1/4 or 64x32 1/8 Scan panel (or chain of such panels). 21 | */ 22 | #include "ESP32-VirtualMatrixPanel-I2S-DMA.h" 23 | 24 | // Define custom class derived from VirtualMatrixPanel 25 | class CustomPxBasePanel : public VirtualMatrixPanel 26 | { 27 | public: 28 | using VirtualMatrixPanel::VirtualMatrixPanel; // inherit VirtualMatrixPanel's constructor(s) 29 | 30 | protected: 31 | 32 | VirtualCoords getCoords(int16_t x, int16_t y); // custom getCoords() method for specific pixel mapping 33 | 34 | }; 35 | 36 | // custom getCoords() method for specific pixel mapping 37 | inline VirtualCoords CustomPxBasePanel ::getCoords(int16_t x, int16_t y) { 38 | 39 | coords = VirtualMatrixPanel::getCoords(x, y); // call base class method to update coords for chaining approach 40 | 41 | if ( coords.x == -1 || coords.y == -1 ) { // Co-ordinates go from 0 to X-1 remember! width() and height() are out of range! 42 | return coords; 43 | } 44 | 45 | uint8_t pxbase = panelResX; // pixel base 46 | // mapper for panels with 32 pixs height (64x32 or 32x32) 47 | if (panelResY == 32) 48 | { 49 | if ((coords.y & 8) == 0) 50 | { 51 | coords.x += ((coords.x / pxbase) + 1) * pxbase; // 1st, 3rd 'block' of 8 rows of pixels 52 | } 53 | else 54 | { 55 | coords.x += (coords.x / pxbase) * pxbase; // 2nd, 4th 'block' of 8 rows of pixels 56 | } 57 | coords.y = (coords.y >> 4) * 8 + (coords.y & 0b00000111); 58 | } 59 | 60 | // mapper for panels with 16 pixs height (32x16 1/4) 61 | else if (panelResY == 16) 62 | { 63 | if ((coords.y & 4) == 0) 64 | { 65 | // 1. Normal line, from left to right 66 | coords.x += ((coords.x / pxbase) + 1) * pxbase; // 1st, 3rd 'block' of 4 rows of pixels 67 | //2. in case the line filled from right to left, use this (and comment 1st) 68 | //coords.x = ((coords.x / pxbase) + 1) * 2 * pxbase - (coords.x % pxbase) - 1; 69 | } 70 | else 71 | { 72 | coords.x += (coords.x / pxbase) * pxbase; // 2nd, 4th 'block' of 4 rows of pixels 73 | } 74 | coords.y = (coords.y >> 3) * 4 + (coords.y & 0b00000011); 75 | } 76 | return coords; 77 | } 78 | 79 | // Panel configuration 80 | #define PANEL_RES_X 32 // Number of pixels wide of each INDIVIDUAL panel module. 81 | #define PANEL_RES_Y 16 // Number of pixels tall of each INDIVIDUAL panel module. 82 | 83 | // Use a single panel for tests 84 | #define NUM_ROWS 1 // Number of rows of chained INDIVIDUAL PANELS 85 | #define NUM_COLS 1 // Number of INDIVIDUAL PANELS per ROW 86 | 87 | // Chain settings, do not cnahge 88 | #define SERPENT true 89 | #define TOPDOWN false 90 | #define VIRTUAL_MATRIX_CHAIN_TYPE CHAIN_BOTTOM_RIGHT_UP 91 | 92 | // placeholder for the matrix object 93 | MatrixPanel_I2S_DMA *dma_display = nullptr; 94 | 95 | // placeholder for the virtual display object 96 | CustomPxBasePanel *FourScanPanel = nullptr; 97 | 98 | /****************************************************************************** 99 | Setup! 100 | ******************************************************************************/ 101 | void setup() 102 | { 103 | HUB75_I2S_CFG mxconfig( 104 | PANEL_RES_X * 2, // DO NOT CHANGE THIS 105 | PANEL_RES_Y / 2, // DO NOT CHANGE THIS 106 | NUM_ROWS * NUM_COLS // DO NOT CHANGE THIS 107 | //,_pins // Uncomment to enable custom pins 108 | ); 109 | 110 | mxconfig.clkphase = false; // Change this if you see pixels showing up shifted wrongly by one column the left or right. 111 | 112 | // OK, now we can create our matrix object 113 | dma_display = new MatrixPanel_I2S_DMA(mxconfig); 114 | 115 | // let's adjust default brightness to about 75% 116 | dma_display->setBrightness8(40); // range is 0-255, 0 - 0%, 255 - 100% 117 | 118 | // Allocate memory and start DMA display 119 | if ( not dma_display->begin() ) 120 | Serial.println("****** !KABOOM! I2S memory allocation failed ***********"); 121 | 122 | 123 | dma_display->clearScreen(); 124 | delay(500); 125 | 126 | // create FourScanPanellay object based on our newly created dma_display object 127 | FourScanPanel = new CustomPxBasePanel ((*dma_display), NUM_ROWS, NUM_COLS, PANEL_RES_X, PANEL_RES_Y, VIRTUAL_MATRIX_CHAIN_TYPE); 128 | 129 | } 130 | 131 | 132 | void loop() { 133 | for (int i = 0; i < FourScanPanel->height(); i++) 134 | { 135 | for (int j = 0; j < FourScanPanel->width(); j++) 136 | { 137 | FourScanPanel->drawPixel(j, i, FourScanPanel->color565(255, 0, 0)); 138 | delay(30); 139 | } 140 | } 141 | delay(2000); 142 | dma_display->clearScreen(); 143 | } // end loop -------------------------------------------------------------------------------- /examples/Pixel_Mapping_Test/README.md: -------------------------------------------------------------------------------- 1 | ## Four Scan Panel pixel mapping test and tune 2 | This example is to help you set up pixel coordinate mapping on most common cases of Four_Scan_Panels such as 64x32 1/8 or 32x16 1/4. Please follow the steps below in sequence. 3 | 4 | ### 1. Run this code on a single panel 5 | If the panel lines are filled sequentially, from left to right and from top to bottom, then you don't need to change the setting. 6 | 7 | ### 2. If your panel filling in parts 8 | Most often, the panel rows are filled in small segments, 4, 8 or 16 pixels (there are other values). This number is the pixel base of the panel. Substitute it into line 45 of the example and run the code again. 9 | 10 | ### 3. Wrong order of rows 11 | At this point, your panel should already be filled with whole rows. If the top row is not the first to be filled, swap the expressions, marked in the comments as "1st, 3rd 'block' of rows" with "2nd, 4th 'block' of rows" one. 12 | 13 | ### 4. Wrong filling direction 14 | If any block of rows is filled from right to left, change the formula according to the example shown in the lines 65-68 of the code. 15 | 16 | ### Conclusion 17 | If your panel works correctly now - congratulations. But if not - it's okay. There are many types of different panels and it is impossible to foresee all the nuances. Create an issue and you will be helped! -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | | Example Name |Description | 2 | |--|--| 3 | |1_SimpleTestShapes |Example for new starters - how to display basic shapes. | 4 | |2_PatternPlasma |Example for new starters - how to display a cool plasma pattern. | 5 | |3_FM6126Panel |Example for new starters - how to initialise FM6126/FM6126A panels with this library. 6 | |AnimatedGIFPanel |Using Larry Bank's GIF Decoder to display animated GIFs. | 7 | |AuroraDemo |Simple example demonstrating various animated effects. | 8 | |BitmapIcons |Simple example of how to display a bitmap image to the display. | 9 | |ChainedPanels |Popular example on how to use the 'VirtualMatrixPanel' class to chain multiple LED Matrix Panels to form a much bigger display! Refer to the README within this example's folder! | 10 | |ChainedPanelsAuroraDemo |As above, but showing a large trippy plasma animation. | 11 | |ChainedPanelsScreenBuffer |Using the same 'VirtualMatrixPanel' class but also implementing a FastLED off-screen pixel buffer to do cool stuff. | 12 | |One_Quarter_1_4_ScanPanel |Using this library with a 32w x 16h 1/4 Scan LED Matrix Panel. Custom co-ordinate remapping logic required. NOT WORKING. | 13 | |One_Eighth_1_8_ScanPanel |Using this library with a 64w x 32h 1/8 Scan LED Matrix Panel. Custom co-ordinate remapping logic required. 14 | |PIO_TestPatterns |Non-Arduino example of how to display basic shapes. | 15 | -------------------------------------------------------------------------------- /examples/VirtualMatrixPanel/README.md: -------------------------------------------------------------------------------- 1 | # The 'VirtualMatrixPanel_T' class 2 | The `VirtualMatrixPanel_T` is used to perform pixel re-mapping in order to support the following use-cases that can be used together: 3 | 1. To create a larger display based on a chain of individual physical panels connected electrically in a Serpentine or Zig-Zag manner. 4 | 2. To provide support for physical panels with non-standard (i.e. Not a 1/2 scan panel) pixel mapping approaches. This is often seen with 1/4 scan outdoor panels. 5 | 6 | ## 1. Chaining individual LED matrix panels to make a larger virtual display ## 7 | 8 | This is the PatternPlasma Demo adopted for use with multiple LED Matrix Panel displays arranged in a non standard order (i.e. a grid) to make a bigger display. 9 | 10 | ![334894846_975082690567510_1362796919784291270_n](https://user-images.githubusercontent.com/89576620/224304944-94fe3483-d3cc-4aba-be0a-40b33ff901dc.jpg) 11 | 12 | ### What do we mean by 'non standard order'? ### 13 | 14 | When you link / chain multiple panels together, the ESP32-HUB75-MatrixPanel-I2S-DMA library treats as one wide horizontal panel. This would be a 'standard' (default) order. 15 | 16 | Non-standard order is essentially the creation of a non-horizontal-only display that you can draw to in the same way you would any other display, with VirtualDisplay library looking after the pixel mapping to the physical chained panels. 17 | 18 | For example: You bought four (4) 64x32px panels, and wanted to use them to create a 128x64pixel display. You would use the VirtualMatrixPanel class. 19 | 20 | [Refer to this document](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/blob/master/doc/VirtualMatrixPanel.pdf) for an explanation and refer to this example on how to use. 21 | 22 | 23 | ### Steps to Use ### 24 | 25 | 1. [Refer to this document](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/blob/master/doc/VirtualMatrixPanel.pdf) for an explanation and refer to this example on how to use. 26 | 27 | 2. Read the `VirtualMatrixPanel.ino` code 28 | 29 | ## 2. Using this library with 1/4 Scan Panels (Four Scan) 30 | 31 | This library does not natively support 'Four Scan' 64x32 1/8 or 32x16 1/4 scan panels such [as this](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-I2S-DMA/issues/154) by default. 32 | 33 | ### Solution 34 | Read the `VirtualMatrixPanel.ino` code. 35 | 36 | The VirtualMatrixPanel_T class provides a way to additionally remap pixel for each individual panel by way of the `ScanTypeMapping` class. 37 | 38 | You can create your own custom per-panel pixel mapping class as well should you wish. 39 | 40 | ```cpp 41 | // --- Example 3: Single non-standard 1/4 Scan (Four-Scan 1/8) --- 42 | 43 | // Use an existing library user-contributed Scan Type pixel mapping 44 | using MyScanTypeMapping = ScanTypeMapping; 45 | 46 | // Create a pointer to the specific instantiation of the VirtualMatrixPanel_T class 47 | VirtualMatrixPanel_T* virtualDisp = nullptr; 48 | ``` 49 | 50 | The library has these user-contributed additions, but given the variety of panels on the market, your success with any of these may vary. 51 | 52 | ```cpp 53 | FOUR_SCAN_32PX_HIGH, ///< Four-scan mode, 32-pixel high panels. 54 | FOUR_SCAN_16PX_HIGH, ///< Four-scan mode, 16-pixel high panels. 55 | FOUR_SCAN_64PX_HIGH, ///< Four-scan mode, 64-pixel high panels. 56 | FOUR_SCAN_40PX_HIGH ///< Four-scan mode, 40-pixel high panels. 57 | ``` -------------------------------------------------------------------------------- /examples/esp-idf/.gitignore: -------------------------------------------------------------------------------- 1 | # ESP-IDF default build directory 2 | build 3 | 4 | # Temporary files 5 | *.swp 6 | 7 | # lock files for examples and components 8 | dependencies.lock 9 | 10 | sdkconfig* 11 | # Unignore sdkconfig.defaults 12 | !sdkconfig.defaults 13 | -------------------------------------------------------------------------------- /examples/esp-idf/with-gfx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This is a boilerplate top-level project CMakeLists.txt file. 2 | # This is the primary file which CMake uses to learn how to build the project. 3 | # 4 | # Most of the important stuff happens in the 'main' directory. 5 | # 6 | # See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#example-project for more details. 7 | cmake_minimum_required(VERSION 3.5) 8 | 9 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 10 | project(with-gfx) 11 | -------------------------------------------------------------------------------- /examples/esp-idf/with-gfx/README.md: -------------------------------------------------------------------------------- 1 | # ESP-IDF Example With Adafruit GFX Library 2 | 3 | This folder contains example code for using this library with `esp-idf` and the [Adafruit GFX library](https://github.com/adafruit/Adafruit-GFX-Library). 4 | 5 | First, follow the [Getting Started Guide for ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) to install ESP-IDF onto your computer. 6 | 7 | When you are ready to start your first project with this library, follow folow these steps: 8 | 9 | 1. Copy the files in this folder (and sub folders) into a new directory for your project. 10 | 1. Clone the required repositories: 11 | ``` 12 | git clone https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA.git components/ESP32-HUB75-MatrixPanel-I2S-DMA 13 | git clone https://github.com/adafruit/Adafruit-GFX-Library.git components/Adafruit-GFX-Library 14 | git clone https://github.com/adafruit/Adafruit_BusIO.git components/Adafruit_BusIO 15 | git clone https://github.com/espressif/arduino-esp32.git components/arduino 16 | ``` 17 | 1. Build your project: `idf.py build` 18 | -------------------------------------------------------------------------------- /examples/esp-idf/with-gfx/components/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /examples/esp-idf/with-gfx/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRC_DIRS "." ${SRCDIRS} 3 | INCLUDE_DIRS ${INCLUDEDIRS} 4 | REQUIRES ESP32-HUB75-MatrixPanel-I2S-DMA 5 | ) 6 | -------------------------------------------------------------------------------- /examples/esp-idf/with-gfx/main/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" 2 | 3 | MatrixPanel_I2S_DMA *dma_display = nullptr; 4 | 5 | extern "C" void app_main() { 6 | HUB75_I2S_CFG mxconfig(/* width = */ 64, /* height = */ 64, /* chain = */ 1); 7 | 8 | dma_display = new MatrixPanel_I2S_DMA(mxconfig); 9 | dma_display->begin(); 10 | dma_display->setBrightness8(80); 11 | dma_display->clearScreen(); 12 | // `println` is only available when the Adafruit GFX library is used. 13 | dma_display->println("Test message"); 14 | } 15 | -------------------------------------------------------------------------------- /examples/esp-idf/with-gfx/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_FREERTOS_HZ=1000 2 | -------------------------------------------------------------------------------- /examples/esp-idf/without-gfx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This is a boilerplate top-level project CMakeLists.txt file. 2 | # This is the primary file which CMake uses to learn how to build the project. 3 | # 4 | # Most of the important stuff happens in the 'main' directory. 5 | # 6 | # See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#example-project for more details. 7 | cmake_minimum_required(VERSION 3.5) 8 | 9 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 10 | project(without-gfx) 11 | -------------------------------------------------------------------------------- /examples/esp-idf/without-gfx/README.md: -------------------------------------------------------------------------------- 1 | # ESP-IDF Example Without Adafruit GFX Library 2 | 3 | This folder contains example code for using this library with `esp-idf`. 4 | 5 | First, follow the [Getting Started Guide for ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) to install ESP-IDF onto your computer. 6 | 7 | When you are ready to start your first project with this library, follow folow these steps: 8 | 9 | 1. Copy the files in this folder (and sub folders) into a new directory for your project. 10 | 1. Clone the required repositories: 11 | ``` 12 | git clone https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA.git components/ESP32-HUB75-MatrixPanel-I2S-DMA 13 | ``` 14 | 1. Build your project: `idf.py build` 15 | -------------------------------------------------------------------------------- /examples/esp-idf/without-gfx/components/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /examples/esp-idf/without-gfx/main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRC_DIRS "." ${SRCDIRS} 3 | INCLUDE_DIRS ${INCLUDEDIRS} 4 | REQUIRES ESP32-HUB75-MatrixPanel-I2S-DMA 5 | ) 6 | -------------------------------------------------------------------------------- /examples/esp-idf/without-gfx/main/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ESP32-HUB75-MatrixPanel-I2S-DMA.h" 2 | 3 | MatrixPanel_I2S_DMA *dma_display = nullptr; 4 | 5 | extern "C" void app_main() { 6 | HUB75_I2S_CFG mxconfig(/* width = */ 64, /* height = */ 64, /* chain = */ 1); 7 | 8 | dma_display = new MatrixPanel_I2S_DMA(mxconfig); 9 | dma_display->begin(); 10 | dma_display->setBrightness8(80); 11 | dma_display->clearScreen(); 12 | } 13 | -------------------------------------------------------------------------------- /examples/esp-idf/without-gfx/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_ESP32_HUB75_USE_GFX=n 2 | -------------------------------------------------------------------------------- /image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/image.jpg -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | RGB64x32MatrixPanel_I2S_DMA KEYWORD1 2 | MatrixPanel_I2S_DMA KEYWORD1 3 | Layer KEYWORD1 4 | fillScreen KEYWORD2 5 | clearScreen KEYWORD2 6 | fillScreenRGB888 KEYWORD2 7 | drawPixelRGB565 KEYWORD2 8 | drawPixelRGB888 KEYWORD2 9 | drawPixelRGB24 KEYWORD2 10 | drawIcon KEYWORD2 11 | color444 KEYWORD2 12 | color565 KEYWORD2 13 | color333 KEYWORD2 14 | flipDMABuffer KEYWORD2 15 | showDMABuffer KEYWORD2 16 | setPanelBrightness KEYWORD2 17 | setMinRefreshRate KEYWORD2 18 | RGB24 KEYWORD1 -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ESP32 HUB75 LED MATRIX PANEL DMA Display", 3 | "version": "3.0.12", 4 | "description": "An Adafruit GFX compatible library for LED matrix modules which uses DMA for ultra-fast refresh rates and therefore very low CPU usage.", 5 | "keywords": "hub75, esp32, esp32s2, esp32s3, display, dma, rgb matrix", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git" 9 | }, 10 | "authors": { 11 | "name": "MrCodetastic", 12 | "url": "https://github.com/mrcodetastic/" 13 | }, 14 | "frameworks": [ 15 | "arduino", 16 | "espidf" 17 | ], 18 | "platforms": [ 19 | "espressif32" 20 | ], 21 | "headers": [ 22 | "ESP32-HUB75-MatrixPanel-I2S-DMA.h", "ESP32-VirtualMatrixPanel-I2S-DMA.h" 23 | ], 24 | "examples": [ 25 | { 26 | "name": "SimpleTestShapes", 27 | "base": "examples/1_SimpleTestShapes", 28 | "files": [ 29 | "1_SimpleTestShapes.ino" 30 | ] 31 | }, 32 | { 33 | "name": "Plasma Pattern", 34 | "base": "examples/2_PatternPlasma", 35 | "files": [ 36 | "2_PatternPlasma.ino", 37 | "README.md" 38 | ] 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESP32 HUB75 LED MATRIX PANEL DMA Display 2 | version= 3.0.12 3 | author=MrCodetastic 4 | maintainer=MrCodetastic 5 | sentence=HUB75 LED Matrix Library for ESP32, ESP32-S2 and ESP32-S3 6 | paragraph=An Adafruit GFX compatible library for LED matrix modules which uses DMA for ultra-fast refresh rates and therefore very low CPU usage. 7 | category=Display 8 | url=https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA 9 | architectures=esp32,esp32s2,esp32s3 10 | -------------------------------------------------------------------------------- /src/platforms/esp32/RGB_HUB75_PINS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/src/platforms/esp32/RGB_HUB75_PINS.png -------------------------------------------------------------------------------- /src/platforms/esp32/esp32-default-pins.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define R1_PIN_DEFAULT 25 4 | #define G1_PIN_DEFAULT 26 5 | #define B1_PIN_DEFAULT 27 6 | #define R2_PIN_DEFAULT 14 7 | #define G2_PIN_DEFAULT 12 8 | #define B2_PIN_DEFAULT 13 9 | 10 | #define A_PIN_DEFAULT 23 11 | #define B_PIN_DEFAULT 19 12 | #define C_PIN_DEFAULT 5 13 | #define D_PIN_DEFAULT 17 14 | #define E_PIN_DEFAULT -1 // IMPORTANT: Change to a valid pin if using a 64x64px panel. 15 | 16 | #define LAT_PIN_DEFAULT 4 17 | #define OE_PIN_DEFAULT 15 18 | #define CLK_PIN_DEFAULT 16 19 | -------------------------------------------------------------------------------- /src/platforms/esp32/esp32_i2s_parallel_dma.hpp: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | Lovyan GFX - Graphics library for embedded devices. 3 | 4 | Original Source: 5 | https://github.com/lovyan03/LovyanGFX/ 6 | 7 | Licence: 8 | [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) 9 | 10 | Author: 11 | [lovyan03](https://twitter.com/lovyan03) 12 | 13 | Contributors: 14 | [ciniml](https://github.com/ciniml) 15 | [mongonta0716](https://github.com/mongonta0716) 16 | [tobozo](https://github.com/tobozo) 17 | 18 | Modified heavily for the ESP32 HUB75 DMA library by: 19 | [mrfaptastic](https://github.com/mrfaptastic) 20 | 21 | ------------------------------------------------------------------------------ 22 | 23 | Putin’s Russia and its genocide of Ukrainians is a disgrace to humanity. 24 | 25 | https://www.reddit.com/r/ukraine/comments/xfuc6v/more_than_460_graves_have_already_been_found_in/ 26 | 27 | /----------------------------------------------------------------------------*/ 28 | 29 | #pragma once 30 | 31 | #include // memcpy 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | //#include 38 | #include 39 | #include 40 | #if (ESP_IDF_VERSION_MAJOR == 5) 41 | #include //includes struct and reg 42 | #else 43 | #include 44 | #include 45 | #endif 46 | 47 | #include //includes struct and reg 48 | 49 | 50 | #define DMA_MAX (4096-4) 51 | 52 | // The type used for this SoC 53 | #define HUB75_DMA_DESCRIPTOR_T lldesc_t 54 | 55 | 56 | #if defined (CONFIG_IDF_TARGET_ESP32S2) 57 | #define ESP32_I2S_DEVICE I2S_NUM_0 58 | #else 59 | #define ESP32_I2S_DEVICE I2S_NUM_1 60 | #endif 61 | 62 | //---------------------------------------------------------------------------- 63 | 64 | void IRAM_ATTR irq_hndlr(void* arg); 65 | i2s_dev_t* getDev(); 66 | 67 | //---------------------------------------------------------------------------- 68 | 69 | class Bus_Parallel16 70 | { 71 | public: 72 | Bus_Parallel16() 73 | { 74 | 75 | } 76 | 77 | struct config_t 78 | { 79 | // max 20MHz (when in 16 bit / 2 byte mode) 80 | uint32_t bus_freq = 10000000; 81 | int8_t pin_wr = -1; // 82 | int8_t pin_rd = -1; 83 | int8_t pin_rs = -1; // D/C 84 | bool invert_pclk = false; 85 | int8_t parallel_width = 16; // do not change 86 | union 87 | { 88 | int8_t pin_data[16]; 89 | struct 90 | { 91 | int8_t pin_d0; 92 | int8_t pin_d1; 93 | int8_t pin_d2; 94 | int8_t pin_d3; 95 | int8_t pin_d4; 96 | int8_t pin_d5; 97 | int8_t pin_d6; 98 | int8_t pin_d7; 99 | int8_t pin_d8; 100 | int8_t pin_d9; 101 | int8_t pin_d10; 102 | int8_t pin_d11; 103 | int8_t pin_d12; 104 | int8_t pin_d13; 105 | int8_t pin_d14; 106 | int8_t pin_d15; 107 | }; 108 | }; 109 | }; 110 | 111 | const config_t& config(void) const { return _cfg; } 112 | void config(const config_t& config); 113 | 114 | bool init(void) ; 115 | void release(void) ; 116 | 117 | void enable_double_dma_desc(); 118 | bool allocate_dma_desc_memory(size_t len); 119 | 120 | void create_dma_desc_link(void *memory, size_t size, bool dmadesc_b = false); 121 | 122 | void dma_transfer_start(); 123 | void dma_transfer_stop(); 124 | 125 | void flip_dma_output_buffer(int buffer_id); 126 | 127 | private: 128 | 129 | void _init_pins() { }; 130 | 131 | config_t _cfg; 132 | 133 | bool _double_dma_buffer = false; 134 | //bool _dmadesc_a_active = true; 135 | 136 | uint32_t _dmadesc_count = 0; // number of dma decriptors 137 | uint32_t _dmadesc_last = 0; 138 | 139 | uint32_t _dmadesc_a_idx = 0; 140 | uint32_t _dmadesc_b_idx = 0; 141 | 142 | HUB75_DMA_DESCRIPTOR_T* _dmadesc_a = nullptr; 143 | HUB75_DMA_DESCRIPTOR_T* _dmadesc_b = nullptr; 144 | 145 | /* 146 | HUB75_DMA_DESCRIPTOR_T* _dmadesc_blank = nullptr; 147 | uint16_t _blank_data[1024] = {0}; 148 | */ 149 | 150 | volatile i2s_dev_t* _dev; 151 | 152 | 153 | 154 | }; 155 | -------------------------------------------------------------------------------- /src/platforms/esp32c6/dma_parallel_io.hpp.notused: -------------------------------------------------------------------------------- 1 | /* 2 | Simple example of using the ESP32-C6's parallel IO peripheral for general-purpose 3 | parallel data output with DMA. 4 | 5 | Credits to ESPRESSIF them selfe, they made the first example: 6 | 7 | https://github.com/espressif/esp-idf/tree/release/v5.1/examples/peripherals/parlio/simple_rgb_led_matrix 8 | 9 | And Credits to the guy who implemented the S3 version of this library. 10 | There is a lot of resusable code 11 | 12 | 13 | */ 14 | 15 | 16 | #pragma once 17 | 18 | #include 19 | 20 | #ifdef CONFIG_IDF_TARGET_ESP32C6 21 | 22 | #include "driver/parlio_tx.h" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | 29 | #define DMA_MAX (4096-4) 30 | #define HUB75_DMA_DESCRIPTOR_T dma_descriptor_t 31 | 32 | 33 | class Bus_Parallel16 34 | { 35 | public: 36 | Bus_Parallel16() 37 | { 38 | 39 | } 40 | 41 | struct config_t 42 | { 43 | // LCD_CAM peripheral number. No need to change (only 0 for ESP32-S3.) 44 | //int port = 0; 45 | 46 | // max 40MHz (when in 16 bit / 2 byte mode) 47 | uint32_t bus_freq = 10000000; 48 | int8_t pin_wr = -1; 49 | //int8_t pin_rd = -1; 50 | //int8_t pin_rs = -1; // D/C 51 | bool invert_pclk = false; 52 | union 53 | { 54 | int8_t pin_data[16]; 55 | struct 56 | { 57 | int8_t pin_d0; 58 | int8_t pin_d1; 59 | int8_t pin_d2; 60 | int8_t pin_d3; 61 | int8_t pin_d4; 62 | int8_t pin_d5; 63 | int8_t pin_d6; 64 | int8_t pin_d7; 65 | int8_t pin_d8; 66 | int8_t pin_d9; 67 | int8_t pin_d10; 68 | int8_t pin_d11; 69 | int8_t pin_d12; 70 | int8_t pin_d13; 71 | int8_t pin_d14; 72 | int8_t pin_d15; 73 | }; 74 | }; 75 | }; 76 | 77 | const config_t& config(void) const { return _cfg; } 78 | void config(const config_t& config); 79 | 80 | bool init(void) ; 81 | 82 | void release(void) ; 83 | 84 | void enable_double_dma_desc(); 85 | bool allocate_dma_desc_memory(size_t len); 86 | 87 | void create_dma_desc_link(void *memory, size_t size, bool dmadesc_b = false); 88 | 89 | void dma_transfer_start(); 90 | void dma_transfer_stop(); 91 | 92 | void flip_dma_output_buffer(int back_buffer_id); 93 | 94 | private: 95 | 96 | config_t _cfg; 97 | 98 | gdma_channel_handle_t dma_chan; 99 | 100 | uint32_t _dmadesc_count = 0; // number of dma decriptors 101 | 102 | uint32_t _dmadesc_a_idx = 0; 103 | uint32_t _dmadesc_b_idx = 0; 104 | 105 | HUB75_DMA_DESCRIPTOR_T* _dmadesc_a = nullptr; 106 | HUB75_DMA_DESCRIPTOR_T* _dmadesc_b = nullptr; 107 | 108 | bool _double_dma_buffer = false; 109 | //bool _dmadesc_a_active = true; 110 | 111 | }; 112 | 113 | 114 | 115 | #endif -------------------------------------------------------------------------------- /src/platforms/esp32c6/esp32c6-default-pins.hpp.notused: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Avoid and QSPI pins 4 | 5 | #define R1_PIN_DEFAULT 7 6 | #define G1_PIN_DEFAULT 4 7 | #define B1_PIN_DEFAULT 1 8 | #define R2_PIN_DEFAULT 6 9 | #define G2_PIN_DEFAULT 3 10 | #define B2_PIN_DEFAULT 0 11 | #define A_PIN_DEFAULT 20 12 | #define B_PIN_DEFAULT 21 13 | #define C_PIN_DEFAULT 22 14 | #define D_PIN_DEFAULT 23 15 | #define E_PIN_DEFAULT -1 // required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32 16 | #define LAT_PIN_DEFAULT 5 17 | #define OE_PIN_DEFAULT 2 18 | #define CLK_PIN_DEFAULT 10 19 | -------------------------------------------------------------------------------- /src/platforms/esp32s2/esp32s2-default-pins.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define R1_PIN_DEFAULT 45 4 | #define G1_PIN_DEFAULT 42 5 | #define B1_PIN_DEFAULT 41 6 | #define R2_PIN_DEFAULT 40 7 | #define G2_PIN_DEFAULT 39 8 | #define B2_PIN_DEFAULT 38 9 | #define A_PIN_DEFAULT 37 10 | #define B_PIN_DEFAULT 36 11 | #define C_PIN_DEFAULT 35 12 | #define D_PIN_DEFAULT 34 13 | #define E_PIN_DEFAULT -1 // required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32 14 | #define LAT_PIN_DEFAULT 26 15 | #define OE_PIN_DEFAULT 21 16 | #define CLK_PIN_DEFAULT 33 17 | -------------------------------------------------------------------------------- /src/platforms/esp32s3/ESP32-S3-DevKitC-1-pin-layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/src/platforms/esp32s3/ESP32-S3-DevKitC-1-pin-layout.png -------------------------------------------------------------------------------- /src/platforms/esp32s3/Readme.md: -------------------------------------------------------------------------------- 1 | https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/external-ram.html 2 | 3 | Restrictions 4 | 5 | External RAM use has the following restrictions: 6 | 7 | When flash cache is disabled (for example, if the flash is being written to), the external RAM also becomes inaccessible; any reads from or writes to it will lead to an illegal cache access exception. This is also the reason why ESP-IDF does not by default allocate any task stacks in external RAM (see below). 8 | 9 | External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Therefore when External RAM is enabled, any buffer that will be used in combination with DMA must be allocated using heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL) and can be freed using a standard free() call. 10 | 11 | *Note, although ESP32-S3 has hardware support for DMA to/from external RAM, this is not yet supported in ESP-IDF.* 12 | 13 | External RAM uses the same cache region as the external flash. This means that frequently accessed variables in external RAM can be read and modified almost as quickly as in internal ram. However, when accessing large chunks of data (>32 KB), the cache can be insufficient, and speeds will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can “push out” cached flash, possibly making the execution of code slower afterwards. 14 | 15 | In general, external RAM will not be used as task stack memory. xTaskCreate() and similar functions will always allocate internal memory for stack and task TCBs. 16 | 17 | Reserved Pins on ESP32-S3: 18 | 19 | ![Reserved Pins](ReservedPinsForPSRAM.PNG) 20 | 21 | Devkit Layout: 22 | 23 | ![ESP32-S3 DevKit layout](ESP32-S3-DevKitC-1-pin-layout.png) 24 | 25 | -------------------------------------------------------------------------------- /src/platforms/esp32s3/ReservedPinsForPSRAM.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/fb3499fb66fb4941af8a818eb9be0548fe4b7a60/src/platforms/esp32s3/ReservedPinsForPSRAM.PNG -------------------------------------------------------------------------------- /src/platforms/esp32s3/esp32s3-default-pins.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Avoid and QSPI pins 4 | 5 | #define R1_PIN_DEFAULT 4 6 | #define G1_PIN_DEFAULT 5 7 | #define B1_PIN_DEFAULT 6 8 | #define R2_PIN_DEFAULT 7 9 | #define G2_PIN_DEFAULT 15 10 | #define B2_PIN_DEFAULT 16 11 | #define A_PIN_DEFAULT 18 12 | #define B_PIN_DEFAULT 8 13 | #define C_PIN_DEFAULT 3 14 | #define D_PIN_DEFAULT 42 15 | #define E_PIN_DEFAULT -1 // required for 1/32 scan panels, like 64x64. Any available pin would do, i.e. IO32 16 | #define LAT_PIN_DEFAULT 40 17 | #define OE_PIN_DEFAULT 2 18 | #define CLK_PIN_DEFAULT 41 19 | -------------------------------------------------------------------------------- /src/platforms/esp32s3/gdma_lcd_parallel16.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Simple example of using the ESP32-S3's LCD peripheral for general-purpose 3 | (non-LCD) parallel data output with DMA. Connect 8 LEDs (or logic analyzer), 4 | cycles through a pattern among them at about 1 Hz. 5 | This code is ONLY for the ESP32-S3, NOT the S2, C3 or original ESP32. 6 | None of this is authoritative canon, just a lot of trial error w/datasheet 7 | and register poking. Probably more robust ways of doing this still TBD. 8 | 9 | 10 | FULL CREDIT goes to AdaFruit 11 | 12 | https://blog.adafruit.com/2022/06/21/esp32uesday-more-s3-lcd-peripheral-hacking-with-code/ 13 | 14 | PLEASE SUPPORT THEM! 15 | 16 | 17 | Putin’s Russia and its genocide in Ukraine is a disgrace to humanity. 18 | 19 | https://www.reddit.com/r/ukraine/comments/xfuc6v/more_than_460_graves_have_already_been_found_in/ 20 | 21 | 22 | /---------------------------------------------------------------------------- 23 | 24 | */ 25 | 26 | #pragma once 27 | 28 | #if __has_include () 29 | 30 | #include 31 | #include 32 | 33 | //#include 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | 42 | 43 | #include 44 | #include 45 | 46 | 47 | 48 | #include 49 | #include 50 | 51 | #include 52 | 53 | /* 54 | #if (ESP_IDF_VERSION_MAJOR == 5) 55 | #include 56 | #else 57 | #include 58 | #endif 59 | */ 60 | 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | #include 67 | #include 68 | #include 69 | 70 | #include 71 | #include 72 | 73 | 74 | #if __has_include () 75 | #include 76 | #else 77 | #include 78 | #endif 79 | 80 | #if __has_include() 81 | #include 82 | #endif 83 | 84 | #define DMA_MAX (4096-4) 85 | 86 | // The type used for this SoC 87 | #define HUB75_DMA_DESCRIPTOR_T dma_descriptor_t 88 | 89 | 90 | //---------------------------------------------------------------------------- 91 | 92 | class Bus_Parallel16 93 | { 94 | public: 95 | Bus_Parallel16() 96 | { 97 | 98 | } 99 | 100 | struct config_t 101 | { 102 | // LCD_CAM peripheral number. No need to change (only 0 for ESP32-S3.) 103 | //int port = 0; 104 | 105 | // max 40MHz (when in 16 bit / 2 byte mode) 106 | uint32_t bus_freq = 10000000; 107 | int8_t pin_wr = -1; 108 | int8_t pin_rd = -1; 109 | int8_t pin_rs = -1; // D/C 110 | bool invert_pclk = false; 111 | union 112 | { 113 | int8_t pin_data[16]; 114 | struct 115 | { 116 | int8_t pin_d0; 117 | int8_t pin_d1; 118 | int8_t pin_d2; 119 | int8_t pin_d3; 120 | int8_t pin_d4; 121 | int8_t pin_d5; 122 | int8_t pin_d6; 123 | int8_t pin_d7; 124 | int8_t pin_d8; 125 | int8_t pin_d9; 126 | int8_t pin_d10; 127 | int8_t pin_d11; 128 | int8_t pin_d12; 129 | int8_t pin_d13; 130 | int8_t pin_d14; 131 | int8_t pin_d15; 132 | }; 133 | }; 134 | }; 135 | 136 | const config_t& config(void) const { return _cfg; } 137 | void config(const config_t& config); 138 | 139 | bool init(void) ; 140 | 141 | void release(void) ; 142 | 143 | void enable_double_dma_desc(); 144 | bool allocate_dma_desc_memory(size_t len); 145 | 146 | void create_dma_desc_link(void *memory, size_t size, bool dmadesc_b = false); 147 | 148 | void dma_transfer_start(); 149 | void dma_transfer_stop(); 150 | 151 | void flip_dma_output_buffer(int back_buffer_id); 152 | 153 | private: 154 | 155 | config_t _cfg; 156 | 157 | volatile lcd_cam_dev_t* _dev; 158 | gdma_channel_handle_t dma_chan; 159 | 160 | uint32_t _dmadesc_count = 0; // number of dma decriptors 161 | 162 | uint32_t _dmadesc_a_idx = 0; 163 | uint32_t _dmadesc_b_idx = 0; 164 | 165 | HUB75_DMA_DESCRIPTOR_T* _dmadesc_a = nullptr; 166 | HUB75_DMA_DESCRIPTOR_T* _dmadesc_b = nullptr; 167 | 168 | bool _double_dma_buffer = false; 169 | 170 | esp_lcd_i80_bus_handle_t _i80_bus = nullptr; 171 | 172 | 173 | }; 174 | 175 | 176 | #endif -------------------------------------------------------------------------------- /src/platforms/platform_detect.hpp: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | Original Source: 3 | https://github.com/lovyan03/LovyanGFX/ 4 | 5 | Licence: 6 | [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) 7 | 8 | Author: 9 | [lovyan03](https://twitter.com/lovyan03) 10 | 11 | Contributors: 12 | [ciniml](https://github.com/ciniml) 13 | [mongonta0716](https://github.com/mongonta0716) 14 | [tobozo](https://github.com/tobozo) 15 | 16 | Modified heavily for the ESP32 HUB75 DMA library by: 17 | [mrfaptastic](https://github.com/mrfaptastic) 18 | /----------------------------------------------------------------------------*/ 19 | #pragma once 20 | 21 | #if defined (ESP_PLATFORM) 22 | 23 | #include 24 | 25 | #if defined (CONFIG_IDF_TARGET_ESP32S2) 26 | 27 | //#pragma message "Compiling for ESP32-S2" 28 | #include "esp32/esp32_i2s_parallel_dma.hpp" 29 | #include "esp32s2/esp32s2-default-pins.hpp" 30 | 31 | 32 | #elif defined (CONFIG_IDF_TARGET_ESP32S3) 33 | 34 | //#pragma message "Compiling for ESP32-S3" 35 | #include "esp32s3/gdma_lcd_parallel16.hpp" 36 | #include "esp32s3/esp32s3-default-pins.hpp" 37 | 38 | #if defined(SPIRAM_FRAMEBUFFER) 39 | #pragma message "Use SPIRAM_DMA_BUFFER instead." 40 | #endif 41 | 42 | #if defined(SPIRAM_DMA_BUFFER) && defined (CONFIG_IDF_TARGET_ESP32S3) 43 | #pragma message "Enabling use of PSRAM/SPIRAM based DMA Buffer" 44 | 45 | // Disable fast functions because I don't understand the interaction with DMA PSRAM and the CPU->DMA->SPIRAM Cache implications.. 46 | #define NO_FAST_FUNCTIONS 1 47 | 48 | #endif 49 | 50 | #elif defined(CONFIG_IDF_TARGET_ESP32C6) 51 | 52 | #pragma message "ESP32C6 is not supported, as this silicon does not support continuous DMA transfer." 53 | 54 | /* 55 | * Refer to: https://github.com/espressif/esp-idf/tree/master/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix 56 | * "Because of the hardware limitation in ESP32-C6 and ESP32-H2, the transaction length can't be controlled by DMA, thus 57 | * we can't flush the LED screen continuously within a hardware loop." 58 | * 59 | */ 60 | 61 | //#include "esp32c6/dma_parallel_io.hpp" 62 | //#include "esp32c6/esp32c6-default-pins.hpp" 63 | 64 | #elif defined(CONFIG_IDF_TARGET_ESP32P4) 65 | 66 | #pragma message "You are ahead of your time. ESP32P4 support is planned" 67 | 68 | #elif defined (CONFIG_IDF_TARGET_ESP32) || defined(ESP32) 69 | 70 | // Assume an ESP32 (the original 2015 version) 71 | // Same include as ESP32S3 72 | //#pragma message "Compiling for original ESP32 (released 2016)" 73 | 74 | #define ESP32_THE_ORIG 1 75 | //#include "esp32/esp32_i2s_parallel_dma.hpp" 76 | //#include "esp32/esp32_i2s_parallel_dma.h" 77 | #include "esp32/esp32_i2s_parallel_dma.hpp" 78 | #include "esp32/esp32-default-pins.hpp" 79 | 80 | #elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32H2) 81 | 82 | #error "ESP32 C2 C3 and H2 devices are not supported by this library." 83 | 84 | 85 | #else 86 | #error "Unknown platform." 87 | 88 | #endif 89 | 90 | 91 | #endif 92 | 93 | -------------------------------------------------------------------------------- /testing/README.md: -------------------------------------------------------------------------------- 1 | Sample app to simulate the VirtualMatrixPanel class for testing / optimisation, without having to test with physical panels. 2 | 3 | ``` 4 | g++ -o myapp.exe virtual.cpp 5 | ``` -------------------------------------------------------------------------------- /testing/baseline.hpp: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Calculate virtual->real co-ordinate mapping to underlying single chain of panels connected to ESP32. 4 | * Updates the private class member variable 'coords', so no need to use the return value. 5 | * Not thread safe, but not a concern for ESP32 sketch anyway... I think. 6 | */ 7 | // DO NOT CHANGE 8 | inline VirtualCoords VirtualMatrixPanelTest::getCoords_WorkingBaslineMarch2023(int16_t virt_x, int16_t virt_y) 9 | { 10 | coords.x = coords.y = -1; // By defalt use an invalid co-ordinates that will be rejected by updateMatrixDMABuffer 11 | 12 | if (virt_x < 0 || virt_x >= virtualResX || virt_y < 0 || virt_y >= virtualResY) 13 | { // Co-ordinates go from 0 to X-1 remember! otherwise they are out of range! 14 | return coords; 15 | } 16 | 17 | // Do we want to rotate? 18 | if (_rotate) 19 | { 20 | int16_t temp_x = virt_x; 21 | virt_x = virt_y; 22 | virt_y = virtualResY - 1 - temp_x; 23 | } 24 | 25 | int row = (virt_y / panelResY); // 0 indexed 26 | switch(panel_chain_type) 27 | { 28 | 29 | case (CHAIN_TOP_RIGHT_DOWN): 30 | { 31 | if ( (row % 2) == 1 ) 32 | { // upside down panel 33 | 34 | //Serial.printf("Condition 1, row %d ", row); 35 | 36 | // refersed for the row 37 | coords.x = dmaResX - virt_x - (row*virtualResX); 38 | 39 | // y co-ord inverted within the panel 40 | coords.y = panelResY - 1 - (virt_y % panelResY); 41 | 42 | 43 | } 44 | else 45 | { 46 | //Serial.printf("Condition 2, row %d ", row); 47 | 48 | coords.x = ((vmodule_rows - (row+1))*virtualResX)+virt_x; 49 | coords.y = virt_y % panelResY; 50 | 51 | } 52 | 53 | } 54 | break; 55 | 56 | 57 | case (CHAIN_TOP_LEFT_DOWN): // OK -> modulus opposite of CHAIN_TOP_RIGHT_DOWN 58 | { 59 | if ( (row % 2) == 0 ) 60 | { // refersed panel 61 | 62 | //Serial.printf("Condition 1, row %d ", row); 63 | coords.x = dmaResX - virt_x - (row*virtualResX); 64 | 65 | // y co-ord inverted within the panel 66 | coords.y = panelResY - 1 - (virt_y % panelResY); 67 | 68 | } 69 | else 70 | { 71 | //Serial.printf("Condition 2, row %d ", row); 72 | coords.x = ((vmodule_rows - (row+1))*virtualResX)+virt_x; 73 | coords.y = virt_y % panelResY; 74 | 75 | } 76 | 77 | } 78 | break; 79 | 80 | 81 | 82 | 83 | case (CHAIN_BOTTOM_LEFT_UP): // 84 | { 85 | row = vmodule_rows - row - 1; 86 | 87 | if ( (row % 2) == 1 ) 88 | { 89 | // Serial.printf("Condition 1, row %d ", row); 90 | coords.x = ((vmodule_rows - (row+1))*virtualResX)+virt_x; 91 | coords.y = virt_y % panelResY; 92 | 93 | } 94 | else 95 | { // inverted panel 96 | 97 | // Serial.printf("Condition 2, row %d ", row); 98 | coords.x = dmaResX - (row*virtualResX) - virt_x; 99 | coords.y = panelResY - 1 - (virt_y % panelResY); 100 | } 101 | 102 | } 103 | break; 104 | 105 | case (CHAIN_BOTTOM_RIGHT_UP): // OK -> modulus opposite of CHAIN_BOTTOM_LEFT_UP 106 | { 107 | row = vmodule_rows - row - 1; 108 | 109 | if ( (row % 2) == 0 ) 110 | { // right side up 111 | 112 | // Serial.printf("Condition 1, row %d ", row); 113 | // refersed for the row 114 | coords.x = ((vmodule_rows - (row+1))*virtualResX)+virt_x; 115 | coords.y = virt_y % panelResY; 116 | 117 | } 118 | else 119 | { // inverted panel 120 | 121 | // Serial.printf("Condition 2, row %d ", row); 122 | coords.x = dmaResX - (row*virtualResX) - virt_x; 123 | coords.y = panelResY - 1 - (virt_y % panelResY); 124 | } 125 | 126 | } 127 | break; 128 | 129 | 130 | default: 131 | return coords; 132 | break; 133 | 134 | } // end switch 135 | 136 | 137 | 138 | /* START: Pixel remapping AGAIN to convert TWO parallel scanline output that the 139 | * the underlying hardware library is designed for (because 140 | * there's only 2 x RGB pins... and convert this to 1/4 or something 141 | */ 142 | if (panel_scan_rate == FOUR_SCAN_32PX_HIGH) 143 | { 144 | /* Convert Real World 'VirtualMatrixPanel' co-ordinates (i.e. Real World pixel you're looking at 145 | on the panel or chain of panels, per the chaining configuration) to a 1/8 panels 146 | double 'stretched' and 'squished' coordinates which is what needs to be sent from the 147 | DMA buffer. 148 | 149 | Note: Look at the FourScanPanel example code and you'll see that the DMA buffer is setup 150 | as if the panel is 2 * W and 0.5 * H ! 151 | */ 152 | 153 | if ((virt_y & 8) == 0) 154 | { 155 | coords.x += ((coords.x / panelResX) + 1) * panelResX; // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer 156 | } 157 | else 158 | { 159 | coords.x += (coords.x / panelResX) * panelResX; // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer 160 | } 161 | 162 | // http://cpp.sh/4ak5u 163 | // Real number of DMA y rows is half reality 164 | // coords.y = (y / 16)*8 + (y & 0b00000111); 165 | coords.y = (virt_y >> 4) * 8 + (virt_y & 0b00000111); 166 | 167 | } 168 | else if (panel_scan_rate == FOUR_SCAN_16PX_HIGH) 169 | { 170 | if ((virt_y & 8) == 0) 171 | { 172 | coords.x += (panelResX >> 2) * (((coords.x & 0xFFF0) >> 4) + 1); // 1st, 3rd 'block' of 8 rows of pixels, offset by panel width in DMA buffer 173 | } 174 | else 175 | { 176 | coords.x += (panelResX >> 2) * (((coords.x & 0xFFF0) >> 4)); // 2nd, 4th 'block' of 8 rows of pixels, offset by panel width in DMA buffer 177 | } 178 | 179 | if (virt_y < 32) 180 | coords.y = (virt_y >> 4) * 8 + (virt_y & 0b00000111); 181 | else 182 | { 183 | coords.y = ((virt_y - 32) >> 4) * 8 + (virt_y & 0b00000111); 184 | coords.x += 256; 185 | } 186 | } 187 | 188 | return coords; 189 | } 190 | -------------------------------------------------------------------------------- /testing/four_scan_40_80px_hfarcan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // For output formatting 3 | 4 | 5 | // FOUR_SCAN_40_80PX_HFARCAN test 6 | struct Coords { 7 | int x; 8 | int y; 9 | }; 10 | 11 | int main() { 12 | int panel_pixel_base = 16; // Updated pixel base 13 | Coords coords; 14 | 15 | // Header for easy Excel copying (Pipe-delimited format) 16 | std::cout << "Input X|Input Y|Output X|Output Y" << std::endl; 17 | 18 | // Loop for testing multiple inputs 19 | for (int y = 0; y < 40; y += 3) { // Updated y increment to 3 20 | for (int x = 0; x < 80; x += 10) { 21 | coords.x = x; 22 | coords.y = y; 23 | 24 | // Store original coordinates for display 25 | int input_x = coords.x; 26 | int input_y = coords.y; 27 | 28 | // Mapping logic 29 | int panel_local_x = coords.x % 80; // Compensate for chain of panels 30 | 31 | if ((((coords.y) / 10) % 2) ^ ((panel_local_x / panel_pixel_base) % 2)) { 32 | coords.x += ((coords.x / panel_pixel_base) * panel_pixel_base); 33 | } else { 34 | coords.x += (((coords.x / panel_pixel_base) + 1) * panel_pixel_base); 35 | } 36 | 37 | coords.y = (coords.y % 10) + 10 * ((coords.y / 20) % 2); 38 | 39 | // Output results in pipe-delimited format for easy Excel import 40 | std::cout << input_x << "|" << input_y << "|" << coords.x << "|" << coords.y << std::endl; 41 | } 42 | } 43 | 44 | return 0; 45 | } --------------------------------------------------------------------------------