This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 65e989e063 arch/risc-v: add support for motor control on ESP32|C6|H2
65e989e063 is described below
commit 65e989e0635e13397bb61b2f04b839b197d99de9
Author: Filipe Cavalcanti <[email protected]>
AuthorDate: Wed Jul 3 09:49:11 2024 -0300
arch/risc-v: add support for motor control on ESP32|C6|H2
---
.../esp32c6/boards/esp32c6-devkitc/index.rst | 28 +-
Documentation/platforms/risc-v/esp32c6/index.rst | 2 +-
arch/risc-v/src/common/espressif/Kconfig | 105 ++
arch/risc-v/src/common/espressif/esp_mcpwm.c | 1607 ++++++++++++++++++--
arch/risc-v/src/common/espressif/esp_mcpwm.h | 25 +
.../esp32c6/common/include/esp_board_mcpwm.h | 22 +-
boards/risc-v/esp32c6/common/src/esp_board_mcpwm.c | 58 +
.../esp32c6-devkitc/configs/motor/defconfig | 52 +
.../esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c | 8 +
.../esp32h2/common/include/esp_board_mcpwm.h | 22 +-
boards/risc-v/esp32h2/common/src/esp_board_mcpwm.c | 58 +
.../esp32h2/esp32h2-devkit/configs/motor/defconfig | 51 +
.../esp32h2/esp32h2-devkit/src/esp32h2_bringup.c | 8 +
13 files changed, 1892 insertions(+), 154 deletions(-)
diff --git
a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst
b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst
index fa5363ad3c..0536d88071 100644
--- a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst
+++ b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst
@@ -105,15 +105,15 @@ capture
The capture configuration enables the capture driver and the capture example,
allowing
the user to measure duty cycle and frequency of a signal. Default pin is GPIO
18 with
an internal pull-up resistor enabled. When connecting a 50 Hz pulse with 50%
duty cycle,
-the following output is expected:
+the following output is expected::
-nsh> cap
-cap_main: Hardware initialized. Opening the capture device: /dev/capture0
-cap_main: Number of samples: 0
-pwm duty cycle: 50 %
-pwm frequence: 50 Hz
-pwm duty cycle: 50 %
-pwm frequence: 50 Hz
+ nsh> cap
+ cap_main: Hardware initialized. Opening the capture device: /dev/capture0
+ cap_main: Number of samples: 0
+ pwm duty cycle: 50 %
+ pwm frequence: 50 Hz
+ pwm duty cycle: 50 %
+ pwm frequence: 50 Hz
coremark
--------
@@ -154,6 +154,18 @@ You can scan for all I2C devices using the following
command::
nsh> i2c dev 0x00 0x7f
+motor
+-------
+
+The motor configuration enables the MCPWM peripheral with support to brushed
DC motor
+control.
+
+It creates a ``/dev/motor0`` device with speed and direction control
capabilities
+by using two GPIOs (GPIO21 and GPIO22) for PWM output. PWM frequency is
configurable
+from 25 Hz to 3 kHz, however it defaults to 1 kHz.
+There is also support for an optional fault GPIO (defaults to GPIO9), which
can be used
+for quick motor braking. All GPIOs are configurable in ``menuconfig``.
+
mcuboot_nsh
--------------------
diff --git a/Documentation/platforms/risc-v/esp32c6/index.rst
b/Documentation/platforms/risc-v/esp32c6/index.rst
index 9642de6fcc..72891f568d 100644
--- a/Documentation/platforms/risc-v/esp32c6/index.rst
+++ b/Documentation/platforms/risc-v/esp32c6/index.rst
@@ -170,7 +170,7 @@ I2S No
Int. Temp. No
LED No
LED_PWM Yes
-MCPWM Yes (Capture)
+MCPWM Yes
Pulse Counter No
RMT No
RNG No
diff --git a/arch/risc-v/src/common/espressif/Kconfig
b/arch/risc-v/src/common/espressif/Kconfig
index 85099a09b2..bc8c68c12c 100644
--- a/arch/risc-v/src/common/espressif/Kconfig
+++ b/arch/risc-v/src/common/espressif/Kconfig
@@ -1309,9 +1309,105 @@ config ESPRESSIF_I2CTIMEOMS
default 500
endmenu # I2C configuration
+
menu "MCPWM Configuration"
depends on ESP_MCPWM
+config ESP_MCPWM_MOTOR
+ bool "MCPWM Motor Support"
+ default n
+
+menu "MCPWM Motor Configuration"
+ depends on ESP_MCPWM_MOTOR
+
+config ESP_MCPWM_MOTOR_BDC
+ bool "Brushed DC Motor Control"
+ depends on ESP_MCPWM
+ depends on ESP_MCPWM_MOTOR
+ select MOTOR
+ select MOTOR_UPPER
+ select MOTOR_UPPER_HAVE_SPEED
+ default n
+ ---help---
+ Enables the use of the MCPWM submodule for control of brushed DC
+ motor.
+
+if ESP_MCPWM_MOTOR_BDC
+
+config ESP_MCPWM_MOTOR_CH0
+ bool "Motor Control Channel 0"
+ default n
+ ---help---
+ Enables motor control on channel 0.
+
+if ESP_MCPWM_MOTOR_CH0
+
+config ESP_MCPWM_MOTOR_CH0_PWMA_GPIO
+ int "Output Pin PWM_A"
+ default 20 if ESPRESSIF_ESP32C6
+ default 10 if ESPRESSIF_ESP32H2
+ ---help---
+ Output pin assigned to channel 0 PWM output PWM_A.
+
+config ESP_MCPWM_MOTOR_CH0_PWMB_GPIO
+ int "Output Pin PWM_B"
+ default 21 if ESPRESSIF_ESP32C6
+ default 11 if ESPRESSIF_ESP32H2
+ ---help---
+ Output pin assigned to channel 0 PWM output PWM_B.
+
+config ESP_MCPWM_MOTOR_CH0_PWM_FREQ
+ int "PWM output frequency for channel 0 [Hz]"
+ default 1000
+ ---help---
+ Select PWM frequency for channel 0.
+ Minimum is 25 Hz and maximum is 3000 Hz.
+
+config ESP_MCPMW_MOTOR_CH0_FAULT
+ bool "Enable fault for channel 0"
+ default n
+ ---help---
+ Enables the use of a fault pin to quickly stop the motor when
+ a GPIO pin pulled high.
+
+if ESP_MCPMW_MOTOR_CH0_FAULT
+
+config ESP_MCPMW_MOTOR_CH0_FAULT_GPIO
+ int "GPIO Pin for fault detection"
+ default 9
+ ---help---
+ Input pin assigned to channel 0 fault indicator.
+
+endif # ESP_MCPMW_MOTOR_CH0_FAULT
+
+endif # ESP_MCPWM_MOTOR_CH0
+
+config ESP_MCPWM_MOTOR_CH1
+ bool "Motor Control Channel 1"
+ default n
+ ---help---
+ Enables motor control on channel 1.
+
+if ESP_MCPWM_MOTOR_CH1
+
+config ESP_MCPWM_MOTOR_CH1_PWMA_GPIO
+ int "Output Pin CH1 PWM_A"
+ default 15
+ ---help---
+ Output pin assigned to channel 1 PWM output PWM_A.
+
+config ESP_MCPWM_MOTOR_CH1_PWMB_GPIO
+ int "Output Pin CH1 PWM_B"
+ default 16
+ ---help---
+ Output pin assigned to channel 1 PWM output PWM_B.
+
+endif # ESP_MCPWM_MOTOR_CH1
+
+endif # ESP_MCPWM_MOTOR_BDC
+
+endmenu # MCPWM Motor Settings
+
config ESP_MCPWM_CAPTURE
bool "MCPWM Capture Submodule"
depends on ESP_MCPWM
@@ -1372,6 +1468,15 @@ endif # ESP_MCPWM_CAPTURE_CH2
endif # ESP_MCPWM_CAPTURE
+config ESP_MCPWM_TEST_LOOPBACK
+ bool "MCPWM loopback test mode"
+ depends on EXPERIMENTAL
+ default n
+ ---help---
+ This enables a lower-half driver-specific loopback test
+ mode that attaches a capture device to the PWM output on
+ motor tests.
+
endmenu # MCPWM Configuration
menu "High Resolution Timer"
diff --git a/arch/risc-v/src/common/espressif/esp_mcpwm.c
b/arch/risc-v/src/common/espressif/esp_mcpwm.c
index e4562e4a95..e172490f45 100644
--- a/arch/risc-v/src/common/espressif/esp_mcpwm.c
+++ b/arch/risc-v/src/common/espressif/esp_mcpwm.c
@@ -33,7 +33,12 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
#include <nuttx/timers/capture.h>
+#endif
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+#include <nuttx/motor/motor.h>
+#endif
#include "esp_gpio.h"
#include "esp_irq.h"
@@ -58,153 +63,1338 @@
# define MCPWM_DEV_CLK_SOURCE SOC_MOD_CLK_PLL_F160M
#endif
-#define MCPWM_DEV_CLK_PRESCALE 4
+#define MCPWM_DEV_CLK_PRESCALE 1
#define MCPWM_CAPTURE_DEFAULT_GROUP 0
+#define GPIO_IN_FUNCTION INPUT_FUNCTION_2
+#define GPIO_OUT_FUNCTION OUTPUT_FUNCTION_2
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR_BDC
+
+/* Peak counter at 13330 in up-down mode allows frequencies at a prescale
+ * of: 2 kHz @ 2; 1.5 kHz @ 3; 1.2 kHz @ 4; 1 kHz @ 5.
+ */
+#ifndef CONFIG_ARCH_CHIP_ESP32H2
+# define PEAK_COUNTER 13330
+# define MCPWM_MAX_PWM_OUT_FREQ 3000
+# define MCPWM_MIN_PWM_OUT_FREQ 25
+#else
+# define PEAK_COUNTER 9595
+# define MCPWM_MAX_PWM_OUT_FREQ 2500
+# define MCPWM_MIN_PWM_OUT_FREQ 20
+#endif
+#endif
+#ifdef CONFIG_ESP_MCPMW_MOTOR_CH0_FAULT
+# define ESP_MCPMW_MOTOR_FAULT
+#endif
/****************************************************************************
* Private Types
****************************************************************************/
-struct mcpwm_dev_common_s
+typedef enum
+{
+ MCPWM_GENERATOR_0,
+ MCPWM_GENERATOR_1,
+ MCPWM_GENERATOR_MAX
+} mcpwm_generator_e;
+
+typedef enum
+{
+ MCPWM_OPERATOR_0,
+ MCPWM_OPERATOR_1,
+ MCPWM_OPERATOR_2,
+ MCPWM_OPERATOR_MAX
+} mcpwm_operator_e;
+
+typedef enum
+{
+ MCPWM_TIMER_0,
+ MCPWM_TIMER_1,
+ MCPWM_TIMER_2,
+ MCPWM_TIMER_MAX
+} mcpwm_timer_e;
+
+typedef enum
+{
+ MCPWM_FAULT_0,
+ MCPWM_FAULT_1,
+ MCPWM_FAULT_2,
+ MCPWM_FAULT_MAX
+} mcpwm_fault_e;
+
+typedef enum
+{
+ MCPWM_MOTOR_CHANNEL_0,
+ MCPWM_MOTOR_CHANNEL_1,
+ MCPWM_MOTOR_CHANNEL_2,
+ MCPWM_MOTOR_CHANNEL_MAX
+} mcpwm_motor_channel_e;
+
+enum mcpwm_capture_channel_e
+{
+ MCPWM_CAP_CHANNEL_0,
+ MCPWM_CAP_CHANNEL_1,
+ MCPWM_CAP_CHANNEL_2,
+ MCPWM_CAP_CHANNEL_MAX
+};
+
+struct mcpwm_dev_common_s
+{
+ mcpwm_hal_init_config_t group;
+ mcpwm_hal_context_t hal;
+ spinlock_t mcpwm_spinlock;
+ bool initialized; /* MCPWM periph. and HAL has been initialized */
+ bool isr_initialized; /* Shared ISR has been initialized */
+ int group_prescale;
+};
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+
+struct mcpwm_motor_lowerhalf_s
+{
+ /* The following block is part of the upper-half device struct */
+
+ FAR const struct motor_ops_s *ops; /* Arch-specific operations */
+ uint8_t opmode; /* Motor operation mode */
+ uint8_t opflags; /* Motor operation flags */
+ struct motor_limits_s limits; /* Motor absolute limits */
+ struct motor_params_s param; /* Motor settings */
+ struct motor_state_s state; /* Motor state */
+ FAR void *priv; /* Private data */
+
+ /* The following is private to the ESP MCPWM driver */
+
+ struct mcpwm_dev_common_s *common;
+ mcpwm_timer_e timer_id;
+ mcpwm_motor_channel_e channel_id;
+ mcpwm_operator_e operator_id;
+ uint32_t pwm_frequency;
+ uint16_t counter_peak;
+ uint8_t timer_prescale;
+ int fault_pin; /* GPIO Pin for fault detection */
+ int generator_pins[MCPWM_GENERATOR_MAX];
+#ifdef ESP_MCPMW_MOTOR_FAULT
+ mcpwm_fault_e fault_id;
+#endif
+};
+#endif /* CONFIG_ESP_MCPWM_MOTOR */
+
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
+/* Capture event data. The 'last_' value is used to calculate frequency */
+
+struct mcpwm_capture_event_data_s
+{
+ uint32_t pos_edge_count;
+ uint32_t neg_edge_count;
+ uint32_t last_pos_edge_count;
+};
+
+/* Lowe-half data structure for a capture channel */
+
+struct mcpwm_cap_channel_lowerhalf_s
+{
+ /* The following block is part of the upper-half device struct */
+
+ const struct cap_ops_s *ops;
+
+ /* The following is private to the ESP MCPWM driver */
+
+ struct mcpwm_dev_common_s *common;
+ struct mcpwm_capture_event_data_s *data;
+ int channel_id;
+ int gpio_pin;
+ uint32_t clock;
+ uint32_t freq;
+ uint8_t duty;
+ uint8_t isr_count;
+ bool ready;
+ bool enabled;
+};
+#endif
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* General use for MCPWM peripheral */
+
+static void esp_mcpwm_group_start(void);
+
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
+static int esp_mcpwm_capture_set_gpio(
+ struct mcpwm_cap_channel_lowerhalf_s *lower);
+
+/* Lower half methods required by capture driver */
+
+static int esp_capture_start(struct cap_lowerhalf_s *lower);
+static int esp_capture_stop(struct cap_lowerhalf_s *lower);
+static int esp_capture_getduty(struct cap_lowerhalf_s *lower,
+ uint8_t *duty);
+static int esp_capture_getfreq(struct cap_lowerhalf_s *lower,
+ uint32_t *freq);
+#endif
+
+/* MCPWM Motor Control */
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+
+/* Upper-half functions required by motor driver */
+
+static int esp_motor_setup(struct motor_lowerhalf_s *dev);
+static int esp_motor_shutdown(struct motor_lowerhalf_s *dev);
+static int esp_motor_stop(struct motor_lowerhalf_s *dev);
+static int esp_motor_start(struct motor_lowerhalf_s *dev);
+static int esp_motor_mode_set(struct motor_lowerhalf_s *dev, uint8_t mode);
+static int esp_motor_fault_set(struct motor_lowerhalf_s *dev, uint8_t fault);
+static int esp_motor_fault_get(struct motor_lowerhalf_s *dev,
+ uint8_t *fault);
+static int esp_motor_params_set(struct motor_lowerhalf_s *dev,
+ struct motor_params_s *param);
+static int esp_motor_state_get(struct motor_lowerhalf_s *dev,
+ struct motor_state_s *state);
+static int esp_motor_limits_set(struct motor_lowerhalf_s *dev,
+ struct motor_limits_s *limits);
+static int esp_motor_fault_clear(struct motor_lowerhalf_s *dev,
+ uint8_t fault);
+static int esp_motor_ioctl(struct motor_lowerhalf_s *dev, int cmd,
+ unsigned long arg);
+
+/* Lower-half motor functions */
+
+static int esp_motor_pwm_config(struct mcpwm_motor_lowerhalf_s *lower);
+static int esp_mcpwm_motor_set_gpio(
+ struct mcpwm_motor_lowerhalf_s *lower, bool enable);
+static int esp_motor_set_duty_cycle(
+ struct mcpwm_motor_lowerhalf_s *lower, float duty);
+static int esp_motor_bdc_set_direction(
+ struct mcpwm_motor_lowerhalf_s *lower);
+#endif
+
+/* MCPWM Fault Control */
+
+#ifdef ESP_MCPMW_MOTOR_FAULT
+static int esp_mcpwm_fault_gpio_config(
+ struct mcpwm_motor_lowerhalf_s *lower, bool enable);
+static int esp_motor_fault_configure(
+ struct mcpwm_motor_lowerhalf_s *lower, bool enable);
+#endif
+
+/* MCPWM Interrupt */
+
+#if defined(CONFIG_ESP_MCPWM_CAPTURE) || defined(ESP_MCPMW_MOTOR_FAULT)
+static int esp_mcpwm_isr_register(int (*fn)(int, void *, void *), void *arg);
+static int IRAM_ATTR mcpwm_driver_isr_default(int irq, void *context,
+ void *arg);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Common MCPWM data structure */
+
+static struct mcpwm_dev_common_s g_mcpwm_common =
+{
+ .group.group_id = MCPWM_CAPTURE_DEFAULT_GROUP,
+ .initialized = false,
+ .isr_initialized = false,
+ .group_prescale = MCPWM_DEV_CLK_PRESCALE,
+};
+
+/* Motor specific data structures */
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static const struct motor_ops_s mcpwm_motor_ops =
+{
+ .setup = esp_motor_setup,
+ .shutdown = esp_motor_shutdown,
+ .stop = esp_motor_stop,
+ .start = esp_motor_start,
+ .params_set = esp_motor_params_set,
+ .mode_set = esp_motor_mode_set,
+ .limits_set = esp_motor_limits_set,
+ .fault_set = esp_motor_fault_set,
+ .state_get = esp_motor_state_get,
+ .fault_get = esp_motor_fault_get,
+ .fault_clear = esp_motor_fault_clear,
+ .ioctl = esp_motor_ioctl,
+};
+
+#if defined(CONFIG_ESP_MCPWM_MOTOR_CH0) &&\
+ defined(CONFIG_ESP_MCPWM_MOTOR_BDC)
+static struct mcpwm_motor_lowerhalf_s mcpwm_bdc_ch0_lowerhalf =
+{
+ .ops = &mcpwm_motor_ops,
+ .common = &g_mcpwm_common,
+ .channel_id = MCPWM_MOTOR_CHANNEL_0,
+ .timer_id = MCPWM_TIMER_0,
+ .operator_id = MCPWM_OPERATOR_0,
+ .counter_peak = PEAK_COUNTER,
+#ifdef ESP_MCPMW_MOTOR_FAULT
+ .fault_id = MCPWM_FAULT_0,
+#endif
+};
+#endif /* CONFIG_ESP_MCPWM_MOTOR_BDC_CH0 && CONFIG_ESP_MCPWM_MOTOR_BDC */
+#endif /* CONFIG_ESP_MCPWM_MOTOR */
+
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
+/* Lower half methods required by the capture driver */
+
+static const struct cap_ops_s mcpwm_cap_ops =
+{
+ .start = esp_capture_start,
+ .stop = esp_capture_stop,
+ .getduty = esp_capture_getduty,
+ .getfreq = esp_capture_getfreq,
+};
+
+/* Data structures for the available capture channels */
+
+#ifdef CONFIG_ESP_MCPWM_CAPTURE_CH0
+static struct mcpwm_capture_event_data_s event_data_ch0;
+static struct mcpwm_cap_channel_lowerhalf_s mcpwm_cap_ch0_lowerhalf =
+{
+ .ops = &mcpwm_cap_ops,
+ .common = &g_mcpwm_common,
+ .data = &event_data_ch0,
+ .channel_id = MCPWM_CAP_CHANNEL_0,
+ .ready = false,
+};
+#endif
+
+#ifdef CONFIG_ESP_MCPWM_CAPTURE_CH1
+static struct mcpwm_capture_event_data_s event_data_ch1;
+static struct mcpwm_cap_channel_lowerhalf_s mcpwm_cap_ch1_lowerhalf =
+{
+ .ops = &mcpwm_cap_ops,
+ .common = &g_mcpwm_common,
+ .data = &event_data_ch1,
+ .channel_id = MCPWM_CAP_CHANNEL_1,
+ .ready = false,
+};
+#endif
+
+#ifdef CONFIG_ESP_MCPWM_CAPTURE_CH2
+static struct mcpwm_capture_event_data_s event_data_ch2;
+static struct mcpwm_cap_channel_lowerhalf_s mcpwm_cap_ch2_lowerhalf =
+{
+ .ops = &mcpwm_cap_ops,
+ .common = &g_mcpwm_common,
+ .data = &event_data_ch2,
+ .channel_id = MCPWM_CAP_CHANNEL_2,
+ .ready = false,
+};
+#endif
+#endif /* CONFIG_ESP_MCPWM_CAPTURE */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_motor_setup
+ *
+ * Description:
+ * Configures the MCPWM operator and generator, setting the PWM clock and
+ * output pins.
+ * If required, also configures fault detection. When done, sets the the
+ * motor state to IDLE.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_setup(struct motor_lowerhalf_s *dev)
+{
+ DEBUGASSERT(dev != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *)dev;
+ mcpwm_hal_context_t *hal = &priv->common->hal;
+ uint32_t base_clock;
+ irqstate_t flags;
+ int ret;
+
+ flags = spin_lock_irqsave(&g_mcpwm_common.mcpwm_spinlock);
+ if ((priv->state.state == MOTOR_STATE_FAULT) ||
+ (priv->state.state == MOTOR_STATE_CRITICAL))
+ {
+ mtrerr("Motor is in fault state. Clear faults first\n");
+ return ERROR;
+ }
+
+ mtrinfo("State: %d\n", priv->state.state);
+
+ esp_clk_tree_src_get_freq_hz(MCPWM_DEV_CLK_SOURCE,
+ ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED,
+ &base_clock);
+
+ mcpwm_hal_timer_reset(hal, priv->timer_id);
+ mcpwm_hal_operator_reset(hal, priv->operator_id);
+
+ /* Setup control in UP-DOWN mode for duty cycle control
+ * Peak value modifies the maximum and minimum possible frequencies.
+ * Important: the HAL subtracts 1 from the target value.
+ */
+
+ priv->timer_prescale = \
+ base_clock / ((2 * priv->counter_peak + 1) * priv->pwm_frequency);
+
+ mcpwm_ll_timer_set_peak(hal->dev, priv->timer_id,
+ priv->counter_peak, true);
+ mcpwm_ll_timer_set_clock_prescale(hal->dev, priv->timer_id,
+ priv->timer_prescale);
+ mcpwm_ll_timer_update_period_at_once(hal->dev, priv->timer_id);
+ mcpwm_ll_timer_enable_update_period_on_tez(hal->dev, priv->timer_id, true);
+ mcpwm_ll_timer_set_count_mode(hal->dev, priv->timer_id,
+ MCPWM_TIMER_COUNT_MODE_UP_DOWN);
+
+ mcpwm_ll_operator_flush_shadow(hal->dev, priv->operator_id);
+ mcpwm_ll_operator_connect_timer(hal->dev, priv->operator_id,
+ priv->timer_id);
+ mcpwm_ll_operator_enable_update_compare_on_tez(hal->dev, priv->operator_id,
+ MCPWM_GENERATOR_0, true);
+
+#ifdef ESP_MCPMW_MOTOR_FAULT
+ esp_motor_fault_configure(priv, true);
+#endif
+ priv->state.state = MOTOR_STATE_IDLE;
+
+ spin_unlock_irqrestore(&g_mcpwm_common.mcpwm_spinlock, flags);
+ mtrinfo("Channel %d starts: prescale %d | freq: %"PRIu32"\n",
+ priv->channel_id, priv->timer_prescale - 1, priv->pwm_frequency);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_shutdown
+ *
+ * Description:
+ * Stop the PWM timer and disable output on GPIO matrix.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ *
+ * Returned Value:
+ * Returns OK on success.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_shutdown(struct motor_lowerhalf_s *dev)
+{
+ DEBUGASSERT(dev != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *)dev;
+ mcpwm_hal_context_t *hal = &priv->common->hal;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&g_mcpwm_common.mcpwm_spinlock);
+
+ /* Stop the motor */
+
+ esp_motor_stop(dev);
+
+ /* Stop the PWM timer */
+
+ mcpwm_ll_timer_set_count_mode(hal->dev, priv->timer_id,
+ MCPWM_TIMER_COUNT_MODE_PAUSE);
+ mcpwm_ll_timer_set_start_stop_command(hal->dev, priv->timer_id,
+ MCPWM_TIMER_STOP_EMPTY);
+
+ /* Disable fault detection */
+
+#ifdef ESP_MCPMW_MOTOR_FAULT
+ esp_motor_fault_configure(priv, false);
+#endif
+
+ spin_unlock_irqrestore(&g_mcpwm_common.mcpwm_spinlock, flags);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_stop
+ *
+ * Description:
+ * Holds the motor at a stand-still. PWM_A and PWM_B are kept low.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_stop(struct motor_lowerhalf_s *dev)
+{
+ DEBUGASSERT(dev != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *)dev;
+ mcpwm_hal_context_t *hal = &priv->common->hal;
+ irqstate_t flags;
+ int ret;
+
+ flags = spin_lock_irqsave(&g_mcpwm_common.mcpwm_spinlock);
+
+ if (priv->state.state == MOTOR_STATE_IDLE)
+ {
+ mtrerr("Motor already stopped\n");
+ return -EPERM;
+ }
+
+ mcpwm_ll_timer_set_start_stop_command(hal->dev, priv->timer_id,
+ MCPWM_TIMER_STOP_EMPTY);
+ mcpwm_ll_gen_set_continue_force_level(hal->dev,
+ priv->operator_id,
+ MCPWM_GENERATOR_0, 0);
+ mcpwm_ll_gen_set_continue_force_level(hal->dev,
+ priv->operator_id,
+ MCPWM_GENERATOR_1, 0);
+
+ ret = esp_motor_set_duty_cycle(priv, 0.0);
+ if (ret < 0)
+ {
+ mtrerr("Failed setting duty cycle to 0 on stop: %d\n", ret);
+ return ret;
+ }
+
+ if ((priv->state.state == MOTOR_STATE_FAULT) ||
+ (priv->state.state == MOTOR_STATE_CRITICAL))
+ {
+ mtrinfo("Channel %d stopped in fault state\n", priv->channel_id);
+ }
+ else
+ {
+ priv->state.state = MOTOR_STATE_IDLE;
+ }
+
+ priv->param.lock = false;
+ spin_unlock_irqrestore(&g_mcpwm_common.mcpwm_spinlock, flags);
+ mtrinfo("Channel %d stopped\n", priv->channel_id);
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_start
+ *
+ * Description:
+ * Start the motor by disabling forced actions and setting the duty cycle.
+ * The motor parameters must have been set before calling this function.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_start(struct motor_lowerhalf_s *dev)
+{
+ DEBUGASSERT(dev != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *)dev;
+ mcpwm_hal_context_t *hal = &priv->common->hal;
+ irqstate_t flags;
+ int ret;
+ float duty;
+
+ flags = spin_lock_irqsave(&g_mcpwm_common.mcpwm_spinlock);
+ if (priv->state.state == MOTOR_STATE_RUN)
+ {
+ mtrerr("Motor already running\n");
+ return -EINVAL;
+ }
+
+ if ((priv->state.state == MOTOR_STATE_CRITICAL) ||
+ (priv->state.state == MOTOR_STATE_FAULT))
+ {
+ mtrerr("Motor is in fault state\n");
+ return -EINVAL;
+ }
+
+ ret = esp_motor_pwm_config(priv);
+ if (ret < 0)
+ {
+ mtrerr("Failed setting PWM configuration\n");
+ return ret;
+ }
+
+ /* Set motor direction */
+
+ esp_motor_bdc_set_direction(priv);
+ mcpwm_ll_timer_set_start_stop_command(hal->dev, priv->timer_id,
+ MCPWM_TIMER_START_NO_STOP);
+
+ /* Set duty cycle based on motor parameter and limits */
+
+#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED
+ if (priv->opmode == MOTOR_OPMODE_SPEED)
+ {
+ duty = priv->param.speed / priv->limits.speed;
+ ret = esp_motor_set_duty_cycle(priv, duty);
+ if (ret < 0)
+ {
+ mtrerr("Failed starting motor\n");
+ return ret;
+ }
+ }
+#endif
+
+ priv->state.state = MOTOR_STATE_RUN;
+ spin_unlock_irqrestore(&g_mcpwm_common.mcpwm_spinlock, flags);
+ mtrinfo("Motor start\n");
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_params_set
+ *
+ * Description:
+ * Set parameters to run the motor.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ * param - Pointer to the motor parameter structure.
+ *
+ * Returned Value:
+ * Returns OK on success.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_params_set(struct motor_lowerhalf_s *dev,
+ struct motor_params_s *param)
+{
+ DEBUGASSERT(dev != NULL);
+ DEBUGASSERT(param != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *) dev;
+
+#ifdef CONFIG_MOTOR_UPPER_HAVE_POSITION
+ priv->param.position = param->position;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED
+ priv->param.speed = param->speed;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_TORQUE
+ priv->param.torque = param->torque;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_FORCE
+ priv->param.force = param->force;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_ACCELERATION
+ priv->param.acceleration = param->acceleration;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_DECELERATION
+ priv->param.deceleration = param->deceleration;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_DIRECTION
+ priv->param.direction = param->direction;
+#endif
+ priv->param.lock = false;
+
+ /* Refresh duty and direction on the go */
+
+ if (priv->state.state == MOTOR_STATE_RUN)
+ {
+ float duty = priv->param.speed / priv->limits.speed;
+ esp_motor_set_duty_cycle(priv, duty);
+ esp_motor_bdc_set_direction(priv);
+ }
+
+ mtrinfo("Motor parameters set\n");
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_mode_set
+ *
+ * Description:
+ * Sets the motor operating mode.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ * mode - Must be one of the motor_opmode_e enum.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_mode_set(struct motor_lowerhalf_s *dev, uint8_t mode)
+{
+ DEBUGASSERT(dev != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *) dev;
+
+ if (mode > MOTOR_OPMODE_PATTERN)
+ {
+ mtrerr("Invalid operation mode: %u\n", mode);
+ return -EINVAL;
+ }
+
+ priv->opmode = mode;
+ mtrinfo("Mode set: %u\n", priv->opmode);
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_limits_set
+ *
+ * Description:
+ * Set motor limits. Must be called before start the motor.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ * limits - Pointer to the motor limits data structure.
+ *
+ * Returned Value:
+ * Returns OK on success.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_limits_set(struct motor_lowerhalf_s *dev,
+ struct motor_limits_s *limits)
+{
+ DEBUGASSERT(dev != NULL);
+ DEBUGASSERT(limits != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *) dev;
+
+#ifdef CONFIG_MOTOR_UPPER_HAVE_POSITION
+ priv->limits.position = limits->position;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_SPEED
+ priv->limits.speed = limits->speed;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_TORQUE
+ priv->limits.torque = limits->torque;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_FORCE
+ priv->limits.force = limits->force;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_ACCELERATION
+ priv->limits.acceleration = limits->acceleration;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_DECELERATION
+ priv->limits.deceleration = limits->deceleration;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_VOLTAGE
+ priv->limits.v_in = limits->v_in;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_CURRENT
+ priv->limits.i_in = limits->i_in;
+#endif
+#ifdef CONFIG_MOTOR_UPPER_HAVE_INPUT_POWER
+ priv->limits.p_in = limits->p_in;
+#endif
+ priv->limits.lock = true;
+ mtrinfo("limits set and locked %d\n", priv->limits.lock);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_fault_set
+ *
+ * Description:
+ * Sets the fault state for the motor.
+ *
+ * Input Parameters:
+ * lower - Pointer to the motor channel lower-half data structure.
+ * fault - Fault value. Must be one of motor_fault_e enum.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_fault_set(struct motor_lowerhalf_s *dev, uint8_t fault)
+{
+ DEBUGASSERT(dev != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *) dev;
+
+ if (fault > MOTOR_FAULT_OTHER)
+ {
+ mtrerr("Invalid fault value: %u\n", fault);
+ return -EINVAL;
+ }
+
+ priv->state.state = MOTOR_STATE_FAULT;
+ priv->state.fault |= fault;
+ mtrinfo("%u\n", priv->state.fault);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_state_get
+ *
+ * Description:
+ * Get the current motor state.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ * state - Pointer to the motor state data structure.
+ *
+ * Returned Value:
+ * Returns OK on success.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_state_get(struct motor_lowerhalf_s *dev,
+ struct motor_state_s *state)
+{
+ DEBUGASSERT(dev != NULL);
+ DEBUGASSERT(state != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *) dev;
+
+ state->state = priv->state.state;
+ state->fault = priv->state.fault;
+ memcpy(&state->state, &priv->state, sizeof(struct motor_feedback_s));
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_fault_get
+ *
+ * Description:
+ * Get current motor fault state.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ * fault - Fault state value. Must be one of motor_fault_e enum.
+ *
+ * Returned Value:
+ * Returns OK on success.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_fault_get(struct motor_lowerhalf_s *dev, uint8_t *fault)
+{
+ DEBUGASSERT(dev != NULL);
+ DEBUGASSERT(fault != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *) dev;
+
+ *fault = priv->state.fault;
+ mtrinfo("%u\n", priv->state.fault);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_fault_clear
+ *
+ * Description:
+ * Clears a motor fault.
+ *
+ * Input Parameters:
+ * lower - Pointer to the capture channel lower-half data structure.
+ * fault - Fault state to clear (one of motor_fault_e enum).
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_fault_clear(struct motor_lowerhalf_s *dev,
+ uint8_t fault)
+{
+ DEBUGASSERT(dev != NULL);
+
+ struct mcpwm_motor_lowerhalf_s *priv = (
+ struct mcpwm_motor_lowerhalf_s *) dev;
+
+ if (fault > MOTOR_FAULT_OTHER)
+ {
+ mtrerr("Invalid fault value: %u\n", fault);
+ return -EINVAL;
+ }
+
+ priv->state.fault &= ~fault;
+ if (priv->state.fault == 0)
+ {
+ priv->state.state = MOTOR_STATE_IDLE;
+ mtrinfo("All faults clear\n");
+ return OK;
+ }
+
+ mtrinfo("Fault clear: %u\n", fault);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_ioctl
+ *
+ * Description:
+ * Unused but required for upper-half motor driver.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ * cmd - Custom IOCTL.
+ * arg - Argument to be passed for custom IOCTL.
+ *
+ * Returned Value:
+ * Returns 1.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_ioctl(struct motor_lowerhalf_s *dev, int cmd,
+ unsigned long arg)
+{
+ return 1;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_fault_configure
+ *
+ * Description:
+ * Configure fault detection for motor channel. Enables the interrupt
+ * handling to set and clear fault state and sets brake action on fault
+ * (holds PWM at low state) in one-shot mode.
+ *
+ * Input Parameters:
+ * dev - Pointer to the motor channel lower-half data structure.
+ * enable - True to setup motor fault. False to disable fault detection.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef ESP_MCPMW_MOTOR_FAULT
+static int esp_motor_fault_configure(struct mcpwm_motor_lowerhalf_s *lower,
+ bool enable)
+{
+ DEBUGASSERT(lower != NULL);
+
+ irqstate_t flags;
+ mcpwm_hal_context_t *hal = &lower->common->hal;
+
+ flags = spin_lock_irqsave(&g_mcpwm_common.mcpwm_spinlock);
+ if (!enable)
+ {
+ mcpwm_ll_fault_enable_detection(hal->dev, lower->fault_id, false);
+ mcpwm_ll_intr_enable(hal->dev,
+ MCPWM_LL_EVENT_FAULT_ENTER(lower->fault_id),
+ false);
+ mcpwm_ll_intr_enable(hal->dev,
+ MCPWM_LL_EVENT_FAULT_EXIT(lower->fault_id),
+ false);
+ return OK;
+ }
+
+ /* Detect fault when signal is high and also enable software trigger */
+
+ mcpwm_ll_fault_set_active_level(hal->dev, lower->fault_id, true);
+ mcpwm_ll_fault_enable_detection(hal->dev, lower->fault_id, true);
+ mcpwm_ll_brake_enable_oneshot_mode(hal->dev, lower->operator_id,
+ lower->fault_id, true);
+ mcpwm_ll_brake_enable_soft_ost(hal->dev, lower->operator_id, true);
+
+ /* Make sure the brake event can be triggered when the timer is
+ * counting up AND down because it is running in up-down mode.
+ */
+
+ mcpwm_ll_generator_set_action_on_brake_event(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_0,
+ MCPWM_TIMER_DIRECTION_UP,
+ MCPWM_OPER_BRAKE_MODE_OST,
+ 1);
+ mcpwm_ll_generator_set_action_on_brake_event(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_0,
+ MCPWM_TIMER_DIRECTION_DOWN,
+ MCPWM_OPER_BRAKE_MODE_OST,
+ 1);
+ mcpwm_ll_generator_set_action_on_brake_event(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_1,
+ MCPWM_TIMER_DIRECTION_UP,
+ MCPWM_OPER_BRAKE_MODE_OST,
+ 1);
+ mcpwm_ll_generator_set_action_on_brake_event(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_1,
+ MCPWM_TIMER_DIRECTION_DOWN,
+ MCPWM_OPER_BRAKE_MODE_OST,
+ 1);
+
+ /* Enable interrupt requests for motor fault */
+
+ mcpwm_ll_brake_clear_ost(hal->dev, lower->operator_id);
+ mcpwm_ll_intr_enable(hal->dev,
+ MCPWM_LL_EVENT_FAULT_ENTER(lower->fault_id),
+ true);
+ mcpwm_ll_intr_enable(hal->dev,
+ MCPWM_LL_EVENT_FAULT_EXIT(lower->fault_id),
+ true);
+ mcpwm_ll_intr_clear_status(hal->dev,
+ MCPWM_LL_EVENT_FAULT_ENTER(lower->fault_id));
+ mcpwm_ll_intr_clear_status(hal->dev,
+ MCPWM_LL_EVENT_FAULT_EXIT(lower->fault_id));
+
+ spin_unlock_irqrestore(&g_mcpwm_common.mcpwm_spinlock, flags);
+ mtrinfo("Brake configured for motor channel %d on fault id %d",
+ lower->channel_id, lower->fault_id);
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_set_duty_cycle
+ *
+ * Description:
+ * Sets the duty cycle on output PWM_A and PWM_B.
+ *
+ * Input Parameters:
+ * lower - Pointer to the motor channel lower-half data structure.
+ * duty - Duty-cycle value from 0.0 to 1.0.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_set_duty_cycle(struct mcpwm_motor_lowerhalf_s *lower,
+ float duty)
+{
+ DEBUGASSERT(lower != NULL);
+
+ mcpwm_hal_context_t *hal = &lower->common->hal;
+
+ if (duty < 0.0 || duty > 1.0)
+ {
+ mtrerr("Invalid duty cycle value: %f\n", duty);
+ return -EINVAL;
+ }
+
+ uint32_t pwm_count = -1 * lower->counter_peak * (duty - 1.0);
+ mcpwm_ll_operator_set_compare_value(hal->dev, lower->operator_id,
+ MCPWM_GENERATOR_0, pwm_count);
+ mtrinfo("Duty %f compare value set: %lu\n", duty, pwm_count);
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_motor_bdc_set_direction
+ *
+ * Description:
+ * Sets direction of motor spin by disabling PWM_A or PWM_B. If
+ * CONFIG_MOTOR_UPPER_HAVE_DIRECTION is not defined, defaults to CW.
+ *
+ * Input Parameters:
+ * lower - Pointer to the motor channel lower-half data structure.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_bdc_set_direction(struct mcpwm_motor_lowerhalf_s *lower)
{
- mcpwm_hal_init_config_t group;
- mcpwm_hal_context_t hal;
- spinlock_t mcpwm_spinlock;
- bool initialized; /* MCPWM peripheral and HAL has been initialized
*/
- bool capture_initialized; /* Capture submodule has been initialized */
- int group_prescale;
-};
+ DEBUGASSERT(lower != NULL);
-#ifdef CONFIG_ESP_MCPWM_CAPTURE
-/* Capture event data. The 'last_' value is used to calculate frequency */
+ mcpwm_hal_context_t *hal = &lower->common->hal;
+ int8_t direction;
-struct mcpwm_capture_event_data_s
-{
- uint32_t pos_edge_count;
- uint32_t neg_edge_count;
- uint32_t last_pos_edge_count;
-};
+ if (lower->opmode == MOTOR_OPMODE_SPEED)
+ {
+#ifdef CONFIG_MOTOR_UPPER_HAVE_DIRECTION
+ if (lower->param.direction == MOTOR_DIR_CW)
+ {
+ mcpwm_ll_gen_disable_continue_force_action(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_0);
+ mcpwm_ll_gen_set_continue_force_level(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_1, 0);
+ }
+ else
+ {
+ mcpwm_ll_gen_disable_continue_force_action(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_1);
+ mcpwm_ll_gen_set_continue_force_level(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_0, 0);
+ }
-enum mcpwm_capture_channel_e
-{
- MCPWM_CAP_CHANNEL_0, /* MCPWM capture channel number 0 */
- MCPWM_CAP_CHANNEL_1, /* MCPWM capture channel number 1 */
- MCPWM_CAP_CHANNEL_2, /* MCPWM capture channel number 2 */
- MCPWM_CAP_CHANNEL_MAX /* Number of MCPWM capture channels */
-};
+ direction = lower->param.direction;
+#else
+ mcpwm_ll_gen_disable_continue_force_action(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_0);
+ mcpwm_ll_gen_set_continue_force_level(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_1, 0);
+ direction = MOTOR_DIR_CW;
+#endif
+ }
-/* Lowe-half data structure for a capture channel */
+ mtrinfo("Motor direction set: %d\n", direction);
+ return OK;
+}
+#endif
-struct mcpwm_cap_channel_lowerhalf_s
+/****************************************************************************
+ * Name: esp_motor_pwm_config
+ *
+ * Description:
+ * Configures the control waveform by setting some configurations for
+ * timer events. Included configurations are: speed control.
+ *
+ * Input Parameters:
+ * lower - Pointer to the motor channel lower-half data structure.
+ *
+ * Returned Value:
+ * Returns OK on success.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_motor_pwm_config(struct mcpwm_motor_lowerhalf_s *lower)
{
- /* The following block is part of the upper-half device struct */
+ mcpwm_hal_context_t *hal = &lower->common->hal;
- const struct cap_ops_s *ops;
+ /* Configure PWM_A and PWM_B as complementary */
- /* The following is private to the ESP MCPWM driver */
+ if (lower->opmode == MOTOR_OPMODE_SPEED)
+ {
+ /* PWM_A Output */
+
+ mcpwm_ll_generator_set_action_on_compare_event(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_0,
+ MCPWM_TIMER_DIRECTION_UP,
+ MCPWM_GENERATOR_0,
+ MCPWM_GEN_ACTION_HIGH);
+ mcpwm_ll_generator_set_action_on_compare_event(
+ hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_0,
+ MCPWM_TIMER_DIRECTION_DOWN,
+ MCPWM_GENERATOR_0,
+ MCPWM_GEN_ACTION_LOW);
+
+ /* PWM_B Output */
+
+ mcpwm_ll_generator_set_action_on_compare_event(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_1,
+ MCPWM_TIMER_DIRECTION_UP,
+ MCPWM_GENERATOR_0,
+ MCPWM_GEN_ACTION_HIGH);
+ mcpwm_ll_generator_set_action_on_compare_event(hal->dev,
+ lower->operator_id,
+ MCPWM_GENERATOR_1,
+ MCPWM_TIMER_DIRECTION_DOWN,
+ MCPWM_GENERATOR_0,
+ MCPWM_GEN_ACTION_LOW);
+ }
+ else
+ {
+ mtrerr("Invalid operation mode\n");
+ return -EPERM;
+ }
- struct mcpwm_dev_common_s *common;
- struct mcpwm_capture_event_data_s *data;
- int channel_id;
- int gpio_pin;
- uint32_t clock;
- uint32_t freq;
- uint8_t duty;
- uint8_t isr_count;
- bool ready;
- bool enabled;
-};
+ return OK;
+}
#endif
/****************************************************************************
- * Private Function Prototypes
+ * Name: esp_mcpwm_fault_configure
+ *
+ * Description:
+ * Configures the fault GPIO.
+ *
+ * Input Parameters:
+ * lower - Pointer to the motor channel lower-half data structure.
+ * enable - True to configure motor fault. False to disable.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
****************************************************************************/
-static void esp_mcpwm_group_start(void);
+#ifdef ESP_MCPMW_MOTOR_FAULT
+static int esp_mcpwm_fault_gpio_config(struct mcpwm_motor_lowerhalf_s *lower,
+ bool enable)
+{
+ int ret;
-#ifdef CONFIG_ESP_MCPWM_CAPTURE
-static int esp_mcpwm_capture_set_gpio(
- struct mcpwm_cap_channel_lowerhalf_s *lower);
-static int esp_mcpwm_capture_isr_register(int (*fn)(int, void *, void *),
- void *arg);
-static int IRAM_ATTR mcpwm_capture_driver_isr_default(int irq, void *context,
- void *arg);
+ if (!enable)
+ {
+ esp_gpio_matrix_in(0x3a,
+ mcpwm_periph_signals.groups[MCPWM_CAPTURE_DEFAULT_GROUP].\
+ gpio_faults[lower->fault_id].fault_sig,
+ false);
+ return OK;
+ }
-/* Lower half methods required by capture driver */
+ ret = esp_configgpio(lower->fault_pin, INPUT_PULLDOWN | GPIO_IN_FUNCTION);
+ if (ret < 0)
+ {
+ mtrerr("Failed configuring fault GPIO\n");
+ return ret;
+ }
-static int esp_capture_start(struct cap_lowerhalf_s *lower);
-static int esp_capture_stop(struct cap_lowerhalf_s *lower);
-static int esp_capture_getduty(struct cap_lowerhalf_s *lower,
- uint8_t *duty);
-static int esp_capture_getfreq(struct cap_lowerhalf_s *lower,
- uint32_t *freq);
+ esp_gpio_matrix_in(
+ lower->fault_pin,
+ mcpwm_periph_signals.groups[MCPWM_CAPTURE_DEFAULT_GROUP].\
+ gpio_faults[lower->fault_id].fault_sig,
+ false);
+
+ mtrinfo("Fault signal configured for GPIO %d in channel %d\n",
+ lower->fault_pin, lower->channel_id);
+
+ return ret;
+}
#endif
/****************************************************************************
- * Private Data
+ * Name: esp_mcpwm_motor_set_gpio
+ *
+ * Description:
+ * Configures the GPIO pins to be used as motor PWM output and the fault
+ * GPIO (if enabled).
+ *
+ * Input Parameters:
+ * lower - Pointer to the motor channel lower-half data structure.
+ * enable - True to configure GPIO for motor PWM. False to disable.
+ *
+ * Returned Value:
+ * OK on success, otherwise a negated errno value is returned on
+ * any failure.
+ *
****************************************************************************/
-static struct mcpwm_dev_common_s mcpwm_common =
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+static int esp_mcpwm_motor_set_gpio(struct mcpwm_motor_lowerhalf_s *lower,
+ bool enable)
{
- .group.group_id = MCPWM_CAPTURE_DEFAULT_GROUP,
- .initialized = false,
- .capture_initialized = false,
- .group_prescale = MCPWM_DEV_CLK_PRESCALE,
-};
+ int ret;
-#ifdef CONFIG_ESP_MCPWM_CAPTURE
-/* Lower half methods required by the capture driver */
+ if (!enable)
+ {
+ esp_gpio_matrix_out(lower->generator_pins[MCPWM_GENERATOR_0], 0x100,
+ false, false);
-static const struct cap_ops_s mcpwm_cap_ops =
-{
- .start = esp_capture_start,
- .stop = esp_capture_stop,
- .getduty = esp_capture_getduty,
- .getfreq = esp_capture_getfreq,
-};
+ esp_gpio_matrix_out(lower->generator_pins[MCPWM_GENERATOR_1], 0x100,
+ false, false);
+ return OK;
+ }
-/* Data structures for the available capture channels */
+ ret = esp_configgpio(lower->generator_pins[MCPWM_GENERATOR_0],
+ GPIO_OUT_FUNCTION);
+ if (ret < 0)
+ {
+ mtrerr("Failed configuring PWM_A GPIO\n");
+ return ret;
+ }
-#ifdef CONFIG_ESP_MCPWM_CAPTURE_CH0
-static struct mcpwm_capture_event_data_s event_data_ch0;
-static struct mcpwm_cap_channel_lowerhalf_s mcpwm_cap_ch0_lowerhalf =
-{
- .ops = &mcpwm_cap_ops,
- .common = &mcpwm_common,
- .data = &event_data_ch0,
- .channel_id = MCPWM_CAP_CHANNEL_0,
- .ready = false,
-};
-#endif
+ ret = esp_configgpio(lower->generator_pins[MCPWM_GENERATOR_1],
+ GPIO_OUT_FUNCTION);
+ if (ret < 0)
+ {
+ mtrerr("Failed configuring PWM_B GPIO\n");
+ return ret;
+ }
-#ifdef CONFIG_ESP_MCPWM_CAPTURE_CH1
-static struct mcpwm_capture_event_data_s event_data_ch1;
-static struct mcpwm_cap_channel_lowerhalf_s mcpwm_cap_ch1_lowerhalf =
-{
- .ops = &mcpwm_cap_ops,
- .common = &mcpwm_common,
- .data = &event_data_ch1,
- .channel_id = MCPWM_CAP_CHANNEL_1,
- .ready = false,
-};
+ esp_gpio_matrix_out(
+ lower->generator_pins[MCPWM_GENERATOR_0],
+ mcpwm_periph_signals.groups[MCPWM_CAPTURE_DEFAULT_GROUP].\
+ operators[lower->channel_id].generators[MCPWM_GENERATOR_0].pwm_sig,
+ false, false);
+
+ esp_gpio_matrix_out(
+ lower->generator_pins[MCPWM_GENERATOR_1],
+ mcpwm_periph_signals.groups[MCPWM_CAPTURE_DEFAULT_GROUP].\
+ operators[lower->channel_id].generators[MCPWM_GENERATOR_1].pwm_sig,
+ false, false);
+
+ /* Connects the PWM output to the Capture input */
+
+#ifdef CONFIG_ESP_MCPWM_TEST_LOOPBACK
+ esp_gpio_matrix_out(CONFIG_ESP_MCPWM_CAPTURE_CH0_GPIO,
+ mcpwm_periph_signals.\
+ groups[MCPWM_CAPTURE_DEFAULT_GROUP].\
+ operators[lower->channel_id].\
+ generators[MCPWM_GENERATOR_0].pwm_sig,
+ 0, 0);
+ esp_gpio_matrix_out(CONFIG_ESP_MCPWM_CAPTURE_CH1_GPIO,
+ mcpwm_periph_signals.\
+ groups[MCPWM_CAPTURE_DEFAULT_GROUP].\
+ operators[lower->channel_id].\
+ generators[MCPWM_GENERATOR_1].pwm_sig,
+ 0, 0);
+ mtrinfo("Loopback for capture device is enabled\n");
#endif
-#ifdef CONFIG_ESP_MCPWM_CAPTURE_CH2
-static struct mcpwm_capture_event_data_s event_data_ch2;
-static struct mcpwm_cap_channel_lowerhalf_s mcpwm_cap_ch2_lowerhalf =
-{
- .ops = &mcpwm_cap_ops,
- .common = &mcpwm_common,
- .data = &event_data_ch2,
- .channel_id = MCPWM_CAP_CHANNEL_2,
- .ready = false,
-};
-#endif
-#endif /* CONFIG_ESP_MCPWM_CAPTURE */
+ mtrinfo("GPIO: %d PWM_A configured for channel %d\n",
+ lower->generator_pins[MCPWM_GENERATOR_0],
+ lower->channel_id);
+ mtrinfo("GPIO: %d PWM_B configured for channel %d\n",
+ lower->generator_pins[MCPWM_GENERATOR_1],
+ lower->channel_id);
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
+ return ret;
+}
+#endif
/****************************************************************************
* Name: esp_capture_start
@@ -226,15 +1416,17 @@ static struct mcpwm_cap_channel_lowerhalf_s
mcpwm_cap_ch2_lowerhalf =
#ifdef CONFIG_ESP_MCPWM_CAPTURE
static int esp_capture_start(struct cap_lowerhalf_s *lower)
{
+ DEBUGASSERT(lower != NULL);
+
struct mcpwm_cap_channel_lowerhalf_s *priv = (
struct mcpwm_cap_channel_lowerhalf_s *)lower;
-
- DEBUGASSERT(priv != NULL);
-
+ irqstate_t flags;
mcpwm_hal_context_t *hal = &priv->common->hal;
+ flags = spin_lock_irqsave(priv->common->mcpwm_spinlock);
/* Enable channel and interruption for rising edge */
+ mcpwm_ll_capture_enable_timer(g_mcpwm_common.hal.dev, true);
mcpwm_ll_capture_enable_channel(hal->dev, priv->channel_id, true);
mcpwm_ll_intr_enable(hal->dev,
MCPWM_LL_EVENT_CAPTURE(priv->channel_id),
@@ -252,6 +1444,7 @@ static int esp_capture_start(struct cap_lowerhalf_s *lower)
priv->enabled = true;
priv->ready = false;
+ spin_unlock_irqrestore(priv->common->mcpwm_spinlock, flags);
cpinfo("Channel enabled: %d\n", priv->channel_id);
return OK;
}
@@ -275,21 +1468,24 @@ static int esp_capture_start(struct cap_lowerhalf_s
*lower)
#ifdef CONFIG_ESP_MCPWM_CAPTURE
static int esp_capture_stop(struct cap_lowerhalf_s *lower)
{
+ DEBUGASSERT(lower != NULL);
+
struct mcpwm_cap_channel_lowerhalf_s *priv = (
struct mcpwm_cap_channel_lowerhalf_s *)lower;
-
- DEBUGASSERT(priv != NULL);
-
+ irqstate_t flags;
mcpwm_hal_context_t *hal = &priv->common->hal;
+ flags = spin_lock_irqsave(priv->common->mcpwm_spinlock);
/* Disable channel and interrupts */
+ mcpwm_ll_capture_enable_timer(g_mcpwm_common.hal.dev, false);
mcpwm_ll_capture_enable_channel(hal->dev, priv->channel_id, false);
mcpwm_ll_intr_enable(hal->dev,
MCPWM_LL_EVENT_CAPTURE(priv->channel_id),
false);
priv->enabled = false;
+ spin_unlock_irqrestore(priv->common->mcpwm_spinlock, flags);
cpinfo("Channel disabled: %d\n", priv->channel_id);
return OK;
}
@@ -374,18 +1570,17 @@ static int esp_capture_getfreq(struct cap_lowerhalf_s
*lower,
static void esp_mcpwm_group_start(void)
{
- mcpwm_hal_context_t *hal = &mcpwm_common.hal;
+ mcpwm_hal_context_t *hal = &g_mcpwm_common.hal;
/* HAL and MCPWM Initialization */
periph_module_enable(PERIPH_MCPWM0_MODULE);
- mcpwm_hal_init(hal, &mcpwm_common.group);
- mcpwm_hal_timer_reset(hal, 0);
+ mcpwm_hal_init(hal, &g_mcpwm_common.group);
mcpwm_ll_group_set_clock_source(hal->dev, MCPWM_DEV_CLK_SOURCE);
- mcpwm_ll_group_set_clock_prescale(hal->dev, 4);
+ mcpwm_ll_group_set_clock_prescale(hal->dev, g_mcpwm_common.group_prescale);
mcpwm_ll_group_enable_clock(hal->dev, true);
- mcpwm_common.initialized = true;
+ g_mcpwm_common.initialized = true;
}
/****************************************************************************
@@ -428,7 +1623,7 @@ static int esp_mcpwm_capture_set_gpio(
#endif
/****************************************************************************
- * Name: esp_mcpwm_capture_isr_register
+ * Name: esp_mcpwm_isr_register
*
* Description:
* Registers a callback function for a channel interrupt request.
@@ -443,8 +1638,8 @@ static int esp_mcpwm_capture_set_gpio(
*
****************************************************************************/
-#ifdef CONFIG_ESP_MCPWM_CAPTURE
-static int esp_mcpwm_capture_isr_register(int (*fn)(int, void *, void *),
+#if defined(CONFIG_ESP_MCPWM_CAPTURE) || defined(ESP_MCPMW_MOTOR_FAULT)
+static int esp_mcpwm_isr_register(int (*fn)(int, void *, void *),
void *arg)
{
int cpuint;
@@ -460,8 +1655,8 @@ static int esp_mcpwm_capture_isr_register(int (*fn)(int,
void *, void *),
}
ret = irq_attach(ESP_IRQ_MCPWM0,
- mcpwm_capture_driver_isr_default,
- &mcpwm_common);
+ fn,
+ &g_mcpwm_common);
if (ret < 0)
{
cperr("Couldn't attach IRQ to handler.\n");
@@ -476,7 +1671,7 @@ static int esp_mcpwm_capture_isr_register(int (*fn)(int,
void *, void *),
#endif
/****************************************************************************
- * Name: mcpwm_capture_driver_isr_default
+ * Name: mcpwm_driver_isr_default
*
* Description:
* Default function called when a capture interrupt occurs.
@@ -499,21 +1694,28 @@ static int esp_mcpwm_capture_isr_register(int (*fn)(int,
void *, void *),
*
****************************************************************************/
-#ifdef CONFIG_ESP_MCPWM_CAPTURE
-static int IRAM_ATTR mcpwm_capture_driver_isr_default(int irq, void *context,
- void *arg)
+#if defined(CONFIG_ESP_MCPWM_CAPTURE) || defined(ESP_MCPMW_MOTOR_FAULT)
+static int IRAM_ATTR mcpwm_driver_isr_default(int irq, void *context,
+ void *arg)
{
struct mcpwm_dev_common_s *common = (struct mcpwm_dev_common_s *)arg;
+ uint32_t status;
+ irqstate_t flags;
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
struct mcpwm_cap_channel_lowerhalf_s *lower = NULL;
struct mcpwm_capture_event_data_s *data = NULL;
- irqstate_t flags;
uint32_t cap_value;
- uint32_t status;
mcpwm_capture_edge_t cap_edge;
+#endif
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+ struct mcpwm_motor_lowerhalf_s *priv = NULL;
+#endif
flags = spin_lock_irqsave(common->mcpwm_spinlock);
status = mcpwm_ll_intr_get_status(common->hal.dev);
+ /* Evaluate capture interrupt for all 3 cap channels */
+
if (status & MCPWM_LL_EVENT_CAPTURE(MCPWM_CAP_CHANNEL_0))
{
#ifdef CONFIG_ESP_MCPWM_CAPTURE_CH0
@@ -532,9 +1734,44 @@ static int IRAM_ATTR mcpwm_capture_driver_isr_default(int
irq, void *context,
lower = &mcpwm_cap_ch2_lowerhalf;
}
#endif
- else
+
+ /* Evaluate fault interrupt which can be of the ENTER or EXIT type */
+
+#ifdef CONFIG_ESP_MCPMW_MOTOR_CH0_FAULT
+ if (status & MCPWM_LL_EVENT_FAULT_ENTER(MCPWM_FAULT_0))
+ {
+ priv = &mcpwm_bdc_ch0_lowerhalf;
+ mcpwm_ll_intr_clear_status(common->hal.dev,
+ status &
+ MCPWM_LL_EVENT_FAULT_ENTER(MCPWM_FAULT_0));
+ esp_motor_fault_set((struct motor_lowerhalf_s *)priv,
+ MOTOR_FAULT_OTHER);
+ mcpwm_ll_brake_trigger_soft_ost(common->hal.dev, priv->operator_id);
+ mtrinfo("enter: %lu\n", status);
+ }
+
+ if (status & MCPWM_LL_EVENT_FAULT_EXIT(MCPWM_FAULT_0))
{
- return -ERANGE;
+ priv = &mcpwm_bdc_ch0_lowerhalf;
+ mcpwm_ll_intr_clear_status(common->hal.dev,
+ status &
+ MCPWM_LL_EVENT_FAULT_EXIT(MCPWM_FAULT_0));
+ esp_motor_fault_clear((struct motor_lowerhalf_s *)priv,
+ MOTOR_FAULT_OTHER);
+ mcpwm_ll_brake_clear_ost(common->hal.dev, MCPWM_FAULT_0);
+ mtrinfo("exit: %lu\n", status);
+ }
+#endif
+
+ /* If capture is disabled or the interrupt was not related to it,
+ * simply return. Otherwise, continue executing capture math
+ */
+
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
+ if (lower == NULL)
+ {
+ spin_unlock_irqrestore(common->mcpwm_spinlock, flags);
+ return OK;
}
mcpwm_ll_intr_clear_status(common->hal.dev,
@@ -598,9 +1835,9 @@ static int IRAM_ATTR mcpwm_capture_driver_isr_default(int
irq, void *context,
lower->channel_id,
true);
}
+#endif
spin_unlock_irqrestore(common->mcpwm_spinlock, flags);
-
return OK;
}
#endif
@@ -609,6 +1846,95 @@ static int IRAM_ATTR mcpwm_capture_driver_isr_default(int
irq, void *context,
* Public Functions
****************************************************************************/
+/****************************************************************************
+ * Name: esp_motor_bdc_initialize
+ *
+ * Description:
+ * This function initializes the MCPWM peripheral and configures the
+ * motor control driver.
+ *
+ * Input Parameters:
+ * channel - Channel to be initialized [0-3].
+ * frequency - PWM output frequency in Hz.
+ * pwm_a_pin - GPIO pin for PWM_A output.
+ * pwm_b_pin - GPIO pin for PWM_B output (complements PWM_A).
+ * fault_pin - Indicates input pin to detect fault (to be implemented).
+ *
+ * Returned Value:
+ * On success, this function returns a valid pointer to the Capture device
+ * structure. If the initialization fails, it returns NULL.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR_BDC
+struct motor_lowerhalf_s *esp_motor_bdc_initialize(int channel,
+ uint32_t frequency, int pwm_a_pin, int pwm_b_pin, int fault_pin)
+{
+ struct mcpwm_motor_lowerhalf_s *lower = NULL;
+ uint32_t ref_clock;
+ int ret;
+
+ if ((frequency > MCPWM_MAX_PWM_OUT_FREQ) ||
+ (frequency < MCPWM_MIN_PWM_OUT_FREQ))
+ {
+ mtrerr("Invalid frequency set. Must be between %d and %d Hz\n",
+ MCPWM_MIN_PWM_OUT_FREQ, MCPWM_MAX_PWM_OUT_FREQ);
+ return NULL;
+ }
+
+ if (!g_mcpwm_common.initialized)
+ {
+ esp_mcpwm_group_start();
+ }
+
+#ifdef ESP_MCPMW_MOTOR_FAULT
+ if (!g_mcpwm_common.isr_initialized)
+ {
+ esp_mcpwm_isr_register(mcpwm_driver_isr_default, &g_mcpwm_common);
+ g_mcpwm_common.isr_initialized = true;
+ }
+#endif
+
+ switch (channel)
+ {
+ case 0:
+ lower = &mcpwm_bdc_ch0_lowerhalf;
+ lower->pwm_frequency = frequency;
+ break;
+ default:
+ mtrerr("Invalid channel selection: %d\n", channel);
+ return NULL;
+ }
+
+ lower->generator_pins[MCPWM_GENERATOR_0] = pwm_a_pin;
+ lower->generator_pins[MCPWM_GENERATOR_1] = pwm_b_pin;
+ lower->fault_pin = fault_pin;
+
+ /* Configure GPIOs before starting */
+
+#ifdef ESP_MCPMW_MOTOR_FAULT
+ ret = esp_mcpwm_fault_gpio_config(lower, true);
+ if (ret < 0)
+ {
+ mtrerr("Failed configuring motor fault GPIOs\n");
+ return NULL;
+ }
+#endif
+
+ ret = esp_mcpwm_motor_set_gpio(lower, true);
+ if (ret < 0)
+ {
+ mtrerr("Failed configuring motor PWM GPIOs\n");
+ return NULL;
+ }
+
+ mtrinfo("Ch %d initialized. GPIO: PWM_A: %d | PWM_B: %d | Freq: %lu\n",
+ lower->channel_id, lower->generator_pins[MCPWM_GENERATOR_0],
+ lower->generator_pins[MCPWM_GENERATOR_1], lower->pwm_frequency);
+ return (struct motor_lowerhalf_s *) lower;
+}
+#endif
+
/****************************************************************************
* Name: esp_mcpwm_capture_initialize
*
@@ -636,17 +1962,16 @@ struct cap_lowerhalf_s *esp_mcpwm_capture_initialize(int
channel, int pin)
* and MCPWM Capture group.
*/
- if (!mcpwm_common.initialized)
+ if (!g_mcpwm_common.initialized)
{
esp_mcpwm_group_start();
}
- if (!mcpwm_common.capture_initialized)
+ if (!g_mcpwm_common.isr_initialized)
{
- mcpwm_ll_capture_enable_timer(mcpwm_common.hal.dev, true);
- esp_mcpwm_capture_isr_register(mcpwm_capture_driver_isr_default,
- &mcpwm_common);
- mcpwm_common.capture_initialized = true;
+ esp_mcpwm_isr_register(mcpwm_driver_isr_default,
+ &g_mcpwm_common);
+ g_mcpwm_common.isr_initialized = true;
}
switch (channel)
@@ -678,7 +2003,7 @@ struct cap_lowerhalf_s *esp_mcpwm_capture_initialize(int
channel, int pin)
/* Set the clock to be used when calculating frequency */
lower->gpio_pin = pin;
- lower->clock = group_clock / MCPWM_DEV_CLK_PRESCALE;
+ lower->clock = group_clock / g_mcpwm_common.group_prescale;
/* Configure GPIO pin */
diff --git a/arch/risc-v/src/common/espressif/esp_mcpwm.h
b/arch/risc-v/src/common/espressif/esp_mcpwm.h
index 946f7310d7..6177905d63 100644
--- a/arch/risc-v/src/common/espressif/esp_mcpwm.h
+++ b/arch/risc-v/src/common/espressif/esp_mcpwm.h
@@ -56,6 +56,31 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
+/****************************************************************************
+ * Name: esp_motor_bdc_initialize
+ *
+ * Description:
+ * This function initializes the MCPWM peripheral and configures the
+ * motor control driver.
+ *
+ * Input Parameters:
+ * channel - Channel to be initialized (only 0 available for now).
+ * frequency - PWM output frequency in Hertz.
+ * pwm_a_pin - GPIO pin number for PWM0_A output.
+ * pwm_b_pin - GPIO pin number for PWM0_B output.
+ * fault_pin - GPIO pin number for fault signal input.
+ *
+ * Returned Value:
+ * On success, this function returns a valid pointer to the Capture device
+ * structure. If the initialization fails, it returns NULL.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR_BDC
+struct motor_lowerhalf_s *esp_motor_bdc_initialize(int channel,
+ uint32_t frequency, int pwm_a_pin, int pwm_b_pin, int fault_pin);
+#endif
+
/****************************************************************************
* Name: esp_mcpwm_capture_initialize
*
diff --git a/boards/risc-v/esp32c6/common/include/esp_board_mcpwm.h
b/boards/risc-v/esp32c6/common/include/esp_board_mcpwm.h
index 421fbffd3a..191deab98a 100644
--- a/boards/risc-v/esp32c6/common/include/esp_board_mcpwm.h
+++ b/boards/risc-v/esp32c6/common/include/esp_board_mcpwm.h
@@ -43,7 +43,24 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
-#ifdef CONFIG_ESP_MCPWM_CAPTURE
+/****************************************************************************
+ * Name: board_motor_initialize
+ *
+ * Description:
+ * Initialize MCPWM peripheral for motor control and register the motor
+ * driver.
+ *
+ * Input Parameters:
+ * None.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+int board_motor_initialize(void);
+#endif
/****************************************************************************
* Name: board_capture_initialize
@@ -59,9 +76,10 @@ extern "C"
*
****************************************************************************/
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
int board_capture_initialize(void);
+#endif
-#endif /* CONFIG_ESP_MCPWM_CAPTURE */
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/boards/risc-v/esp32c6/common/src/esp_board_mcpwm.c
b/boards/risc-v/esp32c6/common/src/esp_board_mcpwm.c
index 5229de617c..43a059855a 100644
--- a/boards/risc-v/esp32c6/common/src/esp_board_mcpwm.c
+++ b/boards/risc-v/esp32c6/common/src/esp_board_mcpwm.c
@@ -29,7 +29,12 @@
#include <debug.h>
#include <nuttx/board.h>
+#ifdef CONFIG_MOTOR
+#include <nuttx/motor/motor.h>
+#endif
+#ifdef CONFIG_CAPTURE
#include <nuttx/timers/capture.h>
+#endif
#include <arch/board/board.h>
@@ -39,10 +44,61 @@
* Pre-processor Definitions
****************************************************************************/
+#ifdef CONFIG_ESP_MCPMW_MOTOR_CH0_FAULT
+# define MCPWM_FAULT_GPIO CONFIG_ESP_MCPMW_MOTOR_CH0_FAULT_GPIO
+#else
+# define MCPWM_FAULT_GPIO 0
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
+/****************************************************************************
+ * Name: board_motor_initialize
+ *
+ * Description:
+ * Initialize MCPWM peripheral for motor control and register the motor
+ * driver.
+ *
+ * Input Parameters:
+ * None.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+int board_motor_initialize(void)
+{
+ int ret;
+ struct motor_lowerhalf_s *motor;
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR_CH0
+ motor = esp_motor_bdc_initialize(0,
+ CONFIG_ESP_MCPWM_MOTOR_CH0_PWM_FREQ,
+ CONFIG_ESP_MCPWM_MOTOR_CH0_PWMA_GPIO,
+ CONFIG_ESP_MCPWM_MOTOR_CH0_PWMB_GPIO,
+ MCPWM_FAULT_GPIO);
+ if (motor == NULL)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to start MCPWM BDC Motor: CH0\n");
+ return -ENODEV;
+ }
+
+ ret = motor_register("/dev/motor0", motor);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: motor_register failed: %d\n", ret);
+ return ret;
+ }
+#endif
+
+ return OK;
+}
+#endif
+
/****************************************************************************
* Name: board_capture_initialize
*
@@ -57,6 +113,7 @@
*
****************************************************************************/
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
int board_capture_initialize(void)
{
int ret;
@@ -112,3 +169,4 @@ int board_capture_initialize(void)
return OK;
}
+#endif
diff --git a/boards/risc-v/esp32c6/esp32c6-devkitc/configs/motor/defconfig
b/boards/risc-v/esp32c6/esp32c6-devkitc/configs/motor/defconfig
new file mode 100644
index 0000000000..bf70eb967e
--- /dev/null
+++ b/boards/risc-v/esp32c6/esp32c6-devkitc/configs/motor/defconfig
@@ -0,0 +1,52 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that
includes your
+# modifications.
+#
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="esp32c6-devkitc"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32C6_DEVKITC=y
+CONFIG_ARCH_CHIP="esp32c6"
+CONFIG_ARCH_CHIP_ESP32C6=y
+CONFIG_ARCH_CHIP_ESP32C6WROOM1=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=15000
+CONFIG_BUILTIN=y
+CONFIG_DEV_ZERO=y
+CONFIG_ESPRESSIF_ESP32C6=y
+CONFIG_ESP_MCPWM=y
+CONFIG_ESP_MCPWM_MOTOR=y
+CONFIG_ESP_MCPWM_MOTOR_BDC=y
+CONFIG_ESP_MCPWM_MOTOR_CH0=y
+CONFIG_FS_PROCFS=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_BACKTRACE=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=29
+CONFIG_START_MONTH=11
+CONFIG_START_YEAR=2019
+CONFIG_SYSTEM_DUMPSTACK=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
index 96aadb503b..c9384cc162 100644
--- a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
+++ b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
@@ -348,6 +348,14 @@ int esp_bringup(void)
}
#endif
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+ ret = board_motor_initialize();
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: board_motor_initialize failed: %d\n", ret);
+ }
+#endif
+
/* If we got here then perhaps not all initialization was successful, but
* at least enough succeeded to bring-up NSH with perhaps reduced
* capabilities.
diff --git a/boards/risc-v/esp32h2/common/include/esp_board_mcpwm.h
b/boards/risc-v/esp32h2/common/include/esp_board_mcpwm.h
index 3572dfe2ce..70cc0d2f88 100644
--- a/boards/risc-v/esp32h2/common/include/esp_board_mcpwm.h
+++ b/boards/risc-v/esp32h2/common/include/esp_board_mcpwm.h
@@ -43,7 +43,24 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
-#ifdef CONFIG_ESP_MCPWM_CAPTURE
+/****************************************************************************
+ * Name: board_motor_initialize
+ *
+ * Description:
+ * Initialize MCPWM peripheral for motor control and register the motor
+ * driver.
+ *
+ * Input Parameters:
+ * None.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+int board_motor_initialize(void);
+#endif
/****************************************************************************
* Name: board_capture_initialize
@@ -59,9 +76,10 @@ extern "C"
*
****************************************************************************/
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
int board_capture_initialize(void);
+#endif
-#endif /* CONFIG_ESP_MCPWM_CAPTURE */
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/boards/risc-v/esp32h2/common/src/esp_board_mcpwm.c
b/boards/risc-v/esp32h2/common/src/esp_board_mcpwm.c
index e5a080af07..3a24912107 100644
--- a/boards/risc-v/esp32h2/common/src/esp_board_mcpwm.c
+++ b/boards/risc-v/esp32h2/common/src/esp_board_mcpwm.c
@@ -29,7 +29,12 @@
#include <debug.h>
#include <nuttx/board.h>
+#ifdef CONFIG_MOTOR
+#include <nuttx/motor/motor.h>
+#endif
+#ifdef CONFIG_CAPTURE
#include <nuttx/timers/capture.h>
+#endif
#include <arch/board/board.h>
@@ -39,10 +44,61 @@
* Pre-processor Definitions
****************************************************************************/
+#ifdef CONFIG_ESP_MCPMW_MOTOR_CH0_FAULT
+# define MCPWM_FAULT_GPIO CONFIG_ESP_MCPMW_MOTOR_CH0_FAULT_GPIO
+#else
+# define MCPWM_FAULT_GPIO 0
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
+/****************************************************************************
+ * Name: board_motor_initialize
+ *
+ * Description:
+ * Initialize MCPWM peripheral for motor control and register the motor
+ * driver.
+ *
+ * Input Parameters:
+ * None.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+int board_motor_initialize(void)
+{
+ int ret;
+ struct motor_lowerhalf_s *motor;
+
+#ifdef CONFIG_ESP_MCPWM_MOTOR_CH0
+ motor = esp_motor_bdc_initialize(0,
+ CONFIG_ESP_MCPWM_MOTOR_CH0_PWM_FREQ,
+ CONFIG_ESP_MCPWM_MOTOR_CH0_PWMA_GPIO,
+ CONFIG_ESP_MCPWM_MOTOR_CH0_PWMB_GPIO,
+ MCPWM_FAULT_GPIO);
+ if (motor == NULL)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to start MCPWM BDC Motor: CH0\n");
+ return -ENODEV;
+ }
+
+ ret = motor_register("/dev/motor0", motor);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: motor_register failed: %d\n", ret);
+ return ret;
+ }
+#endif
+
+ return OK;
+}
+#endif
+
/****************************************************************************
* Name: board_capture_initialize
*
@@ -57,6 +113,7 @@
*
****************************************************************************/
+#ifdef CONFIG_ESP_MCPWM_CAPTURE
int board_capture_initialize(void)
{
int ret;
@@ -112,3 +169,4 @@ int board_capture_initialize(void)
return OK;
}
+#endif
diff --git a/boards/risc-v/esp32h2/esp32h2-devkit/configs/motor/defconfig
b/boards/risc-v/esp32h2/esp32h2-devkit/configs/motor/defconfig
new file mode 100644
index 0000000000..b83654b587
--- /dev/null
+++ b/boards/risc-v/esp32h2/esp32h2-devkit/configs/motor/defconfig
@@ -0,0 +1,51 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that
includes your
+# modifications.
+#
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="esp32h2-devkit"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32H2_DEVKIT=y
+CONFIG_ARCH_CHIP="esp32h2"
+CONFIG_ARCH_CHIP_ESP32H2=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=15000
+CONFIG_BUILTIN=y
+CONFIG_DEV_ZERO=y
+CONFIG_ESPRESSIF_ESP32H2=y
+CONFIG_ESP_MCPWM=y
+CONFIG_ESP_MCPWM_MOTOR=y
+CONFIG_ESP_MCPWM_MOTOR_BDC=y
+CONFIG_ESP_MCPWM_MOTOR_CH0=y
+CONFIG_FS_PROCFS=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_BACKTRACE=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=29
+CONFIG_START_MONTH=11
+CONFIG_START_YEAR=2019
+CONFIG_SYSTEM_DUMPSTACK=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
index 499a17b5b5..f6afd1f4d6 100644
--- a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
+++ b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
@@ -315,6 +315,14 @@ int esp_bringup(void)
}
#endif
+#ifdef CONFIG_ESP_MCPWM_MOTOR
+ ret = board_motor_initialize();
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: board_motor_initialize failed: %d\n", ret);
+ }
+#endif
+
/* If we got here then perhaps not all initialization was successful, but
* at least enough succeeded to bring-up NSH with perhaps reduced
* capabilities.