mcpwm: add HAL layer support

Also improved the unit tests a bit.
This commit is contained in:
michael 2019-11-17 20:53:29 +08:00
parent 1fb2fd89de
commit 538540ce21
13 changed files with 2062 additions and 789 deletions

View file

@ -21,6 +21,8 @@
#include "driver/periph_ctrl.h"
#include "esp_intr_alloc.h"
#include "soc/soc_caps.h"
#include "hal/mcpwm_types.h"
#include "soc/mcpwm_caps.h"
#ifndef SOC_MCPWM_SUPPORTED
#error MCPWM is not supported in this chip target
@ -30,6 +32,7 @@
extern "C" {
#endif
/**
* @brief IO signals for the MCPWM
*
@ -87,6 +90,8 @@ typedef enum {
MCPWM_UNIT_MAX, /*!<Num of MCPWM units on ESP32*/
} mcpwm_unit_t;
_Static_assert(MCPWM_UNIT_MAX == SOC_MCPWM_PERIPH_NUM, "MCPWM unit number not equal to chip capabilities");
/**
* @brief Select MCPWM timer
*/
@ -101,29 +106,16 @@ typedef enum {
* @brief Select MCPWM operator
*/
typedef enum {
MCPWM_OPR_A = 0, /*!<Select MCPWMXA, where 'X' is timer number*/
MCPWM_OPR_B, /*!<Select MCPWMXB, where 'X' is timer number*/
MCPWM_OPR_MAX, /*!<Num of operators to each timer of MCPWM*/
} mcpwm_operator_t;
MCPWM_GEN_A = 0, /*!<Select MCPWMXA, where 'X' is operator number*/
MCPWM_GEN_B, /*!<Select MCPWMXB, where 'X' is operator number*/
MCPWM_GEN_MAX, /*!<Num of generators to each operator of MCPWM*/
} mcpwm_generator_t;
/**
* @brief Select type of MCPWM counter
*/
typedef enum {
MCPWM_UP_COUNTER = 1, /*!<For asymmetric MCPWM*/
MCPWM_DOWN_COUNTER, /*!<For asymmetric MCPWM*/
MCPWM_UP_DOWN_COUNTER, /*!<For symmetric MCPWM, frequency is half of MCPWM frequency set*/
MCPWM_COUNTER_MAX, /*!<Maximum counter mode*/
} mcpwm_counter_type_t;
/**
* @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_DUTY_MODE_MAX, /*!<Num of duty cycle modes*/
} mcpwm_duty_type_t;
//definitions and macros to be back-compatible before IDFv4.1
#define MCPWM_OPR_A MCPWM_GEN_A ///< @deprecated
#define MCPWM_OPR_B MCPWM_GEN_B ///< @deprecated
#define MCPWM_OPR_MAX MCPWM_GEN_MAX ///< @deprecated
typedef mcpwm_generator_t mcpwm_operator_t; ///< @deprecated
/**
* @brief MCPWM carrier oneshot mode, in this mode the width of the first pulse of carrier can be programmed
@ -141,15 +133,6 @@ typedef enum {
MCPWM_CARRIER_OUT_IVT_EN, /*!<Disable carrier output inversion*/
} mcpwm_carrier_out_ivt_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 fault signal input
*/
@ -167,25 +150,20 @@ typedef enum {
MCPWM_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
} mcpwm_fault_input_level_t;
/**
* @brief MCPWM select action to be taken on MCPWMXA when fault occurs
*/
typedef enum {
MCPWM_NO_CHANGE_IN_MCPWMXA = 0, /*!<No change in MCPWMXA output*/
MCPWM_FORCE_MCPWMXA_LOW, /*!<Make MCPWMXA output low*/
MCPWM_FORCE_MCPWMXA_HIGH, /*!<Make MCPWMXA output high*/
MCPWM_TOG_MCPWMXA, /*!<Make MCPWMXA output toggle*/
} mcpwm_action_on_pwmxa_t;
/**
* @brief MCPWM select action to be taken on MCPWMxB when fault occurs
*/
typedef enum {
MCPWM_NO_CHANGE_IN_MCPWMXB = 0, /*!<No change in MCPWMXB output*/
MCPWM_FORCE_MCPWMXB_LOW, /*!<Make MCPWMXB output low*/
MCPWM_FORCE_MCPWMXB_HIGH, /*!<Make MCPWMXB output high*/
MCPWM_TOG_MCPWMXB, /*!<Make MCPWMXB output toggle*/
} mcpwm_action_on_pwmxb_t;
/// @deprecated MCPWM select action to be taken on MCPWMXA when fault occurs
typedef mcpwm_output_action_t mcpwm_action_on_pwmxa_t;
#define MCPWM_NO_CHANGE_IN_MCPWMXA MCPWM_ACTION_NO_CHANGE /*!< @deprecated No change in MCPWMXA output*/
#define MCPWM_FORCE_MCPWMXA_LOW MCPWM_ACTION_FORCE_LOW /*!< @deprecated Make MCPWMXA output low*/
#define MCPWM_FORCE_MCPWMXA_HIGH MCPWM_ACTION_FORCE_HIGH /*!< @deprecated Make MCPWMXA output high*/
#define MCPWM_TOG_MCPWMXA MCPWM_ACTION_TOGGLE /*!< @deprecated Make MCPWMXA output toggle*/
/// @deprecated MCPWM select action to be taken on MCPWMXB when fault occurs
typedef mcpwm_output_action_t mcpwm_action_on_pwmxb_t;
#define MCPWM_NO_CHANGE_IN_MCPWMXB MCPWM_ACTION_NO_CHANGE /*!< @deprecated No change in MCPWMXB output*/
#define MCPWM_FORCE_MCPWMXB_LOW MCPWM_ACTION_FORCE_LOW /*!< @deprecated Make MCPWMXB output low*/
#define MCPWM_FORCE_MCPWMXB_HIGH MCPWM_ACTION_FORCE_HIGH /*!< @deprecated Make MCPWMXB output high*/
#define MCPWM_TOG_MCPWMXB MCPWM_ACTION_TOGGLE /*!< @deprecated Make MCPWMXB output toggle*/
/**
* @brief MCPWM select capture signal input
@ -196,29 +174,6 @@ typedef enum {
MCPWM_SELECT_CAP2, /*!<Select CAP2 as input*/
} mcpwm_capture_signal_t;
/**
* @brief MCPWM select capture starts from which edge
*/
typedef enum {
MCPWM_NEG_EDGE = 0, /*!<Capture starts from negative edge*/
MCPWM_POS_EDGE, /*!<Capture starts from positive edge*/
} mcpwm_capture_on_edge_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_BYPASS_RED = 0, /*!<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 config structure
*/
@ -241,7 +196,6 @@ typedef struct {
mcpwm_carrier_out_ivt_t carrier_ivt_mode; /*!<Invert output of carrier*/
} mcpwm_carrier_config_t;
/**
* @brief This function initializes each gpio signal for MCPWM
* @note
@ -276,7 +230,7 @@ esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_
* @brief Initialize MCPWM parameters
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers.
* @param mcpwm_conf configure structure mcpwm_config_t
*
* @return
@ -303,28 +257,28 @@ esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, u
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param op_num set the operator(MCPWMXA/MCPWMXB), 'X' is timer number selected
* @param gen set the generator(MCPWMXA/MCPWMXB), 'X' is operator number selected
* @param duty set duty cycle in %(i.e for 62.3% duty cycle, duty = 62.3) of each operator
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t op_num, float duty);
esp_err_t mcpwm_set_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, float duty);
/**
* @brief Set duty cycle of each operator(MCPWMXA/MCPWMXB) in us
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param op_num set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
* @param duty set duty value in microseconds of each operator
* @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
* @param duty_in_us set duty value in microseconds of each operator
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t op_num, uint32_t duty);
esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, uint32_t duty_in_us);
/**
* @brief Set duty either active high or active low(out of phase/inverted)
@ -333,14 +287,14 @@ esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param op_num set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
* @param duty_num set active low or active high duty type
* @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
* @param duty_type set active low or active high duty type
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_duty_type(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t op_num, mcpwm_duty_type_t duty_num);
esp_err_t mcpwm_set_duty_type(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, mcpwm_duty_type_t duty_type);
/**
* @brief Get frequency of timer
@ -358,40 +312,41 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param op_num set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
* @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
*
* @return
* - duty cycle in % of each operator(56.7 means duty is 56.7%)
*/
float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t op_num);
float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen);
/**
* @brief Use this function to set MCPWM signal high
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param op_num set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
* @param gen set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_signal_high(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t op_num);
esp_err_t mcpwm_set_signal_high(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen);
/**
* @brief Use this function to set MCPWM signal low
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param op_num set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
* @param gen set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_signal_low(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t op_num);
esp_err_t mcpwm_set_signal_low(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen);
/**
* @brief Start MCPWM signal on timer 'x'
*
@ -578,7 +533,7 @@ esp_err_t mcpwm_fault_init(mcpwm_unit_t mcpwm_num, mcpwm_fault_input_level_t int
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_fault_signal_t fault_sig,
mcpwm_action_on_pwmxa_t action_on_pwmxa, mcpwm_action_on_pwmxb_t action_on_pwmxb);
mcpwm_output_action_t action_on_pwmxa, mcpwm_output_action_t action_on_pwmxb);
/**
* @brief Set cycle-by-cycle mode on fault detection, once fault occur in cyc mode MCPWM signal resumes as soon as fault signal becomes inactive
@ -596,7 +551,7 @@ esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_fault_set_cyc_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_fault_signal_t fault_sig,
mcpwm_action_on_pwmxa_t action_on_pwmxa, mcpwm_action_on_pwmxb_t action_on_pwmxb);
mcpwm_output_action_t action_on_pwmxa, mcpwm_output_action_t action_on_pwmxb);
/**
* @brief Disable fault signal

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@
#include "esp_log.h"
#include "soc/rtc.h"
#define GPIO_PWMA_OUT 4
#define GPIO_PWMB_OUT 13
#define GPIO_CAP_IN 27
@ -65,9 +66,23 @@ typedef struct {
mcpwm_capture_signal_t sel_cap_signal;
} capture;
static const char TAG[] = "test_pwm";
const static mcpwm_io_signals_t pwma[] = {MCPWM0A, MCPWM1A, MCPWM2A};
const static mcpwm_io_signals_t pwmb[] = {MCPWM0B, MCPWM1B, MCPWM2B};
const static mcpwm_fault_signal_t fault_sig_array[] = {MCPWM_SELECT_F0, MCPWM_SELECT_F1, MCPWM_SELECT_F2};
const static mcpwm_io_signals_t fault_io_sig_array[] = {MCPWM_FAULT_0, MCPWM_FAULT_1, MCPWM_FAULT_2};
const static mcpwm_sync_signal_t sync_sig_array[] = {MCPWM_SELECT_SYNC0, MCPWM_SELECT_SYNC1, MCPWM_SELECT_SYNC2};
const static mcpwm_io_signals_t sync_io_sig_array[] = {MCPWM_SYNC_0, MCPWM_SYNC_1, MCPWM_SYNC_2};
const static mcpwm_capture_signal_t cap_sig_array[] = {MCPWM_SELECT_CAP0, MCPWM_SELECT_CAP1, MCPWM_SELECT_CAP2};
const static mcpwm_io_signals_t cap_io_sig_array[] = {MCPWM_CAP_0, MCPWM_CAP_1, MCPWM_CAP_2};
// universal settings of mcpwm
static void mcpwm_basic_config(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer)
static void mcpwm_basic_config(mcpwm_unit_t unit, mcpwm_timer_t timer)
{
mcpwm_io_signals_t mcpwm_a = pwma[timer];
mcpwm_io_signals_t mcpwm_b = pwmb[timer];
mcpwm_gpio_init(unit, mcpwm_a, GPIO_PWMA_OUT);
mcpwm_gpio_init(unit, mcpwm_b, GPIO_PWMB_OUT);
mcpwm_config_t pwm_config = {
@ -119,10 +134,10 @@ static int16_t pcnt_count(int pulse_gpio_num, int ctrl_gpio_num, int last_time)
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("COUNT: %d\n", test_counter);
printf("COUNT (before): %d\n", test_counter);
vTaskDelay(last_time / portTICK_RATE_MS);
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
printf("COUNT: %d\n", test_counter);
printf("COUNT (after): %d\n", test_counter);
return test_counter;
}
@ -139,9 +154,9 @@ static void judge_count_value(int allow_error ,int expect_freq)
}
// test the duty configuration
static void timer_duty_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer)
static void timer_duty_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
{
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
mcpwm_basic_config(unit, timer);
vTaskDelay(1000 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_A, (INITIAL_DUTY * 1)));
@ -149,7 +164,7 @@ static void timer_duty_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm
TEST_ASSERT_EQUAL_INT(mcpwm_get_duty(unit, timer, MCPWM_OPR_A), INITIAL_DUTY * 1);
TEST_ASSERT_EQUAL_INT(mcpwm_get_duty(unit, timer, MCPWM_OPR_B), INITIAL_DUTY * 2);
vTaskDelay(1000 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
vTaskDelay(100 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
mcpwm_set_duty(unit, timer, MCPWM_OPR_A, 55.5f);
mcpwm_set_duty_type(unit, timer, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
@ -157,13 +172,15 @@ static void timer_duty_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm
mcpwm_set_duty_in_us(unit, timer, MCPWM_OPR_B, 500);
printf("mcpwm check = %f\n", mcpwm_get_duty(unit, timer, MCPWM_OPR_B));
vTaskDelay(1000 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
vTaskDelay(100 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
mcpwm_stop(unit, timer);
}
// test the start and stop function work or not
static void start_stop_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer)
static void start_stop_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
{
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
mcpwm_basic_config(unit, timer);
judge_count_value(2, 1000);
TEST_ESP_OK(mcpwm_stop(unit, timer));
vTaskDelay(10 / portTICK_RATE_MS); // wait for a while, stop totally
@ -174,17 +191,21 @@ static void start_stop_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm
}
// test the deadtime
static void deadtime_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer)
static void deadtime_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
{
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
mcpwm_basic_config(unit, timer);
mcpwm_deadtime_type_t deadtime_type[8] = {MCPWM_BYPASS_RED, MCPWM_BYPASS_FED, MCPWM_ACTIVE_HIGH_MODE,
MCPWM_ACTIVE_LOW_MODE, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, MCPWM_ACTIVE_LOW_COMPLIMENT_MODE,
MCPWM_ACTIVE_RED_FED_FROM_PWMXA, MCPWM_ACTIVE_RED_FED_FROM_PWMXB};
for(int i=0; i<8; i++) {
mcpwm_deadtime_enable(unit, timer, deadtime_type[i], 1000, 1000);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(100 / portTICK_RATE_MS);
mcpwm_deadtime_disable(unit, timer);
//add a small gap between tests to make the waveform more clear
mcpwm_stop(unit, timer);
vTaskDelay(10);
mcpwm_start(unit, timer);
}
}
@ -193,11 +214,11 @@ static void deadtime_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_i
* 1. by mcpwm_carrier_init
* 2. by different single setting function
*/
static void carrier_with_set_function_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
mcpwm_carrier_out_ivt_t invert_or_not, uint8_t period, uint8_t duty, uint8_t os_width)
static void carrier_with_set_function_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_carrier_out_ivt_t invert_or_not,
uint8_t period, uint8_t duty, uint8_t os_width)
{
// no inversion and no one shot
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
mcpwm_basic_config(unit, timer);
TEST_ESP_OK(mcpwm_carrier_enable(unit, timer));
TEST_ESP_OK(mcpwm_carrier_set_period(unit, timer, period)); //carrier revolution
TEST_ESP_OK(mcpwm_carrier_set_duty_cycle(unit, timer, duty)); // carrier duty
@ -208,10 +229,11 @@ static void carrier_with_set_function_test(mcpwm_unit_t unit, mcpwm_io_signals_t
vTaskDelay(2000 / portTICK_RATE_MS);
}
static void carrier_with_configuration_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
mcpwm_carrier_os_t oneshot_or_not, mcpwm_carrier_out_ivt_t invert_or_not, uint8_t period, uint8_t duty, uint8_t os_width)
static void carrier_with_configuration_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_carrier_os_t oneshot_or_not,
mcpwm_carrier_out_ivt_t invert_or_not, uint8_t period, uint8_t duty,
uint8_t os_width)
{
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
mcpwm_basic_config(unit, timer);
mcpwm_carrier_config_t chop_config;
chop_config.carrier_period = period; //carrier period = (period + 1)*800ns
@ -263,9 +285,9 @@ static void get_action_level(mcpwm_fault_input_level_t input_sig, mcpwm_action_o
}
// test the fault event
static void cycle_fault_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
mcpwm_fault_signal_t fault_sig, mcpwm_fault_input_level_t input_sig, mcpwm_io_signals_t fault_io,
mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
static void cycle_fault_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_fault_signal_t fault_sig,
mcpwm_fault_input_level_t input_sig, mcpwm_io_signals_t fault_io,
mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
{
gpio_config_t gp;
gp.intr_type = GPIO_INTR_DISABLE;
@ -277,7 +299,7 @@ static void cycle_fault_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpw
pcnt_init(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1);
pcnt_init(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO2);
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
mcpwm_basic_config(unit, timer);
mcpwm_gpio_init(unit, fault_io, GPIO_FAULT_IN);
// cycle mode, it can be triggered more than once
@ -292,9 +314,9 @@ static void cycle_fault_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpw
TEST_ESP_OK(mcpwm_fault_deinit(unit, fault_sig));
}
static void oneshot_fault_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
mcpwm_fault_signal_t fault_sig, mcpwm_fault_input_level_t input_sig, mcpwm_io_signals_t fault_io,
mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
static void oneshot_fault_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_fault_signal_t fault_sig,
mcpwm_fault_input_level_t input_sig, mcpwm_io_signals_t fault_io,
mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
{
gpio_config_t gp;
gp.intr_type = GPIO_INTR_DISABLE;
@ -306,23 +328,22 @@ static void oneshot_fault_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mc
pcnt_init(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1);
pcnt_init(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO2);
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
mcpwm_basic_config(unit, timer);
mcpwm_gpio_init(unit, fault_io, GPIO_FAULT_IN);
// one shot mode, it just can be triggered once
TEST_ESP_OK(mcpwm_fault_init(unit, input_sig, fault_sig));
TEST_ESP_OK(mcpwm_fault_set_oneshot_mode(unit, timer, fault_sig, action_a, action_b));
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(10 / portTICK_RATE_MS);
// trigger it
gpio_set_level(FAULT_SIG_NUM, input_sig);
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(10 / portTICK_RATE_MS);
get_action_level(input_sig, action_a, action_b, 1000, 5);
TEST_ESP_OK(mcpwm_fault_deinit(unit, fault_sig));
}
// test the sync event
static void sync_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
mcpwm_sync_signal_t sync_sig, mcpwm_io_signals_t sync_io)
static void sync_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_sync_signal_t sync_sig, mcpwm_io_signals_t sync_io)
{
gpio_config_t gp;
gp.intr_type = GPIO_INTR_DISABLE;
@ -331,6 +352,8 @@ static void sync_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_si
gpio_config(&gp);
gpio_set_level(SYN_SIG_NUM, 0);
mcpwm_io_signals_t mcpwm_a = pwma[timer];
mcpwm_io_signals_t mcpwm_b = pwmb[timer];
mcpwm_gpio_init(unit, mcpwm_a, GPIO_PWMA_OUT);
mcpwm_gpio_init(unit, mcpwm_b, GPIO_PWMB_OUT);
mcpwm_gpio_init(unit, sync_io, GPIO_SYNC_IN);
@ -345,10 +368,13 @@ static void sync_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_si
gpio_pulldown_en(GPIO_SYNC_IN);
mcpwm_sync_enable(unit, timer, sync_sig, 200);
//wait for some pulses before sync
vTaskDelay(10);
gpio_set_level(SYN_SIG_NUM, 1);
vTaskDelay(2000 / portTICK_RATE_MS);
vTaskDelay(100 / portTICK_RATE_MS);
gpio_set_level(SYN_SIG_NUM, 0);
mcpwm_sync_disable(unit, timer);
vTaskDelay(2000 / portTICK_RATE_MS);
vTaskDelay(100 / portTICK_RATE_MS);
}
/**
@ -398,7 +424,7 @@ static void disp_captured_signal(void *arg)
// mcpwm event
static void IRAM_ATTR isr_handler(void *arg)
{
mcpwm_unit_t unit = (mcpwm_unit_t)arg;
mcpwm_unit_t unit = (mcpwm_unit_t)arg;
uint32_t mcpwm_intr_status;
capture evt;
mcpwm_intr_status = MCPWM[unit]->int_st.val; //Read interrupt status
@ -441,15 +467,19 @@ static void gpio_test_signal(void *arg)
vTaskDelete(NULL);
}
// capture event test function
static void capture_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_io_signals_t cap_io, mcpwm_timer_t timer,
mcpwm_capture_signal_t cap_sig, mcpwm_capture_on_edge_t cap_edge)
static void capture_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_capture_on_edge_t cap_edge)
{
// initialize the capture times
// initialize the capture times
cap0_times = 0;
cap1_times = 0;
cap2_times = 0;
//each timer test the capture sig with the same id with it.
mcpwm_io_signals_t cap_io = cap_io_sig_array[timer];
mcpwm_capture_signal_t cap_sig = cap_sig_array[timer];
mcpwm_gpio_init(unit, cap_io, GPIO_CAP_IN);
cap_queue = xQueueCreate(1, sizeof(capture));
@ -463,11 +493,11 @@ static void capture_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io
vTaskDelay(10 / portTICK_RATE_MS);
}
if(cap_sig == MCPWM_SELECT_CAP0) {
TEST_ASSERT(1000 == cap0_times);
TEST_ASSERT(1000 == cap0_times);
} else if(cap_sig == MCPWM_SELECT_CAP1) {
TEST_ASSERT(1000 == cap1_times);
TEST_ASSERT(1000 == cap1_times);
}else {
TEST_ASSERT(1000 == cap2_times);
TEST_ASSERT(1000 == cap2_times);
}
flag = 0; // set flag to 0 that it can be used in other case
mcpwm_capture_disable(unit, cap_sig);
@ -483,137 +513,126 @@ static void capture_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io
*/
TEST_CASE("MCPWM timer0 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
{
timer_duty_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
timer_duty_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
timer_duty_test(MCPWM_UNIT_0, MCPWM_TIMER_0);
timer_duty_test(MCPWM_UNIT_1, MCPWM_TIMER_0);
}
TEST_CASE("MCPWM timer1 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
{
timer_duty_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
timer_duty_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
timer_duty_test(MCPWM_UNIT_0, MCPWM_TIMER_1);
timer_duty_test(MCPWM_UNIT_1, MCPWM_TIMER_1);
}
TEST_CASE("MCPWM timer2 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
{
timer_duty_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
timer_duty_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
timer_duty_test(MCPWM_UNIT_0, MCPWM_TIMER_2);
timer_duty_test(MCPWM_UNIT_1, MCPWM_TIMER_2);
}
// the deadtime configuration test
// use the logic analyzer to make sure it goes right
TEST_CASE("MCPWM timer0 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
{
deadtime_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
deadtime_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
deadtime_test(MCPWM_UNIT_0, MCPWM_TIMER_0);
deadtime_test(MCPWM_UNIT_1, MCPWM_TIMER_0);
}
TEST_CASE("MCPWM timer1 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
{
deadtime_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
deadtime_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
deadtime_test(MCPWM_UNIT_0, MCPWM_TIMER_1);
deadtime_test(MCPWM_UNIT_1, MCPWM_TIMER_1);
}
TEST_CASE("MCPWM timer2 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
{
deadtime_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
deadtime_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
deadtime_test(MCPWM_UNIT_0, MCPWM_TIMER_2);
deadtime_test(MCPWM_UNIT_1, MCPWM_TIMER_2);
}
TEST_CASE("MCPWM timer0 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
{
start_stop_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
start_stop_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
start_stop_test(MCPWM_UNIT_0, MCPWM_TIMER_0);
start_stop_test(MCPWM_UNIT_1, MCPWM_TIMER_0);
}
// mcpwm start and stop test
TEST_CASE("MCPWM timer1 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
{
start_stop_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
start_stop_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
start_stop_test(MCPWM_UNIT_0, MCPWM_TIMER_1);
start_stop_test(MCPWM_UNIT_1, MCPWM_TIMER_1);
}
TEST_CASE("MCPWM timer2 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
{
start_stop_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
start_stop_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
start_stop_test(MCPWM_UNIT_0, MCPWM_TIMER_2);
start_stop_test(MCPWM_UNIT_1, MCPWM_TIMER_2);
}
TEST_CASE("MCPWM timer0 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
{
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_0,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_0,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_0,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_0,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
}
TEST_CASE("MCPWM timer1 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
{
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_1,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_1,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_1,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_1,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
}
TEST_CASE("MCPWM timer2 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
{
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_2,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_2,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_2,
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_2,
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
}
static void test_carrier_with_config_func(mcpwm_unit_t unit, mcpwm_timer_t timer)
{
mcpwm_carrier_os_t oneshot[2] = {MCPWM_ONESHOT_MODE_DIS, MCPWM_ONESHOT_MODE_EN};
mcpwm_carrier_out_ivt_t invert[2] = {MCPWM_CARRIER_OUT_IVT_DIS, MCPWM_CARRIER_OUT_IVT_EN};
ESP_LOGI(TAG, "test unit%d timer%d", unit, timer);
for(int i=0; i<2; i++){
for(int j=0; j<2; j++) {
printf("i=%d, j=%d\n", i, j);
carrier_with_configuration_test(unit, timer, oneshot[i], invert[j], 6, 3, 3);
}
}
}
TEST_CASE("MCPWM timer0 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]")
{
mcpwm_carrier_os_t oneshot[2] = {MCPWM_ONESHOT_MODE_DIS, MCPWM_ONESHOT_MODE_EN};
mcpwm_carrier_out_ivt_t invert[2] = {MCPWM_CARRIER_OUT_IVT_DIS, MCPWM_CARRIER_OUT_IVT_EN};
for(int i=0; i<2; i++){
for(int j=0; j<2; j++) {
printf("i=%d, j=%d\n", i, j);
carrier_with_configuration_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
oneshot[i], invert[j], 6, 3, 3);
carrier_with_configuration_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
oneshot[i], invert[j], 6, 3, 3);
}
}
test_carrier_with_config_func(MCPWM_UNIT_0, MCPWM_TIMER_0);
test_carrier_with_config_func(MCPWM_UNIT_1, MCPWM_TIMER_0);
}
TEST_CASE("MCPWM timer1 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]")
{
mcpwm_carrier_os_t oneshot[2] = {MCPWM_ONESHOT_MODE_DIS, MCPWM_ONESHOT_MODE_EN};
mcpwm_carrier_out_ivt_t invert[2] = {MCPWM_CARRIER_OUT_IVT_DIS, MCPWM_CARRIER_OUT_IVT_EN};
for(int i=0; i<2; i++){
for(int j=0; j<2; j++) {
carrier_with_configuration_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
oneshot[i], invert[j], 6, 3, 3);
carrier_with_configuration_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
oneshot[i], invert[j], 6, 3, 3);
}
}
TEST_CASE("MCPWM timer1 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]") {
test_carrier_with_config_func(MCPWM_UNIT_0, MCPWM_TIMER_1);
test_carrier_with_config_func(MCPWM_UNIT_1, MCPWM_TIMER_1);
}
TEST_CASE("MCPWM timer2 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]")
{
mcpwm_carrier_os_t oneshot[2] = {MCPWM_ONESHOT_MODE_DIS, MCPWM_ONESHOT_MODE_EN};
mcpwm_carrier_out_ivt_t invert[2] = {MCPWM_CARRIER_OUT_IVT_DIS, MCPWM_CARRIER_OUT_IVT_EN};
for(int i=0; i<2; i++){
for(int j=0; j<2; j++) {
carrier_with_configuration_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
oneshot[i], invert[j], 6, 3, 3);
carrier_with_configuration_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
oneshot[i], invert[j], 6, 3, 3);
}
}
test_carrier_with_config_func(MCPWM_UNIT_0, MCPWM_TIMER_2);
test_carrier_with_config_func(MCPWM_UNIT_1, MCPWM_TIMER_2);
}
/**
@ -624,184 +643,143 @@ TEST_CASE("MCPWM timer2 carrier test with configuration function", "[mcpwm][test
* 2. cycle: it can be triggered more than once, it will changed just as the fault signal changes. If set it triggered by high level,
* when the fault signal is high level, the event will be triggered. But the event will disappear as the fault signal disappears
*/
TEST_CASE("MCPWM timer0 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
void test_cycle_fault(mcpwm_unit_t unit, mcpwm_timer_t timer)
{
// API just supports the high level trigger now, so comment it
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
ESP_LOGI(TAG, "test unit%d timer%d", unit, timer);
//each timer test the fault sig with the same id with it.
mcpwm_fault_signal_t fault_sig = fault_sig_array[timer];
mcpwm_io_signals_t fault_io_sig = fault_io_sig_array[timer];
for(int i=0; i<4; i++){
for(int j=0; j<4; j++) {
printf("i=%d, j=%d\n",i, j);
cycle_fault_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
action_a[i], action_b[j]);
cycle_fault_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
action_a[i], action_b[j]);
cycle_fault_test(unit, timer, fault_sig, MCPWM_HIGH_LEVEL_TGR, fault_io_sig, action_a[i], action_b[j]);
}
}
}
TEST_CASE("MCPWM timer0 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
{
test_cycle_fault(MCPWM_UNIT_0, MCPWM_TIMER_0);
test_cycle_fault(MCPWM_UNIT_1, MCPWM_TIMER_0);
}
TEST_CASE("MCPWM timer1 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
{
// API just supports the high level trigger now, so comment it
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
for(int i=0; i<4; i++){
for(int j=0; j<4; j++) {
cycle_fault_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
MCPWM_SELECT_F1, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_1,
action_a[i], action_b[j]);
cycle_fault_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
MCPWM_SELECT_F1, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_1,
action_a[i], action_b[j]);
}
}
test_cycle_fault(MCPWM_UNIT_0, MCPWM_TIMER_1);
test_cycle_fault(MCPWM_UNIT_1, MCPWM_TIMER_1);
}
TEST_CASE("MCPWM timer2 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
{
test_cycle_fault(MCPWM_UNIT_0, MCPWM_TIMER_2);
test_cycle_fault(MCPWM_UNIT_1, MCPWM_TIMER_2);
}
static void test_oneshot_fault(mcpwm_unit_t unit, mcpwm_timer_t timer)
{
// API just supports the high level trigger now, so comment it
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
//each timer test the fault sig with the same id with it.
mcpwm_fault_signal_t fault_sig = fault_sig_array[timer];
mcpwm_io_signals_t fault_io_sig = fault_io_sig_array[timer];
ESP_LOGI(TAG, "test pwm unit%d, timer%d fault_sig%d", unit, timer, fault_sig);
for(int i=0; i<4; i++){
for(int j=0; j<4; j++) {
cycle_fault_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
MCPWM_SELECT_F2, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_2,
action_a[i], action_b[j]);
cycle_fault_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
MCPWM_SELECT_F2, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_2,
action_a[i], action_b[j]);
printf("action (%d, %d)\n", i, j);
oneshot_fault_test(unit, timer, fault_sig, MCPWM_HIGH_LEVEL_TGR, fault_io_sig, action_a[i], action_b[j]);
}
}
}
TEST_CASE("MCPWM timer0 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
// API just supports the high level trigger now, so comment it
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
for(int i=0; i<4; i++){
for(int j=0; j<4; j++) {
printf("i=%d, j=%d\n",i, j);
oneshot_fault_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
action_a[i], action_b[j]);
oneshot_fault_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
action_a[i], action_b[j]);
}
}
test_oneshot_fault(MCPWM_UNIT_0, MCPWM_TIMER_0);
test_oneshot_fault(MCPWM_UNIT_1, MCPWM_TIMER_0);
}
TEST_CASE("MCPWM timer1 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
// API just supports the high level trigger now, so comment it
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
for(int i=0; i<4; i++){
for(int j=0; j<4; j++) {
oneshot_fault_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
MCPWM_SELECT_F1, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_1,
action_a[i], action_b[j]);
oneshot_fault_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
MCPWM_SELECT_F1, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_1,
action_a[i], action_b[j]);
}
}
test_oneshot_fault(MCPWM_UNIT_0, MCPWM_TIMER_1);
test_oneshot_fault(MCPWM_UNIT_1, MCPWM_TIMER_1);
}
TEST_CASE("MCPWM timer2 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
// API just supports the high level trigger now, so comment it
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
test_oneshot_fault(MCPWM_UNIT_0, MCPWM_TIMER_2);
test_oneshot_fault(MCPWM_UNIT_1, MCPWM_TIMER_2);
}
for(int i=0; i<4; i++){
for(int j=0; j<4; j++) {
oneshot_fault_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
MCPWM_SELECT_F2, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_2,
action_a[i], action_b[j]);
oneshot_fault_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
MCPWM_SELECT_F2, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_2,
action_a[i], action_b[j]);
}
}
static void test_sync(mcpwm_timer_t timer)
{
//each timer test the sync sig with the same id with it.
mcpwm_sync_signal_t sync_sig = sync_sig_array[timer];
mcpwm_io_signals_t sync_io_sig = sync_io_sig_array[timer];
sync_test(MCPWM_UNIT_0, timer, sync_sig, sync_io_sig);
TEST_ESP_OK(mcpwm_stop(MCPWM_UNIT_0, timer)); // make sure can view the next sync signal clearly
vTaskDelay(100 / portTICK_RATE_MS);
TEST_ESP_OK(mcpwm_start(MCPWM_UNIT_0, timer));
sync_test(MCPWM_UNIT_1, timer, sync_sig, sync_io_sig);
}
// need to view its phenomenon in logic analyzer
// set it ignore
TEST_CASE("MCPWM timer0 sync test(logic analyzer)", "[mcpwm][ignore]")
{
sync_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0, MCPWM_SELECT_SYNC0, MCPWM_SYNC_0);
TEST_ESP_OK(mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_0)); // make sure can view the next sync signal clearly
vTaskDelay(1000 / portTICK_RATE_MS);
TEST_ESP_OK(mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_0));
sync_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0, MCPWM_SELECT_SYNC0, MCPWM_SYNC_0);
test_sync(MCPWM_TIMER_0);
}
// need to view its phenomenon in logic analyzer
// set it ignore
TEST_CASE("MCPWM timer1 sync test(logic analyzer)", "[mcpwm][ignore]")
{
sync_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1, MCPWM_SELECT_SYNC1, MCPWM_SYNC_1);
TEST_ESP_OK(mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_1)); // make sure can view the next sync signal clearly
vTaskDelay(1000 / portTICK_RATE_MS);
TEST_ESP_OK(mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_1));
sync_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1, MCPWM_SELECT_SYNC1, MCPWM_SYNC_1);
test_sync(MCPWM_TIMER_1);
}
// need to view its phenomenon in logic analyzer
// set it ignore
TEST_CASE("MCPWM timer2 sync test(logic analyzer)", "[mcpwm][ignore]")
{
sync_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2, MCPWM_SELECT_SYNC2, MCPWM_SYNC_2);
TEST_ESP_OK(mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_2)); // make sure can view the next sync signal clearly
vTaskDelay(1000 / portTICK_RATE_MS);
TEST_ESP_OK(mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_2));
sync_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2, MCPWM_SELECT_SYNC2, MCPWM_SYNC_2);
test_sync(MCPWM_TIMER_2);
}
TEST_CASE("MCPWM unit0, timer0 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
capture_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_CAP_0, MCPWM_TIMER_0, MCPWM_SELECT_CAP0, MCPWM_POS_EDGE);
capture_test(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_POS_EDGE);
}
TEST_CASE("MCPWM uni0, timer1 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
TEST_CASE("MCPWM unit0, timer1 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
capture_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_CAP_1, MCPWM_TIMER_1, MCPWM_SELECT_CAP1, MCPWM_POS_EDGE);
capture_test(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_POS_EDGE);
}
TEST_CASE("MCPWM unit0, timer2 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
capture_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_CAP_2, MCPWM_TIMER_2, MCPWM_SELECT_CAP2, MCPWM_POS_EDGE);
capture_test(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_POS_EDGE);
}
TEST_CASE("MCPWM unit1, timer0 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
capture_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_CAP_0, MCPWM_TIMER_0, MCPWM_SELECT_CAP0, MCPWM_NEG_EDGE);
capture_test(MCPWM_UNIT_1, MCPWM_TIMER_0, MCPWM_NEG_EDGE);
}
TEST_CASE("MCPWM unit1, timer1 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
capture_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_CAP_1, MCPWM_TIMER_1, MCPWM_SELECT_CAP1, MCPWM_POS_EDGE);
capture_test(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_POS_EDGE);
}
TEST_CASE("MCPWM unit1, timer2 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
{
capture_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_CAP_2, MCPWM_TIMER_2, MCPWM_SELECT_CAP2, MCPWM_POS_EDGE);
capture_test(MCPWM_UNIT_1, MCPWM_TIMER_2, MCPWM_POS_EDGE);
}

