Skip to content

Commit dc3edf4

Browse files
authored
Merge pull request #9277 from Sola85/improve_espulp
Fix "espulp module broken in CircuitPython 9"
2 parents 8db7a85 + 55028d0 commit dc3edf4

File tree

8 files changed

+89
-25
lines changed

8 files changed

+89
-25
lines changed

locale/circuitpython.pot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,7 @@ msgstr ""
11731173
msgid "Interrupted by output function"
11741174
msgstr ""
11751175

1176+
#: ports/espressif/common-hal/espulp/ULP.c
11761177
#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c
11771178
#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c
11781179
#: ports/raspberrypi/bindings/picodvi/Framebuffer.c

ports/espressif/bindings/espulp/ULP.c

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
//| Raises an exception if another ULP has been instantiated. This
2020
//| ensures that is is only used by one piece of code at a time.
2121
//|
22-
//| :param Architecture arch: The ulp arch"""
22+
//| :param Architecture arch: The ulp arch.
23+
//| """
2324
//| ...
2425
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) {
2526
enum { ARG_arch };
@@ -70,21 +71,50 @@ static mp_obj_t espulp_ulp_obj___exit__(size_t n_args, const mp_obj_t *args) {
7071
}
7172
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espulp_ulp___exit___obj, 4, 4, espulp_ulp_obj___exit__);
7273

74+
//| def set_wakeup_period(self, period_index: int, period_us: int) -> None:
75+
//| """Sets the wakeup period for the ULP.
76+
//|
77+
//| :param int period_index: = 0..4. Up to 5 different wakeup periods can be stored
78+
//| and used by the wakeup timer.
79+
//| By default, the value stored in period index 0 is used.
80+
//| :param int period_us: The wakeup period given in microseconds."""
81+
//| ...
82+
static mp_obj_t espulp_ulp_set_wakeup_period(mp_obj_t self_in, mp_obj_t period_index, mp_obj_t period_us) {
83+
espulp_ulp_obj_t *self = MP_OBJ_TO_PTR(self_in);
84+
check_for_deinit(self);
85+
86+
// period_index should be between 0 and 4 but bounds checking happens in esp-idf, so no need to do that here
87+
common_hal_espulp_ulp_set_wakeup_period(self, mp_obj_get_int(period_index), mp_obj_get_int(period_us));
88+
89+
return mp_const_none;
90+
}
91+
static MP_DEFINE_CONST_FUN_OBJ_3(espulp_ulp_set_wakeup_period_obj, espulp_ulp_set_wakeup_period);
92+
7393
//| def run(
74-
//| self, program: ReadableBuffer, *, pins: Sequence[microcontroller.Pin] = ()
94+
//| self,
95+
//| program: ReadableBuffer,
96+
//| *,
97+
//| entrypoint: int = 0,
98+
//| pins: Sequence[microcontroller.Pin] = ()
7599
//| ) -> None:
76-
//| """Loads the program into ULP memory and then runs the program. The given pins are
77-
//| claimed and not reset until `halt()` is called.
100+
//| """Loads the program into ULP memory and then runs the program.
78101
//|
79-
//| The program will continue to run even when the running Python is halted."""
102+
//| The program will continue to run even Python is halted or in deep-sleep.
103+
//|
104+
//| :param ReadableBuffer program: the ULP binary.
105+
//| :param int entrypoint: Specifies the offset (in bytes) of the first instruction
106+
//| from the start of the program (Only used by FSM ULP).
107+
//| :param Sequence[microcontroller.Pin] pins: Pins made available to the ULP.
108+
//| The pins are claimed and not reset until `halt()` is called."""
80109
//| ...
81110
static mp_obj_t espulp_ulp_run(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
82111
espulp_ulp_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
83112
check_for_deinit(self);
84113

85-
enum { ARG_program, ARG_pins };
114+
enum { ARG_program, ARG_entrypoint, ARG_pins };
86115
static const mp_arg_t allowed_args[] = {
87116
{ MP_QSTR_program, MP_ARG_REQUIRED | MP_ARG_OBJ},
117+
{ MP_QSTR_entrypoint, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0}},
88118
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple} },
89119
};
90120

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

127+
mp_uint_t entrypoint = args[ARG_entrypoint].u_int;
128+
97129
mp_obj_t pins_in = args[ARG_pins].u_obj;
98130
const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(pins_in));
99131

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

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

114-
common_hal_espulp_ulp_run(self, bufinfo.buf, bufinfo.len, pin_mask);
148+
common_hal_espulp_ulp_run(self, bufinfo.buf, bufinfo.len, entrypoint, pin_mask);
115149
return mp_const_none;
116150
}
117151
static MP_DEFINE_CONST_FUN_OBJ_KW(espulp_ulp_run_obj, 2, espulp_ulp_run);
118152

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

145181
static const mp_rom_map_elem_t espulp_ulp_locals_table[] = {
146-
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&espulp_ulp_deinit_obj) },
147-
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
148-
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&espulp_ulp___exit___obj) },
149-
{ MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&espulp_ulp_run_obj) },
150-
{ MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&espulp_ulp_halt_obj) },
151-
{ MP_ROM_QSTR(MP_QSTR_arch), MP_ROM_PTR(&espulp_ulp_arch_obj) },
182+
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&espulp_ulp_deinit_obj) },
183+
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
184+
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&espulp_ulp___exit___obj) },
185+
{ MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&espulp_ulp_set_wakeup_period_obj) },
186+
{ MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&espulp_ulp_run_obj) },
187+
{ MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&espulp_ulp_halt_obj) },
188+
{ MP_ROM_QSTR(MP_QSTR_arch), MP_ROM_PTR(&espulp_ulp_arch_obj) },
152189
};
153190
static MP_DEFINE_CONST_DICT(espulp_ulp_locals_dict, espulp_ulp_locals_table);
154191

