Merge branch 'refactor/cleanup_mcpwm_examples' into 'master'

mcpwm: more clean up (example + LL + doc)

Closes IDF-3295

See merge request espressif/esp-idf!12798
This commit is contained in:
morris 2021-07-29 10:41:07 +00:00
commit f907009056
20 changed files with 497 additions and 379 deletions

View File

@ -11,7 +11,6 @@
#include "esp_err.h"
#include "soc/soc.h"
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#include "esp_intr_alloc.h"
#include "hal/mcpwm_types.h"
@ -46,8 +45,7 @@ typedef enum {
} mcpwm_io_signals_t;
/**
* @brief MCPWM pin number for
*
* @brief pin number for MCPWM
*/
typedef struct {
int mcpwm0a_out_num; /*!<MCPWM0A out pin*/
@ -71,9 +69,9 @@ typedef struct {
* @brief Select MCPWM unit
*/
typedef enum {
MCPWM_UNIT_0 = 0, /*!<MCPWM unit0 selected*/
MCPWM_UNIT_1, /*!<MCPWM unit1 selected*/
MCPWM_UNIT_MAX, /*!<Num of MCPWM units on ESP32*/
MCPWM_UNIT_0, /*!<MCPWM unit0 selected*/
MCPWM_UNIT_1, /*!<MCPWM unit1 selected*/
MCPWM_UNIT_MAX, /*!<Max number of MCPWM units*/
} mcpwm_unit_t;
_Static_assert(MCPWM_UNIT_MAX == SOC_MCPWM_GROUPS, "MCPWM unit number not equal to chip capabilities");
@ -82,19 +80,19 @@ _Static_assert(MCPWM_UNIT_MAX == SOC_MCPWM_GROUPS, "MCPWM unit number not equal
* @brief Select MCPWM timer
*/
typedef enum {
MCPWM_TIMER_0 = 0, /*!<Select MCPWM timer0*/
MCPWM_TIMER_1, /*!<Select MCPWM timer1*/
MCPWM_TIMER_2, /*!<Select MCPWM timer2*/
MCPWM_TIMER_MAX, /*!<Num of MCPWM timers on ESP32*/
MCPWM_TIMER_0, /*!<Select MCPWM timer0*/
MCPWM_TIMER_1, /*!<Select MCPWM timer1*/
MCPWM_TIMER_2, /*!<Select MCPWM timer2*/
MCPWM_TIMER_MAX, /*!<Max number of timers in a unit*/
} mcpwm_timer_t;
/**
* @brief Select MCPWM operator
*/
typedef enum {
MCPWM_GEN_A = 0, /*!<Select MCPWMXA, where 'X' is operator number*/
MCPWM_GEN_B, /*!<Select MCPWMXB, where 'X' is operator number*/
MCPWM_GEN_MAX, /*!<Num of generators to each operator of MCPWM*/
MCPWM_GEN_A, /*!<Select MCPWMXA, where 'X' is operator number*/
MCPWM_GEN_B, /*!<Select MCPWMXB, where 'X' is operator number*/
MCPWM_GEN_MAX, /*!<Num of generators to each operator of MCPWM*/
} mcpwm_generator_t;
//definitions and macros to be back-compatible before IDFv4.1
@ -107,25 +105,25 @@ typedef mcpwm_generator_t mcpwm_operator_t; ///< @deprecated
* @brief MCPWM carrier oneshot mode, in this mode the width of the first pulse of carrier can be programmed
*/
typedef enum {
MCPWM_ONESHOT_MODE_DIS = 0, /*!<Enable oneshot mode*/
MCPWM_ONESHOT_MODE_EN, /*!<Disable oneshot mode*/
MCPWM_ONESHOT_MODE_DIS, /*!<Enable oneshot mode*/
MCPWM_ONESHOT_MODE_EN, /*!<Disable oneshot mode*/
} mcpwm_carrier_os_t;
/**
* @brief MCPWM carrier output inversion, high frequency carrier signal active with MCPWM signal is high
*/
typedef enum {
MCPWM_CARRIER_OUT_IVT_DIS = 0, /*!<Enable carrier output inversion*/
MCPWM_CARRIER_OUT_IVT_EN, /*!<Disable carrier output inversion*/
MCPWM_CARRIER_OUT_IVT_DIS, /*!<Enable carrier output inversion*/
MCPWM_CARRIER_OUT_IVT_EN, /*!<Disable carrier output inversion*/
} mcpwm_carrier_out_ivt_t;
/**
* @brief MCPWM select fault signal input
*/
typedef enum {
MCPWM_SELECT_F0 = 0, /*!<Select F0 as input*/
MCPWM_SELECT_F1, /*!<Select F1 as input*/
MCPWM_SELECT_F2, /*!<Select F2 as input*/
MCPWM_SELECT_F0, /*!<Select F0 as input*/
MCPWM_SELECT_F1, /*!<Select F1 as input*/
MCPWM_SELECT_F2, /*!<Select F2 as input*/
} mcpwm_fault_signal_t;
/**
@ -141,8 +139,8 @@ typedef enum {
* @brief MCPWM select triggering level of fault signal
*/
typedef enum {
MCPWM_LOW_LEVEL_TGR = 0, /*!<Fault condition occurs when fault input signal goes from high to low, currently not supported*/
MCPWM_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
MCPWM_LOW_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes from high to low, currently not supported*/
MCPWM_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
} mcpwm_fault_input_level_t;
/**
@ -189,7 +187,7 @@ typedef enum {
MCPWM_ACTIVE_LOW_COMPLIMENT_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = falling edge delay*/
MCPWM_ACTIVE_RED_FED_FROM_PWMXA, /*!<MCPWMXA = MCPWMXB = rising edge delay as well as falling edge delay, generated from MCPWMXA*/
MCPWM_ACTIVE_RED_FED_FROM_PWMXB, /*!<MCPWMXA = MCPWMXB = rising edge delay as well as falling edge delay, generated from MCPWMXB*/
MCPWM_DEADTIME_TYPE_MAX,
MCPWM_DEADTIME_TYPE_MAX, /*!<Maximum number of supported dead time modes*/
} mcpwm_deadtime_type_t;
/**
@ -220,9 +218,9 @@ typedef mcpwm_output_action_t mcpwm_action_on_pwmxb_t;
* @brief MCPWM select capture signal input
*/
typedef enum {
MCPWM_SELECT_CAP0 = 0, /*!<Select CAP0 as input*/
MCPWM_SELECT_CAP1, /*!<Select CAP1 as input*/
MCPWM_SELECT_CAP2, /*!<Select CAP2 as input*/
MCPWM_SELECT_CAP0, /*!<Select CAP0 as input*/
MCPWM_SELECT_CAP1, /*!<Select CAP1 as input*/
MCPWM_SELECT_CAP2, /*!<Select CAP2 as input*/
} mcpwm_capture_signal_t;
/**
@ -237,7 +235,7 @@ typedef struct {
} mcpwm_config_t;
/**
* @brief MCPWM config carrier structure
* @brief MCPWM carrier configuration structure
*/
typedef struct {
uint8_t carrier_period; /*!<Set carrier period = (carrier_period + 1)*800ns, carrier_period should be < 16*/
@ -249,8 +247,8 @@ typedef struct {
/**
* @brief This function initializes each gpio signal for MCPWM
* @note
* This function initializes one gpio at a time.
*
* @note This function initializes one gpio at a time.
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param io_signal set MCPWM signals, each MCPWM unit has 6 output(MCPWMXA, MCPWMXB) and 9 input(SYNC_X, FAULT_X, CAP_X)
@ -265,8 +263,8 @@ esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal,
/**
* @brief Initialize MCPWM gpio structure
* @note
* This function can be used to initialize more then one gpio at a time.
*
* @note This function initialize a group of MCPWM GPIOs at a time.
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param mcpwm_pin MCPWM pin structure
@ -619,20 +617,19 @@ esp_err_t mcpwm_fault_deinit(mcpwm_unit_t mcpwm_num, mcpwm_fault_signal_t fault_
/**
* @brief Initialize capture submodule
*
* @note Enabling capture feature could also enable the capture interrupt,
* @note Enabling capture feature would also enable the capture interrupt event,
* users have to register an interrupt handler by `mcpwm_isr_register`, and in there, query the capture data.
* @note The capture timer uses APB_CLK (typically 80MHz) as the count source.
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param cap_edge set capture edge, BIT(0) - negative edge, BIT(1) - positive edge
* @param cap_sig capture pin, which needs to be enabled
* @param num_of_pulse count time between rising/falling edge between 2 *(pulses mentioned), counter uses APB_CLK
* [0~MCPWM_LL_MAX_PRESCALE] (MCPWM_LL_MAX_PRESCALE = 255 on ESP32);
* @param num_of_pulse Input capture signal prescaling, num_of_pulse ranges from 0 to 255, representing prescaling from 1 to 256.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig, mcpwm_capture_on_edge_t cap_edge,
uint32_t num_of_pulse);

View File

@ -35,7 +35,8 @@ static const char *TAG = "mcpwm";
#define MCPWM_GEN_ERROR "MCPWM GENERATOR ERROR"
#define MCPWM_DT_ERROR "MCPWM DEADTIME TYPE ERROR"
#define MCPWM_GROUP_CLK_HZ (SOC_MCPWM_BASE_CLK_HZ / 16)
#define MCPWM_GROUP_CLK_PRESCALE (16)
#define MCPWM_GROUP_CLK_HZ (SOC_MCPWM_BASE_CLK_HZ / MCPWM_GROUP_CLK_PRESCALE)
#define MCPWM_TIMER_CLK_HZ (MCPWM_GROUP_CLK_HZ / 10)
_Static_assert(SOC_MCPWM_OPERATORS_PER_GROUP >= SOC_MCPWM_TIMERS_PER_GROUP, "This driver assumes the timer num equals to the operator num.");
@ -100,12 +101,12 @@ esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal,
esp_rom_gpio_connect_out_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].operators[operator_id].generators[generator_id].pwm_sig, 0, 0);
} else if (io_signal <= MCPWM_SYNC_2) { // External sync input signal
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
int ext_sync_id = io_signal - MCPWM_SYNC_0;
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].ext_syncers[ext_sync_id].sync_sig, 0);
int gpio_sync_id = io_signal - MCPWM_SYNC_0;
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].gpio_synchros[gpio_sync_id].sync_sig, 0);
} else if (io_signal <= MCPWM_FAULT_2) { // Fault input signal
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
int fault_id = io_signal - MCPWM_FAULT_0;
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].detectors[fault_id].fault_sig, 0);
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].gpio_faults[fault_id].fault_sig, 0);
} else if (io_signal >= MCPWM_CAP_0 && io_signal <= MCPWM_CAP_2) { // Capture input signal
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
int capture_id = io_signal - MCPWM_CAP_0;
@ -141,7 +142,7 @@ esp_err_t mcpwm_start(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_timer_set_operate_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_START_NO_STOP);
mcpwm_ll_timer_set_execute_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_START_NO_STOP);
mcpwm_critical_exit(mcpwm_num);
return ESP_OK;
}
@ -151,7 +152,7 @@ esp_err_t mcpwm_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_timer_set_operate_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_STOP_AT_ZERO);
mcpwm_ll_timer_set_execute_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_STOP_AT_ZERO);
mcpwm_critical_exit(mcpwm_num);
return ESP_OK;
}
@ -312,10 +313,10 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw
mcpwm_hal_init(hal, &config);
mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_group_set_clock(hal->dev, MCPWM_GROUP_CLK_HZ);
mcpwm_ll_group_set_clock_prescale(hal->dev, MCPWM_GROUP_CLK_PRESCALE);
mcpwm_ll_group_enable_shadow_mode(hal->dev);
mcpwm_ll_group_flush_shadow(hal->dev);
mcpwm_ll_timer_set_clock(hal->dev, timer_num, MCPWM_GROUP_CLK_HZ, MCPWM_TIMER_CLK_HZ);
mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, MCPWM_GROUP_CLK_HZ / MCPWM_TIMER_CLK_HZ);
mcpwm_ll_timer_set_count_mode(hal->dev, timer_num, mcpwm_conf->counter_mode);
mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num);
mcpwm_ll_timer_set_peak(hal->dev, timer_num, MCPWM_TIMER_CLK_HZ / mcpwm_conf->frequency, false);
@ -336,8 +337,8 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_critical_enter(mcpwm_num);
unsigned long long group_clock = mcpwm_ll_group_get_clock(hal->dev);
unsigned long long timer_clock = mcpwm_ll_timer_get_clock(hal->dev, timer_num, group_clock);
unsigned int group_clock = SOC_MCPWM_BASE_CLK_HZ / mcpwm_ll_group_get_clock_prescale(hal->dev);
unsigned int timer_clock = group_clock / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
mcpwm_critical_exit(mcpwm_num);
return (uint32_t)timer_clock;
}
@ -479,7 +480,8 @@ esp_err_t mcpwm_deadtime_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_deadtime_enable_update_delay_on_tez(hal->dev, op, true);
mcpwm_ll_deadtime_set_resolution_same_to_timer(hal->dev, op, false);
// The dead time delay unit equals to MCPWM group resolution
mcpwm_ll_deadtime_resolution_to_timer(hal->dev, op, false);
mcpwm_ll_deadtime_set_rising_delay(hal->dev, op, red + 1);
mcpwm_ll_deadtime_set_falling_delay(hal->dev, op, fed + 1);
switch (dt_mode) {
@ -611,11 +613,12 @@ esp_err_t mcpwm_fault_set_cyc_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_n
mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_fault_enable_cbc_mode(hal->dev, op, fault_sig, true);
mcpwm_ll_fault_enable_cbc_refresh_on_tez(hal->dev, op, true);
mcpwm_ll_fault_enable_oneshot_mode(hal->dev, op, fault_sig, false);
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_FAULT_REACTION_CBC, action_on_pwmxa);
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_UP, MCPWM_FAULT_REACTION_CBC, action_on_pwmxa);
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_FAULT_REACTION_CBC, action_on_pwmxb);
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_UP, MCPWM_FAULT_REACTION_CBC, action_on_pwmxb);
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TRIP_TYPE_CBC, action_on_pwmxa);
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_UP, MCPWM_TRIP_TYPE_CBC, action_on_pwmxa);
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TRIP_TYPE_CBC, action_on_pwmxb);
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_UP, MCPWM_TRIP_TYPE_CBC, action_on_pwmxb);
mcpwm_critical_exit(mcpwm_num);
return ESP_OK;
}
@ -632,10 +635,10 @@ esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
mcpwm_ll_fault_clear_ost(hal->dev, op);
mcpwm_ll_fault_enable_oneshot_mode(hal->dev, op, fault_sig, true);
mcpwm_ll_fault_enable_cbc_mode(hal->dev, op, fault_sig, false);
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_FAULT_REACTION_OST, action_on_pwmxa);
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_UP, MCPWM_FAULT_REACTION_OST, action_on_pwmxa);
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_FAULT_REACTION_OST, action_on_pwmxb);
mcpwm_ll_generator_set_action_on_fault_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_UP, MCPWM_FAULT_REACTION_OST, action_on_pwmxb);
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TRIP_TYPE_OST, action_on_pwmxa);
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 0, MCPWM_TIMER_DIRECTION_UP, MCPWM_TRIP_TYPE_OST, action_on_pwmxa);
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TRIP_TYPE_OST, action_on_pwmxb);
mcpwm_ll_generator_set_action_on_trip_event(hal->dev, op, 1, MCPWM_TIMER_DIRECTION_UP, MCPWM_TRIP_TYPE_OST, action_on_pwmxb);
mcpwm_critical_exit(mcpwm_num);
return ESP_OK;
}
@ -644,7 +647,7 @@ esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t ca
uint32_t num_of_pulse)
{
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
ESP_RETURN_ON_FALSE(num_of_pulse <= MCPWM_LL_MAX_PRESCALE, ESP_ERR_INVALID_ARG, TAG, MCPWM_PRESCALE_ERROR);
ESP_RETURN_ON_FALSE(num_of_pulse <= MCPWM_LL_MAX_CAPTURE_PRESCALE, ESP_ERR_INVALID_ARG, TAG, MCPWM_PRESCALE_ERROR);
ESP_RETURN_ON_FALSE(cap_sig < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR);
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
// enable MCPWM module incase user don't use `mcpwm_init` at all
@ -654,7 +657,7 @@ esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t ca
};
mcpwm_critical_enter(mcpwm_num);
mcpwm_hal_init(hal, &init_config);
mcpwm_ll_group_set_clock(hal->dev, MCPWM_GROUP_CLK_HZ);
mcpwm_ll_group_set_clock_prescale(hal->dev, MCPWM_GROUP_CLK_PRESCALE);
mcpwm_ll_capture_enable_timer(hal->dev, true);
mcpwm_ll_capture_enable_channel(hal->dev, cap_sig, true);
mcpwm_ll_capture_enable_negedge(hal->dev, cap_sig, cap_edge & MCPWM_NEG_EDGE);
@ -707,9 +710,9 @@ esp_err_t mcpwm_sync_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcp
uint32_t set_phase = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false) * phase_val / 1000;
mcpwm_ll_timer_set_sync_phase_value(hal->dev, timer_num, set_phase);
if (sync_sig >= MCPWM_SELECT_SYNC0) {
mcpwm_ll_timer_enable_sync_from_external(hal->dev, timer_num, sync_sig - MCPWM_SELECT_SYNC0);
mcpwm_ll_timer_set_timer_synchro(hal->dev, timer_num, sync_sig - MCPWM_SELECT_SYNC0);
}
mcpwm_ll_timer_sync_out_same_in(hal->dev, timer_num);
mcpwm_ll_timer_sync_out_penetrate(hal->dev, timer_num);
mcpwm_ll_timer_enable_sync_input(hal->dev, timer_num, true);
mcpwm_critical_exit(mcpwm_num);
return ESP_OK;

View File

@ -52,12 +52,12 @@ static esp_err_t test_mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t
esp_rom_gpio_connect_out_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].operators[operator_id].generators[generator_id].pwm_sig, 0, 0);
} else if (io_signal <= MCPWM_SYNC_2) { // External sync input signal
gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
int ext_sync_id = io_signal - MCPWM_SYNC_0;
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].ext_syncers[ext_sync_id].sync_sig, 0);
int gpio_sync_id = io_signal - MCPWM_SYNC_0;
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].gpio_synchros[gpio_sync_id].sync_sig, 0);
} else if (io_signal <= MCPWM_FAULT_2) { // Fault input signal
gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
int fault_id = io_signal - MCPWM_FAULT_0;
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].detectors[fault_id].fault_sig, 0);
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].gpio_faults[fault_id].fault_sig, 0);
} else if (io_signal >= MCPWM_CAP_0 && io_signal <= MCPWM_CAP_2) { // Capture input signal
gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
int capture_id = io_signal - MCPWM_CAP_0;

View File

@ -26,31 +26,36 @@
#include "soc/soc_caps.h"
#include "soc/mcpwm_struct.h"
#include "hal/mcpwm_types.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
/// Get the address of peripheral registers
#define MCPWM_LL_GET_HW(ID) (((ID) == 0) ? &MCPWM0 : &MCPWM1)
#define MCPWM_LL_MAX_PRESCALE 255
#define MCPWM_LL_GET_HW(ID) (((ID) == 0) ? &MCPWM0 : &MCPWM1)
#define MCPWM_LL_MAX_CAPTURE_PRESCALE 255
#define MCPWM_LL_MAX_COMPARE_VALUE 65535
#define MCPWM_LL_MAX_DEAD_DELAY 65535
#define MCPWM_LL_MAX_PHASE_VALUE 65535
/********************* Group registers *******************/
// Set/Get group clock: PWM_clk = CLK_160M / (prescale + 1)
static inline void mcpwm_ll_group_set_clock(mcpwm_dev_t *mcpwm, unsigned long long group_clk_hz)
static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int pre_scale)
{
mcpwm->clk_cfg.prescale = (SOC_MCPWM_BASE_CLK_HZ / group_clk_hz) - 1;
mcpwm->clk_cfg.prescale = pre_scale - 1;
}
static inline unsigned long long mcpwm_ll_group_get_clock(mcpwm_dev_t *mcpwm)
static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm)
{
return SOC_MCPWM_BASE_CLK_HZ / (mcpwm->clk_cfg.prescale + 1);
return mcpwm->clk_cfg.prescale + 1;
}
static inline void mcpwm_ll_group_enable_shadow_mode(mcpwm_dev_t *mcpwm)
{
mcpwm->update_cfg.global_up_en = 1;
// updating of active registers in MCPWM operators should be enabled
mcpwm->update_cfg.op0_up_en = 1;
mcpwm->update_cfg.op1_up_en = 1;
mcpwm->update_cfg.op2_up_en = 1;
@ -58,7 +63,8 @@ static inline void mcpwm_ll_group_enable_shadow_mode(mcpwm_dev_t *mcpwm)
static inline void mcpwm_ll_group_flush_shadow(mcpwm_dev_t *mcpwm)
{
mcpwm->update_cfg.val ^= (1 << 1);
// a toggle can trigger a forced update of all active registers in MCPWM, i.e. shadow->active
mcpwm->update_cfg.global_force_up = ~mcpwm->update_cfg.global_force_up;
}
/********************* Interrupt registers *******************/
@ -129,47 +135,47 @@ static inline uint32_t mcpwm_ll_intr_get_capture_status(mcpwm_dev_t *mcpwm)
static inline void mcpwm_ll_intr_clear_timer_stop_status(mcpwm_dev_t *mcpwm, uint32_t timer_mask)
{
mcpwm->int_clr.val |= (timer_mask & 0x07) << 0;
mcpwm->int_clr.val = (timer_mask & 0x07) << 0;
}
static inline void mcpwm_ll_intr_clear_timer_tez_status(mcpwm_dev_t *mcpwm, uint32_t timer_mask)
{
mcpwm->int_clr.val |= (timer_mask & 0x07) << 3;
mcpwm->int_clr.val = (timer_mask & 0x07) << 3;
}
static inline void mcpwm_ll_intr_clear_timer_tep_status(mcpwm_dev_t *mcpwm, uint32_t timer_mask)
{
mcpwm->int_clr.val |= (timer_mask & 0x07) << 6;
mcpwm->int_clr.val = (timer_mask & 0x07) << 6;
}
static inline void mcpwm_ll_intr_clear_fault_enter_status(mcpwm_dev_t *mcpwm, uint32_t fault_mask)
{
mcpwm->int_clr.val |= (fault_mask & 0x07) << 9;
mcpwm->int_clr.val = (fault_mask & 0x07) << 9;
}
static inline void mcpwm_ll_intr_clear_fault_exit_status(mcpwm_dev_t *mcpwm, uint32_t fault_mask)
{
mcpwm->int_clr.val |= (fault_mask & 0x07) << 12;
mcpwm->int_clr.val = (fault_mask & 0x07) << 12;
}
static inline void mcpwm_ll_intr_clear_compare_status(mcpwm_dev_t *mcpwm, uint32_t operator_mask, uint32_t cmp_id)
{
mcpwm->int_clr.val |= (operator_mask & 0x07) << (15 + cmp_id * 3);
mcpwm->int_clr.val = (operator_mask & 0x07) << (15 + cmp_id * 3);
}
static inline void mcpwm_ll_intr_clear_trip_cbc_status(mcpwm_dev_t *mcpwm, uint32_t cbc_mask)
{
mcpwm->int_clr.val |= (cbc_mask & 0x07) << 21;
mcpwm->int_clr.val = (cbc_mask & 0x07) << 21;
}
static inline void mcpwm_ll_intr_clear_trip_ost_status(mcpwm_dev_t *mcpwm, uint32_t ost_mask)
{
mcpwm->int_clr.val |= (ost_mask & 0x07) << 24;
mcpwm->int_clr.val = (ost_mask & 0x07) << 24;
}
static inline void mcpwm_ll_intr_clear_capture_status(mcpwm_dev_t *mcpwm, uint32_t capture_mask)
{
mcpwm->int_clr.val |= (capture_mask & 0x07) << 27;
mcpwm->int_clr.val = (capture_mask & 0x07) << 27;
}
//////////// enable interrupt for each event ////////////////
@ -201,13 +207,20 @@ static inline void mcpwm_ll_intr_enable_timer_tep(mcpwm_dev_t *mcpwm, uint32_t t
}
}
static inline void mcpwm_ll_intr_enable_fault(mcpwm_dev_t *mcpwm, uint32_t fault_id, bool enable)
static inline void mcpwm_ll_intr_enable_fault_enter(mcpwm_dev_t *mcpwm, uint32_t fault_id, bool enable)
{
if (enable) {
mcpwm->int_ena.val |= 1 << (9 + fault_id); // enter fault interrupt
mcpwm->int_ena.val |= 1 << (12 + fault_id); // exit fault interrupt
} else {
mcpwm->int_ena.val &= ~(1 << (9 + fault_id));
}
}
static inline void mcpwm_ll_intr_enable_fault_exit(mcpwm_dev_t *mcpwm, uint32_t fault_id, bool enable)
{
if (enable) {
mcpwm->int_ena.val |= 1 << (12 + fault_id); // exit fault interrupt
} else {
mcpwm->int_ena.val &= ~(1 << (12 + fault_id));
}
}
@ -221,13 +234,20 @@ static inline void mcpwm_ll_intr_enable_compare(mcpwm_dev_t *mcpwm, uint32_t ope
}
}
static inline void mcpwm_ll_intr_enable_trip(mcpwm_dev_t *mcpwm, uint32_t operator_id, bool enable)
static inline void mcpwm_ll_intr_enable_trip_cbc(mcpwm_dev_t *mcpwm, uint32_t operator_id, bool enable)
{
if (enable) {
mcpwm->int_ena.val |= (1 << (21 + operator_id));
mcpwm->int_ena.val |= (1 << (24 + operator_id));
} else {
mcpwm->int_ena.val &= ~(1 << (21 + operator_id));
}
}
static inline void mcpwm_ll_intr_enable_trip_ost(mcpwm_dev_t *mcpwm, uint32_t operator_id, bool enable)
{
if (enable) {
mcpwm->int_ena.val |= (1 << (24 + operator_id));
} else {
mcpwm->int_ena.val &= ~(1 << (24 + operator_id));
}
}
@ -243,14 +263,14 @@ static inline void mcpwm_ll_intr_enable_capture(mcpwm_dev_t *mcpwm, uint32_t cap
/********************* Timer registers *******************/
static inline void mcpwm_ll_timer_set_clock(mcpwm_dev_t *mcpwm, int timer_id, unsigned long long group_clock, unsigned long long timer_clock)
static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id, uint32_t prescale)
{
mcpwm->timer[timer_id].period.prescale = group_clock / timer_clock - 1;
mcpwm->timer[timer_id].period.prescale = prescale - 1;
}
static inline unsigned long long mcpwm_ll_timer_get_clock(mcpwm_dev_t *mcpwm, int timer_id, unsigned long long group_clock)
static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id)
{
return group_clock / (mcpwm->timer[timer_id].period.prescale + 1);
return mcpwm->timer[timer_id].period.prescale + 1;
}
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
@ -327,9 +347,9 @@ static inline mcpwm_timer_count_mode_t mcpwm_ll_timer_get_count_mode(mcpwm_dev_t
}
}
static inline void mcpwm_ll_timer_set_operate_command(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_operate_cmd_t mode)
static inline void mcpwm_ll_timer_set_execute_command(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_execute_cmd_t cmd)
{
switch (mode) {
switch (cmd) {
case MCPWM_TIMER_STOP_AT_ZERO:
mcpwm->timer[timer_id].mode.start = 0;
break;
@ -348,23 +368,14 @@ static inline void mcpwm_ll_timer_set_operate_command(mcpwm_dev_t *mcpwm, int ti
}
}
static inline void mcpwm_ll_timer_set_count_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t value)
{
// we use software sync to set count value
int previous_phase = mcpwm->timer[timer_id].sync.timer_phase;
mcpwm->timer[timer_id].sync.timer_phase = value;
mcpwm->timer[timer_id].sync.sync_sw = ~mcpwm->timer[timer_id].sync.sync_sw;
mcpwm->timer[timer_id].sync.timer_phase = previous_phase;
}
static inline uint32_t mcpwm_ll_timer_get_count_value(mcpwm_dev_t *mcpwm, int timer_id)
{
return mcpwm->timer[timer_id].status.value;
}
static inline bool mcpwm_ll_is_timer_decreasing(mcpwm_dev_t *mcpwm, int timer_id)
static inline mcpwm_timer_direction_t mcpwm_ll_timer_get_count_direction(mcpwm_dev_t *mcpwm, int timer_id)
{
return mcpwm->timer[timer_id].status.direction;
return mcpwm->timer[timer_id].status.direction ? MCPWM_TIMER_DIRECTION_DOWN : MCPWM_TIMER_DIRECTION_UP;
}
static inline void mcpwm_ll_timer_enable_sync_input(mcpwm_dev_t *mcpwm, int timer_id, bool enable)
@ -372,8 +383,9 @@ static inline void mcpwm_ll_timer_enable_sync_input(mcpwm_dev_t *mcpwm, int time
mcpwm->timer[timer_id].sync.in_en = enable;
}
static inline void mcpwm_ll_timer_sync_out_same_in(mcpwm_dev_t *mcpwm, int timer_id)
static inline void mcpwm_ll_timer_sync_out_penetrate(mcpwm_dev_t *mcpwm, int timer_id)
{
// sync_out is selected to sync_in
mcpwm->timer[timer_id].sync.out_sel = 0;
}
@ -383,47 +395,51 @@ static inline void mcpwm_ll_timer_sync_out_on_timer_event(mcpwm_dev_t *mcpwm, in
mcpwm->timer[timer_id].sync.out_sel = 1;
} else if (event == MCPWM_TIMER_EVENT_PEAK) {
mcpwm->timer[timer_id].sync.out_sel = 2;
} else {
HAL_ASSERT(false);
}
}
static inline void mcpwm_ll_timer_disable_sync_out(mcpwm_dev_t *mcpwm, int timer_id)
{
// sync_out will always be zero
mcpwm->timer[timer_id].sync.out_sel = 3;
}
static inline void mcpwm_ll_timer_trigger_sw_sync(mcpwm_dev_t *mcpwm, int timer_id)
static inline void mcpwm_ll_timer_trigger_soft_sync(mcpwm_dev_t *mcpwm, int timer_id)
{
mcpwm->timer[timer_id].sync.sync_sw = ~mcpwm->timer[timer_id].sync.sync_sw;
}
static inline void mcpwm_ll_timer_set_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t reload_val)
static inline void mcpwm_ll_timer_set_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t phase_value)
{
mcpwm->timer[timer_id].sync.timer_phase = reload_val;
mcpwm->timer[timer_id].sync.timer_phase = phase_value;
}
static inline uint32_t mcpwm_ll_timer_get_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id)
static inline void mcpwm_ll_timer_set_sync_phase_direction(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_direction_t direction)
{
return mcpwm->timer[timer_id].sync.timer_phase;
mcpwm->timer[timer_id].sync.phase_direct = direction;
}
static inline void mcpwm_ll_timer_set_sync_phase_direction(mcpwm_dev_t *mcpwm, int timer_id, bool decrease)
static inline void mcpwm_ll_timer_set_gpio_synchro(mcpwm_dev_t *mcpwm, int timer, int gpio_sync_id)
{
mcpwm->timer[timer_id].sync.phase_direct = decrease;
mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3));
mcpwm->timer_synci_cfg.val |= (gpio_sync_id + 4) << (timer * 3);
}
static inline void mcpwm_ll_timer_enable_sync_from_internal_timer(mcpwm_dev_t *mcpwm, int this_timer, int internal_sync_timer)
static inline void mcpwm_ll_timer_set_timer_synchro(mcpwm_dev_t *mcpwm, int timer, int timer_sync_id)
{
mcpwm->timer_synci_cfg.val &= ~(0x07 << (this_timer * 3));
mcpwm->timer_synci_cfg.val |= (internal_sync_timer + 1) << (this_timer * 3);
mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3));
mcpwm->timer_synci_cfg.val |= (timer_sync_id + 1) << (timer * 3);
}
static inline void mcpwm_ll_timer_enable_sync_from_external(mcpwm_dev_t *mcpwm, int this_timer, int extern_syncer)
static inline void mcpwm_ll_timer_set_soft_synchro(mcpwm_dev_t *mcpwm, int timer)
{
mcpwm->timer_synci_cfg.val &= ~(0x07 << (this_timer * 3));
mcpwm->timer_synci_cfg.val |= (extern_syncer + 4) << (this_timer * 3);
// no sync input is selected, but software sync can still work
mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3));
}
static inline void mcpwm_ll_invert_external_syncer(mcpwm_dev_t *mcpwm, int sync_id, bool invert)
static inline void mcpwm_ll_invert_gpio_synchro(mcpwm_dev_t *mcpwm, int sync_id, bool invert)
{
if (invert) {
mcpwm->timer_synci_cfg.val |= 1 << (sync_id + 9);
@ -524,6 +540,19 @@ static inline void mcpwm_ll_operator_enable_update_action_on_sync(mcpwm_dev_t *m
}
}
static inline void mcpwm_ll_operator_set_trigger_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_id)
{
mcpwm->channel[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->channel[operator_id].gen_cfg0.val |= (fault_id << (4 + 3 * trig_id));
}
static inline void mcpwm_ll_operator_set_trigger_timer_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id)
{
// the timer here is not selectable, must be the one connected with the operator
mcpwm->channel[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->channel[operator_id].gen_cfg0.val |= (3 << (4 + 3 * trig_id));
}
/********************* Generator registers *******************/
static inline void mcpwm_ll_generator_reset_actions(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
@ -567,31 +596,58 @@ static inline void mcpwm_ll_generator_set_action_on_trigger_event(mcpwm_dev_t *m
}
}
static inline void mcpwm_ll_gen_set_onetime_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int action)
static inline void mcpwm_ll_gen_trigger_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = action;
mcpwm->channel[operator_id].gen_force.a_nciforce = ~mcpwm->channel[operator_id].gen_force.a_nciforce;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = action;
mcpwm->channel[operator_id].gen_force.b_nciforce = ~mcpwm->channel[operator_id].gen_force.b_nciforce;
}
}
static inline void mcpwm_ll_gen_set_continuous_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int action)
static inline void mcpwm_ll_gen_disable_continue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // force action immediately
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // update force method immediately
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = action;
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = 0;
} else {
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = action;
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = 0;
}
}
static inline void mcpwm_ll_gen_disable_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = 0;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = 0;
}
}
static inline void mcpwm_ll_gen_set_continue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level)
{
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // update force method immediately
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = level + 1;
} else {
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = level + 1;
}
}
static inline void mcpwm_ll_gen_set_noncontinue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = level + 1;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = level + 1;
}
}
/********************* Dead time registers *******************/
static inline void mcpwm_ll_deadtime_set_resolution_same_to_timer(mcpwm_dev_t *mcpwm, int operator_id, bool same)
static inline void mcpwm_ll_deadtime_resolution_to_timer(mcpwm_dev_t *mcpwm, int operator_id, bool same)
{
// whether to make the resolution of dead time delay module the same to the timer connected with operator
mcpwm->channel[operator_id].db_cfg.clk_sel = same;
}
@ -637,7 +693,7 @@ static inline void mcpwm_ll_deadtime_enable_deb(mcpwm_dev_t *mcpwm, int operator
mcpwm->channel[operator_id].db_cfg.deb_mode = enable;
}
static inline uint32_t mcpwm_ll_deadtime_get_topology_code(mcpwm_dev_t *mcpwm, int operator_id)
static inline uint32_t mcpwm_ll_deadtime_get_switch_topology(mcpwm_dev_t *mcpwm, int operator_id)
{
return (mcpwm->channel[operator_id].db_cfg.deb_mode << 8) | (mcpwm->channel[operator_id].db_cfg.b_outswap << 7) |
(mcpwm->channel[operator_id].db_cfg.a_outswap << 6) | (mcpwm->channel[operator_id].db_cfg.fed_insel << 5) |
@ -781,25 +837,32 @@ static inline void mcpwm_ll_fault_clear_ost(mcpwm_dev_t *mcpwm, int operator_id)
static inline void mcpwm_ll_fault_enable_oneshot_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable)
{
if (fault_sig == 0) {
mcpwm->channel[operator_id].tz_cfg0.f0_ost = enable;
} else if (fault_sig == 1) {
mcpwm->channel[operator_id].tz_cfg0.f1_ost = enable;
} else {
mcpwm->channel[operator_id].tz_cfg0.f2_ost = enable;
}
mcpwm->channel[operator_id].tz_cfg0.val &= ~(1 << (7 - fault_sig));
mcpwm->channel[operator_id].tz_cfg0.val |= (enable << (7 - fault_sig));
}
static inline void mcpwm_ll_fault_enable_cbc_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable)
{
if (fault_sig == 0) {
mcpwm->channel[operator_id].tz_cfg0.f0_cbc = enable;
} else if (fault_sig == 1) {
mcpwm->channel[operator_id].tz_cfg0.f1_cbc = enable;
mcpwm->channel[operator_id].tz_cfg0.val &= ~(1 << (3 - fault_sig));
mcpwm->channel[operator_id].tz_cfg0.val |= (enable << (3 - fault_sig));
}
static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].tz_cfg1.val |= 1 << 1;
} else {
mcpwm->channel[operator_id].tz_cfg0.f2_cbc = enable;
mcpwm->channel[operator_id].tz_cfg1.val &= ~(1 << 1);
}
}
static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].tz_cfg1.val |= 1 << 2;
} else {
mcpwm->channel[operator_id].tz_cfg1.val &= ~(1 << 2);
}
mcpwm->channel[operator_id].tz_cfg1.cbcpulse = 1 << 0;
}
static inline void mcpwm_ll_fault_enable_sw_cbc(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
@ -817,20 +880,20 @@ static inline void mcpwm_ll_fault_trigger_sw_cbc(mcpwm_dev_t *mcpwm, int operato
mcpwm->channel[operator_id].tz_cfg1.force_cbc = ~mcpwm->channel[operator_id].tz_cfg1.force_cbc;
}
static inline void mcpwm_ll_fault_trigger_sw_oneshot(mcpwm_dev_t *mcpwm, int operator_id)
static inline void mcpwm_ll_fault_trigger_sw_ost(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].tz_cfg1.force_ost = ~mcpwm->channel[operator_id].tz_cfg1.force_ost;
}
static inline void mcpwm_ll_generator_set_action_on_fault_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id,
mcpwm_timer_direction_t direction, mcpwm_fault_reaction_t reaction, int action)
static inline void mcpwm_ll_generator_set_action_on_trip_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id,
mcpwm_timer_direction_t direction, mcpwm_trip_type_t trip, int action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) {
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * reaction + 2));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * reaction + 2);
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip + 2));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip + 2);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) {
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * reaction));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * reaction);
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip);
}
}
@ -856,12 +919,12 @@ static inline void mcpwm_ll_capture_enable_channel(mcpwm_dev_t *mcpwm, int chann
mcpwm->cap_cfg_ch[channel].en = enable;
}
static inline void mcpwm_ll_capture_set_sync_phase(mcpwm_dev_t *mcpwm, uint32_t phase_value)
static inline void mcpwm_ll_capture_set_sync_phase_value(mcpwm_dev_t *mcpwm, uint32_t phase_value)
{
mcpwm->cap_timer_phase = phase_value;
}
static inline uint32_t mcpwm_ll_capture_get_sync_phase(mcpwm_dev_t *mcpwm)
static inline uint32_t mcpwm_ll_capture_get_sync_phase_value(mcpwm_dev_t *mcpwm)
{
return mcpwm->cap_timer_phase;
}
@ -871,14 +934,14 @@ static inline void mcpwm_ll_capture_enable_timer_sync(mcpwm_dev_t *mcpwm, bool e
mcpwm->cap_timer_cfg.synci_en = enable;
}
static inline void mcpwm_ll_capture_set_internal_timer_syncer(mcpwm_dev_t *mcpwm, int sync_out_timer)
static inline void mcpwm_ll_capture_set_internal_timer_synchro(mcpwm_dev_t *mcpwm, int sync_out_timer)
{
mcpwm->cap_timer_cfg.synci_sel = sync_out_timer + 1;
}
static inline void mcpwm_ll_capture_set_external_syncer(mcpwm_dev_t *mcpwm, int extern_syncer)
static inline void mcpwm_ll_capture_set_external_synchro(mcpwm_dev_t *mcpwm, int extern_synchro)
{
mcpwm->cap_timer_cfg.synci_sel = extern_syncer + 4;
mcpwm->cap_timer_cfg.synci_sel = extern_synchro + 4;
}
static inline void mcpwm_ll_capture_trigger_sw_sync(mcpwm_dev_t *mcpwm)

View File

@ -26,6 +26,7 @@
#include "soc/soc_caps.h"
#include "soc/mcpwm_struct.h"
#include "hal/mcpwm_types.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
@ -33,24 +34,28 @@ extern "C" {
/// Get the address of peripheral registers
#define MCPWM_LL_GET_HW(ID) (((ID) == 0) ? &MCPWM0 : &MCPWM1)
#define MCPWM_LL_MAX_PRESCALE 255
#define MCPWM_LL_MAX_CAPTURE_PRESCALE 255
#define MCPWM_LL_MAX_COMPARE_VALUE 65535
#define MCPWM_LL_MAX_DEAD_DELAY 65535
#define MCPWM_LL_MAX_PHASE_VALUE 65535
/********************* Group registers *******************/
// Set/Get group clock: PWM_clk = CLK_160M / (prescale + 1)
static inline void mcpwm_ll_group_set_clock(mcpwm_dev_t *mcpwm, unsigned long long group_clk_hz)
static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int pre_scale)
{
mcpwm->clk_cfg.prescale = (SOC_MCPWM_BASE_CLK_HZ / group_clk_hz) - 1;
mcpwm->clk_cfg.prescale = pre_scale - 1;
}
static inline unsigned long long mcpwm_ll_group_get_clock(mcpwm_dev_t *mcpwm)
static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm)
{
return SOC_MCPWM_BASE_CLK_HZ / (mcpwm->clk_cfg.prescale + 1);
return mcpwm->clk_cfg.prescale + 1;
}
static inline void mcpwm_ll_group_enable_shadow_mode(mcpwm_dev_t *mcpwm)
{
mcpwm->update_cfg.global_up_en = 1;
// updating of active registers in MCPWM operators should be enabled
mcpwm->update_cfg.op0_up_en = 1;
mcpwm->update_cfg.op1_up_en = 1;
mcpwm->update_cfg.op2_up_en = 1;
@ -58,7 +63,8 @@ static inline void mcpwm_ll_group_enable_shadow_mode(mcpwm_dev_t *mcpwm)
static inline void mcpwm_ll_group_flush_shadow(mcpwm_dev_t *mcpwm)
{
mcpwm->update_cfg.val ^= (1 << 1);
// a toggle can trigger a forced update of all active registers in MCPWM, i.e. shadow->active
mcpwm->update_cfg.global_force_up = ~mcpwm->update_cfg.global_force_up;
}
/********************* Interrupt registers *******************/
@ -129,47 +135,47 @@ static inline uint32_t mcpwm_ll_intr_get_capture_status(mcpwm_dev_t *mcpwm)
static inline void mcpwm_ll_intr_clear_timer_stop_status(mcpwm_dev_t *mcpwm, uint32_t timer_mask)
{
mcpwm->int_clr.val |= (timer_mask & 0x07) << 0;
mcpwm->int_clr.val = (timer_mask & 0x07) << 0;
}
static inline void mcpwm_ll_intr_clear_timer_tez_status(mcpwm_dev_t *mcpwm, uint32_t timer_mask)
{
mcpwm->int_clr.val |= (timer_mask & 0x07) << 3;
mcpwm->int_clr.val = (timer_mask & 0x07) << 3;
}
static inline void mcpwm_ll_intr_clear_timer_tep_status(mcpwm_dev_t *mcpwm, uint32_t timer_mask)
{
mcpwm->int_clr.val |= (timer_mask & 0x07) << 6;
mcpwm->int_clr.val = (timer_mask & 0x07) << 6;
}
static inline void mcpwm_ll_intr_clear_fault_enter_status(mcpwm_dev_t *mcpwm, uint32_t fault_mask)
{
mcpwm->int_clr.val |= (fault_mask & 0x07) << 9;
mcpwm->int_clr.val = (fault_mask & 0x07) << 9;
}
static inline void mcpwm_ll_intr_clear_fault_exit_status(mcpwm_dev_t *mcpwm, uint32_t fault_mask)
{
mcpwm->int_clr.val |= (fault_mask & 0x07) << 12;
mcpwm->int_clr.val = (fault_mask & 0x07) << 12;
}
static inline void mcpwm_ll_intr_clear_compare_status(mcpwm_dev_t *mcpwm, uint32_t operator_mask, uint32_t cmp_id)
{
mcpwm->int_clr.val |= (operator_mask & 0x07) << (15 + cmp_id * 3);
mcpwm->int_clr.val = (operator_mask & 0x07) << (15 + cmp_id * 3);
}
static inline void mcpwm_ll_intr_clear_trip_cbc_status(mcpwm_dev_t *mcpwm, uint32_t cbc_mask)
{
mcpwm->int_clr.val |= (cbc_mask & 0x07) << 21;
mcpwm->int_clr.val = (cbc_mask & 0x07) << 21;
}
static inline void mcpwm_ll_intr_clear_trip_ost_status(mcpwm_dev_t *mcpwm, uint32_t ost_mask)
{
mcpwm->int_clr.val |= (ost_mask & 0x07) << 24;
mcpwm->int_clr.val = (ost_mask & 0x07) << 24;
}
static inline void mcpwm_ll_intr_clear_capture_status(mcpwm_dev_t *mcpwm, uint32_t capture_mask)
{
mcpwm->int_clr.val |= (capture_mask & 0x07) << 27;
mcpwm->int_clr.val = (capture_mask & 0x07) << 27;
}
//////////// enable interrupt for each event ////////////////
@ -201,13 +207,20 @@ static inline void mcpwm_ll_intr_enable_timer_tep(mcpwm_dev_t *mcpwm, uint32_t t
}
}
static inline void mcpwm_ll_intr_enable_fault(mcpwm_dev_t *mcpwm, uint32_t fault_id, bool enable)
static inline void mcpwm_ll_intr_enable_fault_enter(mcpwm_dev_t *mcpwm, uint32_t fault_id, bool enable)
{
if (enable) {
mcpwm->int_ena.val |= 1 << (9 + fault_id); // enter fault interrupt
mcpwm->int_ena.val |= 1 << (12 + fault_id); // exit fault interrupt
} else {
mcpwm->int_ena.val &= ~(1 << (9 + fault_id));
}
}
static inline void mcpwm_ll_intr_enable_fault_exit(mcpwm_dev_t *mcpwm, uint32_t fault_id, bool enable)
{
if (enable) {
mcpwm->int_ena.val |= 1 << (12 + fault_id); // exit fault interrupt
} else {
mcpwm->int_ena.val &= ~(1 << (12 + fault_id));
}
}
@ -221,13 +234,20 @@ static inline void mcpwm_ll_intr_enable_compare(mcpwm_dev_t *mcpwm, uint32_t ope
}
}
static inline void mcpwm_ll_intr_enable_trip(mcpwm_dev_t *mcpwm, uint32_t operator_id, bool enable)
static inline void mcpwm_ll_intr_enable_trip_cbc(mcpwm_dev_t *mcpwm, uint32_t operator_id, bool enable)
{
if (enable) {
mcpwm->int_ena.val |= (1 << (21 + operator_id));
mcpwm->int_ena.val |= (1 << (24 + operator_id));
} else {
mcpwm->int_ena.val &= ~(1 << (21 + operator_id));
}
}
static inline void mcpwm_ll_intr_enable_trip_ost(mcpwm_dev_t *mcpwm, uint32_t operator_id, bool enable)
{
if (enable) {
mcpwm->int_ena.val |= (1 << (24 + operator_id));
} else {
mcpwm->int_ena.val &= ~(1 << (24 + operator_id));
}
}
@ -243,14 +263,14 @@ static inline void mcpwm_ll_intr_enable_capture(mcpwm_dev_t *mcpwm, uint32_t cap
/********************* Timer registers *******************/
static inline void mcpwm_ll_timer_set_clock(mcpwm_dev_t *mcpwm, int timer_id, unsigned long long group_clock, unsigned long long timer_clock)
static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id, uint32_t prescale)
{
mcpwm->timer[timer_id].period.prescale = group_clock / timer_clock - 1;
mcpwm->timer[timer_id].period.prescale = prescale - 1;
}
static inline unsigned long long mcpwm_ll_timer_get_clock(mcpwm_dev_t *mcpwm, int timer_id, unsigned long long group_clock)
static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id)
{
return group_clock / (mcpwm->timer[timer_id].period.prescale + 1);
return mcpwm->timer[timer_id].period.prescale + 1;
}
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
@ -327,9 +347,9 @@ static inline mcpwm_timer_count_mode_t mcpwm_ll_timer_get_count_mode(mcpwm_dev_t
}
}
static inline void mcpwm_ll_timer_set_operate_command(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_operate_cmd_t mode)
static inline void mcpwm_ll_timer_set_execute_command(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_execute_cmd_t cmd)
{
switch (mode) {
switch (cmd) {
case MCPWM_TIMER_STOP_AT_ZERO:
mcpwm->timer[timer_id].mode.start = 0;
break;
@ -348,23 +368,23 @@ static inline void mcpwm_ll_timer_set_operate_command(mcpwm_dev_t *mcpwm, int ti
}
}
static inline void mcpwm_ll_timer_set_count_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t value)
{
// we use software sync to set count value
int previous_phase = mcpwm->timer[timer_id].sync.timer_phase;
mcpwm->timer[timer_id].sync.timer_phase = value;
mcpwm->timer[timer_id].sync.sync_sw = ~mcpwm->timer[timer_id].sync.sync_sw;
mcpwm->timer[timer_id].sync.timer_phase = previous_phase;
}
static inline uint32_t mcpwm_ll_timer_get_count_value(mcpwm_dev_t *mcpwm, int timer_id)
{
return mcpwm->timer[timer_id].status.value;
// status.value saves the "next count value", so need an extra round up here to get the current count value according to count mode
// timer is paused
if (mcpwm->timer[timer_id].mode.mode == 0) {
return mcpwm->timer[timer_id].status.value;
}
if (mcpwm->timer[timer_id].status.direction) { // down direction
return (mcpwm->timer[timer_id].status.value + 1) % (mcpwm->timer[timer_id].period.period + 1);
}
// up direction
return (mcpwm->timer[timer_id].status.value + mcpwm->timer[timer_id].period.period) % (mcpwm->timer[timer_id].period.period + 1);
}
static inline bool mcpwm_ll_is_timer_decreasing(mcpwm_dev_t *mcpwm, int timer_id)
static inline mcpwm_timer_direction_t mcpwm_ll_timer_get_count_direction(mcpwm_dev_t *mcpwm, int timer_id)
{
return mcpwm->timer[timer_id].status.direction;
return mcpwm->timer[timer_id].status.direction ? MCPWM_TIMER_DIRECTION_DOWN : MCPWM_TIMER_DIRECTION_UP;
}
static inline void mcpwm_ll_timer_enable_sync_input(mcpwm_dev_t *mcpwm, int timer_id, bool enable)
@ -372,8 +392,9 @@ static inline void mcpwm_ll_timer_enable_sync_input(mcpwm_dev_t *mcpwm, int time
mcpwm->timer[timer_id].sync.in_en = enable;
}
static inline void mcpwm_ll_timer_sync_out_same_in(mcpwm_dev_t *mcpwm, int timer_id)
static inline void mcpwm_ll_timer_sync_out_penetrate(mcpwm_dev_t *mcpwm, int timer_id)
{
// sync_out is selected to sync_in
mcpwm->timer[timer_id].sync.out_sel = 0;
}
@ -383,47 +404,51 @@ static inline void mcpwm_ll_timer_sync_out_on_timer_event(mcpwm_dev_t *mcpwm, in
mcpwm->timer[timer_id].sync.out_sel = 1;
} else if (event == MCPWM_TIMER_EVENT_PEAK) {
mcpwm->timer[timer_id].sync.out_sel = 2;
} else {
HAL_ASSERT(false);
}
}
static inline void mcpwm_ll_timer_disable_sync_out(mcpwm_dev_t *mcpwm, int timer_id)
{
// sync_out will always be zero
mcpwm->timer[timer_id].sync.out_sel = 3;
}
static inline void mcpwm_ll_timer_trigger_sw_sync(mcpwm_dev_t *mcpwm, int timer_id)
static inline void mcpwm_ll_timer_trigger_soft_sync(mcpwm_dev_t *mcpwm, int timer_id)
{
mcpwm->timer[timer_id].sync.sync_sw = ~mcpwm->timer[timer_id].sync.sync_sw;
}
static inline void mcpwm_ll_timer_set_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t reload_val)
static inline void mcpwm_ll_timer_set_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t phase_value)
{
mcpwm->timer[timer_id].sync.timer_phase = reload_val;
mcpwm->timer[timer_id].sync.timer_phase = phase_value;
}
static inline uint32_t mcpwm_ll_timer_get_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id)
static inline void mcpwm_ll_timer_set_sync_phase_direction(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_direction_t direction)
{
return mcpwm->timer[timer_id].sync.timer_phase;
mcpwm->timer[timer_id].sync.phase_direct = direction;
}
static inline void mcpwm_ll_timer_set_sync_phase_direction(mcpwm_dev_t *mcpwm, int timer_id, bool decrease)
static inline void mcpwm_ll_timer_set_gpio_synchro(mcpwm_dev_t *mcpwm, int timer, int gpio_sync_id)
{
mcpwm->timer[timer_id].sync.phase_direct = decrease;
mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3));
mcpwm->timer_synci_cfg.val |= (gpio_sync_id + 4) << (timer * 3);
}
static inline void mcpwm_ll_timer_enable_sync_from_internal_timer(mcpwm_dev_t *mcpwm, int this_timer, int internal_sync_timer)
static inline void mcpwm_ll_timer_set_timer_synchro(mcpwm_dev_t *mcpwm, int timer, int timer_sync_id)
{
mcpwm->timer_synci_cfg.val &= ~(0x07 << (this_timer * 3));
mcpwm->timer_synci_cfg.val |= (internal_sync_timer + 1) << (this_timer * 3);
mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3));
mcpwm->timer_synci_cfg.val |= (timer_sync_id + 1) << (timer * 3);
}
static inline void mcpwm_ll_timer_enable_sync_from_external(mcpwm_dev_t *mcpwm, int this_timer, int extern_syncer)
static inline void mcpwm_ll_timer_set_soft_synchro(mcpwm_dev_t *mcpwm, int timer)
{
mcpwm->timer_synci_cfg.val &= ~(0x07 << (this_timer * 3));
mcpwm->timer_synci_cfg.val |= (extern_syncer + 4) << (this_timer * 3);
// no sync input is selected, but software sync can still work
mcpwm->timer_synci_cfg.val &= ~(0x07 << (timer * 3));
}
static inline void mcpwm_ll_invert_external_syncer(mcpwm_dev_t *mcpwm, int sync_id, bool invert)
static inline void mcpwm_ll_invert_gpio_synchro(mcpwm_dev_t *mcpwm, int sync_id, bool invert)
{
if (invert) {
mcpwm->timer_synci_cfg.val |= 1 << (sync_id + 9);
@ -524,6 +549,19 @@ static inline void mcpwm_ll_operator_enable_update_action_on_sync(mcpwm_dev_t *m
}
}
static inline void mcpwm_ll_operator_set_trigger_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_id)
{
mcpwm->channel[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->channel[operator_id].gen_cfg0.val |= (fault_id << (4 + 3 * trig_id));
}
static inline void mcpwm_ll_operator_set_trigger_timer_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id)
{
// the timer here is not selectable, must be the one connected with the operator
mcpwm->channel[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->channel[operator_id].gen_cfg0.val |= (3 << (4 + 3 * trig_id));
}
/********************* Generator registers *******************/
static inline void mcpwm_ll_generator_reset_actions(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
@ -567,31 +605,58 @@ static inline void mcpwm_ll_generator_set_action_on_trigger_event(mcpwm_dev_t *m
}
}
static inline void mcpwm_ll_gen_set_onetime_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int action)
static inline void mcpwm_ll_gen_trigger_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = action;
mcpwm->channel[operator_id].gen_force.a_nciforce = ~mcpwm->channel[operator_id].gen_force.a_nciforce;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = action;
mcpwm->channel[operator_id].gen_force.b_nciforce = ~mcpwm->channel[operator_id].gen_force.b_nciforce;
}
}
static inline void mcpwm_ll_gen_set_continuous_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int action)
static inline void mcpwm_ll_gen_disable_continue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // force action immediately
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // update force method immediately
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = action;
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = 0;
} else {
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = action;
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = 0;
}
}
static inline void mcpwm_ll_gen_disable_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = 0;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = 0;
}
}
static inline void mcpwm_ll_gen_set_continue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level)
{
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // update force method immediately
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = level + 1;
} else {
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = level + 1;
}
}
static inline void mcpwm_ll_gen_set_noncontinue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = level + 1;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = level + 1;
}
}
/********************* Dead time registers *******************/
static inline void mcpwm_ll_deadtime_set_resolution_same_to_timer(mcpwm_dev_t *mcpwm, int operator_id, bool same)
static inline void mcpwm_ll_deadtime_resolution_to_timer(mcpwm_dev_t *mcpwm, int operator_id, bool same)
{
// whether to make the resolution of dead time delay module the same to the timer connected with operator
mcpwm->channel[operator_id].db_cfg.clk_sel = same;
}
@ -637,7 +702,7 @@ static inline void mcpwm_ll_deadtime_enable_deb(mcpwm_dev_t *mcpwm, int operator
mcpwm->channel[operator_id].db_cfg.deb_mode = enable;
}
static inline uint32_t mcpwm_ll_deadtime_get_topology_code(mcpwm_dev_t *mcpwm, int operator_id)
static inline uint32_t mcpwm_ll_deadtime_get_switch_topology(mcpwm_dev_t *mcpwm, int operator_id)
{
return (mcpwm->channel[operator_id].db_cfg.deb_mode << 8) | (mcpwm->channel[operator_id].db_cfg.b_outswap << 7) |
(mcpwm->channel[operator_id].db_cfg.a_outswap << 6) | (mcpwm->channel[operator_id].db_cfg.fed_insel << 5) |
@ -781,25 +846,32 @@ static inline void mcpwm_ll_fault_clear_ost(mcpwm_dev_t *mcpwm, int operator_id)
static inline void mcpwm_ll_fault_enable_oneshot_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable)
{
if (fault_sig == 0) {
mcpwm->channel[operator_id].tz_cfg0.f0_ost = enable;
} else if (fault_sig == 1) {
mcpwm->channel[operator_id].tz_cfg0.f1_ost = enable;
} else {
mcpwm->channel[operator_id].tz_cfg0.f2_ost = enable;
}
mcpwm->channel[operator_id].tz_cfg0.val &= ~(1 << (7 - fault_sig));
mcpwm->channel[operator_id].tz_cfg0.val |= (enable << (7 - fault_sig));
}
static inline void mcpwm_ll_fault_enable_cbc_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable)
{
if (fault_sig == 0) {
mcpwm->channel[operator_id].tz_cfg0.f0_cbc = enable;
} else if (fault_sig == 1) {
mcpwm->channel[operator_id].tz_cfg0.f1_cbc = enable;
mcpwm->channel[operator_id].tz_cfg0.val &= ~(1 << (3 - fault_sig));
mcpwm->channel[operator_id].tz_cfg0.val |= (enable << (3 - fault_sig));
}
static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].tz_cfg1.val |= 1 << 1;
} else {
mcpwm->channel[operator_id].tz_cfg0.f2_cbc = enable;
mcpwm->channel[operator_id].tz_cfg1.val &= ~(1 << 1);
}
}
static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].tz_cfg1.val |= 1 << 2;
} else {
mcpwm->channel[operator_id].tz_cfg1.val &= ~(1 << 2);
}
mcpwm->channel[operator_id].tz_cfg1.cbcpulse = 1 << 0;
}
static inline void mcpwm_ll_fault_enable_sw_cbc(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
@ -817,20 +889,20 @@ static inline void mcpwm_ll_fault_trigger_sw_cbc(mcpwm_dev_t *mcpwm, int operato
mcpwm->channel[operator_id].tz_cfg1.force_cbc = ~mcpwm->channel[operator_id].tz_cfg1.force_cbc;
}
static inline void mcpwm_ll_fault_trigger_sw_oneshot(mcpwm_dev_t *mcpwm, int operator_id)
static inline void mcpwm_ll_fault_trigger_sw_ost(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].tz_cfg1.force_ost = ~mcpwm->channel[operator_id].tz_cfg1.force_ost;
}
static inline void mcpwm_ll_generator_set_action_on_fault_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id,
mcpwm_timer_direction_t direction, mcpwm_fault_reaction_t reaction, int action)
static inline void mcpwm_ll_generator_set_action_on_trip_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id,
mcpwm_timer_direction_t direction, mcpwm_trip_type_t trip, int action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) {
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * reaction + 2));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * reaction + 2);
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip + 2));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip + 2);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) {
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * reaction));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * reaction);
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip);
}
}
@ -856,12 +928,12 @@ static inline void mcpwm_ll_capture_enable_channel(mcpwm_dev_t *mcpwm, int chann
mcpwm->cap_cfg_ch[channel].en = enable;
}
static inline void mcpwm_ll_capture_set_sync_phase(mcpwm_dev_t *mcpwm, uint32_t phase_value)
static inline void mcpwm_ll_capture_set_sync_phase_value(mcpwm_dev_t *mcpwm, uint32_t phase_value)
{
mcpwm->cap_timer_phase = phase_value;
}
static inline uint32_t mcpwm_ll_capture_get_sync_phase(mcpwm_dev_t *mcpwm)
static inline uint32_t mcpwm_ll_capture_get_sync_phase_value(mcpwm_dev_t *mcpwm)
{
return mcpwm->cap_timer_phase;
}
@ -871,14 +943,14 @@ static inline void mcpwm_ll_capture_enable_timer_sync(mcpwm_dev_t *mcpwm, bool e
mcpwm->cap_timer_cfg.synci_en = enable;
}
static inline void mcpwm_ll_capture_set_internal_timer_syncer(mcpwm_dev_t *mcpwm, int sync_out_timer)
static inline void mcpwm_ll_capture_set_internal_timer_synchro(mcpwm_dev_t *mcpwm, int sync_out_timer)
{
mcpwm->cap_timer_cfg.synci_sel = sync_out_timer + 1;
}
static inline void mcpwm_ll_capture_set_external_syncer(mcpwm_dev_t *mcpwm, int extern_syncer)
static inline void mcpwm_ll_capture_set_external_synchro(mcpwm_dev_t *mcpwm, int extern_synchro)
{
mcpwm->cap_timer_cfg.synci_sel = extern_syncer + 4;
mcpwm->cap_timer_cfg.synci_sel = extern_synchro + 4;
}
static inline void mcpwm_ll_capture_trigger_sw_sync(mcpwm_dev_t *mcpwm)

View File

@ -37,7 +37,7 @@ typedef enum {
MCPWM_TIMER_START_NO_STOP, /*!< MCPWM timer starts couting */
MCPWM_TIMER_START_STOP_AT_ZERO, /*!< MCPWM timer starts counting and stops when couting to zero */
MCPWM_TIMER_START_STOP_AT_PEAK, /*!< MCPWM timer starts counting and stops when counting to peak */
} mcpwm_timer_operate_cmd_t;
} mcpwm_timer_execute_cmd_t;
typedef enum {
MCPWM_GEN_ACTION_KEEP, /*!< Generator action: Keep the same level */
@ -47,6 +47,6 @@ typedef enum {
} mcpwm_generator_action_t;
typedef enum {
MCPWM_FAULT_REACTION_CBC, /*!< Reaction on fault signal: recover cycle by cycle */
MCPWM_FAULT_REACTION_OST, /*!< Reaction on fault signal: one shot trip */
} mcpwm_fault_reaction_t;
MCPWM_TRIP_TYPE_CBC, /*!< CBC trip type, shut down the operator cycle by cycle*/
MCPWM_TRIP_TYPE_OST, /*!< OST trip type, shut down the operator in one shot */
} mcpwm_trip_type_t;

View File

@ -236,26 +236,8 @@
#define PWM1_CAP1_IN_IDX 113
#define PWM1_OUT2B_IDX 113
#define PWM1_CAP2_IN_IDX 114
#define PWM2_OUT1H_IDX 114
#define PWM2_FLTA_IDX 115
#define PWM2_OUT1L_IDX 115
#define PWM2_FLTB_IDX 116
#define PWM2_OUT2H_IDX 116
#define PWM2_CAP1_IN_IDX 117
#define PWM2_OUT2L_IDX 117
#define PWM2_CAP2_IN_IDX 118
#define PWM2_OUT3H_IDX 118
#define PWM2_CAP3_IN_IDX 119
#define PWM2_OUT3L_IDX 119
#define PWM3_FLTA_IDX 120
#define PWM2_OUT4H_IDX 120
#define PWM3_FLTB_IDX 121
#define PWM2_OUT4L_IDX 121
#define PWM3_CAP1_IN_IDX 122
#define PWM3_CAP2_IN_IDX 123
#define TWAI_TX_IDX 123
#define CAN_TX_IDX TWAI_TX_IDX
#define PWM3_CAP3_IN_IDX 124
#define TWAI_BUS_OFF_ON_IDX 124
#define CAN_BUS_OFF_ON_IDX TWAI_BUS_OFF_ON_IDX
#define TWAI_CLKOUT_IDX 125
@ -369,19 +351,11 @@
#define I2S1O_DATA_OUT22_IDX 188
#define I2S1O_DATA_OUT23_IDX 189
#define I2S0I_H_SYNC_IDX 190
#define PWM3_OUT1H_IDX 190
#define I2S0I_V_SYNC_IDX 191
#define PWM3_OUT1L_IDX 191
#define I2S0I_H_ENABLE_IDX 192
#define PWM3_OUT2H_IDX 192
#define I2S1I_H_SYNC_IDX 193
#define PWM3_OUT2L_IDX 193
#define I2S1I_V_SYNC_IDX 194
#define PWM3_OUT3H_IDX 194
#define I2S1I_H_ENABLE_IDX 195
#define PWM3_OUT3L_IDX 195
#define PWM3_OUT4H_IDX 196
#define PWM3_OUT4L_IDX 197
#define U2RXD_IN_IDX 198
#define U2TXD_OUT_IDX 198
#define U2CTS_IN_IDX 199

View File

@ -158,10 +158,11 @@
#define SOC_MCPWM_OPERATORS_PER_GROUP (3) ///< The number of operators that each group has
#define SOC_MCPWM_COMPARATORS_PER_OPERATOR (2) ///< The number of comparators that each operator has
#define SOC_MCPWM_GENERATORS_PER_OPERATOR (2) ///< The number of generators that each operator has
#define SOC_MCPWM_FAULT_DETECTORS_PER_GROUP (3) ///< The number of fault signal detectors that each group has
#define SOC_MCPWM_TRIGGERS_PER_OPERATOR (2) ///< The number of triggers that each operator has
#define SOC_MCPWM_GPIO_FAULTS_PER_GROUP (3) ///< The number of GPIO fault signals that each group has
#define SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP (1) ///< The number of capture timers that each group has
#define SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER (3) ///< The number of capture channels that each capture timer has
#define SOC_MCPWM_EXT_SYNCERS_PER_GROUP (3) ///< The number of external syncers that each group has
#define SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP (3) ///< The number of GPIO synchros that each group has
#define SOC_MCPWM_BASE_CLK_HZ (160000000ULL) ///< Base Clock frequency of 160MHz
/*-------------------------- MPU CAPS ----------------------------------------*/

View File

@ -53,7 +53,7 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
}
}
},
.detectors = {
.gpio_faults = {
[0] = {
.fault_sig = PWM0_F0_IN_IDX
},
@ -75,7 +75,7 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
.cap_sig = PWM0_CAP2_IN_IDX
}
},
.ext_syncers = {
.gpio_synchros = {
[0] = {
.sync_sig = PWM0_SYNC0_IN_IDX
},
@ -122,7 +122,7 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
}
}
},
.detectors = {
.gpio_faults = {
[0] = {
.fault_sig = PWM1_F0_IN_IDX
},
@ -144,7 +144,7 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
.cap_sig = PWM1_CAP2_IN_IDX
}
},
.ext_syncers = {
.gpio_synchros = {
[0] = {
.sync_sig = PWM1_SYNC0_IN_IDX
},

View File

@ -71,10 +71,11 @@
#define SOC_MCPWM_OPERATORS_PER_GROUP (3) ///< The number of operators that each group has
#define SOC_MCPWM_COMPARATORS_PER_OPERATOR (2) ///< The number of comparators that each operator has
#define SOC_MCPWM_GENERATORS_PER_OPERATOR (2) ///< The number of generators that each operator has
#define SOC_MCPWM_FAULT_DETECTORS_PER_GROUP (3) ///< The number of fault signal detectors that each group has
#define SOC_MCPWM_TRIGGERS_PER_OPERATOR (2) ///< The number of triggers that each operator has
#define SOC_MCPWM_GPIO_FAULTS_PER_GROUP (3) ///< The number of fault signal detectors that each group has
#define SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP (1) ///< The number of capture timers that each group has
#define SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER (3) ///< The number of capture channels that each capture timer has
#define SOC_MCPWM_EXT_SYNCERS_PER_GROUP (3) ///< The number of external syncers that each group has
#define SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP (3) ///< The number of GPIO synchros that each group has
#define SOC_MCPWM_BASE_CLK_HZ (160000000ULL) ///< Base Clock frequency of 160MHz
/*-------------------------- MPU CAPS ----------------------------------------*/

View File

@ -53,7 +53,7 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
}
}
},
.detectors = {
.gpio_faults = {
[0] = {
.fault_sig = PWM0_F0_IN_IDX
},
@ -75,7 +75,7 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
.cap_sig = PWM0_CAP2_IN_IDX
}
},
.ext_syncers = {
.gpio_synchros = {
[0] = {
.sync_sig = PWM0_SYNC0_IN_IDX
},
@ -122,7 +122,7 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
}
}
},
.detectors = {
.gpio_faults = {
[0] = {
.fault_sig = PWM1_F0_IN_IDX
},
@ -144,7 +144,7 @@ const mcpwm_signal_conn_t mcpwm_periph_signals = {
.cap_sig = PWM1_CAP2_IN_IDX
}
},
.ext_syncers = {
.gpio_synchros = {
[0] = {
.sync_sig = PWM1_SYNC0_IN_IDX
},

View File

@ -34,13 +34,13 @@ typedef struct {
} operators[SOC_MCPWM_OPERATORS_PER_GROUP];
struct {
const uint32_t fault_sig;
} detectors[SOC_MCPWM_FAULT_DETECTORS_PER_GROUP];
} gpio_faults[SOC_MCPWM_GPIO_FAULTS_PER_GROUP];
struct {
const uint32_t cap_sig;
} captures[SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER];
struct {
const uint32_t sync_sig;
} ext_syncers[SOC_MCPWM_EXT_SYNCERS_PER_GROUP];
} gpio_synchros[SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP];
} groups[SOC_MCPWM_GROUPS];
} mcpwm_signal_conn_t;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -53,7 +53,7 @@ In this case we will describe a simple configuration to control a brushed DC mot
Configuration covers the following steps:
1. Selection of a MPWn unit that will be used to drive the motor. There are two units available on-board of {IDF_TARGET_NAME} and enumerated in :cpp:type:`mcpwm_unit_t`.
1. Selection of a MCPWM unit that will be used to drive the motor. There are two units available on-board of {IDF_TARGET_NAME} and enumerated in :cpp:type:`mcpwm_unit_t`.
2. Initialization of two GPIOs as output signals within selected unit by calling :cpp:func:`mcpwm_gpio_init`. The two output signals are typically used to command the motor to rotate right or left. All available signal options are listed in :cpp:type:`mcpwm_io_signals_t`. To set more than a single pin at a time, use function :cpp:func:`mcpwm_set_pin` together with :cpp:type:`mcpwm_pin_config_t`.
3. Selection of a timer. There are three timers available within the unit. The timers are listed in :cpp:type:`mcpwm_timer_t`.
4. Setting of the timer frequency and initial duty within :cpp:type:`mcpwm_config_t` structure.
@ -146,7 +146,7 @@ The MCPWM has a carrier submodule used if galvanic isolation from the motor driv
To use the carrier submodule, it should be first initialized by calling :cpp:func:`mcpwm_carrier_init`. The carrier parameters are defined in :cpp:type:`mcpwm_carrier_config_t` structure invoked within the function call. Then the carrier functionality may be enabled by calling :cpp:func:`mcpwm_carrier_enable`.
The carrier parameters may be then alerted at a runtime by calling dedicated functions to change individual fields of the :cpp:type:`mcpwm_carrier_config_t` structure, like :cpp:func:`mcpwm_carrier_set_period`, :cpp:func:`mcpwm_carrier_set_duty_cycle`, :cpp:func:`mcpwm_carrier_output_invert`, etc.
The carrier parameters may be then altered at a runtime by calling dedicated functions to change individual fields of the :cpp:type:`mcpwm_carrier_config_t` structure, like :cpp:func:`mcpwm_carrier_set_period`, :cpp:func:`mcpwm_carrier_set_duty_cycle`, :cpp:func:`mcpwm_carrier_output_invert`, etc.
This includes enabling and setting duration of the first pulse of the career with :cpp:func:`mcpwm_carrier_oneshot_mode_enable`. For more details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *Motor Control PWM (MCPWM)* > *PWM Carrier Submodule* [`PDF <{IDF_TARGET_TRM_EN_URL}#mcpwm>`__].

