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

esp32: Add Sigma-Delta peripheral #5452

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/esp32/general.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
14 changes: 14 additions & 0 deletions docs/esp32/quickref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <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
--------------

Expand Down
40 changes: 40 additions & 0 deletions docs/library/esp32.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
<https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/sigmadelta.html>`_.

.. 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
----------------------------

Expand Down
1 change: 1 addition & 0 deletions ports/esp32/esp32_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
156 changes: 156 additions & 0 deletions ports/esp32/esp32_sigmadelta.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Mike Causer <mcauser@gmail.com>
*
* 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
);
1 change: 1 addition & 0 deletions ports/esp32/modesp32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions ports/esp32/modesp32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading