From 699347a79c00949fd6add165a521bec08bc18d75 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 10 Apr 2020 12:22:25 -0700 Subject: [PATCH 1/2] gohci 1 --- .gohci.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .gohci.yml diff --git a/.gohci.yml b/.gohci.yml new file mode 100644 index 0000000000000..94d27e3edaeef --- /dev/null +++ b/.gohci.yml @@ -0,0 +1,24 @@ +version: 1 +workers: +- name: gohci-u3 + checks: + - cmd: + - /home/gohci/repo-info.sh + - cmd: + - /home/gohci/esp32-build.sh + - 4.0 + - cmd: + - /home/gohci/esp32-full.sh + - 4.0 + - cmd: + - /home/gohci/stm32-build.sh + - cmd: + - /home/gohci/stm32-full.sh + - cmd: + - /home/gohci/esp32-build.sh + - 3.3 + - cmd: + - /home/gohci/esp32-full.sh + - 3.3 + - cmd: + - /home/gohci/repo-save.sh From 6896bc37c3431ec472d32b6c8e081d52c1c6de6d Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Sat, 28 Dec 2019 21:31:41 -0800 Subject: [PATCH 2/2] ports/esp32: support dynamic freq scaling and wifi power save ports/esp32: fix some peripheral clocks for low-power op --- docs/esp32/quickref.rst | 11 ++ docs/library/esp32-lowpower.rst | 157 ++++++++++++++++++ docs/library/esp32.rst | 1 + .../img/ESP32-micropython-10-80Mhz-li5.png | Bin 0 -> 24590 bytes .../img/ESP32-micropython-160Mhz-noli.png | Bin 0 -> 22141 bytes docs/library/img/ESP32-micropython-160Mhz.png | Bin 0 -> 24976 bytes ports/esp32/boards/sdkconfig.base | 1 + ports/esp32/esp32_rmt.c | 3 + ports/esp32/machine_pwm.c | 5 +- ports/esp32/machine_uart.c | 6 +- ports/esp32/make | 9 + ports/esp32/modmachine.c | 72 ++++++-- ports/esp32/modnetwork.c | 13 +- ports/esp32/mpconfigport.h | 3 + ports/esp32/mphalport.c | 2 - 15 files changed, 260 insertions(+), 23 deletions(-) create mode 100644 docs/library/esp32-lowpower.rst create mode 100644 docs/library/img/ESP32-micropython-10-80Mhz-li5.png create mode 100644 docs/library/img/ESP32-micropython-160Mhz-noli.png create mode 100644 docs/library/img/ESP32-micropython-160Mhz.png create mode 100755 ports/esp32/make diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 8861ca4ac87ed..e5ed0875586e6 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -366,6 +366,17 @@ Notes: p1 = Pin(4, Pin.OUT, None) +Low-power operation +------------------- + +See :ref:`esp32-lowpower ` :: + + import machine, network + machine.freq(80000000, min_freq=10000000) + wifi = network.WLAN(network.STA_IF) + ... + wifi.connect('SSID', 'PASSWD', listen_interval=3) + RMT --- diff --git a/docs/library/esp32-lowpower.rst b/docs/library/esp32-lowpower.rst new file mode 100644 index 0000000000000..9d5057bb270f1 --- /dev/null +++ b/docs/library/esp32-lowpower.rst @@ -0,0 +1,157 @@ +.. currentmodule:: esp32-lowpower + +.. _esp32-lowpower: + +:mod:`esp32-lowpower` --- low power options for the ESP32 +========================================================= + +The ``machine`` and ``network`` modules have a number of options that enable +low power operation on the ESP32. Overall, these options offer approximately a 2x reduction in +operating power while being connected to a WiFi access point by slowing the CPU when +it is idle and by listening to the access point's beacons less frequently. These low +power options are not without drawbacks, in particular, the ESP32 will respond +with more delay to incoming packets or connections as well as potentially to I/O +events. + +Note that in addition to the options described below the ESP32 offers light-sleep +and deep-sleep modes +as part of the ``machine`` module: both modes consume less power than the +options presented here but they suspend normal operation of WiFi and I/O. + +.. module:: machine + :synopsis: functions related to the hardware + +ESP32-specific low-power options in ``machine`` +----------------------------------------------- + +.. function:: freq(max_freq, [key=None, \*, ...]) + + The ``machine.freq`` function may be used to set the frequency of the esp32's processor + cores. *max_freq* sets the maximum frequency in Hz and accepts the values + 20000000, 40000000, 80000000, 160000000, and 240000000. The optional keyword parameter + *min_freq* sets the minimum frequency, which causes FreeRTOS to reduce the + clock rate when the processor is idle. It accepts the value 10000000 in addition + to those accepted for *max_freq*. + + Note that allowing FreeRTOS to change the processor frequency dynamically by setting different + max/min frequencies can affect some I/O peripherals: + - UART, LEDC (``machine.PWM``): not affected + - RMT: frequency varies, need to be fixed (TODO item) + - SPI, I2C, I2S, SDMMC: not affected, they lock the frequency while active + Please consult the ESP-IDF + section on `Dynamic Frequency Scaling + ` for more details. + + The optional and highly experimental *auto_light_sleep* keyword parameter allows automatic + light sleep to be enabled in which case the system enters light-sleep mode + automatically when idle (see the power management section of the ESP-IDF documentation). + This setting is currently difficult to use because it causes most + I/O peripherals to stop functioning, including the console UART and many GPIO + pins. It is only provided for completeness and to enable further experimentation + with low-power modes. + +.. module:: network + :synopsis: network configuration + +ESP32-specific low-power options in ``network`` +----------------------------------------------- + +.. function:: AbstractNIC.connect([service_id, key=None, \*, ...]) + + For the WLAN ``STA_IF`` the *connect* function supports an optional + *listen_interval* keyword parameter which causes the WiFi driver to + use the 802.11 power-save-mode (PSM) with the specified beacon-skip interval. + + The effect of the listen interval is that the ESP32 tells its access point to queue packets + that are destined for it and to flag the presence of such packets in the standard + WiFi beacon (typ. every 100ms). The ESP32 then enables the radio just in time to receive a + beacon, check the flag, explicitly retrieve queued packets if there are any, and then + it turns the radio off again. + + A *listen_interval* value of N >0 causes the ESP32 to wake up and listen every + N beacons (e.g. a value of 5 can cause packets to be queued for up to about 500ms + assuming the standard beacon interval of 100ms). + A value of 0 enables PSM and uses the DTIM value broadcast by the access point as + listen interval. A DTIM setting is available in many access points, but not all. + A value of -1 disables PSM and causes the ESP32 to keep the radio on at all times. + The default value is 1. + +Low-power examples +------------------ + +The following scope capture shows the power consumption in default mode while connected +to Wifi that has DTIM=1 and being pinged once a second. This mode is equivalent to calling +``machine.freq(160000000)`` and ``connect(..., listen_interval=0)``. +(Because the AP's DTIM setting is 1 the same behavior could be observed by setting +*listen_interval=1*.) + +.. image:: img/ESP32-micropython-160Mhz.png + :alt: Scope capture of power consumption in default mode + :width: 638px + +The blue trace at the bottom shows power consumption in mA at 50mA per vertical division +and a time resolution of 100ms per horizontal division. +For the majority of the time the consumption hovers around 35mA to 60mA but every 100ms +it spikes up to about 120-140mA when the WiFi radio is turned on to receive the +access point's beacon. At the trigger point (500ms into the trace) the beacons indicates +that a packet is queued (presumably due to the pings) and the ESP32 picks-up the packet +and responds to the ping (the first thicker spike up to about 190mA), delays for approx +60ms, and then transmits to the AP that it is re-entering power-save-mode (the thinner +spike to ~190mA). + +Sample output from the ping (running on a Linux box on the same network) shows delays +up to about 100ms:: + 64 bytes from 192.168.0.124: icmp_seq=1 ttl=255 time=49.2 ms + 64 bytes from 192.168.0.124: icmp_seq=2 ttl=255 time=67.5 ms + 64 bytes from 192.168.0.124: icmp_seq=3 ttl=255 time=95.1 ms + 64 bytes from 192.168.0.124: icmp_seq=4 ttl=255 time=114 ms + 64 bytes from 192.168.0.124: icmp_seq=5 ttl=255 time=35.4 ms + 64 bytes from 192.168.0.124: icmp_seq=6 ttl=255 time=57.5 ms + +The cyan trace at the top shows when the micropython interpreter sleeps, i.e. yields the +application processor core: while high the processor is yielded and while low micropython +runs. In this capture the interpreter is idle and just wakes up every 400ms to check +events and yield again. + +The next scope capture shows the same situation but with +``machine.freq(80000000, min_freq=10000000)`` and ``connect(..., listen_interval=5)```. + +.. image:: img/ESP32-micropython-10-80Mhz-li5.png + :alt: Scope capture of power consumption in low-power mode + :width: 637px + +In this capture the scope settings are identical to above. The idle power consumption is now reduced +to approx 12mA and when the radio is on the consumption is around 115mA. The trigger point +again shows an incoming ping and response with about the same timing as previously. +However the frequency at which the ESP32 listens to the access point's beacons is now +500ms as requested with the ``listen_interval`` parameter. One such listen period can be seen +20ms before the end of the trace. + +Sample output from the ping shows irregular and sometimes long delays:: + 64 bytes from 192.168.0.124: icmp_seq=44 ttl=255 time=86.9 ms + 64 bytes from 192.168.0.124: icmp_seq=45 ttl=255 time=110 ms + 64 bytes from 192.168.0.124: icmp_seq=46 ttl=255 time=136 ms + 64 bytes from 192.168.0.124: icmp_seq=47 ttl=255 time=399 ms + 64 bytes from 192.168.0.124: icmp_seq=48 ttl=255 time=76.5 ms + 64 bytes from 192.168.0.124: icmp_seq=49 ttl=255 time=97.8 ms + +Averaged out these scope traces show a reduction of power consumption from around 63mA to +around 25mA, but this should be taken as a rough estimate only because the processor utilitzation +and WiFi traffic have a big impact on the average consumption. + +For completeness, the following cropped capture shows power consumption with +PSM turned off, i.e., ``machine.freq(160000000)`` and ``connect(..., listen_interval=-1)``. + +.. image:: img/ESP32-micropython-160Mhz-noli.png + :alt: Scope capture of power consumption with power-save off + :width: 636px + +While the average power consumption is around 125mA the ping response times are better than with +power-save enabled:: + 64 bytes from 192.168.0.124: icmp_seq=64 ttl=255 time=2.59 ms + 64 bytes from 192.168.0.124: icmp_seq=65 ttl=255 time=2.42 ms + 64 bytes from 192.168.0.124: icmp_seq=66 ttl=255 time=1.68 ms + 64 bytes from 192.168.0.124: icmp_seq=67 ttl=255 time=1.36 ms + 64 bytes from 192.168.0.124: icmp_seq=68 ttl=255 time=1.62 ms + 64 bytes from 192.168.0.124: icmp_seq=69 ttl=255 time=1.30 ms + diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index 5df1f3c9317e1..efd90d6026de8 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -9,6 +9,7 @@ The ``esp32`` module contains functions and classes specifically aimed at controlling ESP32 modules. +To adjust operating power see :ref:`esp32-lowpower `. Functions --------- diff --git a/docs/library/img/ESP32-micropython-10-80Mhz-li5.png b/docs/library/img/ESP32-micropython-10-80Mhz-li5.png new file mode 100644 index 0000000000000000000000000000000000000000..93a6d6ffec39a2048a55ad1c7d065426ad4ec633 GIT binary patch literal 24590 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 literal 0 HcmV?d00001 diff --git a/docs/library/img/ESP32-micropython-160Mhz-noli.png b/docs/library/img/ESP32-micropython-160Mhz-noli.png new file mode 100644 index 0000000000000000000000000000000000000000..b3a6c8d281d259648972fe46403585307b99309c GIT binary patch literal 22141 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 R88W>4Obsm!a`YT-{udqVhHL-; literal 0 HcmV?d00001 diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base index f44ec4e173e9b..435dc384ae1f7 100644 --- a/ports/esp32/boards/sdkconfig.base +++ b/ports/esp32/boards/sdkconfig.base @@ -23,6 +23,7 @@ CONFIG_PM_ENABLE=y CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y # UDP CONFIG_LWIP_PPP_SUPPORT=y diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c index 7998752661227..6f39417cf8e12 100644 --- a/ports/esp32/esp32_rmt.c +++ b/ports/esp32/esp32_rmt.c @@ -83,6 +83,9 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255")); } + // TODO: provide an option to use REF_TICK (1Mhz) to enable low-power operation + // with dynamic frequency scaling. + esp32_rmt_obj_t *self = m_new_obj_with_finaliser(esp32_rmt_obj_t); self->base.type = &esp32_rmt_type; self->channel_id = channel_id; diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 7592f243b76f3..b4bffa8be1e47 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -62,7 +62,10 @@ STATIC ledc_timer_config_t timer_cfg = { .duty_resolution = PWRES, .freq_hz = PWFREQ, .speed_mode = PWMODE, - .timer_num = PWTIMER + .timer_num = PWTIMER, + #ifdef LEDC_USE_REF_TICK + .clk_cfg = LEDC_USE_REF_TICK, // using REF_TICK to allow dynamic freq scaling + #endif }; STATIC void pwm_init(void) { diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c index c334e694b21b0..1e363a160b9d8 100644 --- a/ports/esp32/machine_uart.c +++ b/ports/esp32/machine_uart.c @@ -129,7 +129,8 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co } uart_config_t uartcfg = { .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .rx_flow_ctrl_thresh = 0 + .rx_flow_ctrl_thresh = 0, + .use_ref_tick = 1, }; uint32_t baudrate; uart_get_baudrate(self->uart_num, &baudrate); @@ -267,7 +268,8 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .rx_flow_ctrl_thresh = 0 + .rx_flow_ctrl_thresh = 0, + .use_ref_tick = 1, }; // create instance diff --git a/ports/esp32/make b/ports/esp32/make new file mode 100755 index 0000000000000..4722abb3016b8 --- /dev/null +++ b/ports/esp32/make @@ -0,0 +1,9 @@ +#! /usr/bin/bash +export ESPIDF=/home/src/esp32/esp-idf-micropython +export IDF_PATH=${ESPIDF} +export PATH=/home/src/esp32/esp-idf-micropython/xtensa-esp32-elf/bin:${PATH} +export BOARD=${BOARD:-GENERIC} +export PORT=${PORT:-/dev/ttyUSB0} +#CROSS_COMPILE = xtensa-esp32-elf- + +make -j4 "$@" diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 8d8df995c294b..2a366850ed646 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -65,31 +65,69 @@ typedef enum { MP_SOFT_RESET } reset_reason_t; -STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { +STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { if (n_args == 0) { // get return mp_obj_new_int(esp_clk_cpu_freq()); - } else { - // set - mp_int_t freq = mp_obj_get_int(args[0]) / 1000000; - if (freq != 20 && freq != 40 && freq != 80 && freq != 160 && freq != 240) { - mp_raise_ValueError(MP_ERROR_TEXT("frequency must be 20MHz, 40MHz, 80Mhz, 160MHz or 240MHz")); + } + + // setting freq/sleep + enum {ARG_freq, ARG_min_freq, ARG_auto_light_sleep}; + const mp_arg_t allowed_args[] = { + { MP_QSTR_freq, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_min_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_auto_light_sleep, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // validate frequency + mp_int_t freq = args[ARG_freq].u_int / 1000000; + if (freq != 20 && freq != 40 && freq != 80 && freq != 160 && freq != 240) { + mp_raise_ValueError(MP_ERROR_TEXT("frequency must be 20MHz, 40MHz, 80Mhz, 160MHz or 240MHz")); + } + esp_pm_config_esp32_t pm; + pm.max_freq_mhz = freq; + pm.min_freq_mhz = freq; + pm.light_sleep_enable = false; + + // check optional mininum frequency keyword argument + if (args[ARG_min_freq].u_int != 0) { + mp_int_t mf = args[ARG_min_freq].u_int / 1000000; + if (mf != 10 && mf != 20 && mf != 40 && mf != 80 && mf != 160 && mf != 240) { + mp_raise_ValueError(MP_ERROR_TEXT("frequency must be 10Mhz, 20MHz, 40MHz, 80Mhz, 160MHz or 240MHz")); } - esp_pm_config_esp32_t pm; - pm.max_freq_mhz = freq; - pm.min_freq_mhz = freq; - pm.light_sleep_enable = false; - esp_err_t ret = esp_pm_configure(&pm); - if (ret != ESP_OK) { + pm.min_freq_mhz = mf; + } + + #if 0 + // commented-out because it is ineffective unless the calls to ulTaskNotifyTake in + // mphalport.c use a delay of 4 ticks minimum. Don't want to change those due to + // insufficiently explored side-effects and auto-light-sleep is not that usable in + // the current state anyway... leaving this in for future reference + + // check optional auto-light-sleep keyword argument + if (args[ARG_auto_light_sleep].u_bool) { + pm.light_sleep_enable = true; + } + #endif + + // apply new setting and check result + esp_err_t ret = esp_pm_configure(&pm); + if (ret != ESP_OK) { + if (ret == ESP_ERR_NOT_SUPPORTED) { + mp_raise_ValueError(MP_ERROR_TEXT("auto light-sleep not supported")); + } else { + mp_printf(&mp_plat_print, "esp_pm_configure ret=%d\n", ret); mp_raise_ValueError(NULL); } - while (esp_clk_cpu_freq() != freq * 1000000) { - vTaskDelay(1); - } - return mp_const_none; } + while (esp_clk_cpu_freq() != freq * 1000000) { + vTaskDelay(1); + } + return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_freq_obj, 0, machine_freq); STATIC mp_obj_t machine_sleep_helper(wake_type_t wake_type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c index 85d2f1506d5eb..c47d4ef63a0ad 100644 --- a/ports/esp32/modnetwork.c +++ b/ports/esp32/modnetwork.c @@ -320,11 +320,12 @@ STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active); STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_ssid, ARG_password, ARG_bssid }; + enum { ARG_ssid, ARG_password, ARG_bssid, ARG_listen_interval }; static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_listen_interval, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, }; // parse args @@ -332,6 +333,7 @@ STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); wifi_config_t wifi_sta_config = {{{0}}}; + uint8_t ps_mode = WIFI_PS_MIN_MODEM; // configure any parameters that are given if (n_args > 1) { @@ -353,8 +355,17 @@ STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k wifi_sta_config.sta.bssid_set = 1; memcpy(wifi_sta_config.sta.bssid, p, sizeof(wifi_sta_config.sta.bssid)); } + if (args[ARG_listen_interval].u_int > 0) { + wifi_sta_config.sta.listen_interval = args[ARG_listen_interval].u_int; + ps_mode = WIFI_PS_MAX_MODEM; + } else if (args[ARG_listen_interval].u_int < 0) { + ps_mode = WIFI_PS_NONE; + } + + // apply config ESP_EXCEPTIONS(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config)); } + esp_wifi_set_ps(ps_mode); // set power-save mode depending on listen_interval // connect to the WiFi AP MP_THREAD_GIL_EXIT(); diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 72ecfadc6b29b..9f24417a88c10 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -248,6 +248,9 @@ void *esp_native_code_commit(void *, size_t, void *); mp_handle_pending(true); \ MICROPY_PY_USOCKET_EVENTS_HANDLER \ MP_THREAD_GIL_EXIT(); \ + /* yield the processor for 1 tick or until notified. To allow auto-light-sleep mode \ + // to kick-in this would have to be raised to 4 at least. */ \ + ulTaskNotifyTake(pdFALSE, 1); \ MP_THREAD_GIL_ENTER(); \ } while (0); #else diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index c701cb4bcbae2..bd6de6c7009fd 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -66,7 +66,6 @@ int mp_hal_stdin_rx_chr(void) { return c; } MICROPY_EVENT_POLL_HOOK - ulTaskNotifyTake(pdFALSE, 1); } } @@ -129,7 +128,6 @@ void mp_hal_delay_ms(uint32_t ms) { break; } MICROPY_EVENT_POLL_HOOK - ulTaskNotifyTake(pdFALSE, 1); } if (dt < us) { // do the remaining delay accurately