diff --git a/src/internal/NeoMethods.h b/src/internal/NeoMethods.h
index cc241306..a9863c18 100644
--- a/src/internal/NeoMethods.h
+++ b/src/internal/NeoMethods.h
@@ -59,6 +59,7 @@ License along with NeoPixel. If not, see
#if !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2)
#include "methods/NeoEsp32I2sMethod.h"
+#include "methods/NeoEsp32Ucs7604Method.h"
#include "methods/NeoEsp32RmtMethod.h"
#include "methods/DotStarEsp32DmaSpiMethod.h"
#include "methods/NeoEsp32I2sXMethod.h"
diff --git a/src/internal/methods/NeoEsp32Ucs7604Method.h b/src/internal/methods/NeoEsp32Ucs7604Method.h
new file mode 100644
index 00000000..946086e5
--- /dev/null
+++ b/src/internal/methods/NeoEsp32Ucs7604Method.h
@@ -0,0 +1,190 @@
+/*-------------------------------------------------------------------------
+NeoPixel library helper functions for Esp32.
+
+Written by Michael C. Miller.
+
+I invest time and resources providing this open source code,
+please support me by donating (see https://github.com/Makuna/NeoPixelBus)
+
+-------------------------------------------------------------------------
+This file is part of the Makuna/NeoPixelBus library.
+
+NeoPixelBus is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation, either version 3 of
+the License, or (at your option) any later version.
+
+NeoPixelBus is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with NeoPixel. If not, see
+.
+-------------------------------------------------------------------------*/
+
+#pragma once
+
+// ESP32 C3 & S3 I2S is not supported yet due to significant changes to interface
+#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+
+
+extern "C"
+{
+#include
+#include "Esp32_i2s.h"
+}
+
+
+// fedc ba98 7654 3210
+// 0000 0000 0000 0000
+// 111
+// 3 step cadence, so pulses are 1/3 and 2/3 of pulse width
+//
+class NeoEsp32Ucs7406Cadence3Step
+{
+public:
+ const static size_t DmaBitsPerPixelBit = 3; // 3 step cadence, matches encoding
+
+ static void EncodeIntoDma(uint8_t* dmaBuffer, const uint8_t* data, size_t sizeData)
+ {
+ const uint16_t OneBit = 0b00000110;
+ const uint16_t ZeroBit = 0b00000100;
+ const uint8_t SrcBitMask = 0x80;
+ const size_t BitsInSample = sizeof(uint16_t) * 8;
+
+ uint16_t* pDma = reinterpret_cast(dmaBuffer);
+
+ uint16_t dmaValue = 0;
+ uint8_t destBitsLeft = BitsInSample;
+
+ // First the header
+ constexpr uint8_t header[15] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, //"work code"
+ 0x03, 0x07,//Not sure what this does. The 12 bit controller used 0x03, 0x0b. Found this combination to work with 8 bit colors using trial and error
+ // ^ there will be a gap here
+ 0x0f, 0x0f, 0x0f, 0x0f,//probably max current per channel
+ 0x00, 0x00
+ };
+ const uint8_t* hSrc = header;
+ const uint8_t* hEnd = header + sizeof(header);
+ const uint8_t* space = header + 8;
+ while (hSrc < hEnd)
+ {
+ uint8_t value = *(hSrc++);
+
+ for (uint8_t bitSrc = 0; bitSrc < 8; bitSrc++)
+ {
+ const uint16_t Bit = ((value & SrcBitMask) ? OneBit : ZeroBit);
+
+ if (destBitsLeft > 3)
+ {
+ destBitsLeft -= 3;
+ dmaValue |= Bit << destBitsLeft;
+ }
+ else if (destBitsLeft <= 3)
+ {
+ uint8_t bitSplit = (3 - destBitsLeft);
+ dmaValue |= Bit >> bitSplit;
+
+ // next dma value, store and reset
+ *(pDma++) = dmaValue;
+ dmaValue = 0;
+
+ destBitsLeft = BitsInSample - bitSplit;
+ if (bitSplit)
+ {
+ dmaValue |= Bit << destBitsLeft;
+ }
+ }
+
+ // Next
+ value <<= 1;
+ }
+ // Space/gap
+ if(hSrc == space) {
+ *pDma++ = 0x00;
+ *pDma++ = 0x00;
+ }
+ }
+
+ // Then send the data
+ const uint8_t* pSrc = data;
+ const uint8_t* pEnd = pSrc + sizeData;
+
+ while (pSrc < pEnd)
+ {
+ uint8_t value = *(pSrc++);
+
+ for (uint8_t bitSrc = 0; bitSrc < 8; bitSrc++)
+ {
+ const uint16_t Bit = ((value & SrcBitMask) ? OneBit : ZeroBit);
+
+ if (destBitsLeft > 3)
+ {
+ destBitsLeft -= 3;
+ dmaValue |= Bit << destBitsLeft;
+
+#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
+ NeoUtil::PrintBin(dmaValue);
+ Serial.print(" < ");
+ Serial.println(destBitsLeft);
+#endif
+ }
+ else if (destBitsLeft <= 3)
+ {
+ uint8_t bitSplit = (3 - destBitsLeft);
+ dmaValue |= Bit >> bitSplit;
+
+#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
+ NeoUtil::PrintBin(dmaValue);
+ Serial.print(" > ");
+ Serial.println(bitSplit);
+#endif
+ // next dma value, store and reset
+ *(pDma++) = dmaValue;
+ dmaValue = 0;
+
+ destBitsLeft = BitsInSample - bitSplit;
+ if (bitSplit)
+ {
+ dmaValue |= Bit << destBitsLeft;
+ }
+
+#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
+ NeoUtil::PrintBin(dmaValue);
+ Serial.print(" v ");
+ Serial.println(bitSplit);
+#endif
+ }
+
+ // Next
+ value <<= 1;
+ }
+ }
+ // store the remaining bits
+ *pDma++ = dmaValue;
+ }
+};
+
+
+
+#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+// (SOC_I2S_NUM == 2)
+
+typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Ucs7604Method;
+typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Ucs7604Method;
+
+
+#endif
+
+#if !defined(NEOPIXEL_ESP32_RMT_DEFAULT) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+
+// I2s Bus 1 method is the default method for Esp32
+// Esp32 S2 & C3 & S3 will use RMT as the default always
+typedef NeoEsp32I2s1Ucs7604Method NeoUcs7604Method;
+
+#endif // !defined(NEOPIXEL_ESP32_RMT_DEFAULT) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
+
+#endif