Merge pull request #18 from adafruit/share-program-space
Some checks failed
Pip / build (ubuntu-24.04-arm, 3.11) (push) Has been cancelled
Pip / build (ubuntu-24.04-arm, 3.12) (push) Has been cancelled
Pip / build (ubuntu-24.04-arm, 3.13) (push) Has been cancelled
Wheels / Build SDist (push) Has been cancelled
Wheels / Wheels on ubuntu-24.04-arm (push) Has been cancelled
Wheels / Upload release (push) Has been cancelled
Some checks failed
Pip / build (ubuntu-24.04-arm, 3.11) (push) Has been cancelled
Pip / build (ubuntu-24.04-arm, 3.12) (push) Has been cancelled
Pip / build (ubuntu-24.04-arm, 3.13) (push) Has been cancelled
Wheels / Build SDist (push) Has been cancelled
Wheels / Wheels on ubuntu-24.04-arm (push) Has been cancelled
Wheels / Upload release (push) Has been cancelled
Share program space
This commit is contained in:
commit
cb486ce0fb
1 changed files with 85 additions and 19 deletions
104
src/main.cpp
104
src/main.cpp
|
|
@ -11,7 +11,19 @@ namespace py = pybind11;
|
|||
|
||||
namespace {
|
||||
|
||||
typedef struct { uint32_t value;
|
||||
typedef std::vector<uint16_t> program;
|
||||
struct program_info {
|
||||
std::vector<uint16_t> program;
|
||||
PIO pio;
|
||||
int8_t offset=0;
|
||||
uint8_t refcnt=0;
|
||||
};
|
||||
|
||||
constexpr size_t PIO_INSTRUCTION_SPACE = 32;
|
||||
program_info loaded_programs[PIO_INSTRUCTION_SPACE];
|
||||
|
||||
typedef struct {
|
||||
uint32_t value;
|
||||
} pio_pinmask_t;
|
||||
typedef uint32_t pio_pinmask_value_t;
|
||||
#define PIO_PINMASK_C(c) UINT32_C(c)
|
||||
|
|
@ -50,12 +62,18 @@ PIO pio_open_check() {
|
|||
|
||||
PIO pio = pio_open(0);
|
||||
if(PIO_IS_ERR(pio)) {
|
||||
int err = PIO_ERR_VAL(pio);
|
||||
throw std::runtime_error(
|
||||
py::str("Failed to open PIO device (error {})").attr("format")(PIO_ERR_VAL(pio)).cast<std::string>());
|
||||
py::str("Failed to open PIO device (error {})").attr("format")(strerror(err)).cast<std::string>());
|
||||
}
|
||||
return pio;
|
||||
}
|
||||
|
||||
PIO pio_open_cached() {
|
||||
static PIO result = pio_open_check(); // never pio_close()d even at shutdown.
|
||||
return result;
|
||||
}
|
||||
|
||||
int pio_sm_claim_unused_sm_check(PIO pio) {
|
||||
int sm = pio_claim_unused_sm(pio, false);
|
||||
if (sm < 0) {
|
||||
|
|
@ -97,11 +115,56 @@ int get_default(py::object o, T default_value) {
|
|||
return o.cast<T>();
|
||||
}
|
||||
|
||||
void decref_program(program_info &pi) {
|
||||
assert(pi.refcnt);
|
||||
pi.refcnt--;
|
||||
if(pi.refcnt == 0) {
|
||||
struct pio_program dummy_program = {
|
||||
.instructions = &pi.program[0],
|
||||
.length = static_cast<uint8_t>(pi.program.size()),
|
||||
.origin = pi.offset,
|
||||
};
|
||||
|
||||
pio_remove_program(pi.pio, &dummy_program, pi.offset);
|
||||
pi.pio = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t reuse_or_add_program(PIO pio, int8_t offset, const program &instructions, program_info * &pi) {
|
||||
for(auto & i : loaded_programs) {
|
||||
if(i.program == instructions && (i.pio == pio) && (offset == -1 || offset == i.offset)) {
|
||||
assert(i.refcnt > 0);
|
||||
i.refcnt++;
|
||||
pi = &i;
|
||||
return i.offset;
|
||||
}
|
||||
}
|
||||
|
||||
struct pio_program program = {
|
||||
.instructions = &instructions[0],
|
||||
.length = static_cast<uint8_t>(instructions.size()),
|
||||
.origin = offset,
|
||||
};
|
||||
|
||||
offset = pio_add_program_check(pio, &program);
|
||||
auto &i = loaded_programs[offset];
|
||||
assert(!i.refcnt);
|
||||
assert(!i.pio);
|
||||
i.pio = pio;
|
||||
i.refcnt++;
|
||||
i.offset = offset;
|
||||
|
||||
pi = &i;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
class StateMachine {
|
||||
PIO pio{};
|
||||
int sm{-1};
|
||||
int offset{-1};
|
||||
double frequency;
|
||||
program_info *pi = nullptr;
|
||||
|
||||
void check_for_deinit() {
|
||||
if(PIO_IS_ERR(pio)) {
|
||||
|
|
@ -128,7 +191,7 @@ public:
|
|||
int push_threshold,
|
||||
int wrap,
|
||||
int wrap_target) {
|
||||
pio = pio_open_check();
|
||||
pio = pio_open_cached();
|
||||
sm = pio_sm_claim_unused_sm_check(pio);
|
||||
py::buffer_info info = assembled.request();
|
||||
if (info.itemsize != 2) {
|
||||
|
|
@ -147,7 +210,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
ssize_t program_len = info.size;
|
||||
auto program_ptr = reinterpret_cast<const uint16_t*>(info.ptr);
|
||||
auto program_len = info.size;
|
||||
program instructions{program_ptr, program_ptr+program_len};
|
||||
|
||||
if(wrap == -1) {
|
||||
wrap = program_len - 1;
|
||||
}
|
||||
|
|
@ -160,32 +226,27 @@ public:
|
|||
throw py::value_error("wrap_target out of range");
|
||||
}
|
||||
|
||||
pio_pinmask_t pindirs = PIO_PINMASK_NONE;
|
||||
pio_pinmask_t pins_we_use = PIO_PINMASK_NONE;
|
||||
pio_pinmask_t pin_pull_up = PIO_PINMASK_NONE;
|
||||
pio_pinmask_t pin_pull_down = PIO_PINMASK_NONE;
|
||||
offset = reuse_or_add_program(pio, offset, instructions, pi);
|
||||
|
||||
struct pio_program program = {
|
||||
.instructions = reinterpret_cast<uint16_t*>(info.ptr),
|
||||
.length = static_cast<uint8_t>(info.size),
|
||||
.origin = offset,
|
||||
};
|
||||
|
||||
offset = pio_add_program_check(pio, &program);
|
||||
wrap += offset;
|
||||
wrap_target += offset;
|
||||
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, wrap_target, wrap);
|
||||
|
||||
pio_pinmask_t pindirs = PIO_PINMASK_NONE;
|
||||
pio_pinmask_t pins_we_use = PIO_PINMASK_NONE;
|
||||
pio_pinmask_t pin_pull_up = PIO_PINMASK_NONE;
|
||||
pio_pinmask_t pin_pull_down = PIO_PINMASK_NONE;
|
||||
|
||||
if (!first_sideset_pin.is_none()) {
|
||||
auto first_sideset_pin_number = get_pin_number(first_sideset_pin);
|
||||
if (sideset_pin_count < 1 || (sideset_enable + sideset_pin_count) > 5 || first_sideset_pin_number + sideset_pin_count > NUM_BANK0_GPIOS) {
|
||||
throw py::value_error("sideset_pin_count out of range");
|
||||
}
|
||||
|
||||
PIO_PINMASK_MERGE(pindirs, PIO_PINMASK_CONSECUTIVE_PINS(sideset_pin_count, first_sideset_pin_number));
|
||||
PIO_PINMASK_MERGE(pins_we_use, PIO_PINMASK_CONSECUTIVE_PINS(sideset_pin_count, first_sideset_pin_number));
|
||||
PIO_PINMASK_MERGE(pindirs, PIO_PINMASK_CONSECUTIVE_PINS(first_sideset_pin_number, sideset_pin_count));
|
||||
PIO_PINMASK_MERGE(pins_we_use, PIO_PINMASK_CONSECUTIVE_PINS(first_sideset_pin_number, sideset_pin_count));
|
||||
|
||||
for(int i=0; i<sideset_pin_count; i++) {
|
||||
pio_gpio_init(pio, first_sideset_pin_number + i);
|
||||
|
|
@ -205,7 +266,7 @@ public:
|
|||
sm_config_set_in_pins(&c, first_in_pin_number);
|
||||
PIO_PINMASK_MERGE(pin_pull_up, PIO_PINMASK_FROM_VALUE(pull_in_pin_up << first_in_pin_number));
|
||||
PIO_PINMASK_MERGE(pin_pull_down, PIO_PINMASK_FROM_VALUE(pull_in_pin_down << first_in_pin_number));
|
||||
PIO_PINMASK_MERGE(pins_we_use, PIO_PINMASK_CONSECUTIVE_PINS(in_pin_count, first_in_pin_number));
|
||||
PIO_PINMASK_MERGE(pins_we_use, PIO_PINMASK_CONSECUTIVE_PINS(first_in_pin_number, in_pin_count));
|
||||
}
|
||||
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, PIO_PINMASK_VALUE(pindirs), PIO_PINMASK_VALUE(pins_we_use));
|
||||
|
|
@ -248,8 +309,13 @@ public:
|
|||
}
|
||||
|
||||
void deinit() {
|
||||
if(!PIO_IS_ERR(pio)) pio_close(pio);
|
||||
if(!PIO_IS_ERR(pio) && sm != -1) {
|
||||
pio_sm_unclaim(pio, sm);
|
||||
}
|
||||
pio = nullptr;
|
||||
sm = -1;
|
||||
if(pi) decref_program(*pi);
|
||||
pi = nullptr;
|
||||
}
|
||||
|
||||
~StateMachine() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue