Skip to content
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

Fix "espulp module broken in CircuitPython 9" #9277

Merged
merged 12 commits into from
Jun 3, 2024
12 changes: 12 additions & 0 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,10 @@ msgstr ""
msgid "Invalid multicast MAC address"
msgstr ""

#: ports/espressif/common-hal/espulp/ULP.c
msgid "Invalid parameters"
msgstr ""

#: ports/espressif/common-hal/espidf/__init__.c
msgid "Invalid size"
msgstr ""
Expand Down Expand Up @@ -1280,6 +1284,10 @@ msgstr ""
msgid "Layer must be a Group or TileGrid subclass"
msgstr ""

#: ports/espressif/common-hal/espulp/ULP.c
msgid "Load binary failed"
msgstr ""

#: ports/espressif/common-hal/espidf/__init__.c
msgid "MAC address was invalid"
msgstr ""
Expand Down Expand Up @@ -1826,6 +1834,10 @@ msgstr ""
msgid "Right format but not supported"
msgstr ""

#: ports/espressif/common-hal/espulp/ULP.c
msgid "Run binary failed"
msgstr ""

#: main.c
msgid "Running in safe mode! Not running saved code.\n"
msgstr ""
Expand Down
67 changes: 52 additions & 15 deletions ports/espressif/bindings/espulp/ULP.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
//| Raises an exception if another ULP has been instantiated. This
//| ensures that is is only used by one piece of code at a time.
//|
//| :param Architecture arch: The ulp arch"""
//| :param Architecture arch: The ulp arch.
//| """
//| ...
static mp_obj_t espulp_ulp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_arch };
Expand Down Expand Up @@ -70,21 +71,50 @@ static mp_obj_t espulp_ulp_obj___exit__(size_t n_args, const mp_obj_t *args) {
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espulp_ulp___exit___obj, 4, 4, espulp_ulp_obj___exit__);

//| def set_wakeup_period(self, period_index: int, period_us: int) -> None:
//| """Sets the wakeup period for the ULP.
//|
//| :param int period_index: = 0..4. Up to 5 different wakeup periods can be stored
//| and used by the wakeup timer.
//| By default, the value stored in period index 0 is used.
//| :param int period_us: The wakeup period given in microseconds."""
//| ...
static mp_obj_t espulp_ulp_set_wakeup_period(mp_obj_t self_in, mp_obj_t period_index, mp_obj_t period_us) {
espulp_ulp_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);

// period_index should be between 0 and 4 but bounds checking happens in esp-idf, so no need to do that here
common_hal_espulp_ulp_set_wakeup_period(self, mp_obj_get_int(period_index), mp_obj_get_int(period_us));

return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_3(espulp_ulp_set_wakeup_period_obj, espulp_ulp_set_wakeup_period);

//| def run(
//| self, program: ReadableBuffer, *, pins: Sequence[microcontroller.Pin] = ()
//| self,
//| program: ReadableBuffer,
//| *,
//| entrypoint: int = 0,
//| pins: Sequence[microcontroller.Pin] = ()
//| ) -> None:
//| """Loads the program into ULP memory and then runs the program. The given pins are
//| claimed and not reset until `halt()` is called.
//| """Loads the program into ULP memory and then runs the program.
//|
//| The program will continue to run even when the running Python is halted."""
//| The program will continue to run even Python is halted or in deep-sleep.
//|
//| :param ReadableBuffer program: the ULP binary.
//| :param int entrypoint: Specifies the offset (in bytes) of the first instruction
//| from the start of the program (Only used by FSM ULP).
//| :param Sequence[microcontroller.Pin] pins: Pins made available to the ULP.
//| The pins are claimed and not reset until `halt()` is called."""
//| ...
static mp_obj_t espulp_ulp_run(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
espulp_ulp_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
check_for_deinit(self);

enum { ARG_program, ARG_pins };
enum { ARG_program, ARG_entrypoint, ARG_pins };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ},
{ MP_QSTR_entrypoint, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple} },
};

