Merge branch 'feature/mcpwm_refactor_and_support_esp32s3' into 'master'

MCPWM: refactor driver and support ESP32-S3

Closes IDF-1765

See merge request espressif/esp-idf!11907
This commit is contained in:
Michael (XIAO Xufeng)
2021-06-09 16:45:20 +00:00
13 changed files with 2440 additions and 2748 deletions

View File

@@ -428,7 +428,7 @@ component_ut_test_esp32c3:
UT_001: UT_001:
extends: .unit_test_esp32_template extends: .unit_test_esp32_template
parallel: 49 parallel: 50
tags: tags:
- ESP32_IDF - ESP32_IDF
- UT_T1_1 - UT_T1_1
@@ -540,20 +540,6 @@ UT_022:
- UT_T2_I2C - UT_T2_I2C
- psram - psram
UT_023:
extends: .unit_test_esp32_template
parallel: 2
tags:
- ESP32_IDF
- UT_T1_MCPWM
UT_024:
extends: .unit_test_esp32_template
tags:
- ESP32_IDF
- UT_T1_MCPWM
- psram
UT_028: UT_028:
extends: .unit_test_esp32_template extends: .unit_test_esp32_template
tags: tags:

View File

@@ -59,6 +59,7 @@ if(${target} STREQUAL "esp32s3")
"gdma.c" "gdma.c"
"sdmmc_host.c" "sdmmc_host.c"
"sdmmc_transaction.c" "sdmmc_transaction.c"
"mcpwm.c"
"spi_slave_hd.c" "spi_slave_hd.c"
"touch_sensor_common.c" "touch_sensor_common.c"
) )

View File

@@ -8,7 +8,6 @@
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#if SOC_MCPWM_SUPPORTED #if SOC_MCPWM_SUPPORTED
#include "esp_err.h" #include "esp_err.h"
#include "soc/soc.h" #include "soc/soc.h"
#include "driver/gpio.h" #include "driver/gpio.h"
@@ -20,7 +19,6 @@
extern "C" { extern "C" {
#endif #endif
/** /**
* @brief IO signals for the MCPWM * @brief IO signals for the MCPWM
* *
@@ -130,6 +128,15 @@ typedef enum {
MCPWM_SELECT_F2, /*!<Select F2 as input*/ MCPWM_SELECT_F2, /*!<Select F2 as input*/
} mcpwm_fault_signal_t; } 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 * @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_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
} mcpwm_fault_input_level_t; } 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 /// @deprecated MCPWM select action to be taken on MCPWMXA when fault occurs
typedef mcpwm_output_action_t mcpwm_action_on_pwmxa_t; 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 * @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 mcpwm_num set MCPWM unit(0-1)
* @param cap_edge set capture edge, BIT(0) - negative edge, BIT(1) - positive edge * @param cap_edge set capture edge, BIT(0) - negative edge, BIT(1) - positive edge
* @param cap_sig capture pin, which needs to be enabled * @param cap_sig capture pin, which needs to be enabled

View File

