add ulp fsm

This commit is contained in:
MicroDev 2023-01-21 16:02:59 +05:30
parent 9c066825a7
commit 2bb12293f8
No known key found for this signature in database
GPG Key ID: 2C0867BE60967730
12 changed files with 217 additions and 30 deletions

View File

@ -28,19 +28,35 @@
#include "shared-bindings/util.h"
#include "bindings/espulp/ULP.h"
#include "py/enum.h"
#include "py/runtime.h"
#include "py/objproperty.h"
//| class ULP:
//| def __init__(self):
//| def __init__(self, arch: ULPArch = ULPArch.FSM):
//| """The ultra-low-power processor.
//|
//| Raises an exception if another ULP has been instantiated. This
//| ensures that is is only used by one piece of code at a time."""
//| ensures that is is only used by one piece of code at a time.
//|
//| :param ULPArch 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 };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_arch, MP_ARG_OBJ, {.u_obj = (void *)&ulparch_FSM_obj} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const espulp_ulparch_t arch = cp_enum_value(&espulp_ulparch_type, args[ARG_arch].u_obj, MP_QSTR_arch);
espulp_ulp_obj_t *self = m_new_obj(espulp_ulp_obj_t);
self->base.type = &espulp_ulp_type;
common_hal_espulp_ulp_construct(self);
common_hal_espulp_ulp_construct(self, arch);
return MP_OBJ_FROM_PTR(self);
}
@ -124,7 +140,6 @@ 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()`."""
//| ...
//|
STATIC mp_obj_t espulp_ulp_halt(mp_obj_t self_in) {
espulp_ulp_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
@ -134,12 +149,27 @@ STATIC mp_obj_t espulp_ulp_halt(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(espulp_ulp_halt_obj, espulp_ulp_halt);
//| arch: ULPArch
//| """The ulp arch. (read-only)"""
//|
STATIC mp_obj_t espulp_ulp_get_arch(mp_obj_t self_in) {
espulp_ulp_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return cp_enum_find(&espulp_ulparch_type, self->arch);
}
MP_DEFINE_CONST_FUN_OBJ_1(espulp_ulp_get_arch_obj, espulp_ulp_get_arch);
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) },
};
STATIC MP_DEFINE_CONST_DICT(espulp_ulp_locals_dict, espulp_ulp_locals_table);

View File

@ -29,10 +29,9 @@
#include "py/obj.h"
#include "common-hal/espulp/ULP.h"
extern const mp_obj_type_t espulp_ulp_type;
void common_hal_espulp_ulp_construct(espulp_ulp_obj_t *self);
void common_hal_espulp_ulp_construct(espulp_ulp_obj_t *self, espulp_ulparch_t arch);
bool common_hal_espulp_ulp_deinited(espulp_ulp_obj_t *self);
void common_hal_espulp_ulp_deinit(espulp_ulp_obj_t *self);

View File

@ -25,27 +25,35 @@
*/
#include "bindings/espulp/ULPAlarm.h"
#include "bindings/espulp/ULPArch.h"
#include "py/runtime.h"
//| class ULPAlarm:
//| """Trigger an alarm when the ULP requests wake-up."""
//|
//| def __init__(self) -> None:
//| def __init__(self, ulp: ULP) -> None:
//| """Create an alarm that will be triggered when the ULP requests wake-up.
//|
//| The alarm is not active until it is passed to an `alarm`-enabling function, such as
//| `alarm.light_sleep_until_alarms()` or `alarm.exit_and_deep_sleep_until_alarms()`.
//|
//| """
//| :param ULP ulp: The ulp instance"""
//| ...
//|
STATIC mp_obj_t espulp_ulpalarm_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
STATIC mp_obj_t espulp_ulpalarm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_ulp };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_ulp, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
espulp_ulpalarm_obj_t *self = m_new_obj(espulp_ulpalarm_obj_t);
self->base.type = &espulp_ulpalarm_type;
common_hal_espulp_ulpalarm_construct(self);
self->ulp = mp_arg_validate_type(args[ARG_ulp].u_obj, &espulp_ulp_type, MP_QSTR_ulp);
return MP_OBJ_FROM_PTR(self);
}

View File

@ -0,0 +1,51 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 MicroDev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/enum.h"
#include "bindings/espulp/ULPArch.h"
MAKE_ENUM_VALUE(espulp_ulparch_type, ulparch, FSM, FSM);
MAKE_ENUM_VALUE(espulp_ulparch_type, ulparch, RISCV, RISCV);
//| class ULPArch:
//| """The ULP architectures available."""
//|
//| FSM: ULPArch
//| """The ULP Finite State Machine."""
//|
//| RISCV: ULPArch
//| """The ULP RISC-V Coprocessor."""
//|
MAKE_ENUM_MAP(espulp_ulparch) {
MAKE_ENUM_MAP_ENTRY(ulparch, FSM),
MAKE_ENUM_MAP_ENTRY(ulparch, RISCV),
};
STATIC MP_DEFINE_CONST_DICT(espulp_ulparch_locals_dict, espulp_ulparch_locals_table);
MAKE_PRINTER(espulp, espulp_ulparch);
MAKE_ENUM_TYPE(espulp, ULPArch, espulp_ulparch);

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 MicroDev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_BINDINGS_ESPULP_ULPARCH_H
#define MICROPY_INCLUDED_BINDINGS_ESPULP_ULPARCH_H
#include "py/enum.h"
typedef enum {
FSM,
RISCV
} espulp_ulparch_t;
extern const mp_obj_type_t espulp_ulparch_type;
extern const cp_enum_obj_t ulparch_FSM_obj;
#endif // MICROPY_INCLUDED_BINDINGS_ESPULP_ULPARCH_H

View File

@ -25,9 +25,11 @@
*/
#include "shared-bindings/util.h"
#include "bindings/espulp/__init__.h"
#include "bindings/espulp/ULP.h"
#include "bindings/espulp/ULPAlarm.h"
#include "bindings/espulp/ULPArch.h"
#include "py/runtime.h"
@ -80,6 +82,7 @@ STATIC const mp_rom_map_elem_t espulp_module_globals_table[] = {
// module classes
{ MP_ROM_QSTR(MP_QSTR_ULP), MP_OBJ_FROM_PTR(&espulp_ulp_type) },
{ MP_ROM_QSTR(MP_QSTR_ULPAlarm), MP_OBJ_FROM_PTR(&espulp_ulpalarm_type) },
{ MP_ROM_QSTR(MP_QSTR_ULPArch), MP_ROM_PTR(&espulp_ulparch_type) },
};
STATIC MP_DEFINE_CONST_DICT(espulp_module_globals, espulp_module_globals_table);

View File

@ -31,7 +31,10 @@
#include "shared-bindings/microcontroller/Pin.h"
#if defined(CONFIG_IDF_TARGET_ESP32S2)
#if defined(CONFIG_IDF_TARGET_ESP32)
#include "esp32/ulp.h"
#define ULP_COPROC_RESERVE_MEM (CONFIG_ESP32_ULP_COPROC_RESERVE_MEM)
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#include "esp32s2/ulp.h"
#include "esp32s2/ulp_riscv.h"
#define ULP_COPROC_RESERVE_MEM (CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM)
@ -56,7 +59,14 @@ void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t
if (length > ULP_COPROC_RESERVE_MEM) {
mp_raise_ValueError(translate("Program too long"));
}
if (GET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN)) {
if (
#ifdef CONFIG_IDF_TARGET_ESP32
GET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN)
#else
GET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN)
#endif
) {
mp_raise_RuntimeError(translate("Already running"));
}
@ -78,13 +88,29 @@ void common_hal_espulp_ulp_run(espulp_ulp_obj_t *self, uint32_t *program, size_t
}
pins_used = pin_mask;
ulp_riscv_load_binary((const uint8_t *)program, length);
ulp_set_wakeup_period(0, 20000);
ulp_riscv_run();
switch (self->arch) {
case FSM:
ulp_load_binary(0, (const uint8_t *)program, length);
ulp_run(0);
break;
case RISCV:
#ifndef CONFIG_IDF_TARGET_ESP32
ulp_riscv_load_binary((const uint8_t *)program, length);
ulp_riscv_run();
break;
#endif
default:
mp_raise_NotImplementedError(NULL);
break;
}
}
void common_hal_espulp_ulp_halt(espulp_ulp_obj_t *self) {
#ifdef CONFIG_IDF_TARGET_ESP32
mp_raise_NotImplementedError(NULL);
#else
// To-do idf v5.0: use following functions
// ulp_riscv_timer_stop();
// ulp_riscv_halt();
@ -97,6 +123,7 @@ void common_hal_espulp_ulp_halt(espulp_ulp_obj_t *self) {
// resets the processor
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN);
#endif
// Release pins we were using.
for (uint8_t i = 0; i < 32; i++) {
@ -106,13 +133,21 @@ void common_hal_espulp_ulp_halt(espulp_ulp_obj_t *self) {
}
}
void common_hal_espulp_ulp_construct(espulp_ulp_obj_t *self) {
void common_hal_espulp_ulp_construct(espulp_ulp_obj_t *self, espulp_ulparch_t arch) {
// Use a static variable to track ULP in use so that subsequent code runs can
// use a running ULP. This is only to prevent multiple portions of user code
// from using the ULP concurrently.
if (ulp_used) {
mp_raise_ValueError_varg(translate("%q in use"), MP_QSTR_ULP);
}
#ifdef CONFIG_IDF_TARGET_ESP32
if (self->arch == RISCV) {
mp_raise_NotImplementedError(NULL);
}
#endif
self->arch = arch;
self->inited = true;
}

View File

@ -27,8 +27,10 @@
#pragma once
#include "py/obj.h"
#include "bindings/espulp/ULPArch.h"
typedef struct {
mp_obj_base_t base;
espulp_ulparch_t arch;
bool inited;
} espulp_ulp_obj_t;

View File

@ -37,10 +37,6 @@
static volatile bool woke_up = false;
static bool alarm_set = false;
void common_hal_espulp_ulpalarm_construct(espulp_ulpalarm_obj_t *self) {
}
mp_obj_t espulp_ulpalarm_find_triggered_alarm(const size_t n_alarms, const mp_obj_t *alarms) {
for (size_t i = 0; i < n_alarms; i++) {
if (mp_obj_is_type(alarms[i], &espulp_ulpalarm_type)) {
@ -52,7 +48,6 @@ mp_obj_t espulp_ulpalarm_find_triggered_alarm(const size_t n_alarms, const mp_ob
mp_obj_t espulp_ulpalarm_record_wake_alarm(void) {
espulp_ulpalarm_obj_t *const alarm = &alarm_wake_alarm.ulp_alarm;
alarm->base.type = &espulp_ulpalarm_type;
return alarm;
}
@ -81,8 +76,25 @@ void espulp_ulpalarm_set_alarm(const bool deep_sleep, const size_t n_alarms, con
}
// enable ulp interrupt
rtc_isr_register(&ulp_interrupt, NULL, RTC_CNTL_COCPU_INT_ST);
REG_SET_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_COCPU_INT_ENA);
switch (alarm->ulp->arch) {
case FSM:
#ifdef CONFIG_IDF_TARGET_ESP32
rtc_isr_register(&ulp_interrupt, NULL, RTC_CNTL_ULP_CP_INT_RAW);
#else
rtc_isr_register(&ulp_interrupt, NULL, RTC_CNTL_ULP_CP_INT_ST);
#endif
REG_SET_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_ULP_CP_INT_ENA);
break;
case RISCV:
#ifndef CONFIG_IDF_TARGET_ESP32
rtc_isr_register(&ulp_interrupt, NULL, RTC_CNTL_COCPU_INT_ST);
REG_SET_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_COCPU_INT_ENA);
break;
#endif
default:
mp_raise_NotImplementedError(NULL);
break;
}
alarm_set = true;
}
@ -91,9 +103,13 @@ void espulp_ulpalarm_prepare_for_deep_sleep(void) {
if (!alarm_set) {
return;
}
// disable ulp interrupt
rtc_isr_deregister(&ulp_interrupt, NULL);
REG_CLR_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_ULP_CP_INT_ENA);
#ifndef CONFIG_IDF_TARGET_ESP32
REG_CLR_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_COCPU_INT_ENA);
#endif
// enable ulp wakeup
esp_sleep_enable_ulp_wakeup();

View File

@ -29,8 +29,11 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "bindings/espulp/ULP.h"
typedef struct {
mp_obj_base_t base;
espulp_ulp_obj_t *ulp;
} espulp_ulpalarm_obj_t;
mp_obj_t espulp_ulpalarm_find_triggered_alarm(const size_t n_alarms, const mp_obj_t *alarms);

View File

@ -313,8 +313,8 @@ CONFIG_SPIRAM_SPIWP_SD3_PIN=7
# CONFIG_ESP32_TRAX is not set
CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0
# CONFIG_ESP32_ULP_COPROC_ENABLED is not set
CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0
CONFIG_ESP32_ULP_COPROC_ENABLED=y
CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=4080
CONFIG_ESP32_DEBUG_OCDAWARE=y
CONFIG_ESP32_BROWNOUT_DET=y
CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y

View File

@ -26,11 +26,13 @@ CIRCUITPY_COUNTIO ?= 1
CIRCUITPY_DUALBANK ?= 1
CIRCUITPY_ESP32_CAMERA ?= 1
CIRCUITPY_ESPIDF ?= 1
CIRCUITPY_ESPULP ?= 1
CIRCUITPY_FRAMEBUFFERIO ?= 1
CIRCUITPY_FREQUENCYIO ?= 1
CIRCUITPY_HASHLIB ?= 1
CIRCUITPY_I2CTARGET ?= 1
CIRCUITPY_IMAGECAPTURE = 0
CIRCUITPY_MEMORYMAP ?= 1
CIRCUITPY_NVM ?= 1
CIRCUITPY_PS2IO ?= 1
CIRCUITPY_RGBMATRIX ?= 1
@ -54,7 +56,9 @@ CIRCUITPY_ALARM = 0
CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_COUNTIO = 0
CIRCUITPY_ESP32_CAMERA = 0
CIRCUITPY_ESPULP = 0
CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_MEMORYMAP = 0
CIRCUITPY_PARALLELDISPLAY = 0
CIRCUITPY_ROTARYIO = 0
CIRCUITPY_TOUCHIO ?= 1
@ -65,14 +69,10 @@ CIRCUITPY_USB = 0
else ifeq ($(IDF_TARGET),esp32s2)
# Modules
CIRCUITPY_BLEIO = 0
CIRCUITPY_ESPULP = 1
CIRCUITPY_MEMORYMAP = 1
else ifeq ($(IDF_TARGET),esp32s3)
# Modules
CIRCUITPY_PARALLELDISPLAY = 0
CIRCUITPY_ESPULP = 1
CIRCUITPY_MEMORYMAP = 1
endif
# No room for dualbank on boards with 2MB flash