Skip to content

Commit 3d6a1c7

Browse files
Enable proper reuse of PIO programs (#1526)
* Enable proper reuse of PIO programs Rewrite the PIOProgram helper class to properly re-use loaded programs and to try to re-use loaded instructions before allocating a new PIO program. Supersedes #1524 * Less copy-pasta
1 parent 5b76b06 commit 3d6a1c7

File tree

4 files changed

+120
-60
lines changed

4 files changed

+120
-60
lines changed

cores/rp2040/PIOProgram.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
RP2040 PIO utility class
3+
4+
Copyright (c) 2023 Earle F. Philhower, III <[email protected]>
5+
6+
This library is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU Lesser General Public
8+
License as published by the Free Software Foundation; either
9+
version 2.1 of the License, or (at your option) any later version.
10+
11+
This library is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
Lesser General Public License for more details.
15+
16+
You should have received a copy of the GNU Lesser General Public
17+
License along with this library; if not, write to the Free Software
18+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
21+
#include <Arduino.h>
22+
#include "PIOProgram.h"
23+
#include <map>
24+
25+
static std::map<const pio_program_t *, int> __pioMap[2];
26+
auto_init_mutex(_pioMutex);
27+
28+
29+
PIOProgram::PIOProgram(const pio_program_t *pgm) {
30+
_pgm = pgm;
31+
_pio = nullptr;
32+
_sm = -1;
33+
}
34+
35+
// We leave the INSN loaded in INSN RAM
36+
PIOProgram::~PIOProgram() {
37+
if (_pio) {
38+
pio_sm_unclaim(_pio, _sm);
39+
}
40+
}
41+
42+
// Possibly load into a PIO and allocate a SM
43+
bool PIOProgram::prepare(PIO *pio, int *sm, int *offset) {
44+
CoreMutex m(&_pioMutex);
45+
PIO pi[2] = { pio0, pio1 };
46+
47+
// If it's already loaded into PIO IRAM, try and allocate in that specific PIO
48+
for (int o = 0; o < 2; o++) {
49+
auto p = __pioMap[o].find(_pgm);
50+
if (p != __pioMap[o].end()) {
51+
int idx = pio_claim_unused_sm(pi[o], false);
52+
if (idx >= 0) {
53+
_pio = pi[o];
54+
_sm = idx;
55+
*pio = pi[o];
56+
*sm = idx;
57+
*offset = p->second;
58+
return true;
59+
}
60+
}
61+
}
62+
63+
// Not in any PIO IRAM, so try and add
64+
for (int o = 0; o < 2; o++) {
65+
if (pio_can_add_program(pi[o], _pgm)) {
66+
int idx = pio_claim_unused_sm(pi[o], false);
67+
if (idx >= 0) {
68+
int off = pio_add_program(pi[o], _pgm);
69+
__pioMap[o].insert({_pgm, off});
70+
_pio = pi[o];
71+
_sm = idx;
72+
*pio = pi[o];
73+
*sm = idx;
74+
*offset = off;
75+
return true;
76+
}
77+
}
78+
}
79+
80+
// Nope, no room either for SMs or INSNs
81+
return false;
82+
}

cores/rp2040/PIOProgram.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
RP2040 PIO utility class
3+
4+
Copyright (c) 2023 Earle F. Philhower, III <[email protected]>
5+
6+
This library is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU Lesser General Public
8+
License as published by the Free Software Foundation; either
9+
version 2.1 of the License, or (at your option) any later version.
10+
11+
This library is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
Lesser General Public License for more details.
15+
16+
You should have received a copy of the GNU Lesser General Public
17+
License along with this library; if not, write to the Free Software
18+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
21+
#pragma once
22+
23+
#include <hardware/pio.h>
24+
25+
// Wrapper class for PIO programs, abstracting common operations out
26+
class PIOProgram {
27+
public:
28+
PIOProgram(const pio_program_t *pgm);
29+
~PIOProgram();
30+
// Possibly load into a PIO and allocate a SM
31+
bool prepare(PIO *pio, int *sm, int *offset);
32+
33+
private:
34+
const pio_program_t *_pgm;
35+
PIO _pio;
36+
int _sm;
37+
};

cores/rp2040/RP2040Support.h

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <pico/util/queue.h>
3232
#include <pico/bootrom.h>
3333
#include "CoreMutex.h"
34+
#include "PIOProgram.h"
3435
#include "ccount.pio.h"
3536
#include <malloc.h>
3637

@@ -154,65 +155,9 @@ class _MFIFO {
154155
class RP2040;
155156
extern RP2040 rp2040;
156157
extern "C" void main1();
157-
class PIOProgram;
158-
159158
extern "C" char __StackLimit;
160159
extern "C" char __bss_end__;
161160

162-
// Wrapper class for PIO programs, abstracting common operations out
163-
// TODO - Add unload/destructor
164-
class PIOProgram {
165-
public:
166-
PIOProgram(const pio_program_t *pgm) {
167-
_pgm = pgm;
168-
}
169-
170-
// Possibly load into a PIO and allocate a SM
171-
bool prepare(PIO *pio, int *sm, int *offset) {
172-
extern mutex_t _pioMutex;
173-
CoreMutex m(&_pioMutex);
174-
// Is there an open slot to run in, first?
175-
if (!_findFreeSM(pio, sm)) {
176-
return false;
177-
}
178-
// Is it loaded on that PIO?
179-
if (_offset[pio_get_index(*pio)] < 0) {
180-
// Nope, need to load it
181-
if (!pio_can_add_program(*pio, _pgm)) {
182-
return false;
183-
}
184-
_offset[pio_get_index(*pio)] = pio_add_program(*pio, _pgm);
185-
}
186-
// Here it's guaranteed loaded, return values
187-
// PIO and SM already set
188-
*offset = _offset[pio_get_index(*pio)];
189-
return true;
190-
}
191-
192-
private:
193-
// Find an unused PIO state machine to grab, returns false when none available
194-
static bool _findFreeSM(PIO *pio, int *sm) {
195-
int idx = pio_claim_unused_sm(pio0, false);
196-
if (idx >= 0) {
197-
*pio = pio0;
198-
*sm = idx;
199-
return true;
200-
}
201-
idx = pio_claim_unused_sm(pio1, false);
202-
if (idx >= 0) {
203-
*pio = pio1;
204-
*sm = idx;
205-
return true;
206-
}
207-
return false;
208-
}
209-
210-
211-
private:
212-
int _offset[2] = { -1, -1 };
213-
const pio_program_t *_pgm;
214-
};
215-
216161
class RP2040 {
217162
public:
218163
RP2040() { /* noop */ }

cores/rp2040/main.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ extern "C" {
2929
volatile bool __otherCoreIdled = false;
3030
};
3131

32-
mutex_t _pioMutex;
33-
3432
extern void setup();
3533
extern void loop();
3634

@@ -91,8 +89,6 @@ extern "C" int main() {
9189
_REENT_INIT_PTR(_impure_ptr1);
9290
}
9391

94-
mutex_init(&_pioMutex);
95-
9692
rp2040.begin();
9793

9894
initVariant();

0 commit comments

Comments
 (0)