@@ -5,39 +5,24 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include "esp_log.h" #include "sdkconfig.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "freertos/xtensa_api.h" #include "freertos/xtensa_api.h"
#include "freertos/task.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 "soc/gpio_periph.h"
#include "driver/mcpwm.h" #include "soc/mcpwm_periph.h"
#include "driver/periph_ctrl.h"
#include "sdkconfig.h"
#include "hal/mcpwm_hal.h" #include "hal/mcpwm_hal.h"
#include "hal/gpio_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 { static const char *TAG = "mcpwm";
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); \
}
#define MCPWM_DRIVER_INIT_ERROR "MCPWM DRIVER NOT INITIALIZED" #define MCPWM_DRIVER_INIT_ERROR "MCPWM DRIVER NOT INITIALIZED"
#define MCPWM_GROUP_NUM_ERROR "MCPWM GROUP NUM ERROR" #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_GEN_ERROR "MCPWM GENERATOR ERROR"
#define MCPWM_DT_ERROR "MCPWM DEADTIME TYPE ERROR" #define MCPWM_DT_ERROR "MCPWM DEADTIME TYPE ERROR"
#define MCPWM_CLK_PRESCL 15 //MCPWM clock prescale #define MCPWM_GROUP_CLK_HZ (SOC_MCPWM_BASE_CLK_HZ / 16)
#define TIMER_CLK_PRESCALE 9 //MCPWM timer prescales #define MCPWM_TIMER_CLK_HZ (MCPWM_GROUP_CLK_HZ / 10)
#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
_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_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_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."); _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 {\ #define MCPWM_TIMER_ID_CHECK(mcpwm_num, timer_num) \
MCPWM_CHECK((mcpwm_num) < SOC_MCPWM_GROUPS, MCPWM_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG); \ do { \
MCPWM_CHECK((timer_num) < SOC_MCPWM_TIMERS_PER_GROUP, MCPWM_TIMER_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((timer_num) < SOC_MCPWM_TIMERS_PER_GROUP, ESP_ERR_INVALID_ARG, TAG, MCPWM_TIMER_ERROR); \
} while (0) } while (0)
#define MCPWM_TIMER_CHECK(mcpwm_num, timer_num) do{\ #define MCPWM_TIMER_CHECK(mcpwm_num, timer_num) \
do { \
MCPWM_TIMER_ID_CHECK(mcpwm_num, timer_num); \ MCPWM_TIMER_ID_CHECK(mcpwm_num, timer_num); \
MCPWM_CHECK(context[mcpwm_num].hal.dev != NULL, MCPWM_DRIVER_INIT_ERROR, ESP_ERR_INVALID_STATE); \ ESP_RETURN_ON_FALSE(context[mcpwm_num].hal.dev, ESP_ERR_INVALID_STATE, TAG, MCPWM_DRIVER_INIT_ERROR); \
} while (0) } while (0)
#define MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen) do{ \ #define MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen) \
do { \
MCPWM_TIMER_CHECK(mcpwm_num, timer_num); \ MCPWM_TIMER_CHECK(mcpwm_num, timer_num); \
MCPWM_CHECK(gen < MCPWM_GEN_MAX, MCPWM_GEN_ERROR, ESP_ERR_INVALID_ARG); \ ESP_RETURN_ON_FALSE((gen) < MCPWM_GEN_MAX, ESP_ERR_INVALID_ARG, TAG, MCPWM_GEN_ERROR); \
} while (0) } while (0)
typedef struct {
mcpwm_hal_context_t hal;
portMUX_TYPE spinlock;
} mcpwm_context_t;
static mcpwm_context_t context[SOC_MCPWM_GROUPS] = { static mcpwm_context_t context[SOC_MCPWM_GROUPS] = {
CONTEXT_INITIALIZER(), [0 ... SOC_MCPWM_GROUPS - 1] = {
CONTEXT_INITIALIZER(), .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) 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; return ESP_OK;
} }
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_CHECK((GPIO_IS_VALID_GPIO(gpio_num)), MCPWM_GPIO_ERROR, ESP_ERR_INVALID_ARG); 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 if (io_signal <= MCPWM2B) { // Generator output signal
MCPWM_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)), MCPWM_GPIO_ERROR, ESP_ERR_INVALID_ARG); 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_INPUT_OUTPUT); gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
int operator_id = io_signal / 2; int operator_id = io_signal / 2;
int generator_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); 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 } 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; 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); 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 } 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; int fault_id = io_signal - MCPWM_FAULT_0;
esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].detectors[fault_id].fault_sig, 0); esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].detectors[fault_id].fault_sig, 0);
} else if (io_signal >= MCPWM_CAP_0 && io_signal <= MCPWM_CAP_2) { // Capture input signal } 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; 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); 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; return ESP_OK;
} }
esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_pin) 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, MCPWM0A, mcpwm_pin->mcpwm0a_out_num); //MCPWM0A
mcpwm_gpio_init(mcpwm_num, MCPWM0B, mcpwm_pin->mcpwm0b_out_num); //MCPWM0B mcpwm_gpio_init(mcpwm_num, MCPWM0B, mcpwm_pin->mcpwm0b_out_num); //MCPWM0B
mcpwm_gpio_init(mcpwm_num, MCPWM1A, mcpwm_pin->mcpwm1a_out_num); //MCPWM1A 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_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_critical_enter(mcpwm_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_critical_enter(mcpwm_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_critical_enter(mcpwm_num); mcpwm_critical_enter(mcpwm_num);
hal->timer[timer_num].freq = frequency;
mcpwm_hal_timer_update_basic(hal, timer_num); mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num);
//update the operator to update the duty uint32_t previous_peak = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false);
mcpwm_hal_operator_update_basic(hal, op); 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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_critical_enter(mcpwm_num); mcpwm_critical_enter(mcpwm_num);
hal->op[op].duty[cmp] = duty; uint32_t set_duty = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false) * duty / 100;
mcpwm_hal_operator_update_comparator(hal, op, gen); 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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_critical_enter(mcpwm_num); mcpwm_critical_enter(mcpwm_num);
hal->op[op].duty[cmp] = (100 * duty_in_us * hal->timer[timer_num].freq) / (1000 * 1000.); // the timer resolution is fixed to 1us in the driver, so duty_in_us is the same to compare value
mcpwm_hal_operator_update_comparator(hal, op, gen); 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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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 //the driver currently always use the timer x for operator x
const int op = timer_num; const int op = timer_num;
MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen); 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; 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); mcpwm_critical_enter(mcpwm_num);
hal->op[op].gen[gen] = (mcpwm_hal_generator_config_t) { switch (mcpwm_ll_timer_get_count_mode(hal->dev, timer_num)) {
.comparator = gen, //the driver currently always use the comparator A for PWMxA output, and comparator B for PWMxB output case MCPWM_TIMER_COUNT_MODE_UP:
.duty_type = duty_type, 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_hal_operator_update_generator(hal, op, gen); 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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; return ESP_OK;
} }
esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpwm_config_t *mcpwm_conf) 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; const int op = timer_num;
MCPWM_TIMER_ID_CHECK(mcpwm_num, op); 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_context_t *hal = &context[mcpwm_num].hal;
mcpwm_hal_init_config_t init_config = { periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module);
.host_id = mcpwm_num, mcpwm_hal_init_config_t config = {
.host_id = mcpwm_num
}; };
mcpwm_hal_init(hal, &config);
mcpwm_critical_enter(mcpwm_num); mcpwm_critical_enter(mcpwm_num);
mcpwm_hal_init(hal, &init_config); mcpwm_ll_group_set_clock(hal->dev, MCPWM_GROUP_CLK_HZ);
mcpwm_hal_hw_init(hal); mcpwm_ll_group_enable_shadow_mode(hal->dev);
mcpwm_ll_group_flush_shadow(hal->dev);
hal->timer[timer_num].timer_prescale = TIMER_CLK_PRESCALE; mcpwm_ll_timer_set_clock(hal->dev, timer_num, MCPWM_GROUP_CLK_HZ, MCPWM_TIMER_CLK_HZ);
hal->timer[timer_num].freq = mcpwm_conf->frequency; mcpwm_ll_timer_set_count_mode(hal->dev, timer_num, mcpwm_conf->counter_mode);
hal->timer[timer_num].count_mode = 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);
//the driver currently always use the timer x for operator x mcpwm_ll_operator_select_timer(hal->dev, timer_num, timer_num); //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_critical_exit(mcpwm_num); 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; return ESP_OK;
} }
uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
{ {
MCPWM_TIMER_CHECK(mcpwm_num, 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) 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 //the driver currently always use the timer x for operator x
const int op = timer_num; const int op = timer_num;
MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen); 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) 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 //the driver currently always use the timer x for operator x
const int op = timer_num; return mcpwm_set_duty_type(mcpwm_num, timer_num, gen, MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH);
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;
} }
esp_err_t mcpwm_set_signal_low(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen) 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 //the driver currently always use the timer x for operator x
const int op = timer_num; return mcpwm_set_duty_type(mcpwm_num, timer_num, gen, MCPWM_HAL_GENERATOR_MODE_FORCE_LOW);
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;
} }
esp_err_t mcpwm_carrier_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) 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_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_critical_enter(mcpwm_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_critical_enter(mcpwm_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_hal_carrier_conf_t carrier = { mcpwm_carrier_enable(mcpwm_num, timer_num);
.period = carrier_conf->carrier_period, mcpwm_carrier_set_period(mcpwm_num, timer_num, carrier_conf->carrier_period);
.duty = carrier_conf->carrier_duty, mcpwm_carrier_set_duty_cycle(mcpwm_num, timer_num, carrier_conf->carrier_duty);
.inverted = carrier_conf->carrier_ivt_mode,
};
if (carrier_conf->carrier_os_mode == MCPWM_ONESHOT_MODE_EN) { 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 { } 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_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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 //the driver currently always use the timer x for operator x
const int op = timer_num; const int op = timer_num;
MCPWM_TIMER_CHECK(mcpwm_num, 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_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_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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; const int op = timer_num;
MCPWM_TIMER_CHECK(mcpwm_num, timer_num); MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; 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_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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) 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_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; return ESP_OK;
} }
esp_err_t mcpwm_fault_deinit(mcpwm_unit_t mcpwm_num, mcpwm_fault_signal_t fault_sig) 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_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_critical_enter(mcpwm_num); mcpwm_critical_enter(mcpwm_num);
mcpwm_ll_fault_cbc_enable_signal(hal->dev, op, fault_sig, true); mcpwm_ll_fault_enable_cbc_mode(hal->dev, op, fault_sig, true);
mcpwm_ll_fault_oneshot_enable_signal(hal->dev, op, fault_sig, false); mcpwm_ll_fault_enable_oneshot_mode(hal->dev, op, fault_sig, false);
mcpwm_ll_fault_set_cyc_action(hal->dev, op, 0, action_on_pwmxa, action_on_pwmxa); 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_fault_set_cyc_action(hal->dev, op, 1, action_on_pwmxb, action_on_pwmxb); 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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_critical_enter(mcpwm_num); mcpwm_critical_enter(mcpwm_num);
mcpwm_hal_fault_oneshot_clear(hal, op); mcpwm_ll_fault_clear_ost(hal->dev, op);
mcpwm_ll_fault_cbc_enable_signal(hal->dev, op, fault_sig, false); mcpwm_ll_fault_enable_oneshot_mode(hal->dev, op, fault_sig, true);
mcpwm_ll_fault_oneshot_enable_signal(hal->dev, op, fault_sig, true); mcpwm_ll_fault_enable_cbc_mode(hal->dev, op, fault_sig, false);
mcpwm_ll_fault_set_oneshot_action(hal->dev, op, 0, action_on_pwmxa, action_on_pwmxa); 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_fault_set_oneshot_action(hal->dev, op, 1, action_on_pwmxb, action_on_pwmxb); 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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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, 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) uint32_t num_of_pulse)
{ {
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_CHECK(num_of_pulse <= MCPWM_LL_MAX_PRESCALE, MCPWM_PRESCALE_ERROR, ESP_ERR_INVALID_ARG); 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 // enable MCPWM module incase user don't use `mcpwm_init` at all
periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module); periph_module_enable(mcpwm_periph_signals.groups[mcpwm_num].module);
mcpwm_hal_init_config_t init_config = { mcpwm_hal_init_config_t init_config = {
.host_id = mcpwm_num, .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); 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_init(hal, &init_config);
mcpwm_hal_hw_init(hal); mcpwm_ll_group_set_clock(hal->dev, MCPWM_GROUP_CLK_HZ);
mcpwm_hal_capture_enable(hal, cap_sig, &cap_conf); 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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; return ESP_OK;
} }
esp_err_t mcpwm_capture_disable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig) 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_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); mcpwm_critical_exit(mcpwm_num);
periph_module_disable(mcpwm_periph_signals.groups[mcpwm_num].module); periph_module_disable(mcpwm_periph_signals.groups[mcpwm_num].module);
return ESP_OK; 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) 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); 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);
uint32_t captured_value; mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_hal_capture_get_result(&context[mcpwm_num].hal, cap_sig, &captured_value, NULL); return mcpwm_ll_capture_get_value(hal->dev, cap_sig);
return captured_value;
} }
uint32_t mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t 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); ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR);
mcpwm_capture_on_edge_t edge; ESP_RETURN_ON_FALSE(cap_sig < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR);
mcpwm_hal_capture_get_result(&context[mcpwm_num].hal, cap_sig, NULL, &edge); mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
return (edge == MCPWM_NEG_EDGE ? 2 : 1); 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, 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_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; 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_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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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) esp_err_t mcpwm_sync_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
{ {
MCPWM_TIMER_CHECK(mcpwm_num, timer_num); MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
mcpwm_critical_enter(mcpwm_num); 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); mcpwm_critical_exit(mcpwm_num);
return ESP_OK; 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 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; esp_err_t ret;
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_CHECK(fn != NULL, MCPWM_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG); 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); ret = esp_intr_alloc(mcpwm_periph_signals.groups[mcpwm_num].irq_id, intr_alloc_flags, fn, arg, handle);
return ret; return ret;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -73,6 +73,7 @@ if(NOT BOOTLOADER_BUILD)
list(APPEND srcs list(APPEND srcs
"gdma_hal.c" "gdma_hal.c"
"lcd_hal.c" "lcd_hal.c"
"mcpwm_hal.c"
"pcnt_hal.c" "pcnt_hal.c"
"spi_flash_hal_gpspi.c" "spi_flash_hal_gpspi.c"
"spi_slave_hd_hal.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

View File

@@ -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"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with 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) // 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 #pragma once
#include <esp_err.h> #include "soc/mcpwm_struct.h"
#include "hal/mcpwm_ll.h"
#define MCPWM_BASE_CLK (2 * APB_CLK_FREQ) //2*APB_CLK_FREQ 160Mhz
/// Configuration of HAL that used only once.
typedef struct { 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; } mcpwm_hal_init_config_t;
/// Configuration of each generator (output of operator)
typedef struct { typedef struct {
mcpwm_duty_type_t duty_type; ///< How the generator output mcpwm_dev_t *dev; ///< Beginning address of the peripheral registers of a single MCPWM unit. Call `mcpwm_hal_init` to initialize it.
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_hal_context_t; } 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. * @brief Initialize the internal state of the HAL.
*
* @note Since There are several individual parts (timers + operators, captures), this funciton is
* allowed to called several times.
* *
* @param hal Context of the HAL layer. * @param hal Context of the HAL layer.
* @param init_config Configuration for the HAL to be used only once. * @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); 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);

View File

@@ -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"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -14,74 +14,39 @@
#pragma once #pragma once
/// Interrupts for MCPWM
typedef enum { typedef enum {
MCPWM_LL_INTR_CAP0 = BIT(27), ///< Capture 0 happened MCPWM_TIMER_DIRECTION_UP, /*!< Counting direction: Increase */
MCPWM_LL_INTR_CAP1 = BIT(28), ///< Capture 1 happened MCPWM_TIMER_DIRECTION_DOWN, /*!< Counting direction: Decrease */
MCPWM_LL_INTR_CAP2 = BIT(29), ///< Capture 2 happened } mcpwm_timer_direction_t;
} mcpwm_intr_t;
/**
* @brief Select type of MCPWM counter
*/
typedef enum { typedef enum {
MCPWM_UP_COUNTER = 1, /*!<For asymmetric MCPWM*/ MCPWM_TIMER_EVENT_ZERO, /*!< MCPWM timer counts to zero */
MCPWM_DOWN_COUNTER, /*!<For asymmetric MCPWM*/ MCPWM_TIMER_EVENT_PEAK, /*!< MCPWM timer counts to peak */
MCPWM_UP_DOWN_COUNTER, /*!<For symmetric MCPWM, frequency is half of MCPWM frequency set*/ } mcpwm_timer_event_t;
MCPWM_COUNTER_MAX, /*!<Maximum counter mode*/
} mcpwm_counter_type_t;
/**
* @brief Select type of MCPWM duty cycle mode
*/
typedef enum { typedef enum {
MCPWM_DUTY_MODE_0 = 0, /*!<Active high duty, i.e. duty cycle proportional to high time for asymmetric MCPWM*/ MCPWM_TIMER_COUNT_MODE_PAUSE, /*!< MCPWM timer paused */
MCPWM_DUTY_MODE_1, /*!<Active low duty, i.e. duty cycle proportional to low time for asymmetric MCPWM, out of phase(inverted) MCPWM*/ MCPWM_TIMER_COUNT_MODE_UP, /*!< MCPWM timer counting up */
MCPWM_HAL_GENERATOR_MODE_FORCE_LOW, MCPWM_TIMER_COUNT_MODE_DOWN, /*!< MCPWM timer counting down */
MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH, MCPWM_TIMER_COUNT_MODE_UP_DOWN, /*!< MCPWM timer counting up and down */
MCPWM_DUTY_MODE_MAX, /*!<Num of duty cycle modes*/ } mcpwm_timer_count_mode_t;
} mcpwm_duty_type_t;
/**
* @brief MCPWM select action to be taken on the output when event happens
*/
typedef enum { typedef enum {
MCPWM_ACTION_NO_CHANGE = 0, /*!<No change in the output*/ MCPWM_TIMER_STOP_AT_ZERO, /*!< MCPWM timer stops when couting to zero */
MCPWM_ACTION_FORCE_LOW, /*!<Make output low*/ MCPWM_TIMER_STOP_AT_PEAK, /*!< MCPWM timer stops when counting to peak */
MCPWM_ACTION_FORCE_HIGH, /*!<Make output high*/ MCPWM_TIMER_START_NO_STOP, /*!< MCPWM timer starts couting */
MCPWM_ACTION_TOGGLE, /*!<Make output toggle*/ MCPWM_TIMER_START_STOP_AT_ZERO, /*!< MCPWM timer starts counting and stops when couting to zero */
} mcpwm_output_action_t; 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 { typedef enum {
MCPWM_DEADTIME_BYPASS = 0, /*!<Bypass the deadtime*/ MCPWM_GEN_ACTION_KEEP, /*!< Generator action: Keep the same level */
MCPWM_BYPASS_RED, /*!<MCPWMXA = no change, MCPWMXB = falling edge delay*/ MCPWM_GEN_ACTION_LOW, /*!< Generator action: Force to low level */
MCPWM_BYPASS_FED, /*!<MCPWMXA = rising edge delay, MCPWMXB = no change*/ MCPWM_GEN_ACTION_HIGH, /*!< Generator action: Force to high level */
MCPWM_ACTIVE_HIGH_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = falling edge delay*/ MCPWM_GEN_ACTION_TOGGLE, /*!< Generator action: Toggle level */
MCPWM_ACTIVE_LOW_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = compliment of falling edge delay*/ } mcpwm_generator_action_t;
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 sync signal input
*/
typedef enum { typedef enum {
MCPWM_SELECT_SYNC0 = 4, /*!<Select SYNC0 as input*/ MCPWM_FAULT_REACTION_CBC, /*!< Reaction on fault signal: recover cycle by cycle */
MCPWM_SELECT_SYNC1, /*!<Select SYNC1 as input*/ MCPWM_FAULT_REACTION_OST, /*!< Reaction on fault signal: one shot trip */
MCPWM_SELECT_SYNC2, /*!<Select SYNC2 as input*/ } mcpwm_fault_reaction_t;
} 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;

View File

@@ -15,216 +15,9 @@
// The HAL layer for MCPWM (common part) // The HAL layer for MCPWM (common part)
#include "hal/mcpwm_hal.h" #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) 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); 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);
}

View File

@@ -40,7 +40,7 @@ typedef volatile struct {
union { union {
struct { 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 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 reserved5 : 27;
}; };
uint32_t val; uint32_t val;
@@ -50,7 +50,8 @@ typedef volatile struct {
uint32_t in_en : 1; uint32_t in_en : 1;
uint32_t sync_sw : 1; /*write the negate value will trigger a sw sync*/ uint32_t sync_sw : 1; /*write the negate value will trigger a sw sync*/
uint32_t out_sel : 2; 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 reserved21 : 11;
}; };
uint32_t val; uint32_t val;

View File

@@ -1,9 +1,7 @@
MCPWM MCPWM
===== =====
.. This peripheral is ESP32 only {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.
ESP32 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 .. figure:: ../../../_static/mcpwm-overview.png
:align: center :align: center