Skip to content

esp32/MCPWM: Add motor control MCPWM driver. #12345

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

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
29 changes: 29 additions & 0 deletions docs/esp32/quickref.rst
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,35 @@ Use the DAC::
dac = DAC(Pin(25)) # create an DAC object acting on a pin
dac.write(128) # set a raw analog value in the range 0-255, 50% now

MCPWM (motor control pulse width modulation)
--------------------------------------------

MCPWM can be enabled on all output-enabled pins. The API differs slightly from **machine.PWM** to allow explicit timer selection.
Currently, this implementation only covers basic functionality.

For more details, see Espressif's `MCPWM
<https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/mcpwm.html>`_ documentation.

Use the esp32.MCPWM class::

from machine import Pin
from esp32 import MCPWM

mcpwm = MCPWM(0, (Pin(16), Pin(17)), freq=1000, duty_u16=32768) # create MCPWM object with timer (0..5)

freq = mcpwm.freq() # get current frequency
# mcpwm.freq(500) # set frequency in Hz. Not supported!

duty_u16 = mcpwm.duty_u16() # get current duty cycle, range 0-65535, (now 32768, 50% of duty)
duty_ns = mcpwm.duty_ns() # get current pulse width in ns, (now 500000 ns, 50% of duty)

mcpwm.duty_u16(2**16 * 3 // 4) # set duty cycle from 0 to 65536 as a ratio duty_u16/65536, (now 75% of duty)
mcpwm.duty_ns(250000) # set pulse width in nanoseconds from 0 to 1_000_000_000/freq, (now 25% of duty)

print(mcpwm) # view MCPWM settings

mcpwm.deinit() # turn of MCPWM on pins

ADC (analog to digital conversion)
----------------------------------

Expand Down
1 change: 1 addition & 0 deletions ports/esp32/esp32_common.cmake
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ list(APPEND MICROPY_SOURCE_PORT
esp32_nvs.c
esp32_partition.c
esp32_rmt.c
esp32_mcpwm.c
esp32_ulp.c
modesp32.c
machine_hw_spi.c
Expand Down
897 changes: 897 additions & 0 deletions ports/esp32/esp32_mcpwm.c

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions ports/esp32/modesp32.c
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ static const mp_rom_map_elem_t esp32_module_globals_table[] = {
#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
{ MP_ROM_QSTR(MP_QSTR_MCPWM), MP_ROM_PTR(&esp32_mcpwm_type) },

{ MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_FALSE },
{ MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_TRUE },
Expand Down
1 change: 1 addition & 0 deletions ports/esp32/modesp32.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ 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_ulp_type;
extern const mp_obj_type_t esp32_mcpwm_type;

esp_err_t rmt_driver_install_core1(uint8_t channel_id);

Expand Down
5 changes: 4 additions & 1 deletion ports/esp32/mpconfigport.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@
#define MICROPY_STACK_CHECK_MARGIN (1024)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
// #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
#define MICROPY_WARNINGS (1)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#define MICROPY_STREAMS_POSIX_API (1)
#define MICROPY_USE_INTERNAL_ERRNO (0) // errno.h from xtensa-esp32-elf/sys-include/sys
#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf
#define MICROPY_DEBUG_PRINTERS (1)
#define MICROPY_DEBUG_VERBOSE (0)
#define MICROPY_SCHEDULER_DEPTH (8)
#define MICROPY_VFS (1)

Expand Down
5 changes: 5 additions & 0 deletions ports/esp32/mphalport.c
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "freertos/task.h"
#include "esp_timer.h"

#include "py/mpprint.h"
#include "py/obj.h"
#include "py/objstr.h"
#include "py/stream.h"
Expand All @@ -51,6 +52,7 @@
#if MICROPY_PY_STRING_TX_GIL_THRESHOLD < 0
#error "MICROPY_PY_STRING_TX_GIL_THRESHOLD must be positive"
#endif
#include "py/mpprint.h"

TaskHandle_t mp_main_task_handle;

Expand Down Expand Up @@ -99,6 +101,9 @@ void check_esp_err_(esp_err_t code, const char *func, const int line, const char
#endif
o_str->len = strlen((char *)o_str->data);
o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
#if MICROPY_ERROR_REPORTING > MICROPY_ERROR_REPORTING_NORMAL
mp_printf(MP_PYTHON_PRINTER, "Exception in function '%s' at line %d in file '%s'\n", func, line, file);
#endif
// raise
mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(pcode), MP_OBJ_FROM_PTR(o_str)};
nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));
Expand Down
1 change: 1 addition & 0 deletions ports/esp32/mphalport.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ void mp_hal_wake_main_task_from_isr(void);
#include "driver/gpio.h"
#define MP_HAL_PIN_FMT "%u"
#define mp_hal_pin_obj_t gpio_num_t
// #define pin_find(p) machine_pin_find(p)
mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in);
#define mp_hal_get_pin_obj(o) machine_pin_get_id(o)
#define mp_hal_pin_name(p) (p)
Expand Down
74 changes: 74 additions & 0 deletions py/mpprint.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,78 @@ int mp_printf(const mp_print_t *print, const char *fmt, ...);
int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args);
#endif

// Debug messages during code developing with MP_DEBUG_PRINT(level, ...) & MP_DEBUG_PRINT_LEVEL.
// An approximate hierarchy of debug levels MP_DEBUG_PRINT_LEVEL is:
#define MP_DEBUG_PRINT_SUPPRESS 0 // SUPPRESS all messages. Use it in the release version.
#define MP_DEBUG_PRINT_CRITICAL 10 // For the most CRITICAL errors, often requiring a system reset. Use a message with this level, if possible, raising an exception.
#define MP_DEBUG_PRINT_ERROR 20 // ERROR requiring program restart, use message with this level before raising an exception.
#define MP_DEBUG_PRINT_WARNING 30 // WARNING, something went wrong, but you can fix it with additional operations in code right now or may ignore it.
#define MP_DEBUG_PRINT_INFO 40 // INFO, it is interesting and useful for understanding a bug.
#define MP_DEBUG_PRINT_DEBUG 50 // DEBUG, more detailed information, dig deeper.
#define MP_DEBUG_PRINT_TRACE 60 // TRACE, show a flow of the algorithm, like enter/exit a function.
// In reality, you may use your own classification of debug levels.

#endif // MICROPY_INCLUDED_PY_MPPRINT_H

// This code is placed after `#endif // MICROPY_INCLUDED_PY_MPPRINT_H` to allow the developer
// to use several local `MP_DEBUG_PRINT_LEVEL` definitions in separate _.c files.
// This is not a typo or a bug.