View file

@ -34,6 +34,7 @@ list(APPEND srcs
if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs "src/hal/spi_flash_hal.c"
"src/hal/spi_flash_hal_iram.c"
"src/hal/mcpwm_hal.c"
)
endif()

View file

@ -0,0 +1,727 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32 MCPWM register operations
#pragma once
#include <soc/mcpwm_periph.h>
#include "soc/mcpwm_periph.h"
#include "hal/mcpwm_types.h"
#include "soc/mcpwm_caps.h"
#include "hal/hal_defs.h"
#include "esp_types.h"
/// Get the address of peripheral registers
#define MCPWM_LL_GET_HW(ID) (((ID)==0)? &MCPWM0: &MCPWM1)
/********************* Global *******************/
/**
* Initialize common registers.
*
* @param mcpwm Address of the MCPWM peripheral registers.
*/
static inline void mcpwm_ll_init(mcpwm_dev_t *mcpwm)
{
mcpwm->update_cfg.global_up_en = 1;
mcpwm->update_cfg.global_force_up = 1;
mcpwm->update_cfg.global_force_up = 0;
}
/**
* Set the prescale of the PWM main clock to the input clock.
*
* Input clock is 160MHz, PWM main clock cycle = 6.25ns*(prescale + 1).
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param prescale Prescale factor, 0-255.
*/
static inline void mcpwm_ll_set_clock_prescale(mcpwm_dev_t *mcpwm, int prescale)
{
mcpwm->clk_cfg.prescale = prescale;
}
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_LL_INTR_CAP0, MCPWM_CAP0_INT_RAW);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_LL_INTR_CAP1, MCPWM_CAP1_INT_RAW);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_LL_INTR_CAP2, MCPWM_CAP2_INT_RAW);
/**
* Get raw interrupt status.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @return The triggered interrupts, ORed by active interrupts.
*/
static inline mcpwm_intr_t mcpwm_ll_get_intr(mcpwm_dev_t *mcpwm)
{
return mcpwm->int_raw.val;
}
/**
* Clear the interrupts.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param intr Bitwise ORed interrupts to clear.
*/
static inline void mcpwm_ll_clear_intr(mcpwm_dev_t* mcpwm, mcpwm_intr_t intr)
{
mcpwm->int_clr.val = intr;
}
/********************* Timer *******************/
/**
* Set the prescale of the Timer_x clock to the PWM main clock.
*
* Timer clock frequency = PWM main clock frequency/(prescale + 1).
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer The timer to set the prescale, 0-2.
* @param prescale Prescale factor, 0-255.
*/
static inline void mcpwm_ll_timer_set_prescale(mcpwm_dev_t* mcpwm, int timer, uint32_t prescale)
{
mcpwm->timer[timer].period.prescale = prescale;
}
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_UP_COUNTER, 1);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_DOWN_COUNTER, 2);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_UP_DOWN_COUNTER, 3);
/**
* Set the counting mode for the PWM timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer The timer to change counting mode, 0-2.
* @param mode Counting mode to use.
*/
static inline void mcpwm_ll_timer_set_count_mode(mcpwm_dev_t *mcpwm, int timer, mcpwm_counter_type_t mode)
{
mcpwm->timer[timer].mode.mode = mode;
}
/**
* Start a timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer The timer to start, 0-2.
*/
static inline void mcpwm_ll_timer_start(mcpwm_dev_t *mcpwm, int timer)
{
mcpwm->timer[timer].mode.start = 2;
}
/**
* Stop a timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer The timer to stop, 0-2.
*/
static inline void mcpwm_ll_timer_stop(mcpwm_dev_t *mcpwm, int timer)
{
mcpwm->timer[timer].mode.start = 0;
}
/**
* Set the overflow period of a timer.
*
* The overflow rate will be Frequency of timer / period.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer The timer to set period, 0-2.
* @param period Total timer count of each period, 0-65535.
*/
static inline void mcpwm_ll_timer_set_period(mcpwm_dev_t *mcpwm, int timer, uint32_t period)
{
mcpwm->timer[timer].period.period = period;
mcpwm->timer[timer].period.upmethod = 0;
}
/**
* Get the period setting of a timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer The timer to get the period, 0-2.
* @return Period setting value.
*/
static inline uint32_t mcpwm_ll_timer_get_period(mcpwm_dev_t *mcpwm, int timer)
{
return mcpwm->timer[timer].period.period;
}
/********************* Sync *******************/
/**
* Enable the synchronization feature for a timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer Timer to set, 0-2.
* @param enable true to enable, otherwise false.
*/
static inline void mcpwm_ll_sync_enable(mcpwm_dev_t *mcpwm, int timer, bool enable)
{
if (enable) {
mcpwm->timer[timer].sync.out_sel = 0;
mcpwm->timer[timer].sync.in_en = 1;
} else {
mcpwm->timer[timer].sync.in_en = 0;
}
}
/**
* Set the phase (counter value) to reload when the sync signal triggers.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer Timer to set, 0-2.
* @param reload_val The reloaded value.
*/
static inline void mcpwm_ll_sync_set_phase(mcpwm_dev_t *mcpwm, int timer, uint32_t reload_val)
{
mcpwm->timer[timer].sync.timer_phase = reload_val;
}
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_SELECT_SYNC0, 4);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_SELECT_SYNC1, 5);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_SELECT_SYNC2, 6);
/**
* Set the sync signal source for a timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param timer The timer to set, 0-2.
* @param sync_sig The synchronization signal to use.
*/
static inline void mcpwm_ll_sync_set_input(mcpwm_dev_t *mcpwm, int timer, mcpwm_sync_signal_t sync_sig)
{
if (timer == 0) {
mcpwm->timer_synci_cfg.t0_in_sel = sync_sig;
} else if (timer == 1) {
mcpwm->timer_synci_cfg.t1_in_sel = sync_sig;
} else { //MCPWM_TIMER_2
mcpwm->timer_synci_cfg.t2_in_sel = sync_sig;
}
}
/********************* Comparator *******************/
/**
* Select a timer for the specified operator to use.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to choose timer, 0-2.
* @param timer The timer to use, 0-2.
*/
static inline void mcpwm_ll_operator_select_timer(mcpwm_dev_t *mcpwm, int op, int timer)
{
if (op == 0) {
mcpwm->timer_sel.operator0_sel = timer;
} else if (op == 1) {
mcpwm->timer_sel.operator1_sel = timer;
} else {
mcpwm->timer_sel.operator2_sel = timer;
}
}
/**
* Set the update method of the compare value of a timer
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op Operator to set, 0-2.
*/
static inline void mcpwm_ll_operator_set_compare_upmethod(mcpwm_dev_t *mcpwm, int op)
{
mcpwm->channel[op].cmpr_cfg.a_upmethod = BIT(0);
mcpwm->channel[op].cmpr_cfg.b_upmethod = BIT(0);
}
/**
* Get one of the compare value of a timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to get, 0-2.
* @param cmp_n Comparer id to get, 0-1.
* @return The set compare value.
*/
static inline uint32_t mcpwm_ll_operator_get_compare(mcpwm_dev_t *mcpwm, int op, int cmp_n)
{
return (mcpwm->channel[op].cmpr_value[cmp_n].cmpr_val);
}
/**
* Set one of the compare value of a timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param cmp_n The comparer to set value, 0-1.
* @param compare The compare value, 0-65535.
*/
static inline void mcpwm_ll_operator_set_compare(mcpwm_dev_t *mcpwm, int op, int cmp_n, uint32_t compare)
{
mcpwm->channel[op].cmpr_value[cmp_n].cmpr_val = compare;
}
/********************* Generator *******************/
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_ACTION_NO_CHANGE, 0);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_ACTION_FORCE_LOW, 1);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_ACTION_FORCE_HIGH, 2);
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_ACTION_TOGGLE, 3);
/**
* Set the action will be taken by a operator when its timer counts to zero.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set action, 0-2.
* @param gen One generator of the operator to take the action, 0-1.
* @param action Action to take.
*/
static inline void mcpwm_ll_gen_set_zero_action(mcpwm_dev_t *mcpwm, int op, int gen, mcpwm_output_action_t action)
{
mcpwm->channel[op].generator[gen].utez = action;
mcpwm->channel[op].generator[gen].dtez = action;
}
/**
* Set the action will be taken by a operator when its timer counts to the period value.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set action, 0-2.
* @param gen One generator of the operator to take the action, 0-1.
* @param action Action to take.
*/
static inline void mcpwm_ll_gen_set_period_action(mcpwm_dev_t *mcpwm, int op, int gen, mcpwm_output_action_t action)
{
mcpwm->channel[op].generator[gen].utep = action;
mcpwm->channel[op].generator[gen].dtep = action;
}
/**
* Set the action will be taken by a operator when its timer counts to the compare value.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set action, 0-2.
* @param gen One generator of the operator to take the action, 0-1.
* @param cmp_n The comparer to use.
* @param up_action The action to take when the counter is counting up.
* @param down_action The action to take when the counter is counting down.
*/
static inline void mcpwm_ll_gen_set_cmp_action(mcpwm_dev_t *mcpwm, int op, int gen,
int cmp_n, mcpwm_output_action_t up_action, mcpwm_output_action_t down_action)
{
if (cmp_n == 0) {
mcpwm->channel[op].generator[gen].utea = up_action;
mcpwm->channel[op].generator[gen].dtea = down_action;
} else {
mcpwm->channel[op].generator[gen].uteb = up_action;
mcpwm->channel[op].generator[gen].dteb = down_action;
}
}
/********************* Fault *******************/
/**
* Enable the fault detection feature for an input signal.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param fault_sig One of the signals to select, 0-2.
* @param level The active level of the fault-detection signal.
*/
static inline void mcpwm_ll_fault_enable(mcpwm_dev_t *mcpwm, int fault_sig, bool level)
{
if (fault_sig == 0) {
mcpwm->fault_detect.f0_en = 1;
mcpwm->fault_detect.f0_pole = level;
} else if (fault_sig == 1) {
mcpwm->fault_detect.f1_en = 1;
mcpwm->fault_detect.f1_pole = level;
} else { //MCPWM_SELECT_F2
mcpwm->fault_detect.f2_en = 1;
mcpwm->fault_detect.f2_pole = level;
}
}
/**
* Disable the fault detection of an input signal.
* @param mcpwm Address of the MCPWM peripheral registers.
* @param fault_sig The signal to disable, 0-2.
*/
static inline void mcpwm_ll_fault_disable(mcpwm_dev_t *mcpwm, int fault_sig)
{
if (fault_sig == 0) {
mcpwm->fault_detect.f0_en = 0;
} else if (fault_sig == 1) {
mcpwm->fault_detect.f1_en = 0;
} else { //MCPWM_SELECT_F2
mcpwm->fault_detect.f2_en = 0;
}
}
/**
* Clear the oneshot fault status of an operator.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to clear, 0-2.
*/
static inline void mcpwm_ll_fault_clear_ost(mcpwm_dev_t *mcpwm, int op)
{
mcpwm->channel[op].tz_cfg1.clr_ost = 1;
mcpwm->channel[op].tz_cfg1.clr_ost = 0;
}
/**
* Use the oneshot mode to handle the fault when it occurs
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to handle the fault signal, 0-2.
* @param signal The fault signal to set, 0-2.
* @param enable true to enable oneshot, otherwise false.
*/
static inline void mcpwm_ll_fault_oneshot_enable_signal(mcpwm_dev_t *mcpwm, int op, int signal, bool enable)
{
if (signal == 0) {
mcpwm->channel[op].tz_cfg0.f0_ost = enable;
} else if (signal == 1) {
mcpwm->channel[op].tz_cfg0.f1_ost = enable;
} else { //MCPWM_SELECT_F2
mcpwm->channel[op].tz_cfg0.f2_ost = enable;
}
}
/**
* @brief Get the oneshot enabled status of the operator
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to check, 0-2.
* @param signal The fault signal to get, 0-2.
*/
static inline bool mcpwm_ll_fault_oneshot_signal_enabled(mcpwm_dev_t *mcpwm, int op, int signal)
{
if (signal == 0) {
return mcpwm->channel[op].tz_cfg0.f0_ost;
} else if (signal == 1) {
return mcpwm->channel[op].tz_cfg0.f1_ost;
} else { //MCPWM_SELECT_F2
return mcpwm->channel[op].tz_cfg0.f2_ost;
}
}
/**
* Use the CBC (cycle-by-cycle) mode to handle the fault when it occurs.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to handle the fault signal, 0-2.
* @param signal The fault signal to set, 0-2.
* @param enable true to enable cbc mode, otherwise false.
*/
static inline void mcpwm_ll_fault_cbc_enable_signal(mcpwm_dev_t *mcpwm, int op, int signal, bool enable)
{
if (signal == 0) {
mcpwm->channel[op].tz_cfg0.f0_cbc = enable;
} else if (signal == 1) {
mcpwm->channel[op].tz_cfg0.f1_cbc = enable;
} else { //MCPWM_SELECT_F2
mcpwm->channel[op].tz_cfg0.f2_cbc = enable;
}
}
/**
* Set the action that will be taken when the fault is handled by oneshot.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to handle the fault signal, 0-2.
* @param gen The generator to take the action, 0-1.
* @param up_action Action to take when fault happens when counting up.
* @param down_action Action to take when fault happens when counting down.
*/
static inline void mcpwm_ll_fault_set_oneshot_action(mcpwm_dev_t *mcpwm, int op, int gen,
mcpwm_output_action_t up_action, mcpwm_output_action_t down_action)
{
if (gen == 0) {
mcpwm->channel[op].tz_cfg0.a_ost_u = up_action;
mcpwm->channel[op].tz_cfg0.a_ost_d = down_action;
} else {
mcpwm->channel[op].tz_cfg0.b_ost_u = up_action;
mcpwm->channel[op].tz_cfg0.b_ost_d = down_action;
}
}
/**
* Set the action that will be taken when the fault is handled cycle by cycle.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to handle the fault signal, 0-2.
* @param gen The generator to take the action, 0-1.
* @param up_action Action to take when fault happens when counting up.
* @param down_action Action to take when fault happens when counting down.
*/
static inline void mcpwm_ll_fault_set_cyc_action(mcpwm_dev_t *mcpwm, int op, int gen,
mcpwm_output_action_t up_action, mcpwm_output_action_t down_action)
{
mcpwm->channel[op].tz_cfg1.cbcpulse = BIT(0); //immediately
if (gen == 0) {
mcpwm->channel[op].tz_cfg0.a_cbc_u = up_action;
mcpwm->channel[op].tz_cfg0.a_cbc_d = down_action;
} else {
mcpwm->channel[op].tz_cfg0.b_cbc_u = up_action;
mcpwm->channel[op].tz_cfg0.b_cbc_d = down_action;
}
}
/********************* Dead Zone (deadtime) *******************/
/**
* Initialize the dead zone feature.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to initialize, 0-2.
*/
static inline void mcpwm_ll_deadtime_init(mcpwm_dev_t *mcpwm, int op)
{
mcpwm->channel[op].db_cfg.fed_upmethod = BIT(0);
mcpwm->channel[op].db_cfg.red_upmethod = BIT(0);
mcpwm->channel[op].db_cfg.clk_sel = 0;
}
/**
* Set the output dead zone mode applying to the outputs of a timer.
*
* If the desired internal connection is not provided, you can write your own inside this function.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param mode Dead zone mode to use.
*/
static inline void mcpwm_ll_set_deadtime_mode(mcpwm_dev_t *mcpwm,
int op, mcpwm_deadtime_type_t mode)
{
#define MCPWM_LL_DEADTIME_REG_MASK (MCPWM_DT0_DEB_MODE_M | MCPWM_DT0_A_OUTSWAP_M | MCPWM_DT0_B_OUTSWAP_M | \
MCPWM_DT0_RED_INSEL_M | MCPWM_DT0_FED_INSEL_M | MCPWM_DT0_RED_OUTINVERT_M | MCPWM_DT0_FED_OUTINVERT_M | \
MCPWM_DT0_A_OUTBYPASS_M | MCPWM_DT0_B_OUTBYPASS_M)
static uint32_t deadtime_mode_settings[MCPWM_DEADTIME_TYPE_MAX] = {
[MCPWM_BYPASS_RED] = 0b010010000 << MCPWM_DT0_DEB_MODE_S,
[MCPWM_BYPASS_FED] = 0b100000000 << MCPWM_DT0_DEB_MODE_S,
[MCPWM_ACTIVE_HIGH_MODE] = 0b000010000 << MCPWM_DT0_DEB_MODE_S,
[MCPWM_ACTIVE_LOW_MODE] = 0b001110000 << MCPWM_DT0_DEB_MODE_S,
[MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE] = 0b001010000 << MCPWM_DT0_DEB_MODE_S,
[MCPWM_ACTIVE_LOW_COMPLIMENT_MODE] = 0b000101000 << MCPWM_DT0_DEB_MODE_S,
[MCPWM_ACTIVE_RED_FED_FROM_PWMXA] = 0b000000011 << MCPWM_DT0_DEB_MODE_S,
[MCPWM_ACTIVE_RED_FED_FROM_PWMXB] = 0b000001011 << MCPWM_DT0_DEB_MODE_S,
[MCPWM_DEADTIME_BYPASS] = 0b110000000 << MCPWM_DT0_DEB_MODE_S,
};
mcpwm->channel[op].db_cfg.val =
(mcpwm->channel[op].db_cfg.val & (~MCPWM_LL_DEADTIME_REG_MASK)) | deadtime_mode_settings[mode];
#undef MCPWM_LL_DEADTIME_REG_MASK
}
/**
* Set the delay of the falling edge on the output.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param fed Falling delay, by PWM main clock.
*/
static inline void mcpwm_ll_deadtime_set_falling_delay(mcpwm_dev_t *mcpwm, int op, uint32_t fed)
{
mcpwm->channel[op].db_fed_cfg.fed = fed;
}
/**
* Set the delay of the rising edge on the output.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param fed Rising delay, by PWM main clock.
*/
static inline void mcpwm_ll_deadtime_set_rising_delay(mcpwm_dev_t *mcpwm, int op, uint32_t red)
{
mcpwm->channel[op].db_red_cfg.red = red;
}
/**
* Disable (bypass) the dead zone feature.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
*/
static inline void mcpwm_ll_deadtime_bypass(mcpwm_dev_t *mcpwm, int op)
{
mcpwm_ll_set_deadtime_mode(mcpwm, op, MCPWM_DEADTIME_BYPASS);
}
/********************* Carrier *******************/
/**
* Initialize the carrier feature.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
*/
static inline void mcpwm_ll_carrier_init(mcpwm_dev_t *mcpwm, int op)
{
mcpwm->channel[op].carrier_cfg.in_invert = 0;
}
/**
* Enable the carrier feature for a timer.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param enable true to enable, otherwise false.
*/
static inline void mcpwm_ll_carrier_enable(mcpwm_dev_t *mcpwm, int op, bool enable)
{
mcpwm->channel[op].carrier_cfg.en = enable;
}
/**
* Set the prescale of the carrier timer.
*
* The carrier period will be Frequency of PWM main clock/(carrier_period+1).
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param carrier_period The prescale of the carrier clock, 0-15.
*/
static inline void mcpwm_ll_carrier_set_prescale(mcpwm_dev_t *mcpwm, int op, uint8_t carrier_period)
{
mcpwm->channel[op].carrier_cfg.prescale = carrier_period;
}
/**
* Set the duty rate of the carrier.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param carrier_duty Duty rate will be (carrier_duty/8)*100%. 0-7.
*/
static inline void mcpwm_ll_carrier_set_duty(mcpwm_dev_t *mcpwm, int op, uint8_t carrier_duty)
{
mcpwm->channel[op].carrier_cfg.duty = carrier_duty;
}
/**
* Invert output of the carrier.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param invert true to invert, otherwise false.
*/
static inline void mcpwm_ll_carrier_out_invert(mcpwm_dev_t *mcpwm, int op, bool invert)
{
mcpwm->channel[op].carrier_cfg.out_invert = invert;
}
/**
* Set the oneshot pulse width of the carrier.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param op The operator to set, 0-2.
* @param pulse_width The width of the oneshot pulse, by carrier period. 0 to disable the oneshot pulse.
*/
static inline void mcpwm_ll_carrier_set_oneshot_width(mcpwm_dev_t *mcpwm, int op, uint8_t pulse_width)
{
mcpwm->channel[op].carrier_cfg.oshtwth = pulse_width;
}
/********************* Capture *******************/
/**
* Enable the capture feature for a signal
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param cap_sig Signal to enable, 0-2.
* @param enable true to enable, otherwise false.
*/
static inline void mcpwm_ll_capture_enable(mcpwm_dev_t *mcpwm, int cap_sig, int enable)
{
if (enable) {
mcpwm->cap_timer_cfg.timer_en = 1;
mcpwm->cap_cfg_ch[cap_sig].en = 1;
} else {
mcpwm->cap_cfg_ch[cap_sig].en = 0;
}
}
/**
* Get the captured value.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param cap_sig Of which signal to get the captured value.
* @return The captured value
*/
static inline uint32_t mcpwm_ll_get_capture_val(mcpwm_dev_t *mcpwm, int cap_sig)
{
return mcpwm->cap_val_ch[cap_sig];
}
/**
* Get the set capture edge.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param cap_sig Which signal the edge capture is applied.
* @return Capture signal edge: 1 - positive edge, 2 - negtive edge
*/
static inline mcpwm_capture_on_edge_t mcpwm_ll_get_captured_edge(mcpwm_dev_t *mcpwm, int cap_sig)
{
bool edge;
if (cap_sig == 0) {
edge = mcpwm->cap_status.cap0_edge;
} else if (cap_sig == 1) {
edge = mcpwm->cap_status.cap0_edge;
} else { //2
edge = mcpwm->cap_status.cap0_edge;
}
return (edge? MCPWM_NEG_EDGE: MCPWM_POS_EDGE);
}
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_NEG_EDGE, BIT(0));
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_POS_EDGE, BIT(1));
/**
* Select the edge to capture.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param cap_sig The signal to capture, 0-2.
* @param cap_edge The edge to capture, bitwise.
*/
static inline void mcpwm_ll_capture_select_edge(mcpwm_dev_t *mcpwm, int cap_sig,
mcpwm_capture_on_edge_t cap_edge)
{
mcpwm->cap_cfg_ch[cap_sig].mode = cap_edge;
}
/**
* Set the prescale of the input signal to capture.
*
* @param mcpwm Address of the MCPWM peripheral registers.
* @param cap_sig The prescaled signal to capture, 0-2.
* @param prescale Prescal value, 0 to disable.
*/
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int cap_sig, uint32_t prescale)
{
mcpwm->cap_cfg_ch[cap_sig].prescale = prescale;
}
/**
* Utility function, get the `mcpwm_intr_t` interrupt enum of a specific capture signal.
*
* @param bit x for CAPx.
* @return the corresponding `mcpwm_intr_t`.
*/
static inline mcpwm_intr_t mcpwm_ll_get_cap_intr_def(int bit)
{
return BIT(bit+MCPWM_CAP0_INT_RAW_S);
}