ports/espressif/bindings/espulp/ULP.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ void common_hal_espulp_ulp_construct(espulp_ulp_obj_t *self, espulp_architecture
1515
bool common_hal_espulp_ulp_deinited(espulp_ulp_obj_t *self);
1616
void common_hal_espulp_ulp_deinit(espulp_ulp_obj_t *self);
1717

18-
void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t length, uint32_t pin_mask);
18+
void common_hal_espulp_ulp_set_wakeup_period(espulp_ulp_obj_t *self, size_t period_index, uint32_t period_us);
19+
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);
1920
void common_hal_espulp_ulp_halt(espulp_ulp_obj_t *self);

ports/espressif/common-hal/espulp/ULP.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66

77
#include "bindings/espulp/__init__.h"
88
#include "bindings/espulp/ULP.h"
9+
#include "bindings/espidf/__init__.h"
910

1011
#include "py/runtime.h"
1112
#include "shared-bindings/microcontroller/Pin.h"
1213

14+
#include "esp_sleep.h"
15+
1316
#if defined(CONFIG_IDF_TARGET_ESP32)
1417
#include "esp32/ulp.h"
1518
#define ULP_COPROC_RESERVE_MEM (CONFIG_ESP32_ULP_COPROC_RESERVE_MEM)
@@ -34,7 +37,11 @@ void espulp_reset(void) {
3437
ulp_used = false;
3538
}
3639

37-
void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t length, uint32_t pin_mask) {
40+
void common_hal_espulp_ulp_set_wakeup_period(espulp_ulp_obj_t *self, size_t period_index, uint32_t period_us) {
41+
CHECK_ESP_RESULT(ulp_set_wakeup_period(period_index, period_us));
42+
}
43+
44+
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) {
3845
if (length > CONFIG_ULP_COPROC_RESERVE_MEM) {
3946
mp_raise_ValueError(MP_ERROR_TEXT("Program too long"));
4047
}
@@ -67,19 +74,31 @@ void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t
6774
}
6875
pins_used = pin_mask;
6976

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

84+
esp_err_t result;
7285
switch (self->arch) {
7386
#ifdef CONFIG_ULP_COPROC_TYPE_FSM
7487
case FSM:
75-
ulp_load_binary(0, (const uint8_t *)program, length);
76-
ulp_run(0);
88+
result = ulp_load_binary(0, (const uint8_t *)program, length / sizeof(uint32_t));
89+
if (result != ESP_OK) {
90+
mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_program);
91+
}
92+
CHECK_ESP_RESULT(ulp_run(entry_point / sizeof(uint32_t)));
7793
break;
7894
#endif
7995
#ifdef CONFIG_ULP_COPROC_TYPE_RISCV
8096
case RISCV:
81-
ulp_riscv_load_binary((const uint8_t *)program, length);
82-
ulp_riscv_run();
97+
result = ulp_riscv_load_binary((const uint8_t *)program, length);
98+
if (result != ESP_OK) {
99+
mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_program);
100+
}
101+
CHECK_ESP_RESULT(ulp_riscv_run());
83102
break;
84103
#endif
85104
default:
@@ -90,12 +109,11 @@ void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t
90109

91110
void common_hal_espulp_ulp_halt(espulp_ulp_obj_t *self) {
92111
switch (self->arch) {
93-
/*
94112
#ifdef CONFIG_ULP_COPROC_TYPE_FSM
95113
case FSM:
114+
ulp_timer_stop();
96115
break;
97116
#endif
98-
*/
99117
#ifdef CONFIG_ULP_COPROC_TYPE_RISCV
100118
case RISCV:
101119
ulp_riscv_timer_stop();

ports/espressif/esp-idf-config/sdkconfig-esp32.defaults

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y
8383
# Ultra Low Power (ULP) Co-processor
8484
#
8585
CONFIG_ULP_COPROC_ENABLED=y
86+
CONFIG_ULP_COPROC_TYPE_FSM=y
8687
CONFIG_ULP_COPROC_RESERVE_MEM=4080
8788
# end of Ultra Low Power (ULP) Co-processor
8889

ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ CONFIG_NEWLIB_NANO_FORMAT=y
5252
# Ultra Low Power (ULP) Co-processor
5353
#
5454
CONFIG_ULP_COPROC_ENABLED=y
55+
CONFIG_ULP_COPROC_TYPE_FSM=y
56+
CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only works due to a modification of adafruit/esp-idf
57+
# (see adafruit/esp-idf/pull/16) until espressif/esp-idf/issues/12999 is fixed.
5558
CONFIG_ULP_COPROC_RESERVE_MEM=8176
5659
# end of Ultra Low Power (ULP) Co-processor
5760

ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ CONFIG_NEWLIB_NANO_FORMAT=y
9292
# Ultra Low Power (ULP) Co-processor
9393
#
9494
CONFIG_ULP_COPROC_ENABLED=y
95+
CONFIG_ULP_COPROC_TYPE_FSM=y
96+
CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only works due to a modification of adafruit/esp-idf
97+
# (see adafruit/esp-idf/pull/16) until espressif/esp-idf/issues/12999 is fixed.
9598
CONFIG_ULP_COPROC_RESERVE_MEM=8176
9699
# end of Ultra Low Power (ULP) Co-processor
97100

0 commit comments

Comments
 (0)