forked from Makuna/NeoPixelBus
@@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// NeoPixel_RP2040_PioX4 -
|
||||||
|
// This sketch demonstrates the use of the PIO method allowing upto 4 instances
|
||||||
|
// Per one of the two PIO channels
|
||||||
|
//
|
||||||
|
// This example only works on the RP2040
|
||||||
|
//
|
||||||
|
// The key part of the method name is Rp2040Pio1X4,
|
||||||
|
// Rp2040 (platform specific method),
|
||||||
|
// PIO Channel 1 (most commonly available),
|
||||||
|
// X4 (4 instances allowed)
|
||||||
|
//
|
||||||
|
// In this example, it demonstrates different ColorFeatures, Method specification, and count per strip
|
||||||
|
//
|
||||||
|
#include <NeoPixelBus.h>
|
||||||
|
|
||||||
|
// Demonstrating the use of the four channels
|
||||||
|
NeoPixelBus<NeoBgrFeature, NeoRp2040Pio1X4Ws2811Method> strip1(120, 15); // note: older WS2811 and longer strip
|
||||||
|
NeoPixelBus<NeoGrbFeature, NeoRp2040Pio1X4Ws2812xMethod> strip2(100, 2); // note: modern WS2812 with letter like WS2812b
|
||||||
|
NeoPixelBus<NeoGrbFeature, NeoRp2040Pio1X4Ws2812xInvertedMethod> strip3(100, 4); // note: inverted
|
||||||
|
NeoPixelBus<NeoGrbwFeature, NeoRp2040Pio1X4Sk6812Method> strip4(50, 16); // note: RGBW and Sk6812 and smaller strip
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial); // wait for serial attach
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Initializing...");
|
||||||
|
Serial.flush();
|
||||||
|
|
||||||
|
// must call begin on all the strips
|
||||||
|
strip1.Begin();
|
||||||
|
strip2.Begin();
|
||||||
|
strip3.Begin();
|
||||||
|
strip4.Begin();
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Running...");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// draw on the strips
|
||||||
|
strip1.SetPixelColor(0, RgbColor(255, 0, 0)); // red
|
||||||
|
strip2.SetPixelColor(0, RgbColor(0, 127, 0)); // green
|
||||||
|
strip3.SetPixelColor(0, RgbColor(0, 0, 53)); // blue
|
||||||
|
strip4.SetPixelColor(0, RgbwColor(0, 0, 128, 255)); // white channel with a little blue
|
||||||
|
|
||||||
|
// show them,
|
||||||
|
// only on the last show, no matter the order, will the data be sent
|
||||||
|
strip1.Show();
|
||||||
|
strip2.Show();
|
||||||
|
strip3.Show();
|
||||||
|
strip4.Show();
|
||||||
|
}
|
@@ -62,6 +62,10 @@ License along with NeoPixel. If not, see
|
|||||||
|
|
||||||
#include "methods/NeoNrf52xMethod.h"
|
#include "methods/NeoNrf52xMethod.h"
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040) // must be before __arm__
|
||||||
|
|
||||||
|
#include "methods/Rp2040/NeoRp2040x4Method.h"
|
||||||
|
|
||||||
#elif defined(__arm__) // must be before ARDUINO_ARCH_AVR due to Teensy incorrectly having it set
|
#elif defined(__arm__) // must be before ARDUINO_ARCH_AVR due to Teensy incorrectly having it set
|
||||||
|
|
||||||
#include "methods/NeoArmMethod.h"
|
#include "methods/NeoArmMethod.h"
|
||||||
|
@@ -30,7 +30,7 @@ License along with NeoPixel. If not, see
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(__arm__) && !defined(ARDUINO_ARCH_NRF52840)
|
#if defined(__arm__) && !defined(ARDUINO_ARCH_NRF52840) && !defined(ARDUINO_ARCH_RP2040)
|
||||||
|
|
||||||
template<typename T_SPEED> class NeoArmMethodBase
|
template<typename T_SPEED> class NeoArmMethodBase
|
||||||
{
|
{
|
||||||
|
175
src/internal/methods/Rp2040/NeoRp2040DmaState.h
Normal file
175
src/internal/methods/Rp2040/NeoRp2040DmaState.h
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
NeoPixel library helper functions for RP2040.
|
||||||
|
|
||||||
|
Written by Michael C. Miller.
|
||||||
|
|
||||||
|
I invest time and resources providing this open source code,
|
||||||
|
please support me by dontating (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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
// DMA Finished State Tracking
|
||||||
|
// --------------------------------------------------------
|
||||||
|
|
||||||
|
enum Rp2040PioDmaState
|
||||||
|
{
|
||||||
|
Rp2040PioDmaState_Sending,
|
||||||
|
Rp2040PioDmaState_DmaCompleted,
|
||||||
|
Rp2040PioDmaState_FifoEmptied
|
||||||
|
};
|
||||||
|
|
||||||
|
template <uint V_IRQ_INDEX>
|
||||||
|
class NeoRp2040DmaState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NeoRp2040DmaState() :
|
||||||
|
_endTime(0),
|
||||||
|
_state(Rp2040PioDmaState_FifoEmptied)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSending()
|
||||||
|
{
|
||||||
|
_state = Rp2040PioDmaState_Sending;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DmaFinished()
|
||||||
|
{
|
||||||
|
_endTime = micros();
|
||||||
|
_state = Rp2040PioDmaState_DmaCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsReadyToSend(uint32_t resetTimeUs) const
|
||||||
|
{
|
||||||
|
bool isReady = false;
|
||||||
|
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case Rp2040PioDmaState_Sending:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rp2040PioDmaState_DmaCompleted:
|
||||||
|
{
|
||||||
|
uint32_t delta = micros() - _endTime;
|
||||||
|
|
||||||
|
if (delta >= resetTimeUs)
|
||||||
|
{
|
||||||
|
// const method requires that we const cast to change state
|
||||||
|
*const_cast<Rp2040PioDmaState*>(&_state) = Rp2040PioDmaState_FifoEmptied;
|
||||||
|
isReady = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
isReady = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register(uint dmChannel)
|
||||||
|
{
|
||||||
|
if (s_dmaIrqObjectTable[dmChannel] == nullptr)
|
||||||
|
{
|
||||||
|
s_dmaIrqObjectTable[dmChannel] = this;
|
||||||
|
|
||||||
|
int32_t refCount = s_refCountHandler++;
|
||||||
|
|
||||||
|
if (refCount == 0)
|
||||||
|
{
|
||||||
|
// Set up end-of-DMA interrupt handler
|
||||||
|
irq_add_shared_handler(V_IRQ_INDEX ? DMA_IRQ_1 : DMA_IRQ_0,
|
||||||
|
dmaFinishIrq,
|
||||||
|
PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
|
||||||
|
irq_set_enabled(V_IRQ_INDEX ? DMA_IRQ_1 : DMA_IRQ_0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(NEORP2040_DEBUG)
|
||||||
|
|
||||||
|
Serial.print(" V_IRQ_INDEX = ");
|
||||||
|
Serial.print(V_IRQ_INDEX);
|
||||||
|
Serial.print(", s_dmaIrqObjectTable = ");
|
||||||
|
Serial.print((uint32_t)(s_dmaIrqObjectTable)); // address of s_dmaIrqObjectTable
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unregister(uint dmChannel)
|
||||||
|
{
|
||||||
|
if (s_dmaIrqObjectTable[dmChannel] == this)
|
||||||
|
{
|
||||||
|
int32_t refCount = s_refCountHandler--;
|
||||||
|
|
||||||
|
if (refCount == 0)
|
||||||
|
{
|
||||||
|
irq_set_enabled(V_IRQ_INDEX ? DMA_IRQ_1 : DMA_IRQ_0, false);
|
||||||
|
irq_remove_handler(V_IRQ_INDEX ? DMA_IRQ_1 : DMA_IRQ_0, dmaFinishIrq);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_dmaIrqObjectTable[dmChannel] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
volatile uint32_t _endTime; // Latch/Reset timing reference
|
||||||
|
volatile Rp2040PioDmaState _state;
|
||||||
|
|
||||||
|
static NeoRp2040DmaState* s_dmaIrqObjectTable[NUM_DMA_CHANNELS];
|
||||||
|
static volatile int32_t s_refCountHandler;
|
||||||
|
|
||||||
|
static void dmaFinishIrq()
|
||||||
|
{
|
||||||
|
// dmaChannels are unique across both PIOs, while stateMachines are per
|
||||||
|
// PIO, so this current model below works even if both PIOs are used
|
||||||
|
for (uint dmaChannel = 0; dmaChannel < NUM_DMA_CHANNELS; dmaChannel++)
|
||||||
|
{
|
||||||
|
NeoRp2040DmaState* that = s_dmaIrqObjectTable[dmaChannel];
|
||||||
|
if (that != nullptr)
|
||||||
|
{
|
||||||
|
if (dma_irqn_get_channel_status(V_IRQ_INDEX, dmaChannel))
|
||||||
|
{
|
||||||
|
dma_irqn_acknowledge_channel(V_IRQ_INDEX, dmaChannel);
|
||||||
|
that->DmaFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <uint V_IRQ_INDEX>
|
||||||
|
NeoRp2040DmaState<V_IRQ_INDEX>* NeoRp2040DmaState<V_IRQ_INDEX>::s_dmaIrqObjectTable[NUM_DMA_CHANNELS] =
|
||||||
|
{
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||||
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
template <uint V_IRQ_INDEX>
|
||||||
|
volatile int32_t NeoRp2040DmaState<V_IRQ_INDEX>::s_refCountHandler = 0;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
66
src/internal/methods/Rp2040/NeoRp2040PioInstance.h
Normal file
66
src/internal/methods/Rp2040/NeoRp2040PioInstance.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
NeoPixel library helper functions for RP2040.
|
||||||
|
|
||||||
|
Written by Michael C. Miller.
|
||||||
|
|
||||||
|
I invest time and resources providing this open source code,
|
||||||
|
please support me by dontating (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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
// PIO Instances
|
||||||
|
// --------------------------------------------------------
|
||||||
|
class NeoRp2040PioInstance0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NeoRp2040PioInstance0() :
|
||||||
|
Instance(pio0)
|
||||||
|
{};
|
||||||
|
|
||||||
|
const PIO Instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NeoRp2040PioInstance1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NeoRp2040PioInstance1() :
|
||||||
|
Instance(pio1)
|
||||||
|
{};
|
||||||
|
|
||||||
|
const PIO Instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
// dynamic channel support
|
||||||
|
class NeoRp2040PioInstanceN
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NeoRp2040PioInstanceN(NeoBusChannel channel) :
|
||||||
|
Instance(channel == NeoBusChannel_0 ? pio0 : pio1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
NeoRp2040PioInstanceN() = delete; // no default constructor
|
||||||
|
|
||||||
|
const PIO Instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
77
src/internal/methods/Rp2040/NeoRp2040PioMonoProgram.cpp
Normal file
77
src/internal/methods/Rp2040/NeoRp2040PioMonoProgram.cpp
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
NeoPixel library helper functions for RP2040.
|
||||||
|
|
||||||
|
Written by Michael C. Miller.
|
||||||
|
|
||||||
|
I invest time and resources providing this open source code,
|
||||||
|
please support me by dontating (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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "../../NeoUtil.h"
|
||||||
|
#include "../../NeoBusChannel.h"
|
||||||
|
#include "../../NeoSettings.h"
|
||||||
|
#include "NeoRp2040x4Method.h"
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
// See NeoRp2040PioCadenceMono3Step, NeoRp2040PioCadenceMono4Step in header for details
|
||||||
|
// on changing the PIO programs
|
||||||
|
//
|
||||||
|
// these are only required here in the .cpp due to current compiler version doesn't
|
||||||
|
// support doing this in the header file
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
const uint16_t NeoRp2040PioCadenceMono3Step::program_instructions[] =
|
||||||
|
{
|
||||||
|
// .wrap_target
|
||||||
|
0x6021, // 0: out x, 1 side 0
|
||||||
|
0x1023, // 1: jmp !x, 3 side 1
|
||||||
|
0x1000, // 2: jmp 0 side 1
|
||||||
|
0xa042, // 3: nop side 0
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct pio_program NeoRp2040PioCadenceMono3Step::program =
|
||||||
|
{
|
||||||
|
.instructions = NeoRp2040PioCadenceMono3Step::program_instructions,
|
||||||
|
.length = 4,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const uint16_t NeoRp2040PioCadenceMono4Step::program_instructions[] =
|
||||||
|
{
|
||||||
|
// .wrap_target
|
||||||
|
0x6021, // 0: out x, 1 side 0
|
||||||
|
0x1023, // 1: jmp !x, 3 side 1
|
||||||
|
0x1100, // 2: jmp 0 side 1 [1]
|
||||||
|
0xa142, // 3: nop side 0 [1]
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct pio_program NeoRp2040PioCadenceMono4Step::program =
|
||||||
|
{
|
||||||
|
.instructions = NeoRp2040PioCadenceMono4Step::program_instructions,
|
||||||
|
.length = 4,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
#endif
|
211
src/internal/methods/Rp2040/NeoRp2040PioMonoProgram.h
Normal file
211
src/internal/methods/Rp2040/NeoRp2040PioMonoProgram.h
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
NeoPixel library helper functions for RP2040.
|
||||||
|
|
||||||
|
Written by Michael C. Miller.
|
||||||
|
|
||||||
|
I invest time and resources providing this open source code,
|
||||||
|
please support me by dontating (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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
// PIO Programs (cadence)
|
||||||
|
// --------------------------------------------------------
|
||||||
|
// use https://wokwi.com/tools/pioasm
|
||||||
|
// copy relevant parts into NeoRp2040PioCadenceMono3Step and NeoRp2040PioCadenceMono4Step
|
||||||
|
//
|
||||||
|
// 3 step program
|
||||||
|
// the pulse width is divided by 3, using 33% for each stage
|
||||||
|
// where 0 = 33% and 1 = 66%
|
||||||
|
/*
|
||||||
|
.program rgbic_mono
|
||||||
|
.side_set 1
|
||||||
|
|
||||||
|
; 0 bit
|
||||||
|
; TH0 TH1 TL1
|
||||||
|
; +++ ___ ___
|
||||||
|
|
||||||
|
; 1 bit
|
||||||
|
; TH0 TH1 TL1
|
||||||
|
; +++ +++ ___
|
||||||
|
.define public TH0 1 ; T1
|
||||||
|
.define public TH1 1 ; T2
|
||||||
|
.define public TL1 1 ; T3
|
||||||
|
|
||||||
|
.wrap_target
|
||||||
|
bitloop:
|
||||||
|
out x, 1 side 0 [TL1 - 1] ; Side-set still takes place when instruction stalls
|
||||||
|
jmp !x do_zero side 1 [TH0 - 1] ; Branch on the bit we shifted out. Positive pulse
|
||||||
|
do_one:
|
||||||
|
jmp bitloop side 1 [TH1 - 1] ; Continue driving high, for a long pulse
|
||||||
|
do_zero:
|
||||||
|
nop side 0 [TH1 - 1] ; Or drive low, for a short pulse
|
||||||
|
.wrap
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
class NeoRp2040PioCadenceMono3Step
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static constexpr uint8_t wrap_target = 0;
|
||||||
|
static constexpr uint8_t wrap = 3;
|
||||||
|
|
||||||
|
static constexpr uint8_t TH0 = 1;
|
||||||
|
static constexpr uint8_t TH1 = 1;
|
||||||
|
static constexpr uint8_t TL1 = 1;
|
||||||
|
|
||||||
|
// changed from constexpr with initializtion due to
|
||||||
|
// that is only supported in c17+
|
||||||
|
static const uint16_t program_instructions[];
|
||||||
|
|
||||||
|
public:
|
||||||
|
// changed from constexpr with initializtion due to
|
||||||
|
// that is only supported in c17+
|
||||||
|
static const struct pio_program program;
|
||||||
|
|
||||||
|
static inline pio_sm_config get_default_config(uint offset)
|
||||||
|
{
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
|
||||||
|
sm_config_set_wrap(&c, offset + wrap_target, offset + wrap);
|
||||||
|
sm_config_set_sideset(&c, 1, false, false);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint8_t bit_cycles = TH0 + TH1 + TL1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 4 step program
|
||||||
|
// the pulse width is divided by 4, using 25% for each stage
|
||||||
|
// where 0 = 25% and 1 = 75%
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
.program rgbic_mono
|
||||||
|
.side_set 1
|
||||||
|
|
||||||
|
; 0 bit
|
||||||
|
; TH0 TH1 TL1
|
||||||
|
; +++ ___ ___
|
||||||
|
|
||||||
|
; 1 bit
|
||||||
|
; TH0 TH1 TL1
|
||||||
|
; +++ +++ ___
|
||||||
|
.define public TH0 1 ; T1
|
||||||
|
.define public TH1 2 ; T2
|
||||||
|
.define public TL1 1 ; T3
|
||||||
|
|
||||||
|
.wrap_target
|
||||||
|
bitloop:
|
||||||
|
out x, 1 side 0 [TL1 - 1] ; Side-set still takes place when instruction stalls
|
||||||
|
jmp !x do_zero side 1 [TH0 - 1] ; Branch on the bit we shifted out. Positive pulse
|
||||||
|
do_one:
|
||||||
|
jmp bitloop side 1 [TH1 - 1] ; Continue driving high, for a long pulse
|
||||||
|
do_zero:
|
||||||
|
nop side 0 [TH1 - 1] ; Or drive low, for a short pulse
|
||||||
|
.wrap
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
class NeoRp2040PioCadenceMono4Step
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static constexpr uint8_t wrap_target = 0;
|
||||||
|
static constexpr uint8_t wrap = 3;
|
||||||
|
|
||||||
|
static constexpr uint8_t TH0 = 1;
|
||||||
|
static constexpr uint8_t TH1 = 2;
|
||||||
|
static constexpr uint8_t TL1 = 1;
|
||||||
|
|
||||||
|
// changed from constexpr with initializtion due to
|
||||||
|
// that is only supported in c17+
|
||||||
|
static const uint16_t program_instructions[];
|
||||||
|
|
||||||
|
public:
|
||||||
|
// changed from constexpr with initializtion due to
|
||||||
|
// that is only supported in c17+
|
||||||
|
static const struct pio_program program;
|
||||||
|
|
||||||
|
static inline pio_sm_config get_default_config(uint offset)
|
||||||
|
{
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
|
||||||
|
sm_config_set_wrap(&c, offset + wrap_target, offset + wrap);
|
||||||
|
sm_config_set_sideset(&c, 1, false, false);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint8_t bit_cycles = TH0 + TH1 + TL1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Program Wrapper
|
||||||
|
// --------------------------------------------------------
|
||||||
|
constexpr uint c_ProgramNotLoaded = static_cast<uint>(-1);
|
||||||
|
|
||||||
|
template<typename T_CADENCE>
|
||||||
|
class NeoRp2040PioMonoProgram
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static inline uint add(PIO pio_instance)
|
||||||
|
{
|
||||||
|
if (s_loadedOffset == c_ProgramNotLoaded)
|
||||||
|
{
|
||||||
|
assert(pio_can_add_program(pio_instance, &T_CADENCE::program));
|
||||||
|
s_loadedOffset = pio_add_program(pio_instance, &T_CADENCE::program);
|
||||||
|
}
|
||||||
|
return s_loadedOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void init(PIO pio_instance,
|
||||||
|
uint sm,
|
||||||
|
uint offset,
|
||||||
|
uint pin,
|
||||||
|
float bitrate,
|
||||||
|
uint shiftBits)
|
||||||
|
{
|
||||||
|
float div = clock_get_hz(clk_sys) / (bitrate * T_CADENCE::bit_cycles);
|
||||||
|
pio_sm_config c = T_CADENCE::get_default_config(offset);
|
||||||
|
|
||||||
|
sm_config_set_sideset_pins(&c, pin);
|
||||||
|
|
||||||
|
sm_config_set_out_shift(&c, false, true, shiftBits);
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||||
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
|
||||||
|
// Set this pin's GPIO function (connect PIO to the pad)
|
||||||
|
pio_gpio_init(pio_instance, pin);
|
||||||
|
|
||||||
|
// Set the pin direction to output at the PIO
|
||||||
|
pio_sm_set_consecutive_pindirs(pio_instance, sm, pin, 1, true);
|
||||||
|
|
||||||
|
// Load our configuration, and jump to the start of the program
|
||||||
|
pio_sm_init(pio_instance, sm, offset, &c);
|
||||||
|
|
||||||
|
// Set the state machine running
|
||||||
|
pio_sm_set_enabled(pio_instance, sm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static uint s_loadedOffset; // singlet instance of loaded program
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T_CADENCE>
|
||||||
|
uint NeoRp2040PioMonoProgram<T_CADENCE>::s_loadedOffset = c_ProgramNotLoaded;
|
||||||
|
|
||||||
|
#endif
|
113
src/internal/methods/Rp2040/NeoRp2040PioSpeed.h
Normal file
113
src/internal/methods/Rp2040/NeoRp2040PioSpeed.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
NeoPixel library helper functions for RP2040.
|
||||||
|
|
||||||
|
Written by Michael C. Miller.
|
||||||
|
|
||||||
|
I invest time and resources providing this open source code,
|
||||||
|
please support me by dontating (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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
// Speeds
|
||||||
|
// --------------------------------------------------------
|
||||||
|
class NeoRp2040PioSpeedWs2811 : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono4Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 800000.0f; // 300+950
|
||||||
|
static constexpr uint32_t ResetTimeUs = 300;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NeoRp2040PioSpeedWs2812x : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono3Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 800000.0f; // 400+850
|
||||||
|
static constexpr uint32_t ResetTimeUs = 300;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NeoRp2040PioSpeedSk6812 : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono3Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 800000.0f; // 400+850
|
||||||
|
static constexpr uint32_t ResetTimeUs = 80;
|
||||||
|
};
|
||||||
|
|
||||||
|
// normal is inverted signal
|
||||||
|
class NeoRp2040PioSpeedTm1814 : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono3Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 800000.00f; // 360+890
|
||||||
|
static constexpr uint32_t ResetTimeUs = 200;
|
||||||
|
};
|
||||||
|
|
||||||
|
// normal is inverted signal
|
||||||
|
class NeoRp2040PioSpeedTm1829 : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono4Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 833333.33f; // 300+900
|
||||||
|
static constexpr uint32_t ResetTimeUs = 200;
|
||||||
|
};
|
||||||
|
|
||||||
|
// normal is inverted signal
|
||||||
|
class NeoRp2040PioSpeedTm1914 : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono3Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 800000.0f; // 360+890
|
||||||
|
static constexpr uint32_t ResetTimeUs = 200;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NeoRp2040PioSpeed800Kbps : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono4Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 800000.0f; // 400+850
|
||||||
|
static constexpr uint32_t ResetTimeUs = 50;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NeoRp2040PioSpeed400Kbps : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono3Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 400000.0f; // 800+1700
|
||||||
|
static constexpr uint32_t ResetTimeUs = 50;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NeoRp2040PioSpeedApa106 : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono4Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 588235.29f; // 350+1350
|
||||||
|
static constexpr uint32_t ResetTimeUs = 50;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NeoRp2040PioSpeedTx1812 : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono3Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 1111111.11f; // 300+600
|
||||||
|
static constexpr uint32_t ResetTimeUs = 80;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NeoRp2040PioSpeedGs1903 : public NeoRp2040PioMonoProgram<NeoRp2040PioCadenceMono4Step>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr float BitRateHz = 833333.33f; // 300+900
|
||||||
|
static constexpr uint32_t ResetTimeUs = 40;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
431
src/internal/methods/Rp2040/NeoRp2040x4Method.h
Normal file
431
src/internal/methods/Rp2040/NeoRp2040x4Method.h
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
NeoPixel library helper functions for RP2040.
|
||||||
|
|
||||||
|
Written by Michael C. Miller.
|
||||||
|
|
||||||
|
I invest time and resources providing this open source code,
|
||||||
|
please support me by dontating (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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
|
||||||
|
//#define NEORP2040_DEBUG
|
||||||
|
|
||||||
|
#include "hardware/dma.h"
|
||||||
|
#include "hardware/irq.h"
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
#include "pico/mutex.h"
|
||||||
|
|
||||||
|
#include "NeoRp2040DmaState.h"
|
||||||
|
#include "NeoRp2040PioMonoProgram.h"
|
||||||
|
#include "NeoRp2040PioInstance.h"
|
||||||
|
#include "NeoRp2040PioSpeed.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Method
|
||||||
|
// --------------------------------------------------------
|
||||||
|
template<typename T_SPEED,
|
||||||
|
typename T_PIO_INSTANCE,
|
||||||
|
bool V_INVERT = false,
|
||||||
|
uint V_IRQ_INDEX = 1>
|
||||||
|
class NeoRp2040x4MethodBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef NeoNoSettings SettingsObject;
|
||||||
|
|
||||||
|
NeoRp2040x4MethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||||
|
_sizeData(pixelCount * elementSize + settingsSize),
|
||||||
|
_pin(pin),
|
||||||
|
_mergedFifoCount((_pio.Instance->dbg_cfginfo & PIO_DBG_CFGINFO_FIFO_DEPTH_BITS) * 2) // merged TX / RX FIFO buffer in words
|
||||||
|
{
|
||||||
|
construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoRp2040x4MethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
|
||||||
|
_sizeData(pixelCount* elementSize + settingsSize),
|
||||||
|
_pin(pin),
|
||||||
|
_pio(channel),
|
||||||
|
_mergedFifoCount((_pio.Instance->dbg_cfginfo& PIO_DBG_CFGINFO_FIFO_DEPTH_BITS) * 2) // merged TX / RX FIFO buffer in words
|
||||||
|
{
|
||||||
|
construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
~NeoRp2040x4MethodBase()
|
||||||
|
{
|
||||||
|
// wait for last send
|
||||||
|
while (!IsReadyToUpdate())
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear any remaining just to be extra sure
|
||||||
|
pio_sm_clear_fifos(_pio.Instance, _sm);
|
||||||
|
|
||||||
|
// disable the state machine
|
||||||
|
pio_sm_set_enabled(_pio.Instance, _sm, false);
|
||||||
|
|
||||||
|
// Disable and remove interrupts
|
||||||
|
// dma_channel_cleanup(_dmaChannel); // NOT PRESENT?!
|
||||||
|
dma_irqn_set_channel_enabled(V_IRQ_INDEX, _dmaChannel, false);
|
||||||
|
|
||||||
|
// unregister static dma callback object
|
||||||
|
_dmaState.Unregister(_dmaChannel);
|
||||||
|
|
||||||
|
// unclaim dma channel and then state machine
|
||||||
|
dma_channel_unclaim(_dmaChannel);
|
||||||
|
pio_sm_unclaim(_pio.Instance, _sm);
|
||||||
|
|
||||||
|
pinMode(_pin, INPUT);
|
||||||
|
|
||||||
|
free(_dataEditing);
|
||||||
|
free(_dataSending);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsReadyToUpdate() const
|
||||||
|
{
|
||||||
|
return _dmaState.IsReadyToSend(T_SPEED::ResetTimeUs + _fifoCacheEmptyDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize()
|
||||||
|
{
|
||||||
|
// Select the largest FIFO fetch size that aligns with our data size
|
||||||
|
// BUT, since RP2040 is little endian, if the source element size is
|
||||||
|
// 8 bits, then the larger shift bits accounts for endianess
|
||||||
|
// and will mangle the order thinking its source was a 16/32 bits
|
||||||
|
// must you use channel_config_set_bswap() to address this, see below
|
||||||
|
uint fifoWordBits = 8; // size of a FIFO word in bits
|
||||||
|
|
||||||
|
if (_sizeData % 4 == 0)
|
||||||
|
{
|
||||||
|
// data is 4 byte aligned in size,
|
||||||
|
// use a 32 bit fifo word for effeciency
|
||||||
|
fifoWordBits = 32;
|
||||||
|
}
|
||||||
|
else if (_sizeData % 2 == 0)
|
||||||
|
{
|
||||||
|
// data is 2 byte aligned in size,
|
||||||
|
// use a 16 bit fifo word for effeciency
|
||||||
|
fifoWordBits = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calc the two related values from fifoWordBits
|
||||||
|
dma_channel_transfer_size dmaTransferSize = static_cast<dma_channel_transfer_size>(fifoWordBits / 16);
|
||||||
|
uint dmaTransferCount = _sizeData / (fifoWordBits / 8);;
|
||||||
|
|
||||||
|
// IRQ triggers on DMA buffer finished,
|
||||||
|
// not the FIFO buffer finished sending,
|
||||||
|
// so we calc this delta so it can be added to the reset time
|
||||||
|
//
|
||||||
|
|
||||||
|
// 1000000.0f / T_SPEED::BitRateHz = us to send one bit
|
||||||
|
float bitLengthUs = 1000000.0f / T_SPEED::BitRateHz;
|
||||||
|
|
||||||
|
// _mergedFifoCount is merged TX/RX FIFO buffer in words
|
||||||
|
// Add another word for any IRQ trigger latency (error) as
|
||||||
|
// too short is catastrophic and too long is fine
|
||||||
|
_fifoCacheEmptyDelta = bitLengthUs * fifoWordBits * (_mergedFifoCount + 1);
|
||||||
|
|
||||||
|
#if defined(NEORP2040_DEBUG)
|
||||||
|
|
||||||
|
Serial.print(", _pio.Instance = ");
|
||||||
|
Serial.print((_pio.Instance == pio1));
|
||||||
|
Serial.print(", _sizeData = ");
|
||||||
|
Serial.print(_sizeData);
|
||||||
|
Serial.print(", dmaTransferSize = ");
|
||||||
|
Serial.print(dmaTransferSize);
|
||||||
|
Serial.print(", dmaTransferCount = ");
|
||||||
|
Serial.print(dmaTransferCount);
|
||||||
|
Serial.print(", fifoWordBits = ");
|
||||||
|
Serial.print(fifoWordBits);
|
||||||
|
Serial.print(", _mergedFifoCount = ");
|
||||||
|
Serial.print(_mergedFifoCount);
|
||||||
|
Serial.print(", _fifoCacheEmptyDelta = ");
|
||||||
|
Serial.print(_fifoCacheEmptyDelta);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Our assembled program needs to be loaded into this PIO's instruction
|
||||||
|
// memory. This SDK function will find a location (offset) in the
|
||||||
|
// instruction memory where there is enough space for our program. We need
|
||||||
|
//
|
||||||
|
uint offset = T_SPEED::add(_pio.Instance);
|
||||||
|
|
||||||
|
#if defined(NEORP2040_DEBUG)
|
||||||
|
|
||||||
|
Serial.println();
|
||||||
|
Serial.print("offset = ");
|
||||||
|
Serial.print(offset);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Find a free state machine on our chosen PIO.
|
||||||
|
_sm = pio_claim_unused_sm(_pio.Instance, true); // panic if none available
|
||||||
|
|
||||||
|
#if defined(NEORP2040_DEBUG)
|
||||||
|
|
||||||
|
Serial.print(", _sm = ");
|
||||||
|
Serial.print(_sm);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Configure it to run our program, and start it, using the
|
||||||
|
// helper function we included in our .pio file.
|
||||||
|
T_SPEED::init(_pio.Instance,
|
||||||
|
_sm,
|
||||||
|
offset,
|
||||||
|
_pin,
|
||||||
|
T_SPEED::BitRateHz,
|
||||||
|
fifoWordBits);
|
||||||
|
|
||||||
|
// invert output if needed
|
||||||
|
if (V_INVERT)
|
||||||
|
{
|
||||||
|
gpio_set_outover(_pin, GPIO_OVERRIDE_INVERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find a free dma channel
|
||||||
|
_dmaChannel = dma_claim_unused_channel(true); // panic if none available
|
||||||
|
|
||||||
|
#if defined(NEORP2040_DEBUG)
|
||||||
|
|
||||||
|
Serial.print(", *_dmaChannel = ");
|
||||||
|
Serial.print(_dmaChannel);
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// register for IRQ shared static endTime updates
|
||||||
|
_dmaState.Register(_dmaChannel);
|
||||||
|
|
||||||
|
// Set up DMA transfer
|
||||||
|
dma_channel_config dmaConfig = dma_channel_get_default_config(_dmaChannel);
|
||||||
|
channel_config_set_transfer_data_size(&dmaConfig, dmaTransferSize);
|
||||||
|
channel_config_set_read_increment(&dmaConfig, true);
|
||||||
|
channel_config_set_write_increment(&dmaConfig, false);
|
||||||
|
// source is byte data stream, even with 16/32 transfer size
|
||||||
|
channel_config_set_bswap(&dmaConfig, true);
|
||||||
|
|
||||||
|
// Set DMA trigger
|
||||||
|
channel_config_set_dreq(&dmaConfig, pio_get_dreq(_pio.Instance, _sm, true));
|
||||||
|
|
||||||
|
dma_channel_configure(_dmaChannel,
|
||||||
|
&dmaConfig,
|
||||||
|
&(_pio.Instance->txf[_sm]), // dest
|
||||||
|
_dataSending, // src
|
||||||
|
dmaTransferCount,
|
||||||
|
false);
|
||||||
|
|
||||||
|
dma_irqn_set_channel_enabled(V_IRQ_INDEX, _dmaChannel, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(bool maintainBufferConsistency)
|
||||||
|
{
|
||||||
|
// wait for last send
|
||||||
|
while (!IsReadyToUpdate())
|
||||||
|
{
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
_dmaState.SetSending();
|
||||||
|
|
||||||
|
// start next send
|
||||||
|
//
|
||||||
|
dma_channel_set_read_addr(_dmaChannel, _dataEditing, false);
|
||||||
|
dma_channel_start(_dmaChannel); // Start new transfer
|
||||||
|
|
||||||
|
if (maintainBufferConsistency)
|
||||||
|
{
|
||||||
|
// copy editing to sending,
|
||||||
|
// this maintains the contract that "colors present before will
|
||||||
|
// be the same after", otherwise GetPixelColor will be inconsistent
|
||||||
|
memcpy(_dataSending, _dataEditing, _sizeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// swap so the user can modify without affecting the async operation
|
||||||
|
std::swap(_dataSending, _dataEditing);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlwaysUpdate()
|
||||||
|
{
|
||||||
|
// this method requires update to be called only if changes to buffer
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* getData() const
|
||||||
|
{
|
||||||
|
return _dataEditing;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t getDataSize() const
|
||||||
|
{
|
||||||
|
return _sizeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const size_t _sizeData; // Size of '_data*' buffers
|
||||||
|
const uint8_t _pin; // output pin number
|
||||||
|
const T_PIO_INSTANCE _pio; // holds instance for multi channel support
|
||||||
|
const uint8_t _mergedFifoCount;
|
||||||
|
|
||||||
|
NeoRp2040DmaState<V_IRQ_INDEX> _dmaState; // Latch timing reference
|
||||||
|
uint32_t _fifoCacheEmptyDelta; // delta between dma IRQ finished and PIO Fifo empty
|
||||||
|
|
||||||
|
// Holds data stream which include LED color values and other settings as needed
|
||||||
|
uint8_t* _dataEditing; // exposed for get and set
|
||||||
|
uint8_t* _dataSending; // used for async send using DMA
|
||||||
|
|
||||||
|
// holds pio state
|
||||||
|
int _sm;
|
||||||
|
int _dmaChannel;
|
||||||
|
|
||||||
|
void construct()
|
||||||
|
{
|
||||||
|
_dataEditing = static_cast<uint8_t*>(malloc(_sizeData));
|
||||||
|
// data cleared later in Begin() with a ClearTo(0)
|
||||||
|
|
||||||
|
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
|
||||||
|
// no need to initialize it, it gets overwritten on every send
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// normal
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2811, NeoRp2040PioInstanceN> Rp2040x4NWs2811Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstanceN> Rp2040x4NWs2812xMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstanceN> Rp2040x4NWs2816Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedSk6812, NeoRp2040PioInstanceN> Rp2040x4NSk6812Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1814, NeoRp2040PioInstanceN, true> Rp2040x4NTm1814Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1829, NeoRp2040PioInstanceN, true> Rp2040x4NTm1829Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1914, NeoRp2040PioInstanceN, true> Rp2040x4NTm1914Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedApa106, NeoRp2040PioInstanceN> Rp2040x4NApa106Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTx1812, NeoRp2040PioInstanceN> Rp2040x4NTx1812Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedGs1903, NeoRp2040PioInstanceN> Rp2040x4NGs1903Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed800Kbps, NeoRp2040PioInstanceN> Rp2040x4N800KbpsMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed400Kbps, NeoRp2040PioInstanceN> Rp2040x4N400KbpsMethod;
|
||||||
|
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2811, NeoRp2040PioInstance0> Rp2040x4Pio0Ws2811Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstance0> Rp2040x4Pio0Ws2812xMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstance0> Rp2040x4Pio0Ws2816Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedSk6812, NeoRp2040PioInstance0> Rp2040x4Pio0Sk6812Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1814, NeoRp2040PioInstance0, true> Rp2040x4Pio0Tm1814Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1829, NeoRp2040PioInstance0, true> Rp2040x4Pio0Tm1829Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1914, NeoRp2040PioInstance0, true> Rp2040x4Pio0Tm1914Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedApa106, NeoRp2040PioInstance0> Rp2040x4Pio0Apa106Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTx1812, NeoRp2040PioInstance0> Rp2040x4Pio0Tx1812Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedGs1903, NeoRp2040PioInstance0> Rp2040x4Pio0Gs1903Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed800Kbps, NeoRp2040PioInstance0> Rp2040x4Pio0800KbpsMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed400Kbps, NeoRp2040PioInstance0> Rp2040x4Pio0400KbpsMethod;
|
||||||
|
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2811, NeoRp2040PioInstance1> Rp2040x4Pio1Ws2811Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstance1> Rp2040x4Pio1Ws2812xMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstance1> Rp2040x4Pio1Ws2816Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedSk6812, NeoRp2040PioInstance1> Rp2040x4Pio1Sk6812Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1814, NeoRp2040PioInstance1, true> Rp2040x4Pio1Tm1814Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1829, NeoRp2040PioInstance1, true> Rp2040x4Pio1Tm1829Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1914, NeoRp2040PioInstance1, true> Rp2040x4Pio1Tm1914Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedApa106, NeoRp2040PioInstance1> Rp2040x4Pio1Apa106Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTx1812, NeoRp2040PioInstance1> Rp2040x4Pio1Tx1812Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedGs1903, NeoRp2040PioInstance1> Rp2040x4Pio1Gs1903Method;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed800Kbps, NeoRp2040PioInstance1> Rp2040x4Pio1800KbpsMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed400Kbps, NeoRp2040PioInstance1> Rp2040x4Pio1400KbpsMethod;
|
||||||
|
|
||||||
|
// inverted
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2811, NeoRp2040PioInstanceN, true> Rp2040x4NWs2811InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstanceN, true> Rp2040x4NWs2812xInvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstanceN, true> Rp2040x4NWs2816InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedSk6812, NeoRp2040PioInstanceN, true> Rp2040x4NSk6812InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1814, NeoRp2040PioInstanceN> Rp2040x4NTm1814InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1829, NeoRp2040PioInstanceN> Rp2040x4NTm1829InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1914, NeoRp2040PioInstanceN> Rp2040x4NTm1914InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedApa106, NeoRp2040PioInstanceN, true> Rp2040x4NApa106InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTx1812, NeoRp2040PioInstanceN, true> Rp2040x4NTx1812InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedGs1903, NeoRp2040PioInstanceN, true> Rp2040x4NGs1903InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed800Kbps, NeoRp2040PioInstanceN, true> Rp2040x4N800KbpsInvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed400Kbps, NeoRp2040PioInstanceN, true> Rp2040x4N400KbpsInvertedMethod;
|
||||||
|
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2811, NeoRp2040PioInstance0, true> Rp2040x4Pio0Ws2811InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstance0, true> Rp2040x4Pio0Ws2812xInvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstance0, true> Rp2040x4Pio0Ws2816InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedSk6812, NeoRp2040PioInstance0, true> Rp2040x4Pio0Sk6812InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1814, NeoRp2040PioInstance0> Rp2040x4Pio0Tm1814InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1829, NeoRp2040PioInstance0> Rp2040x4Pio0Tm1829InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1914, NeoRp2040PioInstance0> Rp2040x4Pio0Tm1914InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedApa106, NeoRp2040PioInstance0, true> Rp2040x4Pio0Apa106InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTx1812, NeoRp2040PioInstance0, true> Rp2040x4Pio0Tx1812InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedGs1903, NeoRp2040PioInstance0, true> Rp2040x4Pio0Gs1903InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed800Kbps, NeoRp2040PioInstance0, true> Rp2040x4Pio0800KbpsInvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed400Kbps, NeoRp2040PioInstance0, true> Rp2040x4Pio0400KbpsInvertedMethod;
|
||||||
|
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2811, NeoRp2040PioInstance1, true> Rp2040x4Pio1Ws2811InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstance1, true> Rp2040x4Pio1Ws2812xInvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedWs2812x, NeoRp2040PioInstance1, true> Rp2040x4Pio1Ws2816InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedSk6812, NeoRp2040PioInstance1, true> Rp2040x4Pio1Sk6812InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1814, NeoRp2040PioInstance1> Rp2040x4Pio1Tm1814InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1829, NeoRp2040PioInstance1> Rp2040x4Pio1Tm1829InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTm1914, NeoRp2040PioInstance1> Rp2040x4Pio1Tm1914InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedApa106, NeoRp2040PioInstance1, true> Rp2040x4Pio1Apa106InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedTx1812, NeoRp2040PioInstance1, true> Rp2040x4Pio1Tx1812InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeedGs1903, NeoRp2040PioInstance1, true> Rp2040x4Pio1Gs1903InvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed800Kbps, NeoRp2040PioInstance1, true> Rp2040x4Pio1800KbpsInvertedMethod;
|
||||||
|
typedef NeoRp2040x4MethodBase<NeoRp2040PioSpeed400Kbps, NeoRp2040PioInstance1, true> Rp2040x4Pio1400KbpsInvertedMethod;
|
||||||
|
|
||||||
|
// PIO 1 method is the default method, and still x4 instances
|
||||||
|
typedef Rp2040x4Pio1Ws2812xMethod NeoWs2813Method;
|
||||||
|
typedef Rp2040x4Pio1Ws2812xMethod NeoWs2812xMethod;
|
||||||
|
typedef Rp2040x4Pio1800KbpsMethod NeoWs2812Method;
|
||||||
|
typedef Rp2040x4Pio1Ws2812xMethod NeoWs2811Method;
|
||||||
|
typedef Rp2040x4Pio1Ws2812xMethod NeoWs2816Method;
|
||||||
|
typedef Rp2040x4Pio1Sk6812Method NeoSk6812Method;
|
||||||
|
typedef Rp2040x4Pio1Tm1814Method NeoTm1814Method;
|
||||||
|
typedef Rp2040x4Pio1Tm1829Method NeoTm1829Method;
|
||||||
|
typedef Rp2040x4Pio1Tm1914Method NeoTm1914Method;
|
||||||
|
typedef Rp2040x4Pio1Sk6812Method NeoLc8812Method;
|
||||||
|
typedef Rp2040x4Pio1Apa106Method NeoApa106Method;
|
||||||
|
typedef Rp2040x4Pio1Tx1812Method NeoTx1812Method;
|
||||||
|
typedef Rp2040x4Pio1Gs1903Method NeoGs1903Method;
|
||||||
|
|
||||||
|
typedef Rp2040x4Pio1Ws2812xMethod Neo800KbpsMethod;
|
||||||
|
typedef Rp2040x4Pio1400KbpsMethod Neo400KbpsMethod;
|
||||||
|
|
||||||
|
typedef Rp2040x4Pio1Ws2812xInvertedMethod NeoWs2813InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Ws2812xInvertedMethod NeoWs2811InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1800KbpsInvertedMethod NeoWs2812InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Ws2812xInvertedMethod NeoWs2816InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Sk6812InvertedMethod NeoSk6812InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Tm1814InvertedMethod NeoTm1814InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Tm1829InvertedMethod NeoTm1829InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Tm1914InvertedMethod NeoTm1914InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Sk6812InvertedMethod NeoLc8812InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Apa106InvertedMethod NeoApa106InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Tx1812InvertedMethod NeoTx1812InvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1Gs1903InvertedMethod NeoGs1903InvertedMethod;
|
||||||
|
|
||||||
|
typedef Rp2040x4Pio1Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
|
||||||
|
typedef Rp2040x4Pio1400KbpsInvertedMethod Neo400KbpsInvertedMethod;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user