mcpwm: refactor driver

This commit is contained in:
morris
2021-01-07 17:36:54 +08:00
parent 0716520423
commit d4fe219c49
11 changed files with 2119 additions and 2047 deletions

View File

@@ -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;
}