17#include "platforms/arm/rp/is_rp.h"
19#if defined(FL_IS_RP2040) || defined(FL_IS_RP2350)
27#include "hardware/pio.h"
34constexpr int kContentionPin = 2;
35constexpr int kContentionLeds = 8;
38constexpr int kMaxStateMachines = NUM_PIOS * 4;
40PIO pioForIndex(
int index) {
41 if (index == 0)
return pio0;
42 if (index == 1)
return pio1;
43#if defined(FL_IS_RP2350)
44 if (index == 2)
return pio2;
49int countFreeStateMachines() {
51 for (
int pio_index = 0; pio_index < NUM_PIOS; ++pio_index) {
52 PIO pio = pioForIndex(pio_index);
53 if (pio ==
nullptr)
continue;
54 for (uint sm = 0; sm < 4; ++sm) {
55 if (!pio_sm_is_claimed(pio, sm)) ++free_count;
64 ~PioStarver() { release(); }
67 for (
int pio_index = 0; pio_index < NUM_PIOS; ++pio_index) {
68 PIO pio = pioForIndex(pio_index);
69 if (pio ==
nullptr)
continue;
71 const int sm = pio_claim_unused_sm(pio,
false);
82 bool claimsIntact()
const {
83 for (
int i = 0; i < mCount; ++i) {
84 if (!pio_sm_is_claimed(mPio[i],
static_cast<uint>(mSm[i]))) {
94 pio_sm_unclaim(mPio[mCount],
static_cast<uint>(mSm[mCount]));
99 PIO mPio[kMaxStateMachines] = {};
100 int mSm[kMaxStateMachines] = {};
110 response.set(
"numPios",
static_cast<int64_t
>(NUM_PIOS));
111 response.set(
"pin",
static_cast<int64_t
>(kContentionPin));
117 const int baseline_free = countFreeStateMachines();
118 response.set(
"baselineFreeSms",
static_cast<int64_t
>(baseline_free));
124 bool control_proxy_valid =
false;
125 bool control_claimed_one =
false;
127 LegacyClocklessProxy proxy(kContentionPin,
leds, kContentionLeds);
128 const int free_during = countFreeStateMachines();
129 control_proxy_valid = proxy.valid();
130 control_claimed_one = free_during == baseline_free - 1;
131 control.
set(
"proxyValid", control_proxy_valid);
132 control.
set(
"freeDuring",
static_cast<int64_t
>(free_during));
133 control.
set(
"claimedOne", control_claimed_one);
136 const int control_free_after = countFreeStateMachines();
137 control.
set(
"freeAfter",
static_cast<int64_t
>(control_free_after));
138 control.
set(
"released", control_free_after == baseline_free);
143 bool no_theft =
false;
144 bool survived_show =
false;
147 const int starved = starver.starve();
148 contention.
set(
"starvedSms",
static_cast<int64_t
>(starved));
149 contention.
set(
"freeAfterStarve",
150 static_cast<int64_t
>(countFreeStateMachines()));
152 LegacyClocklessProxy proxy(kContentionPin,
leds, kContentionLeds);
153 contention.
set(
"proxyValid", proxy.valid());
157 no_theft = starver.claimsIntact() && countFreeStateMachines() == 0;
158 contention.
set(
"claimsIntact", starver.claimsIntact());
159 contention.
set(
"noTheft", no_theft);
163 survived_show =
true;
164 contention.
set(
"survivedShow", survived_show);
166 const int contention_free_after = countFreeStateMachines();
167 contention.
set(
"freeAfter",
static_cast<int64_t
>(contention_free_after));
168 response.set(
"contention", contention);
171 const bool no_leak = contention_free_after == baseline_free;
178 response.set(
"success", control_proxy_valid && control_claimed_one &&
179 no_theft && survived_show && no_leak &&
180 control_free_after == baseline_free);
192 response.set(
"success",
false);
193 response.set(
"error",
"RP PIO contention test requires an RP2040/RP2350");
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
void show(fl::u8 scale)
Update all our controllers with the current led colors, using the passed in brightness.
void set(const fl::string &key, const json &value) FL_NO_EXCEPT
static json object() FL_NO_EXCEPT
fl::json runRpPioContentionTest()
Reproduce FastLED#1471's PIO state-machine contention on real RP silicon.
@ PIO
PIO receiver (RP2040/RP2350)