View file

@ -0,0 +1,22 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#define SOC_MCPWM_PERIPH_NUM 2 ///< MCPWM peripheral number
#define SOC_MCPWM_TIMER_NUM 3 ///< Timer that each peripheral has
#define SOC_MCPWM_OP_NUM 3 ///< Operator that each peripheral has
#define SOC_MCPWM_COMPARATOR_NUM 2 ///< Comparator that each operator has
#define SOC_MCPWM_GENERATOR_NUM 2 ///< Generator that each operator has
#define SOC_MCPWM_FAULT_SIG_NUM 3 ///< Fault signal number that each peripheral has

View file

@ -26,3 +26,5 @@
#define HAL_LOGI(...) ESP_LOGI(__VA_ARGS__)
#define HAL_LOGD(...) ESP_LOGD(__VA_ARGS__)
#define HAL_LOGV(...) ESP_LOGV(__VA_ARGS__)
#define STATIC_HAL_REG_CHECK(TAG, ENUM, VAL) _Static_assert((ENUM) == (VAL), #TAG" "#ENUM" definition no longer matches register value")

View file

@ -0,0 +1,328 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
// The HAL layer for MCPWM (common part)
/*
* MCPWM HAL usages:
*
* Initialization:
* 1. Fill the parameters in `mcpwm_hal_context_t`.
* 2. Call `mcpwm_hal_init` to initialize the context.
* 3. Call `mcpwm_hal_hw_init` to initialize the hardware.
*
* Basic PWM:
* 1. Update parameters for the timers, comparators and generators.
* 2. Call `mcpwm_hal_timer_update_basic` to update the timer used.
* 3. Call `mcpwm_hal_operator_update_basic` to update all the parameters of a operator.
*
* Alternatively, if only the comparator is updated (duty rate), call
* `mcpwm_hal_operator_update_comparator` to update the comparator parameters; if only the
* generator is updated (output style), call `mcpwm_hal_operator_update_generator` to update the
* generator parameters.
*
* 4. At any time, call `mcpwm_hal_timer_start` to start the timer (so that PWM output will toggle
* according to settings), or call `mcpwm_hal_timer_stop` to stop the timer (so that the PWM output
* will be kept as called).
*
* Timer settings:
* - Sync: Call `mcpwm_hal_timer_enable_sync` to enable the sync for the timer, and call
* `mcpwm_hal_timer_disable_sync` to disable it.
*
* Operator settings:
* - Carrier: Call `mcpwm_hal_operator_enable_carrier` to enable carrier for an operator, and call
* `mcpwm_hal_operator_disable_carrier` to disable it.
*
* - Deadzone: Call `mcpwm_hal_operator_update_deadzone` to update settings of deadzone for an operator.
*
* Fault handling settings:
* 1. Call `mcpwm_hal_fault_init` to initialize an fault signal to be detected.
* 2. Call `mcpwm_hal_operator_update_fault` to update the behavior of an operator when fault is
* detected.
* 3. If the operator selects oneshot mode to handle the fault event, call
* `mcpwm_hal_fault_oneshot_clear` to clear that fault event after the fault is handled properly.
* 4. Call `mcpwm_hal_fault_disable` to deinitialize the fault signal when it's no longer used.
*
* Capture:
* 1. Call `mcpwm_hal_capture_enable` to enable the capture for one capture signal.
* 2. Call `mcpwm_hal_capture_get_result` to get the last captured result.
* 3. Call `mcpwm_hal_capture_disable` to disable the capture for a signal.
*/
#pragma once
#include <esp_err.h>
#include "hal/mcpwm_ll.h"
#define MCPWM_BASE_CLK (2 * APB_CLK_FREQ) //2*APB_CLK_FREQ 160Mhz
/// Configuration of HAL that used only once.
typedef struct {
int host_id; ///< Which MCPWM peripheral to use, 0-1.
} mcpwm_hal_init_config_t;
/// Configuration of each generator (output of operator)
typedef struct {
mcpwm_duty_type_t duty_type; ///< How the generator output
int comparator; ///< for mode `MCPWM_DUTY_MODE_*`, which comparator it refers to.
} mcpwm_hal_generator_config_t;
/// Configuration of each operator
typedef struct {
mcpwm_hal_generator_config_t gen[SOC_MCPWM_GENERATOR_NUM]; ///< Configuration of the generators
float duty[SOC_MCPWM_COMPARATOR_NUM]; ///< 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_TIMER_NUM]; ///< Configuration of the timers
mcpwm_hal_operator_config_t op[SOC_MCPWM_OP_NUM]; ///< Configuration of the operators
} 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_GENERATOR_NUM]; ///< Action to perform on each generator when any one of the fault signal triggers.
} mcpwm_hal_fault_conf_t;
/// Configuration of the synchronization of each clock
typedef struct {
mcpwm_sync_signal_t sync_sig; ///< Sync signal to use
uint32_t reload_permillage; ///< Reload permillage when the sync is triggered. 100 means the timer will be reload to (period * 100)/1000=10% period value.
} mcpwm_hal_sync_config_t;
/// Configuration of the capture feature on each capture signal
typedef struct {
mcpwm_capture_on_edge_t cap_edge; ///< Whether the edges is captured, bitwise.
uint32_t prescale; ///< Prescale of the input signal.
} mcpwm_hal_capture_config_t;
/**
* @brief Initialize the internal state of the HAL. Call after settings are set and before other functions are called.
*
* @note Since There are several individual parts (timers + operators, captures), this funciton is
* allowed to called several times.
*
* @param hal Context of the HAL layer.
* @param init_config Configuration for the HAL to be used only once.
*/
void mcpwm_hal_init(mcpwm_hal_context_t *hal, const mcpwm_hal_init_config_t *init_config);
/**
* @brief Initialize the hardware, call after `mcpwm_hal_init` and before other functions.
*
* @param hal Context of the HAL layer.
*/
void mcpwm_hal_hw_init(mcpwm_hal_context_t *hal);
/**
* @brief Start a timer
*
* @param hal Context of the HAL layer.
* @param timer Timer to start, 0-2.
*/
void mcpwm_hal_timer_start(mcpwm_hal_context_t *hal, int timer);
/**
* @brief Stop a timer.
*
* @param hal Context of the HAL layer.
* @param timer Timer to stop, 0-2.
*/
void mcpwm_hal_timer_stop(mcpwm_hal_context_t *hal, int timer);
/**
* @brief Update the basic parameters of a timer.
*
* @note This will influence the duty rate and count mode of each operator relies on this timer.
* Call `mcpwm_hal_operator_update_basic` for each of the operator that relies on this timer after
* to update the duty rate and generator output.
*
* @param hal Context of the HAL layer.
* @param timer Timer to update, 0-2.
*/
void mcpwm_hal_timer_update_basic(mcpwm_hal_context_t *hal, int timer);
/**
* @brief Start the synchronization for a timer.
*
* @param hal Context of the HAL layer.
* @param timer Timer to enable, 0-2.
* @param sync_conf Configuration of the sync operation.
*/
void mcpwm_hal_timer_enable_sync(mcpwm_hal_context_t *hal, int timer, const mcpwm_hal_sync_config_t *sync_conf);
/**
* @brief Stop the synchronization for a timer.
*
* @param hal Context of the HAL layer.
* @param timer Timer to disable sync, 0-2.
*/
void mcpwm_hal_timer_disable_sync(mcpwm_hal_context_t *hal, int timer);
/**
* @brief Update the basic settings (duty, output mode) for an operator.
*
* Will call `mcpwm_hal_operator_update_comparator` and `mcpwm_hal_operator_update_generator`
* recursively to update each of their duty and output mode.
*
* @param hal Context of the HAL layer.
* @param op Operator to update, 0-2.
*/
void mcpwm_hal_operator_update_basic(mcpwm_hal_context_t *hal, int op);
/**
* @brief Update a comparator (duty) for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to update, 0-2.
* @param cmp Comparator to update, 0-1.
*/
void mcpwm_hal_operator_update_comparator(mcpwm_hal_context_t *hal, int op, int cmp);
/**
* @brief Update a generator (output mode) for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to update, 0-2.
* @param cmp Comparator to update, 0-1.
*/
void mcpwm_hal_operator_update_generator(mcpwm_hal_context_t *hal, int op, int gen_num);
/**
* @brief Enable the carrier for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to enable carrier, 0-2.
* @param carrier_conf Configuration of the carrier.
*/
void mcpwm_hal_operator_enable_carrier(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_carrier_conf_t *carrier_conf);
/**
* @brief Disable the carrier for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to disable carrier, 0-2.
*/
void mcpwm_hal_operator_disable_carrier(mcpwm_hal_context_t *hal, int op);
/**
* @brief Update the deadzone for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to update the deadzone, 0-2.
* @param deadzone Configuration of the deadzone. Set member `mode` to `MCPWM_DEADTIME_BYPASS` will bypass the deadzone.
*/
void mcpwm_hal_operator_update_deadzone(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_deadzone_conf_t *deadzone);
/**
* @brief Enable one of the fault signal.
*
* @param hal Context of the HAL layer.
* @param fault_sig The signal to enable, 0-2.
* @param level The active level for the fault signal, true for high and false for low.
*/
void mcpwm_hal_fault_init(mcpwm_hal_context_t *hal, int fault_sig, bool level);
/**
* @brief Configure how the operator behave to the fault signals.
*
* Call after the fault signal is enabled by `mcpwm_hal_fault_init`.
*
* @param hal Context of the HAL layer.
* @param op Operator to configure, 0-2.
* @param fault_conf Configuration of the behavior of the operator when fault. Clear member `cbc_enabled_mask` and `ost_enabled_mask` will disable the fault detection of this operator.
*/
void mcpwm_hal_operator_update_fault(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_fault_conf_t *fault_conf);
/**
* @brief Clear the oneshot fault status for an operator.
*
* @param hal Context of the HAL layer.
* @param op The operator to clear oneshot fault status, 0-2.
*/
void mcpwm_hal_fault_oneshot_clear(mcpwm_hal_context_t *hal, int op);
/**
* @brief Disable one of the fault signal.
*
* @param hal Context of the HAL layer.
* @param fault_sig The fault signal to disable, 0-2.
*/
void mcpwm_hal_fault_disable(mcpwm_hal_context_t *hal, int fault_sig);
/**
* @brief Enable one of the capture signal.
*
* @param hal Context of the HAL layer.
* @param cap_sig Capture signal to enable, 0-2.
* @param conf Configuration on how to capture the signal.
*/
void mcpwm_hal_capture_enable(mcpwm_hal_context_t *hal, int cap_sig, const mcpwm_hal_capture_config_t *conf);
/**
* @brief Get the capture result.
*
* @note The output value will always be updated with the register value, no matter event triggered or not.
*
* @param hal Context of the HAL layer.
* @param cap_sig Signal to get capture result, 0-2.
* @param out_count Output of the captured counter.
* @param out_edge Output of the captured edge.
* @return
* - ESP_OK: if a signal is captured
* - ESP_ERR_NOT_FOUND: if no capture event happened.
*/
esp_err_t mcpwm_hal_capture_get_result(mcpwm_hal_context_t *hal, int cap_sig, uint32_t *out_count,
mcpwm_capture_on_edge_t *out_edge);
/**
* @brief Disable one of the capture signal.
*
* @param hal Context of the HAL layer.
* @param cap_sig The signal to capture, 0-2.
*/
void mcpwm_hal_capture_disable(mcpwm_hal_context_t *hal, int cap_sig);

View file

@ -0,0 +1,86 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/// Interrupts for MCPWM
typedef enum {
MCPWM_LL_INTR_CAP0 = BIT(27), ///< Capture 0 happened
MCPWM_LL_INTR_CAP1 = BIT(28), ///< Capture 1 happened
MCPWM_LL_INTR_CAP2 = BIT(29), ///< Capture 2 happened
} mcpwm_intr_t;
/**
* @brief Select type of MCPWM counter
*/
typedef enum {
MCPWM_UP_COUNTER = 1, /*!<For asymmetric MCPWM*/
MCPWM_DOWN_COUNTER, /*!<For asymmetric MCPWM*/
MCPWM_UP_DOWN_COUNTER, /*!<For symmetric MCPWM, frequency is half of MCPWM frequency set*/
MCPWM_COUNTER_MAX, /*!<Maximum counter mode*/
} mcpwm_counter_type_t;
/**
* @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 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;
/**
* @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 sync signal input
*/
typedef enum {
MCPWM_SELECT_SYNC0 = 4, /*!<Select SYNC0 as input*/
MCPWM_SELECT_SYNC1, /*!<Select SYNC1 as input*/
MCPWM_SELECT_SYNC2, /*!<Select SYNC2 as input*/
} mcpwm_sync_signal_t;
/**
* @brief MCPWM select capture starts from which edge
*/
typedef enum {
MCPWM_NEG_EDGE = BIT(0), /*!<Capture the negative edge*/
MCPWM_POS_EDGE = BIT(1), /*!<Capture the positive edge*/
} mcpwm_capture_on_edge_t;

