-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WWA strip support & parallel I2S for S2/S3 (bumping outputs from 5/4 to 12) #4484
base: main
Are you sure you want to change the base?
Conversation
- NeoPixelBus update 2.8.3 - automatic selection of appropriate I2S bus (`X1xxxxxxMethod`) - removed I2S0 on ESP32 (used by AudioReactive) - renumbered internal bus numbers (iType) - added buffer size reporting Bus modifications - WWA strip support - bus initialisation rewrite - optional parallel I2S (ESP32, S2 & S3)
I tried this PR on an S2 lolin: cannot get it to save correctly LED settings if more than 5 outputs are set. It saves but config gets screwed up a little, next time in LED settings, all outputs are gone except the first and it is reset (to a backup I assume) |
Hmm, that may be due to change in initialisation procedure. Will investigate. |
- speed improvements in ABL - verbose debugging
- Implement vector in bus manager - Memory calculation according to explanation from @Makuna - Prefer 8 RMT before 8 I2S on ESP32 (fixes Aircoookie#4380) - speed improvements in ABL - verbose debugging - get bus size from NPB (prototype) - Parallel I2S output bugfix - automatic selection of appropriate I2S bus (`X1xxxxxxMethod`) - removed I2S0 on ESP32 (used by AudioReactive) - renumbered internal bus numbers (iType) - added buffer size reporting
- Segment::setName() - S2 limits - bus debug macros - remove cctBlending from strip
Remove logs form Git tracking
Latest update will also fix #4380 until resolved in NeoPixelBus. |
doInitBusses = true; // finalization done in beginStrip() | ||
} | ||
|
||
busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emplace_back is generally preferable to push_back(move(construct())))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I (personally) would also have tried to simply emplace a default BusConfig, and then modify its values instead of creating a bunch of values, then copying them all over to a BusConfig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea.
BusConfig is fixed in size and has simple constructor though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well in that world I would have removed the explicit constructor. Better for performance anyway, and I imagine better for code size too?
I don't see how BusConfig's size would have any impact here.
Amazing! Are your artifacts using this latest code or should I compile myself? |
You can use artifacts from this PR. Click on ✅ of last commit. |
- experiment with std::unique_ptr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall thoughts: definitely a worthwhile change set. I'm happy to see fewer and fewer C-style pointers.
Longer term, I'd like to squash down all the parallel I2S logic to be inside BusDigital; it bugs me a little bit that this needs to be exposed and handled elsewhere, as in some sense it's an "execution detail" of the digital output subsystem. That said, it's also clear that there's value in having a staged config->plan->construction process which permits more "global" analysis and optimization over the plan, and it's not obvious to me how to devolve that to local knowledge (like how to manage digital output resource allocation).
@@ -613,6 +613,19 @@ Segment &Segment::setPalette(uint8_t pal) { | |||
return *this; | |||
} | |||
|
|||
Segment &Segment::setName(const char *newName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use a String
for the segment name? It already handles all the dynamic allocation and whatnot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Internally?
I added a from String conversion function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes? eg. String name
, instead of char* name
.
if (Bus::isVirtual(bc.type)) { | ||
busses[numBusses] = new BusNetwork(bc); | ||
//busses.push_back(std::make_unique<BusNetwork>(bc)); // when C++ >11 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to wait - make_unique
requires no new compiler features, it's simple enough we can bring a shim implementation:
#if __cplusplus >= 201402L
using std::make_unique;
#else
// Really simple C++11 shim for non-array case; implementation from cppreference.com
template<class T, class... Args>
std::unique_ptr<T>
make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Experimented by using -std=gnu++14
as suggested by @TripleWhy and it worked.
Unfortunately code bloated by 1.4kB.
Wonder if this would make code any smaller.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using this shim and removing delete
increases code by 452B.
Compared to gnu++14 a huge win if it yields same safety.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dug around online for flags to enable newer C++ standards, and turned up a bunch of forum posts from people recommending against it - something something ESP32 platform not tested, doesn't support it, strange crashes, etc. I was surprised - I wouldn't've anticipated trouble from a whole-system build - but it didn't seem to be worth chasing down how applicable those old posts still were for this one case.
I did a quick test with the shim above, and the results were within few hundred bytes for most targets (though the older ESP32 platform really suffers - we need to drop that ASAP)
Target | a98685d | 244e0c9 | Cost |
---|---|---|---|
nodemcuv2 | 879847 | 879879 | 32 |
esp8266_2m | 878183 | 878215 | 32 |
esp01_1m_full | 886715 | 886763 | 48 |
nodemcuv2_160 | 879851 | 879883 | 32 |
esp8266_2m_160 | 878187 | 878219 | 32 |
esp01_1m_full_160 | 886719 | 886767 | 48 |
nodemcuv2_compat | 866399 | 866447 | 48 |
esp8266_2m_compat | 864719 | 864767 | 48 |
esp01_1m_full_compat | 873347 | 873379 | 32 |
esp32dev | 1347273 | 1347709 | 436 |
esp32dev_V4 | 1250905 | 1251001 | 96 |
esp32_eth | 1357633 | 1358029 | 396 |
lolin_s2_mini | 1280009 | 1280137 | 128 |
esp32c3dev | 1152868 | 1152938 | 70 |
esp32s3dev_16MB_opi | 1150241 | 1150337 | 96 |
esp32s3dev_8MB_opi | 1150241 | 1150337 | 96 |
esp32s3_4M_qspi | 1148601 | 1148697 | 96 |
esp32_wrover | 1171514 | 1171506 | -8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when you inline it?
If it's not inlined, the compiler would have to generate one function per template argument it's called with, so might might be the number of bytes of your table times the number of classes that use this (potentially times number compilation units using it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are only 4 calls in BusManager::add() function. Each for one of the classes: BusDigital, BusPwm, BusOnOff and BusNetwork.
There may be additional classes in the future (BusUsermod or BusVirtual).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking more long term: What happens if make_unique starts to get used in more places
What I also wanted to do is convert BusManager into namespace. But got linker errors that |
A missing extern in the header maybe? I think making BusManager in to a namespace is a good idea, too, but it could be a second PR. |
Got it working as a namespace. No real benefits that I can see, though. |
@willmmiles @TripleWhy would such approach be ok? I am not sure about |
Re conversion to namespace: Alas, exposing a couple internal variables is the price we pay for inlining. Best we can do without link-time optimization. Re getBus(): Hm, it's probably not ideal to return something strange given an invalid input. It's not unreasonable to expect the callers of |
Your question is just about line 473 in bus_manager.h in that commit, right? (I could say more about the changes of that commit if you want, but I'm not sure you'd like it :) If it is ok depends on how sure you can be that You could also make it the caller's responsibility to never call Also note that typically you'd define two |
It is supposed to have 1 bus at least unless compilation overrides made impossible bus configuration (GPIO conflict).
That is already in place as all loops go: All in all it may be best to stick with returning a pointer and do explicit nullptr check everywhere.
Go ahead unless it is personal. 😉 Best done inline in the commit. |
After this is merged (if it is) I have another set of updates ready to allow unlimited virtual buses. |
Bus wrapper modifications
X1xxxxxxMethod
)Bus modifications
WS2812FX::finalizeInit()
)This modification will allow unrestricted use of AudioReactive usermod on ESP32 and ESP32-S3. S2 is still prone to conflict but since it is not best suited for large LED counts in combination with AudioReactive the compromise may be acceptable.
WWA strip support may need WW/CW channel swap as I do not have one for test. A(mber) channel is not supported.
Fixes #552