Expand All @@ -94,6 +124,8 @@ static mp_obj_t espulp_ulp_run(size_t n_args, const mp_obj_t *pos_args, mp_map_t
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_program].u_obj, &bufinfo, MP_BUFFER_READ);

mp_uint_t entrypoint = args[ARG_entrypoint].u_int;

mp_obj_t pins_in = args[ARG_pins].u_obj;
const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(pins_in));

Expand All @@ -103,21 +135,25 @@ static mp_obj_t espulp_ulp_run(size_t n_args, const mp_obj_t *pos_args, mp_map_t

for (mp_uint_t i = 0; i < num_pins; i++) {
mp_obj_t pin_obj = mp_obj_subscr(pins_in, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL);
validate_obj_is_free_pin(pin_obj, MP_QSTR_pin);
// common-hal checks that pin is free (that way a possible "ULP already running" error
// is triggered before a possible "Pin in use" error, if ulp.run is called twice with the same pins).
validate_obj_is_pin(pin_obj, MP_QSTR_pin);
const mcu_pin_obj_t *pin = ((const mcu_pin_obj_t *)pin_obj);
if (pin->number >= 32) {
raise_ValueError_invalid_pin();
}
pin_mask |= 1 << pin->number;
}

common_hal_espulp_ulp_run(self, bufinfo.buf, bufinfo.len, pin_mask);
common_hal_espulp_ulp_run(self, bufinfo.buf, bufinfo.len, entrypoint, pin_mask);
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_KW(espulp_ulp_run_obj, 2, espulp_ulp_run);

//| def halt(self) -> None:
//| """Halts the running program and releases the pins given in `run()`."""
//| """Halts the running program and releases the pins given in `run()`.
//| Note: for the FSM ULP, a running ULP program is not actually interrupted.
//| Instead, only the wakeup timer is stopped."""
//| ...
static mp_obj_t espulp_ulp_halt(mp_obj_t self_in) {
espulp_ulp_obj_t *self = MP_OBJ_TO_PTR(self_in);
Expand All @@ -143,12 +179,13 @@ MP_PROPERTY_GETTER(espulp_ulp_arch_obj,
(mp_obj_t)&espulp_ulp_get_arch_obj);

static const mp_rom_map_elem_t espulp_ulp_locals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&espulp_ulp_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&espulp_ulp___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&espulp_ulp_run_obj) },
{ MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&espulp_ulp_halt_obj) },
{ MP_ROM_QSTR(MP_QSTR_arch), MP_ROM_PTR(&espulp_ulp_arch_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&espulp_ulp_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&espulp_ulp___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&espulp_ulp_set_wakeup_period_obj) },
{ MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&espulp_ulp_run_obj) },
{ MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&espulp_ulp_halt_obj) },
{ MP_ROM_QSTR(MP_QSTR_arch), MP_ROM_PTR(&espulp_ulp_arch_obj) },
};
static MP_DEFINE_CONST_DICT(espulp_ulp_locals_dict, espulp_ulp_locals_table);

Expand Down
3 changes: 2 additions & 1 deletion ports/espressif/bindings/espulp/ULP.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ void common_hal_espulp_ulp_construct(espulp_ulp_obj_t *self, espulp_architecture
bool common_hal_espulp_ulp_deinited(espulp_ulp_obj_t *self);
void common_hal_espulp_ulp_deinit(espulp_ulp_obj_t *self);

void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t length, uint32_t pin_mask);
void common_hal_espulp_ulp_set_wakeup_period(espulp_ulp_obj_t *self, size_t period_index, uint32_t period_us);
void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t length, uint32_t entry_point, uint32_t pin_mask);
void common_hal_espulp_ulp_halt(espulp_ulp_obj_t *self);
32 changes: 26 additions & 6 deletions ports/espressif/common-hal/espulp/ULP.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "py/runtime.h"
#include "shared-bindings/microcontroller/Pin.h"

#include "esp_sleep.h"

#if defined(CONFIG_IDF_TARGET_ESP32)
#include "esp32/ulp.h"
#define ULP_COPROC_RESERVE_MEM (CONFIG_ESP32_ULP_COPROC_RESERVE_MEM)
Expand All @@ -34,7 +36,14 @@ void espulp_reset(void) {
ulp_used = false;
}

