diff --git a/docs/esp32/general.rst b/docs/esp32/general.rst index 8137c042d9214..ed09f213d20e0 100644 --- a/docs/esp32/general.rst +++ b/docs/esp32/general.rst @@ -53,6 +53,7 @@ For your convenience, some of technical specifications are provided below: * ADC: 12-bit SAR ADC up to 18 channels * DAC: 2 8-bit DACs * RMT: 8 channels allowing accurate pulse transmit/receive +* SigmaDelta: 8 channels of hardware sigma-delta modulated output * Programming: using BootROM bootloader from UART - due to external FlashROM and always-available BootROM bootloader, the ESP32 is not brickable diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index f4eb9a0ce8ca2..002d5749e1aad 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -655,6 +655,20 @@ The RMT is ESP32-specific and allows generation of accurate digital pulses with # The channel resolution is 100ns (1/(source_freq/clock_div)). r.write_pulses((1, 20, 2, 40), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns +Sigma-Delta +----------- + +An ESP32-specific peripheral for generating hardware sigma-delta modulated output +on any GPIO. See :ref:`esp32.SigmaDelta ` for details. Usage is:: + + import esp32 + from machine import Pin + + sd = esp32.SigmaDelta(0, pin=Pin(4), duty=0, prescale=80) + sd.duty(20) # -128 to 127 + sd.prescale(160) # 0 to 255 + sd.deinit() + OneWire driver -------------- diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index efdd6c1be289c..1fefb6438ea78 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -272,6 +272,46 @@ For more details see Espressif's `ESP-IDF RMT documentation. Passing in no argument will not change the channel. This function returns the current channel number. +.. _esp32.SigmaDelta: + +Sigma-Delta +----------- + +ESP32 has a second-order sigma-delta modulation module. Each of the eight +independent channels (0-7) are capable of outputting a binary hardware generated +signal with the sigma-delta modulation:: + + import esp32 + from machine import Pin + + sd = esp32.SigmaDelta(3, pin=Pin(4), duty=0, prescale=80) + sd # SigmaDelta(channel=3, pin=4, duty=0, prescale=80) + sd.duty(90) + sd.prescale(8) + sd.deinit() + +For more details see Espressif's `ESP-IDF Sigma-delta documentation. +`_. + +.. class:: SigmaDelta(channel, \*, pin=None, duty=0, prescale=80) + + This class provides access to the Sigma-Delta hardware signal generator. + +.. method:: SigmaDelta.duty(duty) + + Set the duty of the output signal in the range -128 to 127. A zero value will + result in the output signal's duty of around 50%. Recommended range is -90 to 90. + +.. method:: SigmaDelta.prescale(prescale) + + Set the sigma-delta channel's clock pre-scale value. The source clock is + APP_CLK, 80MHz. The clock frequency of the sigma-delta channel is + ``APP_CLK / pre_scale``. + +.. method:: SigmaDelta.deinit() + + Disconnect the signal generator from the pin. + Ultra-Low-Power co-processor ---------------------------- diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake index d55dd38134fb8..2cd743774d51c 100644 --- a/ports/esp32/esp32_common.cmake +++ b/ports/esp32/esp32_common.cmake @@ -80,6 +80,7 @@ list(APPEND MICROPY_SOURCE_PORT esp32_nvs.c esp32_partition.c esp32_rmt.c + esp32_sigmadelta.c esp32_ulp.c modesp32.c machine_hw_spi.c diff --git a/ports/esp32/esp32_sigmadelta.c b/ports/esp32/esp32_sigmadelta.c new file mode 100644 index 0000000000000..68277cc4f7f8a --- /dev/null +++ b/ports/esp32/esp32_sigmadelta.c @@ -0,0 +1,156 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Mike Causer + * + * 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/runtime.h" +#include "modmachine.h" +#include "mphalport.h" +#include "driver/sigmadelta.h" + +// Forward declaration +extern const mp_obj_type_t esp32_sigmadelta_type; + +typedef struct _esp32_sigmadelta_obj_t { + mp_obj_base_t base; + uint8_t channel_id; + gpio_num_t pin; + int8_t duty; + uint8_t prescale; +} esp32_sigmadelta_obj_t; + +STATIC mp_obj_t esp32_sigmadelta_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_channel, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_duty, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_prescale, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 80} }, + }; + 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); + mp_uint_t channel_id = args[0].u_int; + gpio_num_t pin_id = machine_pin_get_id(args[1].u_obj); + mp_int_t duty = args[2].u_int; + mp_uint_t prescale = args[3].u_int; + + if (duty < -128 || duty > 127) { + mp_raise_ValueError(MP_ERROR_TEXT("duty must be between -128 and 127")); + } + + if (prescale > 255) { + mp_raise_ValueError(MP_ERROR_TEXT("prescale must be between 0 and 255")); + } + + esp32_sigmadelta_obj_t *self = m_new_obj_with_finaliser(esp32_sigmadelta_obj_t); + self->base.type = &esp32_sigmadelta_type; + self->channel_id = channel_id; + self->pin = pin_id; + self->duty = duty; + self->prescale = prescale; + + sigmadelta_config_t config; + config.channel = (sigmadelta_channel_t)self->channel_id; + config.sigmadelta_gpio = self->pin; + config.sigmadelta_duty = self->duty; + config.sigmadelta_prescale = self->prescale; + + check_esp_err(sigmadelta_config(&config)); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void esp32_sigmadelta_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + esp32_sigmadelta_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->pin != -1) { + mp_printf(print, "SigmaDelta(channel=%u, pin=%u, duty=%d, prescale=%u)", + self->channel_id, self->pin, self->duty, self->prescale); + } else { + mp_printf(print, "SigmaDelta()"); + } +} + +STATIC mp_obj_t esp32_sigmadelta_deinit(mp_obj_t self_in) { + esp32_sigmadelta_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->pin != -1) { // Check if channel has already been deinitialised. + gpio_matrix_out(self->pin, SIG_GPIO_OUT_IDX, 0, 0); + self->pin = -1; // -1 to indicate SigmaDelta is unused + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_sigmadelta_deinit_obj, esp32_sigmadelta_deinit); + +STATIC mp_obj_t esp32_sigmadelta_duty(size_t n_args, const mp_obj_t *args) { + esp32_sigmadelta_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_int_t duty; + if (n_args == 1) { + // get + return mp_obj_new_int(self->duty); + } + + // set + duty = mp_obj_get_int(args[1]); + if (duty < -128 || duty > 127) { + mp_raise_ValueError(MP_ERROR_TEXT("duty must be between -128 and 127")); + } + check_esp_err(sigmadelta_set_duty(self->channel_id, duty)); + self->duty = duty; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_sigmadelta_duty_obj, 1, 2, esp32_sigmadelta_duty); + +STATIC mp_obj_t esp32_sigmadelta_prescale(size_t n_args, const mp_obj_t *args) { + esp32_sigmadelta_obj_t *self = MP_OBJ_TO_PTR(args[0]); + mp_uint_t prescale; + if (n_args == 1) { + // get + return mp_obj_new_int(self->prescale); + } + + // set + prescale = mp_obj_get_int(args[1]); + if (prescale > 255) { + mp_raise_ValueError(MP_ERROR_TEXT("prescale must be between 0 and 255")); + } + check_esp_err(sigmadelta_set_prescale(self->channel_id, prescale)); + self->prescale = prescale; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_sigmadelta_prescale_obj, 1, 2, esp32_sigmadelta_prescale); + +STATIC const mp_rom_map_elem_t esp32_sigmadelta_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&esp32_sigmadelta_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_sigmadelta_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_sigmadelta_duty_obj) }, + { MP_ROM_QSTR(MP_QSTR_prescale), MP_ROM_PTR(&esp32_sigmadelta_prescale_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(esp32_sigmadelta_locals_dict, esp32_sigmadelta_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + esp32_sigmadelta_type, + MP_QSTR_SIGMADELTA, + MP_TYPE_FLAG_NONE + make_new, esp32_sigmadelta_make_new, + print, esp32_sigmadelta_print, + locals_dict, &esp32_sigmadelta_locals_dict + ); diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index ef3ad0b76d459..fa24ab3dd7c1c 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -208,6 +208,7 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_NVS), MP_ROM_PTR(&esp32_nvs_type) }, { MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) }, { MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) }, + { MP_ROM_QSTR(MP_QSTR_SigmaDelta), MP_ROM_PTR(&esp32_sigmadelta_type) }, #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, #endif diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index a685b7b38fe6f..b7263385b4155 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -64,6 +64,7 @@ extern int8_t esp32_rmt_bitstream_channel_id; extern const mp_obj_type_t esp32_nvs_type; extern const mp_obj_type_t esp32_partition_type; extern const mp_obj_type_t esp32_rmt_type; +extern const mp_obj_type_t esp32_sigmadelta_type; extern const mp_obj_type_t esp32_ulp_type; esp_err_t rmt_driver_install_core1(uint8_t channel_id); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy