mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
mcpwm: refactor driver
This commit is contained in:
parent
0716520423
commit
d4fe219c49
@ -59,6 +59,7 @@ if(${target} STREQUAL "esp32s3")
|
||||
"gdma.c"
|
||||
"sdmmc_host.c"
|
||||
"sdmmc_transaction.c"
|
||||
"mcpwm.c"
|
||||
"spi_slave_hd.c"
|
||||
"touch_sensor_common.c"
|
||||
)
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_MCPWM_SUPPORTED
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "soc/soc.h"
|
||||
#include "driver/gpio.h"
|
||||
@ -20,7 +19,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief IO signals for the MCPWM
|
||||
*
|
||||
@ -130,6 +128,15 @@ typedef enum {
|
||||
MCPWM_SELECT_F2, /*!<Select F2 as input*/
|
||||
} mcpwm_fault_signal_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM select sync signal input
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_SELECT_SYNC0 = 4, /*!<Select SYNC0 as input*/
|
||||
MCPWM_SELECT_SYNC1, /*!<Select SYNC1 as input*/
|
||||
MCPWM_SELECT_SYNC2, /*!<Select SYNC2 as input*/
|
||||
} mcpwm_sync_signal_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM select triggering level of fault signal
|
||||
*/
|
||||
@ -138,6 +145,62 @@ typedef enum {
|
||||
MCPWM_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
|
||||
} mcpwm_fault_input_level_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM select capture starts from which edge
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_NEG_EDGE = BIT(0), /*!<Capture the negative edge*/
|
||||
MCPWM_POS_EDGE = BIT(1), /*!<Capture the positive edge*/
|
||||
MCPWM_BOTH_EDGE = BIT(1) | BIT(0), /*!<Capture both edges*/
|
||||
} mcpwm_capture_on_edge_t;
|
||||
|
||||
/**
|
||||
* @brief Select type of MCPWM counter
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_FREEZE_COUNTER, /*!<Counter freeze */
|
||||
MCPWM_UP_COUNTER, /*!<For asymmetric MCPWM*/
|
||||
MCPWM_DOWN_COUNTER, /*!<For asymmetric MCPWM*/
|
||||
MCPWM_UP_DOWN_COUNTER, /*!<For symmetric MCPWM, frequency is half of MCPWM frequency set*/
|
||||
MCPWM_COUNTER_MAX, /*!<Maximum counter mode*/
|
||||
} mcpwm_counter_type_t;
|
||||
|
||||
/**
|
||||
* @brief Select type of MCPWM duty cycle mode
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_DUTY_MODE_0 = 0, /*!<Active high duty, i.e. duty cycle proportional to high time for asymmetric MCPWM*/
|
||||
MCPWM_DUTY_MODE_1, /*!<Active low duty, i.e. duty cycle proportional to low time for asymmetric MCPWM, out of phase(inverted) MCPWM*/
|
||||
MCPWM_HAL_GENERATOR_MODE_FORCE_LOW,
|
||||
MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH,
|
||||
MCPWM_DUTY_MODE_MAX, /*!<Num of duty cycle modes*/
|
||||
} mcpwm_duty_type_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM deadtime types, used to generate deadtime, RED refers to rising edge delay and FED refers to falling edge delay
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_DEADTIME_BYPASS = 0, /*!<Bypass the deadtime*/
|
||||
MCPWM_BYPASS_RED, /*!<MCPWMXA = no change, MCPWMXB = falling edge delay*/
|
||||
MCPWM_BYPASS_FED, /*!<MCPWMXA = rising edge delay, MCPWMXB = no change*/
|
||||
MCPWM_ACTIVE_HIGH_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = falling edge delay*/
|
||||
MCPWM_ACTIVE_LOW_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = compliment of falling edge delay*/
|
||||
MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = compliment of falling edge delay*/
|
||||
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_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM select action to be taken on the output when event happens
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_ACTION_NO_CHANGE = 0, /*!<No change in the output*/
|
||||
MCPWM_ACTION_FORCE_LOW, /*!<Make output low*/
|
||||
MCPWM_ACTION_FORCE_HIGH, /*!<Make output high*/
|
||||
MCPWM_ACTION_TOGGLE, /*!<Make output toggle*/
|
||||
} mcpwm_output_action_t;
|
||||
|
||||
/// @deprecated MCPWM select action to be taken on MCPWMXA when fault occurs
|
||||
typedef mcpwm_output_action_t mcpwm_action_on_pwmxa_t;
|
||||
@ -556,6 +619,9 @@ 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,
|
||||
* users have to register an interrupt handler by `mcpwm_isr_register`, and in there, query the capture data.
|
||||
*
|
||||
* @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
|
||||
|
@ -5,39 +5,24 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "driver/mcpwm.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/mcpwm_periph.h"
|
||||
#include "hal/mcpwm_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "hal/mcpwm_ll.h"
|
||||
#include "driver/mcpwm.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
typedef struct {
|
||||
mcpwm_hal_context_t hal;
|
||||
portMUX_TYPE spinlock;
|
||||
} mcpwm_context_t;
|
||||
|
||||
#define CONTEXT_INITIALIZER() { \
|
||||
.spinlock = portMUX_INITIALIZER_UNLOCKED, \
|
||||
.hal = { \
|
||||
.prescale = MCPWM_CLK_PRESCL, \
|
||||
}, \
|
||||
}
|
||||
|
||||
|
||||
static const char *MCPWM_TAG = "MCPWM";
|
||||
|
||||
#define MCPWM_CHECK(a, str, ret_val) if (!(a)) { \
|
||||
ESP_LOGE(MCPWM_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
|
||||
return (ret_val); \
|
||||
}
|
||||
static const char *TAG = "mcpwm";
|
||||
|
||||
#define MCPWM_DRIVER_INIT_ERROR "MCPWM DRIVER NOT INITIALIZED"
|
||||
#define MCPWM_GROUP_NUM_ERROR "MCPWM GROUP NUM ERROR"
|
||||
@ -50,38 +35,43 @@ static const char *MCPWM_TAG = "MCPWM";
|
||||
#define MCPWM_GEN_ERROR "MCPWM GENERATOR ERROR"
|
||||
#define MCPWM_DT_ERROR "MCPWM DEADTIME TYPE ERROR"
|
||||
|
||||
#define MCPWM_CLK_PRESCL 15 //MCPWM clock prescale
|
||||
#define TIMER_CLK_PRESCALE 9 //MCPWM timer prescales
|
||||
#define MCPWM_CLK (MCPWM_BASE_CLK/(MCPWM_CLK_PRESCL +1))
|
||||
#define MCPWM_PIN_IGNORE (-1)
|
||||
#define OFFSET_FOR_GPIO_IDX_1 6
|
||||
#define OFFSET_FOR_GPIO_IDX_2 75
|
||||
#define MCPWM_GROUP_CLK_HZ (SOC_MCPWM_BASE_CLK_HZ / 16)
|
||||
#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.");
|
||||
_Static_assert(SOC_MCPWM_COMPARATORS_PER_OPERATOR >= SOC_MCPWM_GENERATORS_PER_OPERATOR, "This driver assumes the generator num equals to the generator num.");
|
||||
_Static_assert(SOC_MCPWM_GENERATORS_PER_OPERATOR == 2, "This driver assumes the generator num equals to 2.");
|
||||
|
||||
#define MCPWM_TIMER_ID_CHECK(mcpwm_num, timer_num) do {\
|
||||
MCPWM_CHECK((mcpwm_num) < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); \
|
||||
MCPWM_CHECK((timer_num) < SOC_MCPWM_TIMERS_PER_GROUP, MCPWM_TIMER_ERROR, ESP_ERR_INVALID_ARG); \
|
||||
} while(0)
|
||||
#define MCPWM_TIMER_ID_CHECK(mcpwm_num, timer_num) \
|
||||
do { \
|
||||
ESP_RETURN_ON_FALSE((mcpwm_num) < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR); \
|
||||
ESP_RETURN_ON_FALSE((timer_num) < SOC_MCPWM_TIMERS_PER_GROUP, ESP_ERR_INVALID_ARG, TAG, MCPWM_TIMER_ERROR); \
|
||||
} while (0)
|
||||
|
||||
#define MCPWM_TIMER_CHECK(mcpwm_num, timer_num) do{\
|
||||
MCPWM_TIMER_ID_CHECK(mcpwm_num, timer_num); \
|
||||
MCPWM_CHECK(context[mcpwm_num].hal.dev != NULL, MCPWM_DRIVER_INIT_ERROR, ESP_ERR_INVALID_STATE); \
|
||||
} while(0)
|
||||
#define MCPWM_TIMER_CHECK(mcpwm_num, timer_num) \
|
||||
do { \
|
||||
MCPWM_TIMER_ID_CHECK(mcpwm_num, timer_num); \
|
||||
ESP_RETURN_ON_FALSE(context[mcpwm_num].hal.dev, ESP_ERR_INVALID_STATE, TAG, MCPWM_DRIVER_INIT_ERROR); \
|
||||
} while (0)
|
||||
|
||||
#define MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen) do{ \
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num); \
|
||||
MCPWM_CHECK(gen < MCPWM_GEN_MAX, MCPWM_GEN_ERROR, ESP_ERR_INVALID_ARG); \
|
||||
} while(0)
|
||||
#define MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen) \
|
||||
do { \
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num); \
|
||||
ESP_RETURN_ON_FALSE((gen) < MCPWM_GEN_MAX, ESP_ERR_INVALID_ARG, TAG, MCPWM_GEN_ERROR); \
|
||||
} while (0)
|
||||
|
||||
typedef struct {
|
||||
mcpwm_hal_context_t hal;
|
||||
portMUX_TYPE spinlock;
|
||||
} mcpwm_context_t;
|
||||
|
||||
static mcpwm_context_t context[SOC_MCPWM_GROUPS] = {
|
||||
CONTEXT_INITIALIZER(),
|
||||
CONTEXT_INITIALIZER(),
|
||||
[0 ... SOC_MCPWM_GROUPS - 1] = {
|
||||
.spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
}
|
||||
};
|
||||
|
||||
typedef void (*mcpwm_ll_gen_set_event_action_t)(mcpwm_dev_t *mcpwm, int op, int gen, int action);
|
||||
|
||||
static inline void mcpwm_critical_enter(mcpwm_unit_t mcpwm_num)
|
||||
{
|
||||
@ -99,36 +89,35 @@ esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal,
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
MCPWM_CHECK((GPIO_IS_VALID_GPIO(gpio_num)), MCPWM_GPIO_ERROR, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, MCPWM_GPIO_ERROR);
|
||||
|
||||
// we enabled both input and output mode for GPIO used here, which can help to simulate trigger source especially in test code
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
if (io_signal <= MCPWM2B) { // Generator output signal
|
||||
MCPWM_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)), MCPWM_GPIO_ERROR, ESP_ERR_INVALID_ARG);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, MCPWM_GPIO_ERROR);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
int operator_id = io_signal / 2;
|
||||
int generator_id = io_signal % 2;
|
||||
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);
|
||||
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);
|
||||
} else if (io_signal <= MCPWM_FAULT_2) { // Fault input signal
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
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);
|
||||
} else if (io_signal >= MCPWM_CAP_0 && io_signal <= MCPWM_CAP_2) { // Capture input signal
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
|
||||
int capture_id = io_signal - MCPWM_CAP_0;
|
||||
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].captures[capture_id].cap_sig, 0);
|
||||
}
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_pin)
|
||||
{
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
mcpwm_gpio_init(mcpwm_num, MCPWM0A, mcpwm_pin->mcpwm0a_out_num); //MCPWM0A
|
||||
mcpwm_gpio_init(mcpwm_num, MCPWM0B, mcpwm_pin->mcpwm0b_out_num); //MCPWM0B
|
||||
mcpwm_gpio_init(mcpwm_num, MCPWM1A, mcpwm_pin->mcpwm1a_out_num); //MCPWM1A
|
||||
@ -152,7 +141,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_hal_timer_start(&context[mcpwm_num].hal, timer_num);
|
||||
mcpwm_ll_timer_set_operate_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_START_NO_STOP);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -162,7 +151,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_hal_timer_stop(&context[mcpwm_num].hal, timer_num);
|
||||
mcpwm_ll_timer_set_operate_command(context[mcpwm_num].hal.dev, timer_num, MCPWM_TIMER_STOP_AT_ZERO);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -175,10 +164,22 @@ esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, u
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
hal->timer[timer_num].freq = frequency;
|
||||
mcpwm_hal_timer_update_basic(hal, timer_num);
|
||||
//update the operator to update the duty
|
||||
mcpwm_hal_operator_update_basic(hal, op);
|
||||
|
||||
mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num);
|
||||
uint32_t previous_peak = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false);
|
||||
uint32_t new_peak = MCPWM_TIMER_CLK_HZ / frequency;
|
||||
mcpwm_ll_timer_set_peak(hal->dev, timer_num, new_peak, false);
|
||||
// keep the duty cycle unchanged
|
||||
float scale = ((float)new_peak) / previous_peak;
|
||||
// the driver currently always use the comparator A for PWMxA output, and comparator B for PWMxB output
|
||||
uint32_t previous_cmp_a = mcpwm_ll_operator_get_compare_value(hal->dev, op, 0);
|
||||
uint32_t previous_cmp_b = mcpwm_ll_operator_get_compare_value(hal->dev, op, 1);
|
||||
// update compare value immediately
|
||||
mcpwm_ll_operator_update_compare_at_once(hal->dev, op, 0);
|
||||
mcpwm_ll_operator_update_compare_at_once(hal->dev, op, 1);
|
||||
mcpwm_ll_operator_set_compare_value(hal->dev, op, 0, (uint32_t)(previous_cmp_a * scale));
|
||||
mcpwm_ll_operator_set_compare_value(hal->dev, op, 1, (uint32_t)(previous_cmp_b * scale));
|
||||
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -193,8 +194,9 @@ esp_err_t mcpwm_set_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
hal->op[op].duty[cmp] = duty;
|
||||
mcpwm_hal_operator_update_comparator(hal, op, gen);
|
||||
uint32_t set_duty = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false) * duty / 100;
|
||||
mcpwm_ll_operator_set_compare_value(hal->dev, op, cmp, set_duty);
|
||||
mcpwm_ll_operator_enable_update_compare_on_tez(hal->dev, op, cmp, true);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -209,8 +211,9 @@ esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
hal->op[op].duty[cmp] = (100 * duty_in_us * hal->timer[timer_num].freq) / (1000 * 1000.);
|
||||
mcpwm_hal_operator_update_comparator(hal, op, gen);
|
||||
// the timer resolution is fixed to 1us in the driver, so duty_in_us is the same to compare value
|
||||
mcpwm_ll_operator_set_compare_value(hal->dev, op, cmp, duty_in_us);
|
||||
mcpwm_ll_operator_enable_update_compare_on_tez(hal->dev, op, cmp, true);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -221,67 +224,122 @@ esp_err_t mcpwm_set_duty_type(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, m
|
||||
//the driver currently always use the timer x for operator x
|
||||
const int op = timer_num;
|
||||
MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen);
|
||||
MCPWM_CHECK(duty_type < MCPWM_DUTY_MODE_MAX, MCPWM_DUTY_TYPE_ERROR, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(duty_type < MCPWM_DUTY_MODE_MAX, ESP_ERR_INVALID_ARG, TAG, MCPWM_DUTY_TYPE_ERROR);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
//the driver currently always use the comparator A for PWMxA output, and comparator B for PWMxB output
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
hal->op[op].gen[gen] = (mcpwm_hal_generator_config_t) {
|
||||
.comparator = gen, //the driver currently always use the comparator A for PWMxA output, and comparator B for PWMxB output
|
||||
.duty_type = duty_type,
|
||||
};
|
||||
mcpwm_hal_operator_update_generator(hal, op, gen);
|
||||
switch (mcpwm_ll_timer_get_count_mode(hal->dev, timer_num)) {
|
||||
case MCPWM_TIMER_COUNT_MODE_UP:
|
||||
if (duty_type == MCPWM_DUTY_MODE_0) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_ZERO, MCPWM_GEN_ACTION_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_PEAK, MCPWM_GEN_ACTION_KEEP);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, gen, MCPWM_ACTION_FORCE_LOW);
|
||||
} else if (duty_type == MCPWM_DUTY_MODE_1) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_ZERO, MCPWM_GEN_ACTION_LOW);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_NO_CHANGE);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, gen, MCPWM_ACTION_FORCE_HIGH);
|
||||
} else if (duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_LOW) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, gen, MCPWM_ACTION_FORCE_LOW);
|
||||
} else if (duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, gen, MCPWM_ACTION_FORCE_HIGH);
|
||||
}
|
||||
break;
|
||||
case MCPWM_TIMER_COUNT_MODE_DOWN:
|
||||
if (duty_type == MCPWM_DUTY_MODE_0) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_NO_CHANGE);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, gen, MCPWM_ACTION_FORCE_HIGH);
|
||||
} else if (duty_type == MCPWM_DUTY_MODE_1) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_NO_CHANGE);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, gen, MCPWM_ACTION_FORCE_LOW);
|
||||
} else if (duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_LOW) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, gen, MCPWM_ACTION_FORCE_LOW);
|
||||
} else if (duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, gen, MCPWM_ACTION_FORCE_HIGH);
|
||||
}
|
||||
break;
|
||||
case MCPWM_TIMER_COUNT_MODE_UP_DOWN:
|
||||
if (duty_type == MCPWM_DUTY_MODE_0) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, gen, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, gen, MCPWM_ACTION_FORCE_HIGH);
|
||||
} else if (duty_type == MCPWM_DUTY_MODE_1) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, gen, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, gen, MCPWM_ACTION_FORCE_LOW);
|
||||
} else if (duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_LOW) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, gen, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, gen, MCPWM_ACTION_FORCE_LOW);
|
||||
} else if (duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH) {
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_ZERO, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_timer_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_PEAK, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_DOWN, gen, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_generator_set_action_on_compare_event(hal->dev, op, gen, MCPWM_TIMER_DIRECTION_UP, gen, MCPWM_ACTION_FORCE_HIGH);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpwm_config_t *mcpwm_conf)
|
||||
{
|
||||
//the driver currently always use the timer x for operator x
|
||||
const int op = timer_num;
|
||||
MCPWM_TIMER_ID_CHECK(mcpwm_num, op);
|
||||
periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module);
|
||||
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_hal_init_config_t init_config = {
|
||||
.host_id = mcpwm_num,
|
||||
periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module);
|
||||
mcpwm_hal_init_config_t config = {
|
||||
.host_id = mcpwm_num
|
||||
};
|
||||
mcpwm_hal_init(hal, &config);
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_init(hal, &init_config);
|
||||
mcpwm_hal_hw_init(hal);
|
||||
|
||||
hal->timer[timer_num].timer_prescale = TIMER_CLK_PRESCALE;
|
||||
hal->timer[timer_num].freq = mcpwm_conf->frequency;
|
||||
hal->timer[timer_num].count_mode = mcpwm_conf->counter_mode;
|
||||
|
||||
//the driver currently always use the timer x for operator x
|
||||
hal->op[op].timer = timer_num;
|
||||
hal->op[op].duty[0] = mcpwm_conf->cmpr_a;
|
||||
hal->op[op].duty[1] = mcpwm_conf->cmpr_b;
|
||||
|
||||
mcpwm_hal_timer_update_basic(hal, timer_num);
|
||||
//update the comparer to keep the same duty rate
|
||||
mcpwm_hal_operator_update_basic(hal, op);
|
||||
|
||||
for (int gen = 0; gen < SOC_MCPWM_GENERATORS_PER_OPERATOR; gen++) {
|
||||
hal->op[op].gen[gen] = (mcpwm_hal_generator_config_t) {
|
||||
.comparator = gen, //the driver currently always use the comparator A for PWMxA output, and comparator B for PWMxB output
|
||||
.duty_type = mcpwm_conf->duty_mode,
|
||||
};
|
||||
mcpwm_hal_operator_update_generator(hal, op, gen);
|
||||
}
|
||||
|
||||
mcpwm_hal_timer_start(hal, timer_num);
|
||||
mcpwm_ll_group_set_clock(hal->dev, MCPWM_GROUP_CLK_HZ);
|
||||
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_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);
|
||||
mcpwm_ll_operator_select_timer(hal->dev, timer_num, timer_num); //the driver currently always use the timer x for operator x
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
|
||||
mcpwm_set_duty(mcpwm_num, timer_num, 0, mcpwm_conf->cmpr_a);
|
||||
mcpwm_set_duty(mcpwm_num, timer_num, 1, mcpwm_conf->cmpr_b);
|
||||
mcpwm_set_duty_type(mcpwm_num, timer_num, 0, mcpwm_conf->duty_mode);
|
||||
mcpwm_set_duty_type(mcpwm_num, timer_num, 1, mcpwm_conf->duty_mode);
|
||||
mcpwm_start(mcpwm_num, timer_num);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
|
||||
{
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
return context[mcpwm_num].hal.timer[timer_num].freq;
|
||||
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);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return (uint32_t)timer_clock;
|
||||
}
|
||||
|
||||
float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen)
|
||||
@ -289,44 +347,23 @@ float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_gene
|
||||
//the driver currently always use the timer x for operator x
|
||||
const int op = timer_num;
|
||||
MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen);
|
||||
return context[mcpwm_num].hal.op[op].duty[gen];
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
float duty = 100.0 * mcpwm_ll_operator_get_compare_value(hal->dev, op, gen) / mcpwm_ll_timer_get_peak(hal->dev, timer_num, false);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return duty;
|
||||
}
|
||||
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_GEN_A, 0);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_GEN_B, 1);
|
||||
|
||||
esp_err_t mcpwm_set_signal_high(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen)
|
||||
{
|
||||
//the driver currently always use the timer x for operator x
|
||||
const int op = timer_num;
|
||||
MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
hal->op[op].gen[gen] = (mcpwm_hal_generator_config_t) {
|
||||
.comparator = gen, //the driver currently always use the comparator A for PWMxA output, and comparator B for PWMxB output
|
||||
.duty_type = MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH,
|
||||
};
|
||||
mcpwm_hal_operator_update_generator(hal, op, gen);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
return mcpwm_set_duty_type(mcpwm_num, timer_num, gen, MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH);
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_set_signal_low(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen)
|
||||
{
|
||||
//the driver currently always use the timer x for operator x
|
||||
const int op = timer_num;
|
||||
MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
hal->op[op].gen[gen] = (mcpwm_hal_generator_config_t) {
|
||||
.comparator = gen, //the driver currently always use the comparator A for PWMxA output, and comparator B for PWMxB output
|
||||
.duty_type = MCPWM_HAL_GENERATOR_MODE_FORCE_LOW,
|
||||
};
|
||||
mcpwm_hal_operator_update_generator(hal, op, gen);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
return mcpwm_set_duty_type(mcpwm_num, timer_num, gen, MCPWM_HAL_GENERATOR_MODE_FORCE_LOW);
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_carrier_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
|
||||
@ -360,7 +397,7 @@ esp_err_t mcpwm_carrier_set_period(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_n
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_carrier_set_prescale(context[mcpwm_num].hal.dev, op, carrier_period);
|
||||
mcpwm_ll_carrier_set_prescale(context[mcpwm_num].hal.dev, op, carrier_period + 1);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -384,7 +421,7 @@ esp_err_t mcpwm_carrier_oneshot_mode_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_carrier_set_oneshot_width(context[mcpwm_num].hal.dev, op, pulse_width);
|
||||
mcpwm_ll_carrier_set_oneshot_width(context[mcpwm_num].hal.dev, op, pulse_width + 1);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -414,20 +451,20 @@ esp_err_t mcpwm_carrier_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, co
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_hal_carrier_conf_t carrier = {
|
||||
.period = carrier_conf->carrier_period,
|
||||
.duty = carrier_conf->carrier_duty,
|
||||
.inverted = carrier_conf->carrier_ivt_mode,
|
||||
};
|
||||
mcpwm_carrier_enable(mcpwm_num, timer_num);
|
||||
mcpwm_carrier_set_period(mcpwm_num, timer_num, carrier_conf->carrier_period);
|
||||
mcpwm_carrier_set_duty_cycle(mcpwm_num, timer_num, carrier_conf->carrier_duty);
|
||||
if (carrier_conf->carrier_os_mode == MCPWM_ONESHOT_MODE_EN) {
|
||||
carrier.oneshot_pulse_width = carrier_conf->pulse_width_in_os;
|
||||
mcpwm_carrier_oneshot_mode_enable(mcpwm_num, timer_num, carrier_conf->pulse_width_in_os);
|
||||
} else {
|
||||
carrier.oneshot_pulse_width = 0;
|
||||
mcpwm_carrier_oneshot_mode_disable(mcpwm_num, timer_num);
|
||||
}
|
||||
mcpwm_carrier_output_invert(mcpwm_num, timer_num, carrier_conf->carrier_ivt_mode);
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_operator_enable_carrier(hal, op, &carrier);
|
||||
mcpwm_ll_carrier_in_invert(hal->dev, op, false);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -437,16 +474,82 @@ esp_err_t mcpwm_deadtime_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
|
||||
//the driver currently always use the timer x for operator x
|
||||
const int op = timer_num;
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
MCPWM_CHECK(dt_mode < MCPWM_DEADTIME_TYPE_MAX, MCPWM_DT_ERROR, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(dt_mode < MCPWM_DEADTIME_TYPE_MAX, ESP_ERR_INVALID_ARG, TAG, MCPWM_DT_ERROR);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_hal_deadzone_conf_t deadzone = {
|
||||
.red = red,
|
||||
.fed = fed,
|
||||
.mode = dt_mode,
|
||||
};
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_operator_update_deadzone(hal, op, &deadzone);
|
||||
mcpwm_ll_deadtime_enable_update_delay_on_tez(hal->dev, op, true);
|
||||
mcpwm_ll_deadtime_set_resolution_same_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) {
|
||||
case MCPWM_BYPASS_RED:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, true); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 1); // S5
|
||||
break;
|
||||
case MCPWM_BYPASS_FED:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, true); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5
|
||||
break;
|
||||
case MCPWM_ACTIVE_HIGH_MODE:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 1); // S5
|
||||
break;
|
||||
case MCPWM_ACTIVE_LOW_MODE:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, true); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, true); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 1); // S5
|
||||
break;
|
||||
case MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, true); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 1); // S5
|
||||
break;
|
||||
case MCPWM_ACTIVE_LOW_COMPLIMENT_MODE:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, false); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, true); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 1); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5
|
||||
break;
|
||||
case MCPWM_ACTIVE_RED_FED_FROM_PWMXA:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 1); // S4
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 0, true); // S6
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 1, false); // S7
|
||||
mcpwm_ll_deadtime_enable_deb(hal->dev, op, true); // S8
|
||||
break;
|
||||
case MCPWM_ACTIVE_RED_FED_FROM_PWMXB:
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, false); // S0
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 0, true); // S6
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 1, false); // S7
|
||||
mcpwm_ll_deadtime_enable_deb(hal->dev, op, true); // S8
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -457,30 +560,43 @@ esp_err_t mcpwm_deadtime_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num
|
||||
const int op = timer_num;
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_hal_deadzone_conf_t deadzone = { .mode = MCPWM_DEADTIME_BYPASS };
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_operator_update_deadzone(hal, op, &deadzone);
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 1, true); // S0
|
||||
mcpwm_ll_deadtime_bypass_path(hal->dev, op, 0, true); // S1
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 0, false); // S2
|
||||
mcpwm_ll_deadtime_invert_outpath(hal->dev, op, 1, false); // S3
|
||||
mcpwm_ll_deadtime_red_select_generator(hal->dev, op, 0); // S4
|
||||
mcpwm_ll_deadtime_fed_select_generator(hal->dev, op, 0); // S5
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 0, false); // S6
|
||||
mcpwm_ll_deadtime_swap_out_path(hal->dev, op, 1, false); // S7
|
||||
mcpwm_ll_deadtime_enable_deb(hal->dev, op, false); // S8
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_fault_init(mcpwm_unit_t mcpwm_num, mcpwm_fault_input_level_t intput_level, mcpwm_fault_signal_t fault_sig)
|
||||
{
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_fault_init(&context[mcpwm_num].hal, fault_sig, intput_level);
|
||||
mcpwm_ll_fault_enable_detection(hal->dev, fault_sig, true);
|
||||
mcpwm_ll_fault_set_active_level(hal->dev, fault_sig, intput_level);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_fault_deinit(mcpwm_unit_t mcpwm_num, mcpwm_fault_signal_t fault_sig)
|
||||
{
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_fault_disable(&context[mcpwm_num].hal, fault_sig);
|
||||
mcpwm_ll_fault_enable_detection(hal->dev, fault_sig, false);
|
||||
for (int i = 0; i < SOC_MCPWM_OPERATORS_PER_GROUP; i++) {
|
||||
mcpwm_ll_fault_clear_ost(hal->dev, i); // make sure operator has exit the ost fault state totally
|
||||
}
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -494,10 +610,12 @@ esp_err_t mcpwm_fault_set_cyc_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_n
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_fault_cbc_enable_signal(hal->dev, op, fault_sig, true);
|
||||
mcpwm_ll_fault_oneshot_enable_signal(hal->dev, op, fault_sig, false);
|
||||
mcpwm_ll_fault_set_cyc_action(hal->dev, op, 0, action_on_pwmxa, action_on_pwmxa);
|
||||
mcpwm_ll_fault_set_cyc_action(hal->dev, op, 1, action_on_pwmxb, action_on_pwmxb);
|
||||
mcpwm_ll_fault_enable_cbc_mode(hal->dev, op, fault_sig, 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_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -511,11 +629,13 @@ esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_fault_oneshot_clear(hal, op);
|
||||
mcpwm_ll_fault_cbc_enable_signal(hal->dev, op, fault_sig, false);
|
||||
mcpwm_ll_fault_oneshot_enable_signal(hal->dev, op, fault_sig, true);
|
||||
mcpwm_ll_fault_set_oneshot_action(hal->dev, op, 0, action_on_pwmxa, action_on_pwmxa);
|
||||
mcpwm_ll_fault_set_oneshot_action(hal->dev, op, 1, action_on_pwmxb, action_on_pwmxb);
|
||||
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_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -523,35 +643,39 @@ esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
|
||||
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)
|
||||
{
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
MCPWM_CHECK(num_of_pulse <= MCPWM_LL_MAX_PRESCALE, MCPWM_PRESCALE_ERROR, ESP_ERR_INVALID_ARG);
|
||||
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(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
|
||||
periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module);
|
||||
mcpwm_hal_init_config_t init_config = {
|
||||
.host_id = mcpwm_num,
|
||||
};
|
||||
mcpwm_hal_capture_config_t cap_conf = {
|
||||
.cap_edge = cap_edge,
|
||||
.prescale = num_of_pulse,
|
||||
};
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
//We have to do this here, since there is no standalone init function
|
||||
//without enabling any PWM channels.
|
||||
mcpwm_hal_init(hal, &init_config);
|
||||
mcpwm_hal_hw_init(hal);
|
||||
mcpwm_hal_capture_enable(hal, cap_sig, &cap_conf);
|
||||
mcpwm_ll_group_set_clock(hal->dev, MCPWM_GROUP_CLK_HZ);
|
||||
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);
|
||||
mcpwm_ll_capture_enable_posedge(hal->dev, cap_sig, cap_edge & MCPWM_POS_EDGE);
|
||||
mcpwm_ll_capture_set_prescale(hal->dev, cap_sig, num_of_pulse + 1);
|
||||
// capture feature should be used with interupt, so enable it by default
|
||||
mcpwm_ll_intr_enable_capture(hal->dev, cap_sig, true);
|
||||
mcpwm_ll_intr_clear_capture_status(hal->dev, 1 << cap_sig);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_capture_disable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig)
|
||||
{
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_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;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_capture_disable(&context[mcpwm_num].hal, cap_sig);
|
||||
mcpwm_ll_capture_enable_channel(hal->dev, cap_sig, false);
|
||||
mcpwm_ll_intr_enable_capture(hal->dev, cap_sig, false);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
periph_module_disable(mcpwm_periph_signals.groups[mcpwm_num].module);
|
||||
return ESP_OK;
|
||||
@ -559,19 +683,18 @@ esp_err_t mcpwm_capture_disable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t c
|
||||
|
||||
uint32_t mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig)
|
||||
{
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
uint32_t captured_value;
|
||||
mcpwm_hal_capture_get_result(&context[mcpwm_num].hal, cap_sig, &captured_value, NULL);
|
||||
return captured_value;
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_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;
|
||||
return mcpwm_ll_capture_get_value(hal->dev, cap_sig);
|
||||
}
|
||||
|
||||
uint32_t mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig)
|
||||
{
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
mcpwm_capture_on_edge_t edge;
|
||||
mcpwm_hal_capture_get_result(&context[mcpwm_num].hal, cap_sig, NULL, &edge);
|
||||
return (edge == MCPWM_NEG_EDGE ? 2 : 1);
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_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;
|
||||
return mcpwm_ll_capture_is_negedge(hal->dev, cap_sig) ? 2 : 1;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_sync_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_sync_signal_t sync_sig,
|
||||
@ -579,13 +702,15 @@ esp_err_t mcpwm_sync_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcp
|
||||
{
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_hal_sync_config_t sync_config = {
|
||||
.reload_permillage = phase_val,
|
||||
.sync_sig = sync_sig,
|
||||
};
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_timer_enable_sync(hal, timer_num, &sync_config);
|
||||
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_sync_out_same_in(hal->dev, timer_num);
|
||||
mcpwm_ll_timer_enable_sync_input(hal->dev, timer_num, true);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -593,9 +718,10 @@ esp_err_t mcpwm_sync_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcp
|
||||
esp_err_t mcpwm_sync_disable(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);
|
||||
mcpwm_hal_timer_disable_sync(&context[mcpwm_num].hal, timer_num);
|
||||
mcpwm_ll_timer_enable_sync_input(hal->dev, timer_num, false);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -603,8 +729,8 @@ esp_err_t mcpwm_sync_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
|
||||
esp_err_t mcpwm_isr_register(mcpwm_unit_t mcpwm_num, void (*fn)(void *), void *arg, int intr_alloc_flags, intr_handle_t *handle)
|
||||
{
|
||||
esp_err_t ret;
|
||||
MCPWM_CHECK(mcpwm_num < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
MCPWM_CHECK(fn != NULL, MCPWM_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
|
||||
ESP_RETURN_ON_FALSE(fn, ESP_ERR_INVALID_ARG, TAG, MCPWM_PARAM_ADDR_ERROR);
|
||||
ret = esp_intr_alloc(mcpwm_periph_signals.groups[mcpwm_num].irq_id, intr_alloc_flags, fn, arg, handle);
|
||||
return ret;
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ if(NOT BOOTLOADER_BUILD)
|
||||
list(APPEND srcs
|
||||
"gdma_hal.c"
|
||||
"lcd_hal.c"
|
||||
"mcpwm_hal.c"
|
||||
"pcnt_hal.c"
|
||||
"spi_flash_hal_gpspi.c"
|
||||
"spi_slave_hd_hal.c"
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -20,309 +20,22 @@
|
||||
|
||||
// The HAL layer for MCPWM (common part)
|
||||
|
||||
/*
|
||||
* MCPWM HAL usages:
|
||||
*
|
||||
* Initialization:
|
||||
* 1. Fill the parameters in `mcpwm_hal_context_t`.
|
||||
* 2. Call `mcpwm_hal_init` to initialize the context.
|
||||
* 3. Call `mcpwm_hal_hw_init` to initialize the hardware.
|
||||
*
|
||||
* Basic PWM:
|
||||
* 1. Update parameters for the timers, comparators and generators.
|
||||
* 2. Call `mcpwm_hal_timer_update_basic` to update the timer used.
|
||||
* 3. Call `mcpwm_hal_operator_update_basic` to update all the parameters of a operator.
|
||||
*
|
||||
* Alternatively, if only the comparator is updated (duty rate), call
|
||||
* `mcpwm_hal_operator_update_comparator` to update the comparator parameters; if only the
|
||||
* generator is updated (output style), call `mcpwm_hal_operator_update_generator` to update the
|
||||
* generator parameters.
|
||||
*
|
||||
* 4. At any time, call `mcpwm_hal_timer_start` to start the timer (so that PWM output will toggle
|
||||
* according to settings), or call `mcpwm_hal_timer_stop` to stop the timer (so that the PWM output
|
||||
* will be kept as called).
|
||||
*
|
||||
* Timer settings:
|
||||
* - Sync: Call `mcpwm_hal_timer_enable_sync` to enable the sync for the timer, and call
|
||||
* `mcpwm_hal_timer_disable_sync` to disable it.
|
||||
*
|
||||
* Operator settings:
|
||||
* - Carrier: Call `mcpwm_hal_operator_enable_carrier` to enable carrier for an operator, and call
|
||||
* `mcpwm_hal_operator_disable_carrier` to disable it.
|
||||
*
|
||||
* - Deadzone: Call `mcpwm_hal_operator_update_deadzone` to update settings of deadzone for an operator.
|
||||
*
|
||||
* Fault handling settings:
|
||||
* 1. Call `mcpwm_hal_fault_init` to initialize an fault signal to be detected.
|
||||
* 2. Call `mcpwm_hal_operator_update_fault` to update the behavior of an operator when fault is
|
||||
* detected.
|
||||
* 3. If the operator selects oneshot mode to handle the fault event, call
|
||||
* `mcpwm_hal_fault_oneshot_clear` to clear that fault event after the fault is handled properly.
|
||||
* 4. Call `mcpwm_hal_fault_disable` to deinitialize the fault signal when it's no longer used.
|
||||
*
|
||||
* Capture:
|
||||
* 1. Call `mcpwm_hal_capture_enable` to enable the capture for one capture signal.
|
||||
* 2. Call `mcpwm_hal_capture_get_result` to get the last captured result.
|
||||
* 3. Call `mcpwm_hal_capture_disable` to disable the capture for a signal.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <esp_err.h>
|
||||
#include "hal/mcpwm_ll.h"
|
||||
#include "soc/mcpwm_struct.h"
|
||||
|
||||
#define MCPWM_BASE_CLK (2 * APB_CLK_FREQ) //2*APB_CLK_FREQ 160Mhz
|
||||
|
||||
/// Configuration of HAL that used only once.
|
||||
typedef struct {
|
||||
int host_id; ///< Which MCPWM peripheral to use, 0-1.
|
||||
int host_id; ///< Which MCPWM peripheral to use, 0-1.
|
||||
} mcpwm_hal_init_config_t;
|
||||
|
||||
/// Configuration of each generator (output of operator)
|
||||
typedef struct {
|
||||
mcpwm_duty_type_t duty_type; ///< How the generator output
|
||||
int comparator; ///< for mode `MCPWM_DUTY_MODE_*`, which comparator it refers to.
|
||||
} mcpwm_hal_generator_config_t;
|
||||
|
||||
/// Configuration of each operator
|
||||
typedef struct {
|
||||
mcpwm_hal_generator_config_t gen[SOC_MCPWM_GENERATORS_PER_OPERATOR]; ///< Configuration of the generators
|
||||
float duty[SOC_MCPWM_COMPARATORS_PER_OPERATOR]; ///< Duty rate for each comparator, 10 means 10%.
|
||||
int timer; ///< The timer this operator is using
|
||||
} mcpwm_hal_operator_config_t;
|
||||
|
||||
/// Configuration of each timer
|
||||
typedef struct {
|
||||
uint32_t timer_prescale; ///< The prescale from the MCPWM main clock to the timer clock, TIMER_FREQ=(MCPWM_FREQ/(timer_prescale+1))
|
||||
uint32_t freq; ///< Frequency desired, will be updated to actual value after the `mcpwm_hal_timer_update_freq` is called.
|
||||
mcpwm_counter_type_t count_mode; ///< Counting mode
|
||||
} mcpwm_hal_timer_config_t;
|
||||
|
||||
typedef struct {
|
||||
mcpwm_dev_t *dev; ///< Beginning address of the MCPWM peripheral registers. Call `mcpwm_hal_init` to initialize it.
|
||||
uint32_t prescale; ///< Prescale from the 160M clock to MCPWM main clock.
|
||||
mcpwm_hal_timer_config_t timer[SOC_MCPWM_TIMERS_PER_GROUP]; ///< Configuration of the timers
|
||||
mcpwm_hal_operator_config_t op[SOC_MCPWM_OPERATORS_PER_GROUP]; ///< Configuration of the operators
|
||||
mcpwm_dev_t *dev; ///< Beginning address of the peripheral registers of a single MCPWM unit. Call `mcpwm_hal_init` to initialize it.
|
||||
} mcpwm_hal_context_t;
|
||||
|
||||
/// Configuration of the carrier
|
||||
typedef struct {
|
||||
bool inverted; ///< Whether to invert the output
|
||||
uint8_t duty; ///< Duty of the carrier, 0-7. Duty rate = duty/8.
|
||||
uint8_t oneshot_pulse_width; ///< oneshot pulse width, in carrier periods. 0 to disable. 0-15.
|
||||
uint32_t period; ///< Prescale from the MCPWM main clock to the carrier clock. CARRIER_FREQ=(MCPWM_FREQ/(period+1)/8.)
|
||||
} mcpwm_hal_carrier_conf_t;
|
||||
|
||||
/// Configuration of the deadzone
|
||||
typedef struct {
|
||||
mcpwm_deadtime_type_t mode; ///< Deadzone mode, `MCPWM_DEADTIME_BYPASS` to disable.
|
||||
uint32_t fed; ///< Delay on falling edge. By MCPWM main clock.
|
||||
uint32_t red; ///< Delay on rising edge. By MCPWM main clock.
|
||||
} mcpwm_hal_deadzone_conf_t;
|
||||
|
||||
/// Configuration of the fault handling for each operator
|
||||
typedef struct {
|
||||
uint32_t cbc_enabled_mask; ///< Whether the cycle-by-cycle fault handling is enabled on each fault signal. BIT(n) stands for signal n.
|
||||
uint32_t ost_enabled_mask; ///< Whether the oneshot fault handling is enabled on each on each fault signal. BIT(n) stands for signal n.
|
||||
mcpwm_output_action_t action_on_fault[SOC_MCPWM_GENERATORS_PER_OPERATOR]; ///< Action to perform on each generator when any one of the fault signal triggers.
|
||||
} mcpwm_hal_fault_conf_t;
|
||||
|
||||
/// Configuration of the synchronization of each clock
|
||||
typedef struct {
|
||||
mcpwm_sync_signal_t sync_sig; ///< Sync signal to use
|
||||
uint32_t reload_permillage; ///< Reload permillage when the sync is triggered. 100 means the timer will be reload to (period * 100)/1000=10% period value.
|
||||
} mcpwm_hal_sync_config_t;
|
||||
|
||||
/// Configuration of the capture feature on each capture signal
|
||||
typedef struct {
|
||||
mcpwm_capture_on_edge_t cap_edge; ///< Whether the edges is captured, bitwise.
|
||||
uint32_t prescale; ///< Prescale of the input signal.
|
||||
} mcpwm_hal_capture_config_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the internal state of the HAL. Call after settings are set and before other functions are called.
|
||||
*
|
||||
* @note Since There are several individual parts (timers + operators, captures), this funciton is
|
||||
* allowed to called several times.
|
||||
* @brief Initialize the internal state of the HAL.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param init_config Configuration for the HAL to be used only once.
|
||||
*/
|
||||
void mcpwm_hal_init(mcpwm_hal_context_t *hal, const mcpwm_hal_init_config_t *init_config);
|
||||
|
||||
/**
|
||||
* @brief Initialize the hardware, call after `mcpwm_hal_init` and before other functions.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
*/
|
||||
void mcpwm_hal_hw_init(mcpwm_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Start a timer
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param timer Timer to start, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_timer_start(mcpwm_hal_context_t *hal, int timer);
|
||||
|
||||
/**
|
||||
* @brief Stop a timer.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param timer Timer to stop, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_timer_stop(mcpwm_hal_context_t *hal, int timer);
|
||||
|
||||
/**
|
||||
* @brief Update the basic parameters of a timer.
|
||||
*
|
||||
* @note This will influence the duty rate and count mode of each operator relies on this timer.
|
||||
* Call `mcpwm_hal_operator_update_basic` for each of the operator that relies on this timer after
|
||||
* to update the duty rate and generator output.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param timer Timer to update, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_timer_update_basic(mcpwm_hal_context_t *hal, int timer);
|
||||
|
||||
/**
|
||||
* @brief Start the synchronization for a timer.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param timer Timer to enable, 0-2.
|
||||
* @param sync_conf Configuration of the sync operation.
|
||||
*/
|
||||
void mcpwm_hal_timer_enable_sync(mcpwm_hal_context_t *hal, int timer, const mcpwm_hal_sync_config_t *sync_conf);
|
||||
|
||||
/**
|
||||
* @brief Stop the synchronization for a timer.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param timer Timer to disable sync, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_timer_disable_sync(mcpwm_hal_context_t *hal, int timer);
|
||||
|
||||
/**
|
||||
* @brief Update the basic settings (duty, output mode) for an operator.
|
||||
*
|
||||
* Will call `mcpwm_hal_operator_update_comparator` and `mcpwm_hal_operator_update_generator`
|
||||
* recursively to update each of their duty and output mode.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param op Operator to update, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_operator_update_basic(mcpwm_hal_context_t *hal, int op);
|
||||
|
||||
/**
|
||||
* @brief Update a comparator (duty) for an operator.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param op Operator to update, 0-2.
|
||||
* @param cmp Comparator to update, 0-1.
|
||||
*/
|
||||
void mcpwm_hal_operator_update_comparator(mcpwm_hal_context_t *hal, int op, int cmp);
|
||||
|
||||
/**
|
||||
* @brief Update a generator (output mode) for an operator.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param op Operator to update, 0-2.
|
||||
* @param cmp Comparator to update, 0-1.
|
||||
*/
|
||||
void mcpwm_hal_operator_update_generator(mcpwm_hal_context_t *hal, int op, int gen_num);
|
||||
|
||||
/**
|
||||
* @brief Enable the carrier for an operator.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param op Operator to enable carrier, 0-2.
|
||||
* @param carrier_conf Configuration of the carrier.
|
||||
*/
|
||||
void mcpwm_hal_operator_enable_carrier(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_carrier_conf_t *carrier_conf);
|
||||
|
||||
/**
|
||||
* @brief Disable the carrier for an operator.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param op Operator to disable carrier, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_operator_disable_carrier(mcpwm_hal_context_t *hal, int op);
|
||||
|
||||
/**
|
||||
* @brief Update the deadzone for an operator.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param op Operator to update the deadzone, 0-2.
|
||||
* @param deadzone Configuration of the deadzone. Set member `mode` to `MCPWM_DEADTIME_BYPASS` will bypass the deadzone.
|
||||
*/
|
||||
void mcpwm_hal_operator_update_deadzone(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_deadzone_conf_t *deadzone);
|
||||
|
||||
/**
|
||||
* @brief Enable one of the fault signal.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param fault_sig The signal to enable, 0-2.
|
||||
* @param level The active level for the fault signal, true for high and false for low.
|
||||
*/
|
||||
void mcpwm_hal_fault_init(mcpwm_hal_context_t *hal, int fault_sig, bool level);
|
||||
|
||||
/**
|
||||
* @brief Configure how the operator behave to the fault signals.
|
||||
*
|
||||
* Call after the fault signal is enabled by `mcpwm_hal_fault_init`.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param op Operator to configure, 0-2.
|
||||
* @param fault_conf Configuration of the behavior of the operator when fault. Clear member `cbc_enabled_mask` and `ost_enabled_mask` will disable the fault detection of this operator.
|
||||
*/
|
||||
void mcpwm_hal_operator_update_fault(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_fault_conf_t *fault_conf);
|
||||
|
||||
/**
|
||||
* @brief Clear the oneshot fault status for an operator.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param op The operator to clear oneshot fault status, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_fault_oneshot_clear(mcpwm_hal_context_t *hal, int op);
|
||||
|
||||
/**
|
||||
* @brief Disable one of the fault signal.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param fault_sig The fault signal to disable, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_fault_disable(mcpwm_hal_context_t *hal, int fault_sig);
|
||||
|
||||
/**
|
||||
* @brief Enable one of the capture signal.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param cap_sig Capture signal to enable, 0-2.
|
||||
* @param conf Configuration on how to capture the signal.
|
||||
*/
|
||||
void mcpwm_hal_capture_enable(mcpwm_hal_context_t *hal, int cap_sig, const mcpwm_hal_capture_config_t *conf);
|
||||
|
||||
/**
|
||||
* @brief Get the capture result.
|
||||
*
|
||||
* @note The output value will always be updated with the register value, no matter event triggered or not.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param cap_sig Signal to get capture result, 0-2.
|
||||
* @param out_count Output of the captured counter.
|
||||
* @param out_edge Output of the captured edge.
|
||||
* @return
|
||||
* - ESP_OK: if a signal is captured
|
||||
* - ESP_ERR_NOT_FOUND: if no capture event happened.
|
||||
*/
|
||||
esp_err_t mcpwm_hal_capture_get_result(mcpwm_hal_context_t *hal, int cap_sig, uint32_t *out_count,
|
||||
mcpwm_capture_on_edge_t *out_edge);
|
||||
|
||||
/**
|
||||
* @brief Disable one of the capture signal.
|
||||
*
|
||||
* @param hal Context of the HAL layer.
|
||||
* @param cap_sig The signal to capture, 0-2.
|
||||
*/
|
||||
void mcpwm_hal_capture_disable(mcpwm_hal_context_t *hal, int cap_sig);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -14,74 +14,39 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
/// Interrupts for MCPWM
|
||||
typedef enum {
|
||||
MCPWM_LL_INTR_CAP0 = BIT(27), ///< Capture 0 happened
|
||||
MCPWM_LL_INTR_CAP1 = BIT(28), ///< Capture 1 happened
|
||||
MCPWM_LL_INTR_CAP2 = BIT(29), ///< Capture 2 happened
|
||||
} mcpwm_intr_t;
|
||||
MCPWM_TIMER_DIRECTION_UP, /*!< Counting direction: Increase */
|
||||
MCPWM_TIMER_DIRECTION_DOWN, /*!< Counting direction: Decrease */
|
||||
} mcpwm_timer_direction_t;
|
||||
|
||||
/**
|
||||
* @brief Select type of MCPWM counter
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_UP_COUNTER = 1, /*!<For asymmetric MCPWM*/
|
||||
MCPWM_DOWN_COUNTER, /*!<For asymmetric MCPWM*/
|
||||
MCPWM_UP_DOWN_COUNTER, /*!<For symmetric MCPWM, frequency is half of MCPWM frequency set*/
|
||||
MCPWM_COUNTER_MAX, /*!<Maximum counter mode*/
|
||||
} mcpwm_counter_type_t;
|
||||
MCPWM_TIMER_EVENT_ZERO, /*!< MCPWM timer counts to zero */
|
||||
MCPWM_TIMER_EVENT_PEAK, /*!< MCPWM timer counts to peak */
|
||||
} mcpwm_timer_event_t;
|
||||
|
||||
/**
|
||||
* @brief Select type of MCPWM duty cycle mode
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_DUTY_MODE_0 = 0, /*!<Active high duty, i.e. duty cycle proportional to high time for asymmetric MCPWM*/
|
||||
MCPWM_DUTY_MODE_1, /*!<Active low duty, i.e. duty cycle proportional to low time for asymmetric MCPWM, out of phase(inverted) MCPWM*/
|
||||
MCPWM_HAL_GENERATOR_MODE_FORCE_LOW,
|
||||
MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH,
|
||||
MCPWM_DUTY_MODE_MAX, /*!<Num of duty cycle modes*/
|
||||
} mcpwm_duty_type_t;
|
||||
MCPWM_TIMER_COUNT_MODE_PAUSE, /*!< MCPWM timer paused */
|
||||
MCPWM_TIMER_COUNT_MODE_UP, /*!< MCPWM timer counting up */
|
||||
MCPWM_TIMER_COUNT_MODE_DOWN, /*!< MCPWM timer counting down */
|
||||
MCPWM_TIMER_COUNT_MODE_UP_DOWN, /*!< MCPWM timer counting up and down */
|
||||
} mcpwm_timer_count_mode_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM select action to be taken on the output when event happens
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_ACTION_NO_CHANGE = 0, /*!<No change in the output*/
|
||||
MCPWM_ACTION_FORCE_LOW, /*!<Make output low*/
|
||||
MCPWM_ACTION_FORCE_HIGH, /*!<Make output high*/
|
||||
MCPWM_ACTION_TOGGLE, /*!<Make output toggle*/
|
||||
} mcpwm_output_action_t;
|
||||
MCPWM_TIMER_STOP_AT_ZERO, /*!< MCPWM timer stops when couting to zero */
|
||||
MCPWM_TIMER_STOP_AT_PEAK, /*!< MCPWM timer stops when counting to peak */
|
||||
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;
|
||||
|
||||
/**
|
||||
* @brief MCPWM deadtime types, used to generate deadtime, RED refers to rising edge delay and FED refers to falling edge delay
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_DEADTIME_BYPASS = 0, /*!<Bypass the deadtime*/
|
||||
MCPWM_BYPASS_RED, /*!<MCPWMXA = no change, MCPWMXB = falling edge delay*/
|
||||
MCPWM_BYPASS_FED, /*!<MCPWMXA = rising edge delay, MCPWMXB = no change*/
|
||||
MCPWM_ACTIVE_HIGH_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = falling edge delay*/
|
||||
MCPWM_ACTIVE_LOW_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = compliment of falling edge delay*/
|
||||
MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = compliment of falling edge delay*/
|
||||
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_t;
|
||||
MCPWM_GEN_ACTION_KEEP, /*!< Generator action: Keep the same level */
|
||||
MCPWM_GEN_ACTION_LOW, /*!< Generator action: Force to low level */
|
||||
MCPWM_GEN_ACTION_HIGH, /*!< Generator action: Force to high level */
|
||||
MCPWM_GEN_ACTION_TOGGLE, /*!< Generator action: Toggle level */
|
||||
} mcpwm_generator_action_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM select sync signal input
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_SELECT_SYNC0 = 4, /*!<Select SYNC0 as input*/
|
||||
MCPWM_SELECT_SYNC1, /*!<Select SYNC1 as input*/
|
||||
MCPWM_SELECT_SYNC2, /*!<Select SYNC2 as input*/
|
||||
} mcpwm_sync_signal_t;
|
||||
|
||||
/**
|
||||
* @brief MCPWM select capture starts from which edge
|
||||
*/
|
||||
typedef enum {
|
||||
MCPWM_NEG_EDGE = BIT(0), /*!<Capture the negative edge*/
|
||||
MCPWM_POS_EDGE = BIT(1), /*!<Capture the positive edge*/
|
||||
MCPWM_BOTH_EDGE = BIT(1)|BIT(0), /*!<Capture both edges*/
|
||||
} mcpwm_capture_on_edge_t;
|
||||
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;
|
||||
|
@ -15,216 +15,9 @@
|
||||
// The HAL layer for MCPWM (common part)
|
||||
|
||||
#include "hal/mcpwm_hal.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/mcpwm_ll.h"
|
||||
|
||||
void mcpwm_hal_init(mcpwm_hal_context_t *hal, const mcpwm_hal_init_config_t *init_config)
|
||||
{
|
||||
hal->dev = MCPWM_LL_GET_HW(init_config->host_id);
|
||||
}
|
||||
|
||||
void mcpwm_hal_hw_init(mcpwm_hal_context_t *hal)
|
||||
{
|
||||
mcpwm_ll_init(hal->dev);
|
||||
mcpwm_ll_set_clock_prescale(hal->dev, hal->prescale);
|
||||
}
|
||||
|
||||
void mcpwm_hal_timer_start(mcpwm_hal_context_t *hal, int timer)
|
||||
{
|
||||
mcpwm_ll_timer_start(hal->dev, timer);
|
||||
}
|
||||
|
||||
void mcpwm_hal_timer_stop(mcpwm_hal_context_t *hal, int timer)
|
||||
{
|
||||
mcpwm_ll_timer_stop(hal->dev, timer);
|
||||
}
|
||||
|
||||
void mcpwm_hal_timer_update_basic(mcpwm_hal_context_t *hal, int timer)
|
||||
{
|
||||
mcpwm_ll_timer_set_prescale(hal->dev, timer, hal->timer[timer].timer_prescale);
|
||||
|
||||
uint32_t period = MCPWM_BASE_CLK / (hal->timer[timer].freq *
|
||||
(hal->prescale + 1) * (hal->timer[timer].timer_prescale + 1));
|
||||
mcpwm_ll_timer_set_period(hal->dev, timer, period);
|
||||
//write back the actual value to the context
|
||||
hal->timer[timer].freq = MCPWM_BASE_CLK / (period *
|
||||
(hal->prescale + 1) * (hal->timer[timer].timer_prescale + 1));
|
||||
|
||||
mcpwm_ll_timer_set_count_mode(hal->dev, timer, hal->timer[timer].count_mode);
|
||||
}
|
||||
|
||||
void mcpwm_hal_timer_enable_sync(mcpwm_hal_context_t *hal, int timer, const mcpwm_hal_sync_config_t *sync_conf)
|
||||
{
|
||||
uint32_t set_phase = mcpwm_ll_timer_get_period(hal->dev, timer) * sync_conf->reload_permillage / 1000;
|
||||
mcpwm_ll_sync_set_phase(hal->dev, timer, set_phase);
|
||||
|
||||
mcpwm_ll_sync_set_input(hal->dev, timer, sync_conf->sync_sig);
|
||||
mcpwm_ll_sync_enable(hal->dev, timer, 1);
|
||||
}
|
||||
|
||||
void mcpwm_hal_timer_disable_sync(mcpwm_hal_context_t *hal, int timer)
|
||||
{
|
||||
mcpwm_ll_sync_enable(hal->dev, timer, 0);
|
||||
}
|
||||
|
||||
void mcpwm_hal_operator_update_basic(mcpwm_hal_context_t *hal, int op)
|
||||
{
|
||||
mcpwm_hal_operator_config_t *op_conf = &hal->op[op];
|
||||
mcpwm_ll_operator_select_timer(hal->dev, op, op_conf->timer);
|
||||
for (int cmp = 0; cmp < SOC_MCPWM_COMPARATORS_PER_OPERATOR; cmp++) {
|
||||
mcpwm_hal_operator_update_comparator(hal, op, cmp);
|
||||
}
|
||||
for (int gen = 0; gen < SOC_MCPWM_GENERATORS_PER_OPERATOR; gen++) {
|
||||
mcpwm_hal_operator_update_generator(hal, op, gen);
|
||||
}
|
||||
}
|
||||
|
||||
void mcpwm_hal_operator_update_comparator(mcpwm_hal_context_t *hal, int op, int cmp)
|
||||
{
|
||||
int timer = hal->op[op].timer;
|
||||
uint32_t period = mcpwm_ll_timer_get_period(hal->dev, timer);
|
||||
mcpwm_ll_operator_set_compare(hal->dev, op, cmp, (hal->op[op].duty[cmp] * period) / 100);
|
||||
mcpwm_ll_operator_set_compare_upmethod(hal->dev, timer);
|
||||
}
|
||||
|
||||
void mcpwm_hal_operator_update_generator(mcpwm_hal_context_t *hal, int op, int gen_num)
|
||||
{
|
||||
mcpwm_hal_generator_config_t *gen_config = &(hal->op[op].gen[gen_num]);
|
||||
if (gen_config->duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH) {
|
||||
mcpwm_ll_gen_set_zero_action(hal->dev, op, gen_num, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_gen_set_period_action(hal->dev, op, gen_num, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_gen_set_cmp_action(hal->dev, op, gen_num, 0, MCPWM_ACTION_FORCE_HIGH, MCPWM_ACTION_FORCE_HIGH);
|
||||
mcpwm_ll_gen_set_cmp_action(hal->dev, op, gen_num, 1, MCPWM_ACTION_FORCE_HIGH, MCPWM_ACTION_FORCE_HIGH);
|
||||
} else if (gen_config->duty_type == MCPWM_HAL_GENERATOR_MODE_FORCE_LOW) {
|
||||
mcpwm_ll_gen_set_zero_action(hal->dev, op, gen_num, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_gen_set_period_action(hal->dev, op, gen_num, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_gen_set_cmp_action(hal->dev, op, gen_num, 0, MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_LOW);
|
||||
mcpwm_ll_gen_set_cmp_action(hal->dev, op, gen_num, 1, MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_LOW);
|
||||
} else if (gen_config->duty_type == MCPWM_DUTY_MODE_1 || gen_config->duty_type == MCPWM_DUTY_MODE_0) {
|
||||
const int timer_used = hal->op[op].timer;
|
||||
const int cmp_used = gen_config->comparator;
|
||||
const int cmp_not_used = 1 - gen_config->comparator;
|
||||
|
||||
mcpwm_output_action_t inactive_action;
|
||||
mcpwm_output_action_t active_action;
|
||||
const mcpwm_output_action_t no_action = MCPWM_ACTION_NO_CHANGE;
|
||||
if (gen_config->duty_type == MCPWM_DUTY_MODE_1) {
|
||||
active_action = MCPWM_ACTION_FORCE_LOW; //active low
|
||||
inactive_action = MCPWM_ACTION_FORCE_HIGH; //inactive high
|
||||
} else { //MCPWM_DUTY_MODE_0
|
||||
inactive_action = MCPWM_ACTION_FORCE_LOW; //inactive low
|
||||
active_action = MCPWM_ACTION_FORCE_HIGH; //active high
|
||||
}
|
||||
|
||||
if (hal->timer[timer_used].count_mode == MCPWM_UP_COUNTER) {
|
||||
mcpwm_ll_gen_set_zero_action(hal->dev, op, gen_num, active_action);
|
||||
mcpwm_ll_gen_set_period_action(hal->dev, op, gen_num, no_action);
|
||||
mcpwm_ll_gen_set_cmp_action(hal->dev, op, gen_num, cmp_used, inactive_action, no_action);
|
||||
} else if (hal->timer[timer_used].count_mode == MCPWM_DOWN_COUNTER) {
|
||||
mcpwm_ll_gen_set_zero_action(hal->dev, op, gen_num, no_action);
|
||||
mcpwm_ll_gen_set_period_action(hal->dev, op, gen_num, inactive_action);
|
||||
mcpwm_ll_gen_set_cmp_action(hal->dev, op, gen_num, cmp_used, no_action, active_action);
|
||||
} else { //Timer count up-down
|
||||
mcpwm_ll_gen_set_zero_action(hal->dev, op, gen_num, active_action);
|
||||
mcpwm_ll_gen_set_period_action(hal->dev, op, gen_num, no_action);
|
||||
mcpwm_ll_gen_set_cmp_action(hal->dev, op, gen_num, cmp_used, inactive_action, active_action);
|
||||
}
|
||||
mcpwm_ll_gen_set_cmp_action(hal->dev, op, gen_num, cmp_not_used, no_action, no_action);
|
||||
}
|
||||
}
|
||||
|
||||
void mcpwm_hal_operator_enable_carrier(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_carrier_conf_t *carrier_conf)
|
||||
{
|
||||
mcpwm_ll_carrier_init(hal->dev, op);
|
||||
mcpwm_ll_carrier_set_prescale(hal->dev, op, carrier_conf->period);
|
||||
mcpwm_ll_carrier_set_duty(hal->dev, op, carrier_conf->duty);
|
||||
mcpwm_ll_carrier_enable(hal->dev, op, true);
|
||||
mcpwm_ll_carrier_set_oneshot_width(hal->dev, op, carrier_conf->oneshot_pulse_width);
|
||||
mcpwm_ll_carrier_out_invert(hal->dev, op, carrier_conf->inverted);
|
||||
}
|
||||
|
||||
void mcpwm_hal_operator_disable_carrier(mcpwm_hal_context_t *hal, int op)
|
||||
{
|
||||
mcpwm_ll_carrier_enable(hal->dev, op, false);
|
||||
}
|
||||
|
||||
void mcpwm_hal_operator_update_deadzone(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_deadzone_conf_t *deadzone)
|
||||
{
|
||||
if (deadzone->mode != MCPWM_DEADTIME_BYPASS) {
|
||||
mcpwm_ll_deadtime_init(hal->dev, op);
|
||||
mcpwm_ll_deadtime_set_rising_delay(hal->dev, op, deadzone->red);
|
||||
mcpwm_ll_deadtime_set_falling_delay(hal->dev, op, deadzone->fed);
|
||||
mcpwm_ll_set_deadtime_mode(hal->dev, op, deadzone->mode);
|
||||
} else {
|
||||
mcpwm_ll_deadtime_bypass(hal->dev, op);
|
||||
}
|
||||
}
|
||||
|
||||
void mcpwm_hal_fault_init(mcpwm_hal_context_t *hal, int fault_sig, bool level)
|
||||
{
|
||||
mcpwm_ll_fault_enable(hal->dev, fault_sig, level);
|
||||
}
|
||||
|
||||
void mcpwm_hal_operator_update_fault(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_fault_conf_t *fault_conf)
|
||||
{
|
||||
for (int fault_sig = 0; fault_sig < SOC_MCPWM_FAULT_DETECTORS_PER_GROUP; fault_sig++) {
|
||||
bool enabled = (fault_conf->cbc_enabled_mask & BIT(fault_sig)) ? true : false;
|
||||
mcpwm_ll_fault_cbc_enable_signal(hal->dev, op, fault_sig, enabled);
|
||||
}
|
||||
for (int fault_sig = 0; fault_sig < SOC_MCPWM_FAULT_DETECTORS_PER_GROUP; fault_sig++) {
|
||||
bool enabled = (fault_conf->ost_enabled_mask & BIT(fault_sig)) ? true : false;
|
||||
mcpwm_ll_fault_oneshot_enable_signal(hal->dev, op, fault_sig, enabled);
|
||||
}
|
||||
if (fault_conf->cbc_enabled_mask) {
|
||||
for (int gen = 0; gen < SOC_MCPWM_GENERATORS_PER_OPERATOR; gen++) {
|
||||
mcpwm_ll_fault_set_cyc_action(hal->dev, op, gen, fault_conf->action_on_fault[gen], fault_conf->action_on_fault[gen]);
|
||||
}
|
||||
}
|
||||
if (fault_conf->ost_enabled_mask) {
|
||||
for (int gen = 0; gen < SOC_MCPWM_GENERATORS_PER_OPERATOR; gen++) {
|
||||
mcpwm_ll_fault_set_oneshot_action(hal->dev, op, gen, fault_conf->action_on_fault[gen], fault_conf->action_on_fault[gen]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mcpwm_hal_fault_oneshot_clear(mcpwm_hal_context_t *hal, int op)
|
||||
{
|
||||
mcpwm_ll_fault_clear_ost(hal->dev, op);
|
||||
}
|
||||
|
||||
void mcpwm_hal_fault_disable(mcpwm_hal_context_t *hal, int fault_sig)
|
||||
{
|
||||
for (int op = 0; op < SOC_MCPWM_OPERATORS_PER_GROUP; op++) {
|
||||
if (mcpwm_ll_fault_oneshot_signal_enabled(hal->dev, op, fault_sig)) {
|
||||
mcpwm_ll_fault_clear_ost(hal->dev, op);
|
||||
}
|
||||
}
|
||||
mcpwm_ll_fault_disable(hal->dev, fault_sig);
|
||||
}
|
||||
|
||||
void mcpwm_hal_capture_enable(mcpwm_hal_context_t *hal, int cap_sig, const mcpwm_hal_capture_config_t *conf)
|
||||
{
|
||||
mcpwm_ll_capture_enable(hal->dev, cap_sig, 1);
|
||||
mcpwm_ll_capture_select_edge(hal->dev, cap_sig, conf->cap_edge);
|
||||
mcpwm_ll_capture_set_prescale(hal->dev, cap_sig, conf->prescale);
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_hal_capture_get_result(mcpwm_hal_context_t *hal, int cap_sig, uint32_t *out_count, mcpwm_capture_on_edge_t *out_edge)
|
||||
{
|
||||
const mcpwm_intr_t sig_intr = mcpwm_ll_get_cap_intr_def(cap_sig);
|
||||
//unconditionally update the output value
|
||||
if (out_edge) {
|
||||
*out_edge = mcpwm_ll_get_captured_edge(hal->dev, cap_sig);
|
||||
}
|
||||
if (out_count) {
|
||||
*out_count = mcpwm_ll_get_capture_val(hal->dev, cap_sig);
|
||||
}
|
||||
if (mcpwm_ll_get_intr(hal->dev) & sig_intr) {
|
||||
mcpwm_ll_clear_intr(hal->dev, sig_intr);
|
||||
}
|
||||
return (mcpwm_ll_get_intr(hal->dev) & sig_intr ? ESP_OK : ESP_ERR_NOT_FOUND);
|
||||
}
|
||||
|
||||
void mcpwm_hal_capture_disable(mcpwm_hal_context_t *hal, int cap_sig)
|
||||
{
|
||||
mcpwm_ll_capture_enable(hal->dev, cap_sig, 0);
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ typedef volatile struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t start : 3; /*0: stop @ eqz, 1: stop @ eqp, 2: free run, 3: start and stop @ next eqz, 4: start and stop @ next eqp,*/
|
||||
uint32_t mod : 2; /* 0: freeze, 1: inc, 2: dec, 3: up-down*/
|
||||
uint32_t mode : 2; /* 0: freeze, 1: inc, 2: dec, 3: up-down*/
|
||||
uint32_t reserved5 : 27;
|
||||
};
|
||||
uint32_t val;
|
||||
@ -50,7 +50,8 @@ typedef volatile struct {
|
||||
uint32_t in_en : 1;
|
||||
uint32_t sync_sw : 1; /*write the negate value will trigger a sw sync*/
|
||||
uint32_t out_sel : 2;
|
||||
uint32_t phase : 17;
|
||||
uint32_t timer_phase : 16; /*phase for timer reload on sync event*/
|
||||
uint32_t phase_direct : 1; /*counter direction to apply on sync event*/
|
||||
uint32_t reserved21 : 11;
|
||||
};
|
||||
uint32_t val;
|
||||
|
@ -1,9 +1,7 @@
|
||||
MCPWM
|
||||
=====
|
||||
|
||||
.. This peripheral is ESP32 only
|
||||
|
||||
ESP32 has two MCPWM units which can be used to control different types of motors. Each unit has three pairs of PWM outputs.
|
||||
{IDF_TARGET_NAME} has two MCPWM units which can be used to control different types of motors. Each unit has three pairs of PWM outputs.
|
||||
|
||||
.. figure:: ../../../_static/mcpwm-overview.png
|
||||
:align: center
|
||||
|
Loading…
x
Reference in New Issue
Block a user