Arm Nrf52x compile

This commit is contained in:
Michael Miller
2024-04-22 07:40:01 -07:00
parent 588d7707ef
commit 346762237a
3 changed files with 185 additions and 106 deletions

View File

@@ -37,21 +37,19 @@ template<typename T_SPEED> class NeoArmMethodBase
public: public:
typedef NeoNoSettings SettingsObject; typedef NeoNoSettings SettingsObject;
NeoArmMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : NeoArmMethodBase(uint8_t pin,
_sizeData(pixelCount * elementSize + settingsSize), uint16_t pixelCount,
_pin(pin) [[maybe_unused]] size_t elementSize,
[[maybe_unused]] size_t settingsSize) :
_pin(pin),
_pixelCount(pixelCount)
{ {
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
_data = static_cast<uint8_t*>(malloc(_sizeData));
// data cleared later in Begin()
} }
~NeoArmMethodBase() ~NeoArmMethodBase()
{ {
pinMode(_pin, INPUT); pinMode(_pin, INPUT);
free(_data);
} }
bool IsReadyToUpdate() const bool IsReadyToUpdate() const
@@ -68,55 +66,97 @@ public:
_endTime = micros(); _endTime = micros();
} }
void Update(bool) template <typename T_COLOR_OBJECT,
typename T_COLOR_FEATURE,
typename T_SHADER>
void Update(
T_COLOR_OBJECT* pixels,
size_t countPixels,
const typename T_COLOR_FEATURE::SettingsObject& featureSettings,
const T_SHADER& shader)
{ {
// Data latch = 50+ microsecond pause in the output stream. Rather than // wait for not actively sending data
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while (!IsReadyToUpdate()) while (!IsReadyToUpdate())
{ {
yield(); // allows for system yield if needed yield();
} }
const size_t sendDataSize = T_COLOR_FEATURE::SettingsSize >= T_COLOR_FEATURE::PixelSize ? T_COLOR_FEATURE::SettingsSize : T_COLOR_FEATURE::PixelSize;
uint8_t sendData[sendDataSize];
uint8_t* transaction = this->BeginTransaction();
// if there are settings at the front
//
if (T_COLOR_FEATURE::applyFrontSettings(sendData, sendDataSize, featureSettings))
{
this->AppendData(&transaction, sendData, T_COLOR_FEATURE::SettingsSize);
}
// fill primary color data
//
T_COLOR_OBJECT* pixel = pixels;
const T_COLOR_OBJECT* pixelEnd = pixel + countPixels;
uint16_t stripCount = this->_pixelCount;
while (stripCount--)
{
typename T_COLOR_FEATURE::ColorObject color = shader.Apply(*pixel);
T_COLOR_FEATURE::applyPixelColor(sendData, sendDataSize, color);
this->AppendData(&transaction, sendData, T_COLOR_FEATURE::PixelSize);
pixel++;
if (pixel >= pixelEnd)
{
// restart at first
pixel = pixels;
}
}
// if there are settings at the back
//
if (T_COLOR_FEATURE::applyBackSettings(sendData, sendDataSize, featureSettings))
{
this->AppendData(&transaction, sendData, T_COLOR_FEATURE::SettingsSize);
}
this->EndTransaction();
}
uint8_t* BeginTransaction()
{
noInterrupts(); // Need 100% focus on instruction timing noInterrupts(); // Need 100% focus on instruction timing
// weird, but we need a valid pointer
// the pointer is dereferenced, but what it points out is not
return reinterpret_cast<uint8_t*>(this);
}
T_SPEED::send_pixels(_data, _sizeData, _pin); bool AppendData([[maybe_unused]] uint8_t** buffer, const uint8_t* sendData, size_t sendDataSize)
{
T_SPEED::send_data(sendData, sendDataSize, _pin);
return true;
}
bool EndTransaction()
{
interrupts(); interrupts();
// save EOD time for latch on next call // save EOD time for latch on next call
_endTime = micros(); _endTime = micros();
return true;
} }
bool AlwaysUpdate()
{
// this method requires update to be called only if changes to buffer
return false;
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
void applySettings([[maybe_unused]] const SettingsObject& settings) void applySettings([[maybe_unused]] const SettingsObject& settings)
{ {
} }
private: private:
const size_t _sizeData; // Size of '_data' buffer below const uint8_t _pin; // output pin number
const uint16_t _pixelCount; // count of pixels in the strip
uint32_t _endTime; // Latch timing reference uint32_t _endTime; // Latch timing reference
uint8_t* _data; // Holds LED color values uint8_t* _data; // Holds LED color values
uint8_t _pin; // output pin number
}; };
// Teensy 3.0 or 3.1 (3.2) or 3.5 or 3.6 // Teensy 3.0 or 3.1 (3.2) or 3.5 or 3.6
@@ -192,10 +232,10 @@ template<typename T_SPEEDPROPS> class NeoArmMk20dxSpeedBase
public: public:
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) static void send_data(const uint8_t* data, size_t sizeData, uint8_t pin)
{ {
uint8_t* p = pixels; const uint8_t* p = data;
uint8_t* end = p + sizePixels; const uint8_t* end = p + sizeData;
uint8_t pix; uint8_t pix;
uint8_t mask; uint8_t mask;
@@ -249,15 +289,15 @@ typedef NeoArmTm1814InvertedMethod NeoArmTm1914InvertedMethod;
class NeoArmMk26z64Speed800KbpsBase class NeoArmMk26z64Speed800KbpsBase
{ {
public: public:
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) static void send_data(const uint8_t* data, size_t sizeData, uint8_t pin)
{ {
uint8_t* p = pixels; const uint8_t* p = data;
uint8_t pix; uint8_t pix;
uint8_t count; uint8_t count;
uint8_t dly; uint8_t dly;
uint8_t bitmask = digitalPinToBitMask(pin); uint8_t bitmask = digitalPinToBitMask(pin);
volatile uint8_t* reg = portSetRegister(pin); volatile uint8_t* reg = portSetRegister(pin);
uint32_t num = sizePixels; uint32_t num = sizeData;
asm volatile( asm volatile(
"L%=_begin:" "\n\t" "L%=_begin:" "\n\t"
@@ -491,12 +531,12 @@ template<typename T_SPEEDPROPS> class NeoArmSamd21g18aSpeedBase
public: public:
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) static void send_data(const uint8_t* data, size_t sizeData, uint8_t pin)
{ {
// Tried this with a timer/counter, couldn't quite get adequate // Tried this with a timer/counter, couldn't quite get adequate
// resolution. So yay, you get a load of goofball NOPs... // resolution. So yay, you get a load of goofball NOPs...
uint8_t* ptr = pixels; const uint8_t* ptr = data;
uint8_t* end = ptr + sizePixels;; const uint8_t* end = ptr + sizeData;;
uint8_t p = *ptr++; uint8_t p = *ptr++;
uint8_t bitMask = 0x80; uint8_t bitMask = 0x80;
uint8_t portNum = g_APinDescription[pin].ulPort; uint8_t portNum = g_APinDescription[pin].ulPort;
@@ -657,13 +697,13 @@ template<typename T_SPEEDPROPS> class NeoArmStm32SpeedBase
public: public:
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) static void send_data(const uint8_t* data, size_t sizeData, uint8_t pin)
{ {
// Tried this with a timer/counter, couldn't quite get adequate // Tried this with a timer/counter, couldn't quite get adequate
// resolution. So yay, you get a load of goofball NOPs... // resolution. So yay, you get a load of goofball NOPs...
uint8_t* ptr = pixels; const uint8_t* ptr = data;
uint8_t* end = ptr + sizePixels; const uint8_t* end = ptr + sizeData;
uint8_t p = *ptr++; uint8_t p = *ptr++;
uint8_t bitMask = 0x80; uint8_t bitMask = 0x80;
@@ -814,7 +854,7 @@ template<typename T_SPEEDPROPS> class NeoArmOtherSpeedBase
public: public:
static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs;
static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) static void send_data(const uint8_t* data, size_t sizeData, uint8_t pin)
{ {
uint32_t pinMask; uint32_t pinMask;
uint32_t t; uint32_t t;
@@ -823,8 +863,8 @@ public:
volatile WoReg* portClear; volatile WoReg* portClear;
volatile WoReg* timeValue; volatile WoReg* timeValue;
volatile WoReg* timeReset; volatile WoReg* timeReset;
uint8_t* p; const uint8_t* p;
uint8_t* end; const uint8_t* end;
uint8_t pix; uint8_t pix;
uint8_t mask; uint8_t mask;
@@ -841,8 +881,8 @@ public:
portClear = &(port->PIO_CODR); // starting timer to minimize portClear = &(port->PIO_CODR); // starting timer to minimize
timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'.
timeReset = &(TC1->TC_CHANNEL[0].TC_CCR); timeReset = &(TC1->TC_CHANNEL[0].TC_CCR);
p = pixels; p = data;
end = p + sizePixels; end = p + sizeData;
pix = *p++; pix = *p++;
mask = 0x80; mask = 0x80;

View File

@@ -360,18 +360,18 @@ public:
typedef NeoNoSettings SettingsObject; typedef NeoNoSettings SettingsObject;
NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize), _pin(pin),
_pin(pin) _pixelCount(pixelCount)
{ {
construct(); construct(pixelCount * elementSize + settingsSize);
} }
NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
_sizeData(pixelCount* elementSize + settingsSize),
_pin(pin), _pin(pin),
_pixelCount(pixelCount),
_bus(channel) _bus(channel)
{ {
construct(); construct(pixelCount * elementSize + settingsSize);
} }
~NeoNrf52xMethodBase() ~NeoNrf52xMethodBase()
@@ -385,7 +385,6 @@ public:
pinMode(_pin, INPUT); pinMode(_pin, INPUT);
free(_data);
free(_dmaBuffer); free(_dmaBuffer);
} }
@@ -406,60 +405,112 @@ public:
dmaStart(); dmaStart();
} }
void Update(bool) template <typename T_COLOR_OBJECT,
typename T_COLOR_FEATURE,
typename T_SHADER>
void Update(
T_COLOR_OBJECT* pixels,
size_t countPixels,
const typename T_COLOR_FEATURE::SettingsObject& featureSettings,
const T_SHADER& shader)
{ {
// Data latch = 50+ microsecond pause in the output stream. Rather than // wait for not actively sending data
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while (!IsReadyToUpdate()) while (!IsReadyToUpdate())
{ {
yield(); // allows for system yield if needed yield();
} }
FillBuffer(); const size_t sendDataSize = T_COLOR_FEATURE::SettingsSize >= T_COLOR_FEATURE::PixelSize ? T_COLOR_FEATURE::SettingsSize : T_COLOR_FEATURE::PixelSize;
uint8_t sendData[sendDataSize];
uint8_t* transaction = this->BeginTransaction();
// if there are settings at the front
//
if (T_COLOR_FEATURE::applyFrontSettings(sendData, sendDataSize, featureSettings))
{
this->AppendData(&transaction, sendData, T_COLOR_FEATURE::SettingsSize);
}
// fill primary color data
//
T_COLOR_OBJECT* pixel = pixels;
const T_COLOR_OBJECT* pixelEnd = pixel + countPixels;
uint16_t stripCount = this->_pixelCount;
while (stripCount--)
{
typename T_COLOR_FEATURE::ColorObject color = shader.Apply(*pixel);
T_COLOR_FEATURE::applyPixelColor(sendData, sendDataSize, color);
this->AppendData(&transaction, sendData, T_COLOR_FEATURE::PixelSize);
pixel++;
if (pixel >= pixelEnd)
{
// restart at first
pixel = pixels;
}
}
// if there are settings at the back
//
if (T_COLOR_FEATURE::applyBackSettings(sendData, sendDataSize, featureSettings))
{
this->AppendData(&transaction, sendData, T_COLOR_FEATURE::SettingsSize);
}
this->EndTransaction(&transaction);
}
uint8_t* BeginTransaction()
{
return reinterpret_cast<uint8_t*>(_dmaBuffer);
}
bool AppendData(uint8_t** buffer, const uint8_t* sendData, size_t sendDataSize)
{
nrf_pwm_values_common_t* pDma = reinterpret_cast<nrf_pwm_values_common_t*>(*buffer);
const uint8_t* pEnd = sendData + sendDataSize;
for (const uint8_t* pData = sendData; pData < pEnd; pData++)
{
uint8_t data = *pData;
for (uint8_t bit = 0; bit < 8; bit++)
{
*(pDma++) = (data & 0x80) ? T_SPEED::Bit1 : T_SPEED::Bit0;
data <<= 1;
}
}
*buffer = reinterpret_cast<uint8_t*>(pDma);
return true;
}
bool EndTransaction([[maybe_unused]] uint8_t** buffer)
{
dmaStart(); dmaStart();
return true;
} }
bool AlwaysUpdate()
{
// this method requires update to be called only if changes to buffer
return false;
}
uint8_t* getData() const
{
return _data;
};
size_t getDataSize() const
{
return _sizeData;
};
void applySettings([[maybe_unused]] const SettingsObject& settings) void applySettings([[maybe_unused]] const SettingsObject& settings)
{ {
} }
private: private:
const size_t _sizeData; // Size of '_data' buffer below
const uint8_t _pin; // output pin number const uint8_t _pin; // output pin number
const uint16_t _pixelCount; // count of pixels in the strip
const T_BUS _bus; // holds instance for multi channel support const T_BUS _bus; // holds instance for multi channel support
uint8_t* _data; // Holds LED color values
size_t _dmaBufferSize; // total size of _dmaBuffer size_t _dmaBufferSize; // total size of _dmaBuffer
nrf_pwm_values_common_t* _dmaBuffer; // Holds pixel data in native format for PWM hardware nrf_pwm_values_common_t* _dmaBuffer; // Holds pixel data in native format for PWM hardware
void construct() void construct(size_t sizeData)
{ {
pinMode(_pin, OUTPUT); pinMode(_pin, OUTPUT);
_data = static_cast<uint8_t*>(malloc(_sizeData)); _dmaBufferSize = c_dmaBytesPerDataByte * sizeData + sizeof(nrf_pwm_values_common_t);
// data cleared later in Begin()
_dmaBufferSize = c_dmaBytesPerDataByte * _sizeData + sizeof(nrf_pwm_values_common_t);
_dmaBuffer = static_cast<nrf_pwm_values_common_t*>(malloc(_dmaBufferSize)); _dmaBuffer = static_cast<nrf_pwm_values_common_t*>(malloc(_dmaBufferSize));
} }
@@ -507,22 +558,10 @@ private:
void FillBuffer() void FillBuffer()
{ {
nrf_pwm_values_common_t* pDma = _dmaBuffer; nrf_pwm_values_common_t* pDma = _dmaBuffer;
nrf_pwm_values_common_t* pDmaEnd = _dmaBuffer + (_dmaBufferSize / sizeof(nrf_pwm_values_common_t)); const nrf_pwm_values_common_t* pDmaEnd = _dmaBuffer + (_dmaBufferSize / sizeof(nrf_pwm_values_common_t));
uint8_t* pEnd = _data + _sizeData;
for (uint8_t* pData = _data; pData < pEnd; pData++) // fill the dma buffer with BitReset
{ //
uint8_t data = *pData;
for (uint8_t bit = 0; bit < 8; bit++)
{
*(pDma++) = (data & 0x80) ? T_SPEED::Bit1 : T_SPEED::Bit0;
data <<= 1;
}
}
// fill the rest with BitReset as it will get repeated when delaying or
// at the end before being stopped
while (pDma < pDmaEnd) while (pDma < pDmaEnd)
{ {
*(pDma++) = T_SPEED::BitReset; *(pDma++) = T_SPEED::BitReset;

View File

@@ -26,7 +26,7 @@ License along with NeoPixel. If not, see
#pragma once #pragma once
#ifdef ARDUINO_ARCH_RP2040 #if defined(ARDUINO_ARCH_RP2040)
//#define NEORP2040_DEBUG //#define NEORP2040_DEBUG