Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/Fans
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2021-03-21 12:46:59 +0300
committerDavid Crocker <dcrocker@eschertech.com>2021-03-21 12:46:59 +0300
commit7b10730a5fee550e1d7b248631e900b88cd5b792 (patch)
treed6b6892968c535966e9ca70e50221d34b2447c41 /src/Fans
parente898ae08700eb6caea54ff10a0f8618823c433eb (diff)
Added support for RGBW NeoPixel LED strips
Diffstat (limited to 'src/Fans')
-rw-r--r--src/Fans/LedStripDriver.cpp107
1 files changed, 79 insertions, 28 deletions
diff --git a/src/Fans/LedStripDriver.cpp b/src/Fans/LedStripDriver.cpp
index 3e84a91a..df619b85 100644
--- a/src/Fans/LedStripDriver.cpp
+++ b/src/Fans/LedStripDriver.cpp
@@ -49,15 +49,48 @@ namespace LedStripDriver
{
constexpr uint32_t DefaultDotStarSpiClockFrequency = 100000; // try sending at 100kHz
constexpr uint32_t DefaultNeoPixelSpiClockFrequency = 2500000; // must be between about 2MHz and about 4MHz
- constexpr uint32_t DefaultSpiFrequencies[2] = { DefaultDotStarSpiClockFrequency, DefaultNeoPixelSpiClockFrequency };
constexpr uint32_t MinNeoPixelResetTicks = (250 * StepTimer::StepClockRate)/1000000; // 250us minimum Neopixel reset time on later chips
- constexpr size_t ChunkBufferSize = 720; // the size of our DMA buffer. DotStar LEDs use 4 bytes/LED, NeoPixels use 12 bytes/LED.
+ constexpr size_t ChunkBufferSize = 60 * 16; // the size of our DMA buffer. DotStar LEDs use 4 bytes/LED, NeoPixel RGBW use 16 bytes/LED.
constexpr unsigned int MaxDotStarChunkSize = ChunkBufferSize/4; // maximum number of DotStarLEDs we DMA to in one go. Most strips have 30 LEDs/metre.
- constexpr unsigned int MaxNeoPixelChunkSize = ChunkBufferSize/12; // maximum number of NeoPixels we can support. A full ring contains 60.
+ constexpr unsigned int MaxNeoPixelRGBChunkSize = ChunkBufferSize/12; // maximum number of NeoPixels we can support. A full ring contains 60.
+ constexpr unsigned int MaxNeoPixelRGBWChunkSize = ChunkBufferSize/16; // maximum number of NeoPixels we can support. A full ring contains 60.
+
+ enum class LedType : unsigned int
+ {
+ dotstar,
+ neopixelRGB,
+ neopixelBitBang,
+ neopixelRGBW
+ };
+
+ constexpr const char *LedTypeNames[] =
+ {
+ "DotStar on LED port",
+ "NeoPixel RGB on LED port",
+ "NeoPixel RGB on 12864 display",
+ "NeoPixel RGBW on LED port"
+ };
+ constexpr unsigned int NumSupportedLedTypes = ARRAY_SIZE(LedTypeNames);
+
+ constexpr unsigned int MaxChunkSize[] =
+ {
+ MaxDotStarChunkSize,
+ MaxNeoPixelRGBChunkSize,
+ MaxNeoPixelRGBChunkSize,
+ MaxNeoPixelRGBWChunkSize
+ };
+
+ constexpr uint32_t DefaultSpiFrequencies[] =
+ {
+ DefaultDotStarSpiClockFrequency,
+ DefaultNeoPixelSpiClockFrequency,
+ DefaultNeoPixelSpiClockFrequency,
+ DefaultNeoPixelSpiClockFrequency
+ };
static uint32_t currentFrequency; // the SPI frequency we are using
- static unsigned int ledType = 1; // 0 = DotStar (not supported on Duet 3 Mini), 1 = NeoPixel, 2 = NeoPixel on Mini 12864 display (Duet 3 Mini only)
+ static LedType ledType = LedType::neopixelRGB; // 0 = DotStar (not supported on Duet 3 Mini), 1 = NeoPixel, 2 = NeoPixel on Mini 12864 display (Duet 3 Mini only). 4 = NeoPixel RGBW
static uint32_t whenDmaFinished = 0; // the time in step clocks when we determined that the DMA had finished
static unsigned int numRemaining = 0; // how much of the current request remains after the current transfer (DotStar only)
static unsigned int totalSent = 0; // total amount of data sent since the start frame (DotStar only)
@@ -72,15 +105,6 @@ namespace LedStripDriver
alignas(4) static uint8_t chunkBuffer[ChunkBufferSize]; // buffer for sending data to LEDs
#endif
- constexpr const char *LedTypeNames[] =
- {
- "DotStar",
- "NeoPixel",
-#if SUPPORT_BITBANG_NEOPIXEL
- "NeoPixel on 12864 display"
-#endif
- };
- constexpr unsigned int NumSupportedLedTypes = ARRAY_SIZE(LedTypeNames);
// DMA the data. Must be a multiple of 2 bytes if USE_16BIT_SPI is true.
static void DmaSendChunkBuffer(size_t numBytes) noexcept
@@ -192,7 +216,7 @@ namespace LedStripDriver
# endif
QSPI->QSPI_SCR = QSPI_SCR_CPOL | QSPI_SCR_CPHA | QSPI_SCR_SCBR(SystemPeripheralClock()/currentFrequency - 1);
QSPI->QSPI_CR = QSPI_CR_QSPIEN;
- if (ledType == 1)
+ if (ledType == LedType::neopixelRGB || ledType == LedType::neopixelRGBW)
{
QSPI->QSPI_TDR = 0; // send a word of zeros to set the data line low
}
@@ -261,7 +285,7 @@ namespace LedStripDriver
static constexpr uint8_t EncodedByte[4] = { 0b10001000, 0b10001110, 0b11101000, 0b11101110 };
#if USE_16BIT_SPI
- if (ledType == 1)
+ if (ledType == LedType::neopixelRGB || ledType == LedType::neopixelRGBW)
{
// Swap bytes for 16-bit DMA
*p++ = EncodedByte[(val >> 4) & 3];
@@ -280,7 +304,7 @@ namespace LedStripDriver
}
// Send data to NeoPixel LEDs by DMA to SPI
- static GCodeResult SpiSendNeoPixelData(uint8_t red, uint8_t green, uint8_t blue, uint32_t numLeds, bool following) noexcept
+ static GCodeResult SpiSendNeoPixelData(uint8_t red, uint8_t green, uint8_t blue, uint8_t white, uint32_t numLeds, bool includeWhite, bool following) noexcept
{
uint8_t *p = chunkBuffer + (12 * numAlreadyInBuffer);
while (numLeds != 0 && p <= chunkBuffer + ARRAY_SIZE(chunkBuffer) - 12)
@@ -291,13 +315,18 @@ namespace LedStripDriver
p += 4;
EncodeNeoPixelByte(p, blue);
p += 4;
+ if (includeWhite)
+ {
+ EncodeNeoPixelByte(p, white);
+ p += 4;
+ }
--numLeds;
++numAlreadyInBuffer;
}
if (!following)
{
- DmaSendChunkBuffer(12 * numAlreadyInBuffer); // send data by DMA to SPI
+ DmaSendChunkBuffer(((includeWhite) ? 16 : 12) * numAlreadyInBuffer); // send data by DMA to SPI
numAlreadyInBuffer = 0;
needStartFrame = true;
}
@@ -382,7 +411,7 @@ void LedStripDriver::Init() noexcept
pmc_enable_periph_clk(DotStarClockId);
#endif
- currentFrequency = DefaultSpiFrequencies[ledType];
+ currentFrequency = DefaultSpiFrequencies[(unsigned int)ledType];
SetupSpi();
// Initialise variables
@@ -406,7 +435,7 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
return GCodeResult::notFinished;
}
- if (needStartFrame && (ledType == 1 || ledType == 2) && StepTimer::GetTimerTicks() - whenDmaFinished < MinNeoPixelResetTicks)
+ if (needStartFrame && (ledType != LedType::neopixelBitBang) && StepTimer::GetTimerTicks() - whenDmaFinished < MinNeoPixelResetTicks)
{
return GCodeResult::notFinished; // give the NeoPixels time to reset
}
@@ -424,9 +453,17 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
#endif
NumSupportedLedTypes
);
- const bool typeChanged = (newType != ledType);
+ const bool typeChanged = (newType != (unsigned int)ledType);
+#if SUPPORT_BITBANG_NEOPIXEL
if (newType != 2)
+#else
+ if (newType == 2)
+ {
+ reply.copy("Unsupported LED strip type");
+ return GCodeResult::error;
+ }
+#endif
{
bool setFrequency = typeChanged;
currentFrequency = DefaultSpiFrequencies[newType];
@@ -439,7 +476,7 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
if (typeChanged)
{
- ledType = newType;
+ ledType = (LedType)newType;
needInit = true;
}
}
@@ -463,13 +500,15 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
}
// Get the RGB and brightness values
- uint32_t red = 0, green = 0, blue = 0, brightness = 128, numLeds = MaxDotStarChunkSize;
+ uint32_t red = 0, green = 0, blue = 0, white = 0, brightness = 128;
+ uint32_t numLeds = MaxChunkSize[(unsigned int)ledType];
bool following = false;
bool seenColours = false;
gb.TryGetLimitedUIValue('R', red, seenColours, 256);
gb.TryGetLimitedUIValue('U', green, seenColours, 256);
gb.TryGetLimitedUIValue('B', blue, seenColours, 256);
+ gb.TryGetLimitedUIValue('W', white, seenColours, 256); // W value is used by RGBW NeoPixels only
if (gb.Seen('P'))
{
@@ -488,7 +527,7 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
if (!seenType)
{
// Report the current configuration
- reply.printf("Led type is %s, frequency %.2fMHz", LedTypeNames[ledType], (double)((float)currentFrequency * 0.000001));
+ reply.printf("Led type is %s, frequency %.2fMHz", LedTypeNames[(unsigned int)ledType], (double)((float)currentFrequency * 0.000001));
}
return GCodeResult::ok;
}
@@ -496,7 +535,7 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
// If there are no LEDs to set, we have finished unless we need to send a start frame to DotStar LEDs
if (numLeds == 0
#if SUPPORT_DOTSTAR
- && (ledType != 0 || (!needStartFrame && !following))
+ && (ledType != LedType::dotstar || (!needStartFrame && !following))
#endif
)
{
@@ -506,7 +545,7 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
switch (ledType)
{
#if SUPPORT_DOTSTAR
- case 0: // DotStar
+ case LedType::dotstar:
{
if (numRemaining != 0)
{
@@ -523,16 +562,17 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
}
#endif
- case 1: // NeoPixel
+ case LedType::neopixelRGB:
// Scale RGB by the brightness
return SpiSendNeoPixelData( (uint8_t)((red * brightness + 255) >> 8),
(uint8_t)((green * brightness + 255) >> 8),
(uint8_t)((blue * brightness + 255) >> 8),
- numLeds, following
+ 0,
+ numLeds, false, following
);
+ case LedType::neopixelBitBang:
#if SUPPORT_BITBANG_NEOPIXEL
- case 2:
// Interrupts are disabled while bit-banging the data, so make sure movement has stopped
if (!reprap.GetGCodes().LockMovementAndWaitForStandstill(gb))
{
@@ -545,7 +585,18 @@ GCodeResult LedStripDriver::SetColours(GCodeBuffer& gb, const StringRef& reply)
(uint8_t)((blue * brightness + 255) >> 8),
numLeds, following
);
+#else
+ break;
#endif
+
+ case LedType::neopixelRGBW:
+ // Scale RGBW by the brightness
+ return SpiSendNeoPixelData( (uint8_t)((red * brightness + 255) >> 8),
+ (uint8_t)((green * brightness + 255) >> 8),
+ (uint8_t)((blue * brightness + 255) >> 8),
+ (uint8_t)((white * brightness + 255) >> 8),
+ numLeds, true, following
+ );
}
return GCodeResult::ok; // should never get here
}