View File

@ -1,10 +1,10 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
| Supported Targets | ESP32 | ESP32-S3 |
| ----------------- | ----- | -------- |
# MCPWM BLDC motor control(hall sensor feedback) Example
# MCPWM BLDC motor control (hall sensor feedback) Example
This example will show you how to use MCPWM module to control BLDC motor with hall sensor feedback.
This example will show you how to use MCPWM module to control bldc motor with hall sensor feedback
The following examples uses MCPWM module to control bldc motor and vary its speed continuously
The bldc motor used for testing this code had hall sensor capture sequence of 6-->4-->5-->1-->3-->2-->6-->4--> and so on
@ -13,7 +13,7 @@ IR2136 3-ph bridge driver is used for testing this example code
User needs to make changes according to the motor and gate driver ic used
## Step 1: Pin assignment
* The gpio init function initializes:
* GPIO15 is assigned as the MCPWM signal for 1H(UH)

View File

@ -215,7 +215,7 @@ static void mcpwm_example_bldc_control(void *arg)
//2. initial mcpwm configuration
printf("Configuring Initial Parameters of mcpwm bldc control...\n");
mcpwm_config_t pwm_config;
pwm_config.frequency = 1000; //frequency = 1000Hz
pwm_config.frequency = 14400; //frequency = 1000Hz
pwm_config.cmpr_a = 50.0; //duty cycle of PWMxA = 50.0%
pwm_config.cmpr_b = 50.0; //duty cycle of PWMxb = 50.0%
pwm_config.counter_mode = MCPWM_UP_COUNTER;

View File

@ -1,22 +1,59 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
| Supported Targets | ESP32 | ESP32-S3 |
| ----------------- | ----- | -------- |
# MCPWM RC Servo Control Example
# MCPWM servo motor control Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example will show you how to use MCPWM module to control servo motor
Assign pulse width range and the maximum degree, accordingly the servo will move from 0 to maximum degree continuously
This example illustrates how to drive a typical [RC Servo](https://en.wikipedia.org/wiki/Servo_(radio_control)) by sending a PWM signal using the MCPWM driver. The PWM pulse has a frequency of 50Hz (period of 20ms), and the active-high time (which controls the rotation) ranges from 1ms to 2ms with 1.5ms always being center of range.
## Step 1: Pin assignment
* GPIO18 is assigned as the MCPWM signal for servo motor
## How to Use Example
### Hardware Required
* A development board with any Espressif SoC which features MCPWM peripheral (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for Power supply and programming
* A RC servo motor, e.g. [SG90](http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf)
Connection :
```
+-------+ +-----------------+
| | | |
| +-+ GPIO18++ PWM(Orange) +----------+ |
| ESP |---5V------+ Vcc(Red) +--------------| Servo Motor |
| +---------+ GND(Brown) +----------+ |
| | | |
+-------+ +-----------------+
```
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Step 2: Connection
* connect GPIO18 with servo pwm signal
* other two wires of servo motor are VCC and GND
## Example Output
Run the example, you will see the following output log:
## Step 3: Initialize MCPWM
* You need to set the frequency(generally 50 Hz) and duty cycle of MCPWM timer
* You need to set the MCPWM channel you want to use, and bind the channel with one of the timers
```
...
I (0) cpu_start: Starting scheduler on APP CPU.
I (349) example: Angle of rotation: -90
I (449) example: Angle of rotation: -89
I (549) example: Angle of rotation: -88
I (649) example: Angle of rotation: -87
I (749) example: Angle of rotation: -86
...
```
The servo will rotate from -90 degree to 90 degree, and then turn back again.
## Troubleshooting
Note that, some kind of servo might need a higher current supply than the development board usually can provide. It's recommended to power the servo separately.
For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

View File

@ -1,2 +1,2 @@
idf_component_register(SRCS "mcpwm_servo_control_example.c"
idf_component_register(SRCS "mcpwm_servo_control_example_main.c"
INCLUDE_DIRS ".")

View File

@ -1,77 +0,0 @@
/* servo motor control example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "driver/mcpwm.h"
#include "soc/mcpwm_periph.h"
//You can get these value from the datasheet of servo you use, in general pulse width varies between 1000 to 2000 mocrosecond
#define SERVO_MIN_PULSEWIDTH 1000 //Minimum pulse width in microsecond
#define SERVO_MAX_PULSEWIDTH 2000 //Maximum pulse width in microsecond
#define SERVO_MAX_DEGREE 90 //Maximum angle in degree upto which servo can rotate
static void mcpwm_example_gpio_initialize(void)
{
printf("initializing mcpwm servo control gpio......\n");
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 18); //Set GPIO 18 as PWM0A, to which servo is connected
}
/**
* @brief Use this function to calcute pulse width for per degree rotation
*
* @param degree_of_rotation the angle in degree to which servo has to rotate
*
* @return
* - calculated pulse width
*/
static uint32_t servo_per_degree_init(uint32_t degree_of_rotation)
{
uint32_t cal_pulsewidth = 0;
cal_pulsewidth = (SERVO_MIN_PULSEWIDTH + (((SERVO_MAX_PULSEWIDTH - SERVO_MIN_PULSEWIDTH) * (degree_of_rotation)) / (SERVO_MAX_DEGREE)));
return cal_pulsewidth;
}
/**
* @brief Configure MCPWM module
*/
void mcpwm_example_servo_control(void *arg)
{
uint32_t angle, count;
//1. mcpwm gpio initialization
mcpwm_example_gpio_initialize();
//2. initial mcpwm configuration
printf("Configuring Initial Parameters of mcpwm......\n");
mcpwm_config_t pwm_config;
pwm_config.frequency = 50; //frequency = 50Hz, i.e. for every servo motor time period should be 20ms
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0
pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings
while (1) {
for (count = 0; count < SERVO_MAX_DEGREE; count++) {
printf("Angle of rotation: %d\n", count);
angle = servo_per_degree_init(count);
printf("pulse width: %dus\n", angle);
mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, angle);
vTaskDelay(10); //Add delay, since it takes time for servo to rotate, generally 100ms/60degree rotation at 5V
}
}
}
void app_main(void)
{
printf("Testing servo motor.......\n");
xTaskCreate(mcpwm_example_servo_control, "mcpwm_example_servo_control", 4096, NULL, 5, NULL);
}

View File

@ -0,0 +1,47 @@
/* Servo Motor control example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/mcpwm.h"
static const char *TAG = "example";
// You can get these value from the datasheet of servo you use, in general pulse width varies between 1000 to 2000 mocrosecond
#define SERVO_MIN_PULSEWIDTH_US (1000) // Minimum pulse width in microsecond
#define SERVO_MAX_PULSEWIDTH_US (2000) // Maximum pulse width in microsecond
#define SERVO_MAX_DEGREE (90) // Maximum angle in degree upto which servo can rotate
#define SERVO_PULSE_GPIO (18) // GPIO connects to the PWM signal line
static inline uint32_t example_convert_servo_angle_to_duty_us(int angle)
{
return (angle + SERVO_MAX_DEGREE) * (SERVO_MAX_PULSEWIDTH_US - SERVO_MIN_PULSEWIDTH_US) / (2 * SERVO_MAX_DEGREE) + SERVO_MIN_PULSEWIDTH_US;
}
void app_main(void)
{
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, SERVO_PULSE_GPIO); // To drive a RC servo, one MCPWM generator is enough
mcpwm_config_t pwm_config = {
.frequency = 50, // frequency = 50Hz, i.e. for every servo motor time period should be 20ms
.cmpr_a = 0, // duty cycle of PWMxA = 0
.counter_mode = MCPWM_UP_COUNTER,
.duty_mode = MCPWM_DUTY_MODE_0,
};
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);
while (1) {
for (int angle = -SERVO_MAX_DEGREE; angle < SERVO_MAX_DEGREE; angle++) {
ESP_LOGI(TAG, "Angle of rotation: %d", angle);
ESP_ERROR_CHECK(mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, example_convert_servo_angle_to_duty_us(angle)));
vTaskDelay(pdMS_TO_TICKS(100)); //Add delay, since it takes time for servo to rotate, generally 100ms/60degree rotation under 5V power supply
}
}
}