View file

@ -0,0 +1,229 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The HAL layer for MCPWM (common part)
#include "hal/mcpwm_hal.h"
void mcpwm_hal_init(mcpwm_hal_context_t *hal, const mcpwm_hal_init_config_t *init_config)
{
hal->dev = MCPWM_LL_GET_HW(init_config->host_id);
}
void mcpwm_hal_hw_init(mcpwm_hal_context_t *hal)
{
mcpwm_ll_init(hal->dev);
mcpwm_ll_set_clock_prescale(hal->dev, hal->prescale);
}
void mcpwm_hal_timer_start(mcpwm_hal_context_t *hal, int timer)
{
mcpwm_ll_timer_start(hal->dev, timer);
}
void mcpwm_hal_timer_stop(mcpwm_hal_context_t *hal, int timer)
{
mcpwm_ll_timer_stop(hal->dev, timer);
}
void mcpwm_hal_timer_update_basic(mcpwm_hal_context_t *hal, int timer)
{
mcpwm_ll_timer_set_prescale(hal->dev, timer, hal->timer[timer].timer_prescale);
uint32_t period = MCPWM_BASE_CLK / (hal->timer[timer].freq *
(hal->prescale +1) * (hal->timer[timer].timer_prescale + 1));
mcpwm_ll_timer_set_period(hal->dev, timer, period);
//write back the actual value to the context
hal->timer[timer].freq = MCPWM_BASE_CLK / (period *
(hal->prescale +1) * (hal->timer[timer].timer_prescale + 1));
mcpwm_ll_timer_set_count_mode(hal->dev, timer, hal->timer[timer].count_mode);
}
void mcpwm_hal_timer_enable_sync(mcpwm_hal_context_t *hal, int timer, const mcpwm_hal_sync_config_t *sync_conf)
{
uint32_t set_phase = mcpwm_ll_timer_get_period(hal->dev, timer) * sync_conf->reload_permillage / 1000;
mcpwm_ll_sync_set_phase(hal->dev, timer, set_phase);
mcpwm_ll_sync_set_input(hal->dev, timer, sync_conf->sync_sig);
mcpwm_ll_sync_enable(hal->dev, timer, 1);
}
void mcpwm_hal_timer_disable_sync(mcpwm_hal_context_t *hal, int timer)
{
mcpwm_ll_sync_enable(hal->dev, timer, 0);
}
void mcpwm_hal_operator_update_basic(mcpwm_hal_context_t *hal, int op)
{
mcpwm_hal_operator_config_t *op_conf = &hal->op[op];
mcpwm_ll_operator_select_timer(hal->dev, op, op_conf->timer);
for (int cmp = 0; cmp < SOC_MCPWM_COMPARATOR_NUM; cmp++) {
mcpwm_hal_operator_update_comparator(hal, op, cmp);
}
for (int gen = 0; gen < SOC_MCPWM_GENERATOR_NUM; 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_SIG_NUM; 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_SIG_NUM; 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_GENERATOR_NUM; 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_GENERATOR_NUM; 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_OP_NUM; 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);
}
*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