void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t length, uint32_t pin_mask) {
void common_hal_espulp_ulp_set_wakeup_period(espulp_ulp_obj_t *self, size_t period_index, uint32_t period_us) {
int _errno = ulp_set_wakeup_period(period_index, period_us);
if (_errno != ESP_OK) {
mp_raise_ValueError(MP_ERROR_TEXT("Invalid parameters"));
tannewt marked this conversation as resolved.
Show resolved Hide resolved
}
}

void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t length, uint32_t entry_point, uint32_t pin_mask) {
if (length > CONFIG_ULP_COPROC_RESERVE_MEM) {
mp_raise_ValueError(MP_ERROR_TEXT("Program too long"));
}
Expand Down Expand Up @@ -67,13 +76,25 @@ void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t
}
pins_used = pin_mask;

ulp_set_wakeup_period(0, 20000);
// Main purpose of ULP is to run while main cpu is in deep sleep, so
// ensure GPIO Power Domain remains enabled during deep sleep,
// if any GPIO were supplied here.
if (pins_used > 0) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
}

int _errno;
switch (self->arch) {
#ifdef CONFIG_ULP_COPROC_TYPE_FSM
case FSM:
ulp_load_binary(0, (const uint8_t *)program, length);
ulp_run(0);
_errno = ulp_load_binary(0, (const uint8_t *)program, length / sizeof(uint32_t));
if (_errno != ESP_OK) {
mp_raise_RuntimeError(MP_ERROR_TEXT("Load binary failed"));
}
_errno = ulp_run(entry_point / sizeof(uint32_t));
if (_errno != ESP_OK) {
mp_raise_RuntimeError(MP_ERROR_TEXT("Run binary failed"));
}
tannewt marked this conversation as resolved.
Show resolved Hide resolved
break;
#endif
#ifdef CONFIG_ULP_COPROC_TYPE_RISCV
Expand All @@ -90,12 +111,11 @@ void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t

void common_hal_espulp_ulp_halt(espulp_ulp_obj_t *self) {
switch (self->arch) {
/*
#ifdef CONFIG_ULP_COPROC_TYPE_FSM
case FSM:
ulp_timer_stop();
break;
#endif
*/
#ifdef CONFIG_ULP_COPROC_TYPE_RISCV
case RISCV:
ulp_riscv_timer_stop();
Expand Down
2 changes: 1 addition & 1 deletion ports/espressif/esp-idf
1 change: 1 addition & 0 deletions ports/espressif/esp-idf-config/sdkconfig-esp32.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y
# Ultra Low Power (ULP) Co-processor
#
CONFIG_ULP_COPROC_ENABLED=y
CONFIG_ULP_COPROC_TYPE_FSM=y
CONFIG_ULP_COPROC_RESERVE_MEM=4080
# end of Ultra Low Power (ULP) Co-processor

Expand Down
3 changes: 3 additions & 0 deletions ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ CONFIG_NEWLIB_NANO_FORMAT=y
# Ultra Low Power (ULP) Co-processor
#
CONFIG_ULP_COPROC_ENABLED=y
CONFIG_ULP_COPROC_TYPE_FSM=y
CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only works due to a modification of adafruit/esp-idf
# (see adafruit/esp-idf/pull/16) until espressif/esp-idf/issues/12999 is fixed.
CONFIG_ULP_COPROC_RESERVE_MEM=8176
# end of Ultra Low Power (ULP) Co-processor

Expand Down
3 changes: 3 additions & 0 deletions ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ CONFIG_NEWLIB_NANO_FORMAT=y
# Ultra Low Power (ULP) Co-processor
#
CONFIG_ULP_COPROC_ENABLED=y
CONFIG_ULP_COPROC_TYPE_FSM=y
CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only works due to a modification of adafruit/esp-idf
# (see adafruit/esp-idf/pull/16) until espressif/esp-idf/issues/12999 is fixed.
CONFIG_ULP_COPROC_RESERVE_MEM=8176
# end of Ultra Low Power (ULP) Co-processor

Expand Down