/*
// Debugging macro for developers.

// How to use:
// Important! Set MP_DEBUG_PRINT_LEVEL in *.c or *.cpp development file BEFORE any "MicroPython's *.h" includes.
// For example:
#define MP_DEBUG_PRINT_LEVEL MP_DEBUG_PRINT_TRACE // show all messages
// Include mpprint.h after defining the MP_DEBUG_PRINT_LEVEL
#include "py/mpprint.h"
...
#include "py/obj.h"
#include "py/runtime.h"
...

// Add MP_DEBUG_PRINT() macro in code, like
void foo(int arg) {
MP_DEBUG_PRINT(MP_DEBUG_PRINT_TRACE, "Enter foo()")
if (arg < 0) {
MP_DEBUG_PRINT(MP_DEBUG_PRINT_WARNING, "arg=%d less zero", arg)
...
}
...
int value;
...
// calculate value
...
MP_DEBUG_PRINT(MP_DEBUG_PRINT_INFO, "See a value=%d", value)
...
MP_DEBUG_PRINT(MP_DEBUG_PRINT_TRACE, "Exit foo()")
}

// It is not a dogma. You may start debugging from level 30.
#define MP_DEBUG_PRINT_LEVEL 30
// Then add MP_DEBUG_PRINT(30, ...) and when gets too many messages then change some messages to the next level MP_DEBUG_PRINT(40, ...), or MP_DEBUG_PRINT(20, ...) etc.
// Then you may change MP_DEBUG_PRINT_LEVEL to 20(reduce printing), and finally to 0(suppress printing).

// Usually, you will debug one or two source files. Debug printing from other files is suppressed if MP_DEBUG_PRINT_LEVEL is 0 or undefined.
*/
#if defined(MP_DEBUG_PRINT_LEVEL) && (MP_DEBUG_PRINT_LEVEL > 0)

#if defined(MP_DEBUG_PRINT)
#undef MP_DEBUG_PRINT
#endif

#define MP_DEBUG_PRINT(level, ...) \
do { \
if ((0 < level) && (level <= MP_DEBUG_PRINT_LEVEL)) { \
mp_printf(MP_PYTHON_PRINTER, " %s: ", #level); \
mp_printf(MP_PYTHON_PRINTER, __VA_ARGS__); \
mp_printf(MP_PYTHON_PRINTER, "\t : FUNC=%s LINE=%d FILE=%s\n", __FUNCTION__, __LINE__, __FILE__); \
} \
} while (0);

#else

#define MP_DEBUG_PRINT(level, ...)

#endif
Loading
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