@ -92,6 +92,7 @@ INPUT = \
../../components/driver/include/driver/i2s.h \
../../components/driver/include/driver/ledc.h \
../../components/driver/include/driver/mcpwm.h \
../../components/soc/include/hal/mcpwm_types.h \
../../components/driver/include/driver/pcnt.h \
../../components/driver/include/driver/rmt.h \
../../components/driver/include/driver/sigmadelta.h \

View file

@ -23,7 +23,7 @@ More detailed block diagram of the MCPWM unit is shown below. Each A/B pair may
MCPWM Block Diagram
Description of this API starts with configuration of MCPWM's **Timer** and **Operator** submodules to provide the basic motor control functionality. Then it discusses more advanced submodules and functionalities of a **Fault Handler**, signal **Capture**, **Carrier** and **Interrupts**.
Description of this API starts with configuration of MCPWM's **Timer** and **Generator** submodules to provide the basic motor control functionality. Then it discusses more advanced submodules and functionalities of a **Fault Handler**, signal **Capture**, **Carrier** and **Interrupts**.
Contents
--------
@ -51,9 +51,9 @@ In this case we will describe a simple configuration to control a brushed DC mot
Example of Brushed DC Motor Control with MCPWM
Configuration covers the following steps:
Configuration covers the following steps:
1. Selection of a MPWN unit that will be used to drive the motor. There are two units available on-board of ESP32 and enumerated in :cpp:type:`mcpwm_unit_t`.
1. Selection of a MPWn unit that will be used to drive the motor. There are two units available on-board of ESP32 and enumerated in :cpp:type:`mcpwm_unit_t`.
2. Initialization of two GPIOs as output signals within selected unit by calling :cpp:func:`mcpwm_gpio_init`. The two output signals are typically used to command the motor to rotate right or left. All available signal options are listed in :cpp:type:`mcpwm_io_signals_t`. To set more than a single pin at a time, use function :cpp:func:`mcpwm_set_pin` together with :cpp:type:`mcpwm_pin_config_t`.
3. Selection of a timer. There are three timers available within the unit. The timers are listed in :cpp:type:`mcpwm_timer_t`.
4. Setting of the timer frequency and initial duty within :cpp:type:`mcpwm_config_t` structure.
@ -63,13 +63,13 @@ Configuration covers the following steps:
Operate
-------
To operate a motor connected to the MCPWM unit, e.g. turn it left or right, or vary the speed, we should apply some control signals to the unit's outputs. The outputs are organized into three pairs. Within a pair they are labeled "A" and "B" and driven by a submodule called an "Operator". To provide a PWM signal, the Operator itself should be clocked by one of three available Timers. To make the API simpler, each Timer is automatically associated by the API to drive an Operator of the same index, e.g. Timer 0 is associated with Operator 0.
To operate a motor connected to the MCPWM unit, e.g. turn it left or right, or vary the speed, we should apply some control signals to the unit's outputs. The outputs are organized into three pairs. Within a pair they are labeled "A" and "B" and each driven by a submodule called an "Generator". To provide a PWM signal, the Operator itself, which contains two Generator, should be clocked by one of three available Timers. To make the API simpler, each Timer is automatically associated by the API to drive an Operator of the same index, e.g. Timer 0 is associated with Operator 0.
There are the following basic ways to control the outputs:
There are the following basic ways to control the outputs:
* We can drive particular signal steady high or steady low with function :cpp:func:`mcpwm_set_signal_high` or :cpp:func:`mcpwm_set_signal_low`. This will make the motor to turn with a maximum speed or stop. Depending on selected output A or B the motor will rotate either right or left.
* Another option is to drive the outputs with the PWM signal by calling :cpp:func:`mcpwm_start` or :cpp:func:`mcpwm_stop`. The motor speed will be proportional to the PWM duty.
* To vary PWM's duty call :cpp:func:`mcpwm_set_duty` and provide the duty value in %. Optionally, you may call :cpp:func:`mcpwm_set_duty_in_us`, if you prefer to set the duty in microseconds. Checking of currently set value is possible by calling :cpp:func:`mcpwm_get_duty`. Phase of the PWM signal may be altered by calling :cpp:func:`mcpwm_set_duty_type`. The duty is set individually for each A and B output using :cpp:type:`mcpwm_operator_t` in specific function calls. The duty value refers either to high or low output signal duration. This is configured when calling :cpp:func:`mcpwm_init`, as discussed in section `Configure`_, and selecting one of options from :cpp:type:`mcpwm_duty_type_t`.
* Another option is to drive the outputs with the PWM signal by calling :cpp:func:`mcpwm_start` or :cpp:func:`mcpwm_stop`. The motor speed will be proportional to the PWM duty.
* To vary PWM's duty call :cpp:func:`mcpwm_set_duty` and provide the duty value in %. Optionally, you may call :cpp:func:`mcpwm_set_duty_in_us`, if you prefer to set the duty in microseconds. Checking of currently set value is possible by calling :cpp:func:`mcpwm_get_duty`. Phase of the PWM signal may be altered by calling :cpp:func:`mcpwm_set_duty_type`. The duty is set individually for each A and B output using :cpp:type:`mcpwm_generator_t` in specific function calls. The duty value refers either to high or low output signal duration. This is configured when calling :cpp:func:`mcpwm_init`, as discussed in section `Configure`_, and selecting one of options from :cpp:type:`mcpwm_duty_type_t`.
.. note::
@ -107,9 +107,9 @@ One of requirements of BLDC (Brushless DC, see figure below) motor control is se
The capture functionality may be used for other types of motors or tasks. The functionality is enabled in two steps:
1. Configuration of GPIOs to act as the capture signal inputs by calling functions :cpp:func:`mcpwm_gpio_init` or :cpp:func:`mcpwm_set_pin`, that were described in section `Configure`_.
2. Enabling of the functionality itself by invoking :cpp:func:`mcpwm_capture_enable`, selecting desired signal input from :cpp:type:`mcpwm_capture_signal_t`, setting the signal edge with :cpp:type:`mcpwm_capture_on_edge_t` and the signal count prescaler.
2. Enabling of the functionality itself by invoking :cpp:func:`mcpwm_capture_enable`, selecting desired signal input from :cpp:type:`mcpwm_capture_signal_t`, setting the signal edge with :cpp:type:`mcpwm_capture_on_edge_t` and the signal count prescaler.
Within the second step above a 32-bit capture timer is enabled. The timer runs continuously driven by the APB clock. The clock frequency is typically 80 MHz. On each capture event the capture timers value is stored in time-stamp register that may be then checked by calling :cpp:func:`mcpwm_capture_signal_get_value`. The edge of the last signal may be checked with :cpp:func:`mcpwm_capture_signal_get_edge`.
Within the second step above a 32-bit capture timer is enabled. The timer runs continuously driven by the APB clock. The clock frequency is typically 80 MHz. On each capture event the capture timers value is stored in time-stamp register that may be then checked by calling :cpp:func:`mcpwm_capture_signal_get_value`. The edge of the last signal may be checked with :cpp:func:`mcpwm_capture_signal_get_edge`.
If not required anymore, the capture functionality may be disabled with :cpp:func:`mcpwm_capture_disable`.
@ -131,12 +131,12 @@ The fault handler functionality is enabled in two steps:
1. Configuration of GPIOs to act as fault signal inputs. This is done in analogous way as described for capture signals in section above. It includes setting the signal level to trigger the fault as defined in :cpp:type:`mcpwm_fault_input_level_t`.
2. Initialization of the fault handler by calling either :cpp:func:`mcpwm_fault_set_oneshot_mode` or :cpp:func:`mcpwm_fault_set_cyc_mode`. These functions set the mode that MCPWM should operate once fault signal becomes inactive. There are two modes possible:
* State of MCPWM unit will be locked until reset - :cpp:func:`mcpwm_fault_set_oneshot_mode`.
* The MCPWM will resume operation once fault signal becoming inactive - :cpp:func:`mcpwm_fault_set_cyc_mode`.
* State of MCPWM unit will be locked until reset - :cpp:func:`mcpwm_fault_set_oneshot_mode`.
* The MCPWM will resume operation once fault signal becoming inactive - :cpp:func:`mcpwm_fault_set_cyc_mode`.
The function call parameters include selection of one of three fault inputs defined in :cpp:type:`mcpwm_fault_signal_t` and specific action on outputs A and B defined in :cpp:type:`mcpwm_action_on_pwmxa_t` and :cpp:type:`mcpwm_action_on_pwmxb_t`.
Particular fault signal may be disabled at the runtime by calling :cpp:func:`mcpwm_fault_deinit`.
Particular fault signal may be disabled at the runtime by calling :cpp:func:`mcpwm_fault_deinit`.
Carrier
@ -158,7 +158,7 @@ Interrupts
Registering of the MCPWM interrupt handler is possible by calling :cpp:func:`mcpwm_isr_register`.
Application Example
-------------------
@ -175,5 +175,6 @@ Examples of using MCPWM for motor control: :example:`peripherals/mcpwm`:
API Reference
-------------
.. include:: /_build/inc/mcpwm_types.inc
.. include:: /_build/inc/mcpwm.inc

