mcpwm: can't apply the same delay module to multiple generators

This is a hardware limitation, one delay module can only be used by one generator at one time.

Closes https://github.com/espressif/esp-idf/issues/11327
This commit is contained in:
morris
2023-05-09 16:41:47 +08:00
parent 66c999fcf8
commit 72d0f5b35b
9 changed files with 105 additions and 12 deletions
@@ -215,12 +215,17 @@ typedef struct {
/**
* @brief Set dead time for MCPWM generator
*
* @note Due to a hardware limitation, you can't set rising edge delay for both MCPWM generator 0 and 1 at the same time,
* otherwise, there will be a conflict inside the dead time module. The same goes for the falling edge setting.
* But you can set both the rising edge and falling edge delay for the same MCPWM generator.
*
* @param[in] in_generator MCPWM generator, before adding the dead time
* @param[in] out_generator MCPWM generator, after adding the dead time
* @param[in] config MCPWM dead time configuration
* @return
* - ESP_OK: Set dead time for MCPWM generator successfully
* - ESP_ERR_INVALID_ARG: Set dead time for MCPWM generator failed because of invalid argument
* - ESP_ERR_INVALID_STATE: Set dead time for MCPWM generator failed because of invalid state (e.g. delay module is already in use by other generator)
* - ESP_FAIL: Set dead time for MCPWM generator failed because of other error
*/
esp_err_t mcpwm_generator_set_dead_time(mcpwm_gen_handle_t in_generator, mcpwm_gen_handle_t out_generator, const mcpwm_dead_time_config_t *config);
+30
View File
@@ -268,6 +268,36 @@ esp_err_t mcpwm_generator_set_dead_time(mcpwm_gen_handle_t in_generator, mcpwm_g
mcpwm_hal_context_t *hal = &group->hal;
int oper_id = oper->oper_id;
// one delay module can only be used by one generator at a time
bool delay_module_conflict = false;
portENTER_CRITICAL(&oper->spinlock);
if (config->posedge_delay_ticks) {
if (oper->posedge_delay_owner && oper->posedge_delay_owner != in_generator) {
delay_module_conflict = true;
}
}
if (config->negedge_delay_ticks) {
if (oper->negedge_delay_owner && oper->negedge_delay_owner != in_generator) {
delay_module_conflict = true;
}
}
if (!delay_module_conflict) {
if (config->posedge_delay_ticks) {
// set owner if delay module is used
oper->posedge_delay_owner = in_generator;
} else if (oper->posedge_delay_owner == in_generator) {
// clear owner if delay module is previously used by in_generator, but now it is not used
oper->posedge_delay_owner = NULL;
}
if (config->negedge_delay_ticks) {
oper->negedge_delay_owner = in_generator;
} else if (oper->negedge_delay_owner == in_generator) {
oper->negedge_delay_owner = NULL;
}
}
portEXIT_CRITICAL(&oper->spinlock);
ESP_RETURN_ON_FALSE(!delay_module_conflict, ESP_ERR_INVALID_STATE, TAG, "delay module is in use by other generator");
// Note: to better understand the following code, you should read the deadtime module topology diagram in the TRM
// check if we want to bypass the deadtime module
bool bypass = (config->negedge_delay_ticks == 0) && (config->posedge_delay_ticks == 0);
+3 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -102,6 +102,8 @@ struct mcpwm_oper_t {
mcpwm_operator_brake_mode_t brake_mode_on_soft_fault; // brake mode on software triggered fault
mcpwm_operator_brake_mode_t brake_mode_on_gpio_fault[SOC_MCPWM_GPIO_FAULTS_PER_GROUP]; // brake mode on GPIO triggered faults
uint32_t deadtime_resolution_hz; // resolution of deadtime submodule
mcpwm_gen_t *posedge_delay_owner; // which generator owns the positive edge delay
mcpwm_gen_t *negedge_delay_owner; // which generator owns the negative edge delay
mcpwm_brake_event_cb_t on_brake_cbc; // callback function which would be invoked when mcpwm operator goes into trip zone
mcpwm_brake_event_cb_t on_brake_ost; // callback function which would be invoked when mcpwm operator goes into trip zone
void *user_data; // user data which would be passed to the trip zone callback
@@ -591,6 +591,23 @@ static void redfedb_only_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle
TEST_ESP_OK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
}
static void invalid_reda_redb_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
{
mcpwm_dead_time_config_t dead_time_config = {
.posedge_delay_ticks = 10,
};
// generator_a adds delay on the posedge
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
// generator_b adds delay on the posedge as well, which is not allowed
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
// bypass the delay module for generator_a
dead_time_config.posedge_delay_ticks = 0;
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
// now generator_b can add delay on the posedge
dead_time_config.posedge_delay_ticks = 10;
TEST_ESP_OK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
}
TEST_CASE("mcpwm_generator_deadtime_classical_configuration", "[mcpwm]")
{
printf("Active High Complementary\r\n");
@@ -613,6 +630,9 @@ TEST_CASE("mcpwm_generator_deadtime_classical_configuration", "[mcpwm]")
printf("Bypass A, RED + FED on B\r\n");
mcpwm_deadtime_test_template(1000000, 500, 350, 350, 0, 2, redfedb_only_set_generator_actions, redfedb_only_set_dead_time);
printf("Can't apply one delay module to multiple generators\r\n");
mcpwm_deadtime_test_template(1000000, 500, 350, 350, 0, 2, redfedb_only_set_generator_actions, invalid_reda_redb_set_dead_time);
}
TEST_CASE("mcpwm_duty_empty_full", "[mcpwm]")