mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
MCPWM: expose API to set timer resolution
Closes https://github.com/espressif/esp-idf/issues/1101
This commit is contained in:
parent
1063f0c9dd
commit
f4314af913
@ -277,6 +277,10 @@ esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_
|
||||
|
||||
/**
|
||||
* @brief Initialize MCPWM parameters
|
||||
* @note
|
||||
* The default resolution configured for MCPWM group and timer are 160M / 16 = 10M and 10M / 10 = 1M
|
||||
* The default resolution can be changed by calling mcpwm_group_set_resolution() and mcpwm_timer_set_resolution(),
|
||||
* before calling this function.
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers.
|
||||
@ -288,6 +292,39 @@ esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_
|
||||
*/
|
||||
esp_err_t mcpwm_init( mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpwm_config_t *mcpwm_conf);
|
||||
|
||||
/**
|
||||
* @brief Set resolution of the MCPWM group
|
||||
* @note
|
||||
* This will override default resolution of group(=10,000,000).
|
||||
* This WILL NOT automatically update frequency and duty. Call mcpwm_set_frequency() and mcpwm_set_duty() manually
|
||||
* to set them back.
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
* @param resolution set expected frequency resolution
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, unsigned long int resolution);
|
||||
|
||||
/**
|
||||
* @brief Set resolution of each timer
|
||||
* @note
|
||||
* This WILL override default resolution of timer(=1,000,000).
|
||||
* This WILL NOT automatically update frequency and duty. Call mcpwm_set_frequency() and mcpwm_set_duty() manually
|
||||
* to set them back.
|
||||
*
|
||||
* @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 resolution set expected frequency resolution
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t mcpwm_timer_set_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, unsigned long int resolution);
|
||||
|
||||
/**
|
||||
* @brief Set frequency(in Hz) of MCPWM timer
|
||||
*
|
||||
@ -331,7 +368,7 @@ esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
|
||||
|
||||
/**
|
||||
* @brief Set duty either active high or active low(out of phase/inverted)
|
||||
* @note
|
||||
* @note
|
||||
* Call this function every time after mcpwm_set_signal_high or mcpwm_set_signal_low to resume with previously set duty cycle
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
@ -368,6 +405,18 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
|
||||
*/
|
||||
float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen);
|
||||
|
||||
/**
|
||||
* @brief Get duty cycle of each operator 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 gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
|
||||
*
|
||||
* @return
|
||||
* - duty cycle in us of each operator
|
||||
*/
|
||||
uint32_t mcpwm_get_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen);
|
||||
|
||||
/**
|
||||
* @brief Use this function to set MCPWM signal high
|
||||
*
|
||||
@ -568,7 +617,7 @@ esp_err_t mcpwm_fault_init(mcpwm_unit_t mcpwm_num, mcpwm_fault_input_level_t int
|
||||
|
||||
/**
|
||||
* @brief Set oneshot mode on fault detection, once fault occur in oneshot mode reset is required to resume MCPWM signals
|
||||
* @note
|
||||
* @note
|
||||
* currently low level triggering is not supported
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
@ -586,7 +635,7 @@ esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t tim
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @note
|
||||
* @note
|
||||
* currently low level triggering is not supported
|
||||
*
|
||||
* @param mcpwm_num set MCPWM unit(0-1)
|
||||
|
@ -64,12 +64,25 @@ _Static_assert(SOC_MCPWM_GENERATORS_PER_OPERATOR == 2, "This driver assumes the
|
||||
typedef struct {
|
||||
mcpwm_hal_context_t hal;
|
||||
portMUX_TYPE spinlock;
|
||||
int group_pre_scale; // starts from 1, not 0. will be subtracted by 1 in ll driver
|
||||
int timer_pre_scale[SOC_MCPWM_TIMERS_PER_GROUP]; // same as above
|
||||
} mcpwm_context_t;
|
||||
|
||||
static mcpwm_context_t context[SOC_MCPWM_GROUPS] = {
|
||||
[0 ... SOC_MCPWM_GROUPS - 1] = {
|
||||
.spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
}
|
||||
[0] = {
|
||||
.hal = {MCPWM_LL_GET_HW(0)},
|
||||
.spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
.group_pre_scale = SOC_MCPWM_BASE_CLK_HZ / MCPWM_GROUP_CLK_HZ,
|
||||
.timer_pre_scale = {[0 ... SOC_MCPWM_TIMERS_PER_GROUP - 1] =
|
||||
MCPWM_GROUP_CLK_HZ / MCPWM_TIMER_CLK_HZ},
|
||||
},
|
||||
[1] = {
|
||||
.hal = {MCPWM_LL_GET_HW(1)},
|
||||
.spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
.group_pre_scale = SOC_MCPWM_BASE_CLK_HZ / MCPWM_GROUP_CLK_HZ,
|
||||
.timer_pre_scale = {[0 ... SOC_MCPWM_TIMERS_PER_GROUP - 1] =
|
||||
MCPWM_GROUP_CLK_HZ / MCPWM_TIMER_CLK_HZ},
|
||||
}
|
||||
};
|
||||
|
||||
typedef void (*mcpwm_ll_gen_set_event_action_t)(mcpwm_dev_t *mcpwm, int op, int gen, int action);
|
||||
@ -157,6 +170,30 @@ esp_err_t mcpwm_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_group_set_resolution(mcpwm_unit_t mcpwm_num, unsigned long int resolution) {
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
int pre_scale_temp = SOC_MCPWM_BASE_CLK_HZ / resolution;
|
||||
ESP_RETURN_ON_FALSE(pre_scale_temp >= 1, ESP_ERR_INVALID_ARG, TAG, "invalid resolution");
|
||||
context[mcpwm_num].group_pre_scale = pre_scale_temp;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, context[mcpwm_num].group_pre_scale);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_timer_set_resolution(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, unsigned long int resolution) {
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
int pre_scale_temp = SOC_MCPWM_BASE_CLK_HZ / context[mcpwm_num].group_pre_scale / resolution;
|
||||
ESP_RETURN_ON_FALSE(pre_scale_temp >= 1, ESP_ERR_INVALID_ARG, TAG, "invalid resolution");
|
||||
context[mcpwm_num].timer_pre_scale[timer_num] = pre_scale_temp;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, context[mcpwm_num].timer_pre_scale[timer_num]);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, uint32_t frequency)
|
||||
{
|
||||
//the driver currently always use the timer x for operator x
|
||||
@ -168,7 +205,10 @@ esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, u
|
||||
|
||||
mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num);
|
||||
uint32_t previous_peak = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false);
|
||||
uint32_t new_peak = MCPWM_TIMER_CLK_HZ / frequency;
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
uint32_t new_peak = real_timer_clk_hz / frequency;
|
||||
mcpwm_ll_timer_set_peak(hal->dev, timer_num, new_peak, false);
|
||||
// keep the duty cycle unchanged
|
||||
float scale = ((float)new_peak) / previous_peak;
|
||||
@ -212,8 +252,10 @@ esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
// the timer resolution is fixed to 1us in the driver, so duty_in_us is the same to compare value
|
||||
mcpwm_ll_operator_set_compare_value(hal->dev, op, cmp, duty_in_us);
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
mcpwm_ll_operator_set_compare_value(hal->dev, op, cmp, duty_in_us * real_timer_clk_hz / 1000000);
|
||||
mcpwm_ll_operator_enable_update_compare_on_tez(hal->dev, op, cmp, true);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return ESP_OK;
|
||||
@ -313,13 +355,16 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw
|
||||
mcpwm_hal_init(hal, &config);
|
||||
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, MCPWM_GROUP_CLK_PRESCALE);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, context[mcpwm_num].group_pre_scale);
|
||||
mcpwm_ll_group_enable_shadow_mode(hal->dev);
|
||||
mcpwm_ll_group_flush_shadow(hal->dev);
|
||||
mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, MCPWM_GROUP_CLK_HZ / MCPWM_TIMER_CLK_HZ);
|
||||
mcpwm_ll_timer_set_clock_prescale(hal->dev, timer_num, context[mcpwm_num].timer_pre_scale[timer_num]);
|
||||
mcpwm_ll_timer_set_count_mode(hal->dev, timer_num, mcpwm_conf->counter_mode);
|
||||
mcpwm_ll_timer_update_period_at_once(hal->dev, timer_num);
|
||||
mcpwm_ll_timer_set_peak(hal->dev, timer_num, MCPWM_TIMER_CLK_HZ / mcpwm_conf->frequency, false);
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
mcpwm_ll_timer_set_peak(hal->dev, timer_num, real_timer_clk_hz / mcpwm_conf->frequency, false);
|
||||
mcpwm_ll_operator_select_timer(hal->dev, timer_num, timer_num); //the driver currently always use the timer x for operator x
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
|
||||
@ -337,10 +382,13 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num)
|
||||
MCPWM_TIMER_CHECK(mcpwm_num, timer_num);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
unsigned int group_clock = SOC_MCPWM_BASE_CLK_HZ / mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned int timer_clock = group_clock / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
uint32_t peak = mcpwm_ll_timer_get_peak(hal->dev, timer_num, false);
|
||||
uint32_t freq = real_timer_clk_hz / peak;
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return (uint32_t)timer_clock;
|
||||
return freq;
|
||||
}
|
||||
|
||||
float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen)
|
||||
@ -355,6 +403,20 @@ float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_gene
|
||||
return duty;
|
||||
}
|
||||
|
||||
uint32_t mcpwm_get_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen){
|
||||
//the driver currently always use the timer x for operator x
|
||||
const int op = timer_num;
|
||||
MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen);
|
||||
mcpwm_hal_context_t *hal = &context[mcpwm_num].hal;
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev);
|
||||
unsigned long int real_timer_clk_hz =
|
||||
SOC_MCPWM_BASE_CLK_HZ / real_group_prescale / mcpwm_ll_timer_get_clock_prescale(hal->dev, timer_num);
|
||||
uint32_t duty = mcpwm_ll_operator_get_compare_value(hal->dev, op, gen) * (1000000.0 / real_timer_clk_hz);
|
||||
mcpwm_critical_exit(mcpwm_num);
|
||||
return duty;
|
||||
}
|
||||
|
||||
esp_err_t mcpwm_set_signal_high(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen)
|
||||
{
|
||||
//the driver currently always use the timer x for operator x
|
||||
@ -657,7 +719,7 @@ esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t ca
|
||||
};
|
||||
mcpwm_critical_enter(mcpwm_num);
|
||||
mcpwm_hal_init(hal, &init_config);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, MCPWM_GROUP_CLK_PRESCALE);
|
||||
mcpwm_ll_group_set_clock_prescale(hal->dev, context[mcpwm_num].group_pre_scale);
|
||||
mcpwm_ll_capture_enable_timer(hal->dev, true);
|
||||
mcpwm_ll_capture_enable_channel(hal->dev, cap_sig, true);
|
||||
mcpwm_ll_capture_enable_negedge(hal->dev, cap_sig, cap_edge & MCPWM_NEG_EDGE);
|
||||
|
@ -26,6 +26,10 @@
|
||||
#define TEST_SYNC_GPIO (21)
|
||||
#define TEST_CAP_GPIO (21)
|
||||
|
||||
#define MCPWM_TEST_GROUP_CLK_HZ (SOC_MCPWM_BASE_CLK_HZ / 16)
|
||||
#define MCPWM_TEST_TIMER_CLK_HZ (MCPWM_TEST_GROUP_CLK_HZ / 10)
|
||||
|
||||
|
||||
static mcpwm_dev_t *MCPWM[2] = {&MCPWM0, &MCPWM1}; // interrupt handling still lacks API to get/clear pending event, currently we have to read/write interrupt register
|
||||
const static mcpwm_io_signals_t pwma[] = {MCPWM0A, MCPWM1A, MCPWM2A};
|
||||
const static mcpwm_io_signals_t pwmb[] = {MCPWM0B, MCPWM1B, MCPWM2B};
|
||||
@ -67,7 +71,8 @@ static esp_err_t test_mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void mcpwm_setup_testbench(mcpwm_unit_t group, mcpwm_timer_t timer, uint32_t pwm_freq, float pwm_duty)
|
||||
static void mcpwm_setup_testbench(mcpwm_unit_t group, mcpwm_timer_t timer, uint32_t pwm_freq, float pwm_duty,
|
||||
unsigned long int group_resolution, unsigned long int timer_resolution)
|
||||
{
|
||||
// PWMA <--> PCNT UNIT0
|
||||
pcnt_config_t pcnt_config = {
|
||||
@ -100,6 +105,8 @@ static void mcpwm_setup_testbench(mcpwm_unit_t group, mcpwm_timer_t timer, uint3
|
||||
.counter_mode = MCPWM_UP_COUNTER,
|
||||
.duty_mode = MCPWM_DUTY_MODE_0,
|
||||
};
|
||||
mcpwm_group_set_resolution(group, group_resolution);
|
||||
mcpwm_timer_set_resolution(group, timer, timer_resolution);
|
||||
TEST_ESP_OK(mcpwm_init(group, timer, &pwm_config));
|
||||
}
|
||||
|
||||
@ -115,24 +122,24 @@ static uint32_t mcpwm_pcnt_get_pulse_number(pcnt_unit_t pwm_pcnt_unit, int captu
|
||||
return (uint32_t)count_value;
|
||||
}
|
||||
|
||||
static void mcpwm_timer_duty_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
|
||||
static void mcpwm_timer_duty_test(mcpwm_unit_t unit, mcpwm_timer_t timer, unsigned long int group_resolution, unsigned long int timer_resolution)
|
||||
{
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0);
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, group_resolution, timer_resolution);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_A, 10.0));
|
||||
TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_B, 20.0));
|
||||
TEST_ASSERT_EQUAL_FLOAT(10.0, mcpwm_get_duty(unit, timer, MCPWM_OPR_A));
|
||||
TEST_ASSERT_EQUAL_FLOAT(20.0, mcpwm_get_duty(unit, timer, MCPWM_OPR_B));
|
||||
TEST_ASSERT_FLOAT_WITHIN(0.1, 10.0, mcpwm_get_duty(unit, timer, MCPWM_OPR_A));
|
||||
TEST_ASSERT_FLOAT_WITHIN(0.1, 20.0, mcpwm_get_duty(unit, timer, MCPWM_OPR_B));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_A, 55.5f));
|
||||
TEST_ESP_OK(mcpwm_set_duty_type(unit, timer, MCPWM_OPR_A, MCPWM_DUTY_MODE_0));
|
||||
TEST_ASSERT_EQUAL_FLOAT(55.5, mcpwm_get_duty(unit, timer, MCPWM_OPR_A));
|
||||
TEST_ASSERT_FLOAT_WITHIN(0.1, 55.5, mcpwm_get_duty(unit, timer, MCPWM_OPR_A));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
TEST_ESP_OK(mcpwm_set_duty_in_us(unit, timer, MCPWM_OPR_B, 500));
|
||||
TEST_ASSERT_EQUAL_FLOAT(50.0, mcpwm_get_duty(unit, timer, MCPWM_OPR_B));
|
||||
TEST_ASSERT_INT_WITHIN(5, 500, mcpwm_get_duty_in_us(unit, timer, MCPWM_OPR_B));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
TEST_ESP_OK(mcpwm_stop(unit, timer));
|
||||
@ -143,7 +150,8 @@ TEST_CASE("MCPWM duty test", "[mcpwm]")
|
||||
{
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
|
||||
mcpwm_timer_duty_test(i, j);
|
||||
mcpwm_timer_duty_test(i, j, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
|
||||
mcpwm_timer_duty_test(i, j, MCPWM_TEST_GROUP_CLK_HZ / 2, MCPWM_TEST_TIMER_CLK_HZ * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -154,7 +162,7 @@ static void mcpwm_start_stop_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
|
||||
{
|
||||
uint32_t pulse_number = 0;
|
||||
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0); // Period: 1000us, 1ms
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ); // Period: 1000us, 1ms
|
||||
// count the pulse number within 100ms
|
||||
pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMA_PCNT_UNIT, 100);
|
||||
TEST_ASSERT_INT_WITHIN(2, 100, pulse_number);
|
||||
@ -187,7 +195,7 @@ TEST_CASE("MCPWM start and stop test", "[mcpwm]")
|
||||
|
||||
static void mcpwm_deadtime_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
|
||||
{
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0); // Period: 1000us, 1ms
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ); // Period: 1000us, 1ms
|
||||
mcpwm_deadtime_type_t deadtime_type[] = {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
|
||||
@ -220,7 +228,7 @@ static void mcpwm_carrier_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_car
|
||||
{
|
||||
uint32_t pulse_number = 0;
|
||||
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0);
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
|
||||
mcpwm_set_signal_high(unit, timer, MCPWM_GEN_A);
|
||||
mcpwm_set_signal_high(unit, timer, MCPWM_GEN_B);
|
||||
TEST_ESP_OK(mcpwm_carrier_enable(unit, timer));
|
||||
@ -276,7 +284,7 @@ static void mcpwm_fault_cbc_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
|
||||
mcpwm_fault_signal_t fault_sig = fault_sig_array[timer];
|
||||
mcpwm_io_signals_t fault_io_sig = fault_io_sig_array[timer];
|
||||
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0);
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
|
||||
TEST_ESP_OK(test_mcpwm_gpio_init(unit, fault_io_sig, TEST_FAULT_GPIO));
|
||||
gpio_set_level(TEST_FAULT_GPIO, 0);
|
||||
TEST_ESP_OK(mcpwm_fault_init(unit, MCPWM_HIGH_LEVEL_TGR, fault_sig));
|
||||
@ -312,7 +320,7 @@ static void mcpwm_fault_ost_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
|
||||
mcpwm_fault_signal_t fault_sig = fault_sig_array[timer];
|
||||
mcpwm_io_signals_t fault_io_sig = fault_io_sig_array[timer];
|
||||
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0);
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
|
||||
TEST_ESP_OK(test_mcpwm_gpio_init(unit, fault_io_sig, TEST_FAULT_GPIO));
|
||||
gpio_set_level(TEST_FAULT_GPIO, 0);
|
||||
TEST_ESP_OK(mcpwm_fault_init(unit, MCPWM_HIGH_LEVEL_TGR, fault_sig));
|
||||
@ -345,7 +353,7 @@ static void mcpwm_sync_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
|
||||
mcpwm_sync_signal_t sync_sig = sync_sig_array[timer];
|
||||
mcpwm_io_signals_t sync_io_sig = sync_io_sig_array[timer];
|
||||
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0);
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
|
||||
TEST_ESP_OK(test_mcpwm_gpio_init(unit, sync_io_sig, TEST_SYNC_GPIO));
|
||||
gpio_set_level(TEST_SYNC_GPIO, 0);
|
||||
|
||||
|
@ -41,7 +41,7 @@ extern "C" {
|
||||
|
||||
/********************* Group registers *******************/
|
||||
|
||||
// Set/Get group clock: PWM_clk = CLK_160M / (prescale + 1)
|
||||
// Set/Get group clock: PWM_clk = CLK_160M / (clk_cfg.prescale + 1)
|
||||
static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int pre_scale)
|
||||
{
|
||||
mcpwm->clk_cfg.prescale = pre_scale - 1;
|
||||
|
@ -41,15 +41,20 @@ extern "C" {
|
||||
|
||||
/********************* Group registers *******************/
|
||||
|
||||
// Set/Get group clock: PWM_clk = CLK_160M / (prescale + 1)
|
||||
// Set/Get group clock: PWM_clk = CLK_160M / (clk_cfg.prescale + 1)
|
||||
static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int pre_scale)
|
||||
{
|
||||
mcpwm->clk_cfg.prescale = pre_scale - 1;
|
||||
// In case the compiler optimise a 32bit instruction (e.g. s32i) into 8bit instruction (e.g. s8i, which is not allowed to access a register)
|
||||
// We take care of the "read-modify-write" procedure by ourselves.
|
||||
typeof(mcpwm->clk_cfg) clkcfg = mcpwm->clk_cfg;
|
||||
clkcfg.prescale = pre_scale - 1;
|
||||
mcpwm->clk_cfg = clkcfg;
|
||||
}
|
||||
|
||||
static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm)
|
||||
{
|
||||
return mcpwm->clk_cfg.prescale + 1;
|
||||
typeof(mcpwm->clk_cfg) clkcfg = mcpwm->clk_cfg;
|
||||
return clkcfg.prescale + 1;
|
||||
}
|
||||
|
||||
static inline void mcpwm_ll_group_enable_shadow_mode(mcpwm_dev_t *mcpwm)
|
||||
@ -265,12 +270,17 @@ static inline void mcpwm_ll_intr_enable_capture(mcpwm_dev_t *mcpwm, uint32_t cap
|
||||
|
||||
static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id, uint32_t prescale)
|
||||
{
|
||||
mcpwm->timer[timer_id].period.prescale = prescale - 1;
|
||||
// In case the compiler optimise a 32bit instruction (e.g. s32i) into 8bit instruction (e.g. s8i, which is not allowed to access a register)
|
||||
// We take care of the "read-modify-write" procedure by ourselves.
|
||||
typeof(mcpwm->timer[timer_id].period) period = mcpwm->timer[timer_id].period;
|
||||
period.prescale = prescale - 1;
|
||||
mcpwm->timer[timer_id].period = period;
|
||||
}
|
||||
|
||||
static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id)
|
||||
{
|
||||
return mcpwm->timer[timer_id].period.prescale + 1;
|
||||
typeof(mcpwm->timer[timer_id].period) period = mcpwm->timer[timer_id].period;
|
||||
return period.prescale + 1;
|
||||
}
|
||||
|
||||
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
|
||||
|
@ -35,6 +35,7 @@ Contents
|
||||
* Use `Fault Handler`_ to detect and manage faults
|
||||
* Add a higher frequency `Carrier`_, if output signals are passed through an isolation transformer
|
||||
* Configuration and handling of `Interrupts`_.
|
||||
* Extra configuration of `Resolution`_.
|
||||
|
||||
|
||||
Configure
|
||||
@ -57,7 +58,8 @@ Configuration covers the following steps:
|
||||
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.
|
||||
5. Calling of :cpp:func:`mcpwm_init` with the above parameters to make the configuration effective.
|
||||
5. Setting timer resolution if necessary, by calling :cpp:func:`mcpwm_group_set_resolution` and :cpp:func:`mcpwm_timer_set_resolution`
|
||||
6. Calling of :cpp:func:`mcpwm_init` with the above parameters to make the configuration effective.
|
||||
|
||||
|
||||
Operate
|
||||
@ -159,6 +161,16 @@ Interrupts
|
||||
Registering of the MCPWM interrupt handler is possible by calling :cpp:func:`mcpwm_isr_register`.
|
||||
|
||||
|
||||
Resolution
|
||||
----------
|
||||
|
||||
The default resolution for MCPWM group and MCPWM timer are configured to **10MHz** and **1MHz** in :cpp:func:`mcpwm_init`, which might be not enough for some applications.
|
||||
The driver also provides two APIs that can be used to override the default resolution: :cpp:func:`mcpwm_group_set_resolution` and :cpp:func:`mcpwm_timer_set_resolution`.
|
||||
|
||||
Note that, these two APIs won't update the frequency and duty automatically, to achieve that, one has to call :cpp:func:`mcpwm_set_frequency` and :cpp:func:`mcpwm_set_duty` accordingly.
|
||||
|
||||
To get PWM pulse that is below 15Hz, please set the resolution to a lower value. For high frequency PWM with limited step range, please set them with higher value.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user