View file

@ -75,6 +75,64 @@ If type alias or template alias:
Invalid definition: Expected identifier in nested name, got keyword: void [error at 4]
void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
----^
mcpwm.inc:line: WARNING: Error when parsing function declaration.
If the function has no return type:
Error in declarator or parameters and qualifiers
Invalid definition: Expected identifier in nested name. [error at 31]
_Static_assert(MCPWM_UNIT_MAX, "MCPWM unit number not equal to chip capabilities")
-------------------------------^
If the function has a return type:
Error in declarator
If pointer to member declarator:
Invalid definition: Expected identifier in nested name. [error at 14]
_Static_assert(MCPWM_UNIT_MAX, "MCPWM unit number not equal to chip capabilities")
--------------^
If declId, parameters, and qualifiers:
Invalid definition: Expected identifier in nested name. [error at 14]
_Static_assert(MCPWM_UNIT_MAX, "MCPWM unit number not equal to chip capabilities")
--------------^
If parenthesis in noptr-declarator:
Error in declarator or parameters and qualifiers
If pointer to member declarator:
Invalid definition: Expected '::' in pointer to member (function). [error at 29]
_Static_assert(MCPWM_UNIT_MAX, "MCPWM unit number not equal to chip capabilities")
-----------------------------^
If declarator-id:
Invalid definition: Expecting "(" in parameters_and_qualifiers. [error at 29]
_Static_assert(MCPWM_UNIT_MAX, "MCPWM unit number not equal to chip capabilities")
-----------------------------^
mcpwm.inc:line: WARNING: Error when parsing function declaration.
If the function has no return type:
Error in declarator or parameters and qualifiers
Invalid definition: Expected identifier in nested name, got keyword: sizeof [error at 21]
_Static_assert(sizeof( ulp_insn_t ), "ULP coprocessor instruction size should be 4 bytes")
---------------------^
If the function has a return type:
Error in declarator
If pointer to member declarator:
Invalid definition: Expected identifier in nested name. [error at 14]
_Static_assert(sizeof( ulp_insn_t ), "ULP coprocessor instruction size should be 4 bytes")
--------------^
If declId, parameters, and qualifiers:
Invalid definition: Expected identifier in nested name. [error at 14]
_Static_assert(sizeof( ulp_insn_t ), "ULP coprocessor instruction size should be 4 bytes")
--------------^
If parenthesis in noptr-declarator:
Error in declarator or parameters and qualifiers
If pointer to member declarator:
Invalid definition: Expected identifier in nested name, got keyword: sizeof [error at 21]
_Static_assert(sizeof( ulp_insn_t ), "ULP coprocessor instruction size should be 4 bytes")
---------------------^
If declarator-id:
Invalid definition: Expected identifier in nested name, got keyword: sizeof [error at 21]
_Static_assert(sizeof( ulp_insn_t ), "ULP coprocessor instruction size should be 4 bytes")
---------------------^
mcpwm.inc:line: WARNING: doxygenfunction: Unable to resolve multiple matches for function "_Static_assert" with arguments () in doxygen xml output for project "esp32-idf" from directory: xml_in/.
Potential matches:
- _Static_assert(MCPWM_UNIT_MAX, "MCPWM unit number not equal to chip capabilities")
- _Static_assert(sizeof( ulp_insn_t ), "ULP coprocessor instruction size should be 4 bytes")
#
# Issue present only when building on msys2 / mingw32 END <<<
#