Explorar el Código

mcpwm: fix bldc example force output level inverted

set_force_level can only set the generator level before the deadtime module.
if the deadtime module enables the inverter, then the real output level is inverted accordingly
morris hace 2 años
padre
commit
5680d28b0e

+ 1 - 0
components/driver/mcpwm/include/driver/mcpwm_gen.h

@@ -59,6 +59,7 @@ esp_err_t mcpwm_del_generator(mcpwm_gen_handle_t gen);
  * @note The force level will be applied to the generator immediately, regardless any other events that would change the generator's behaviour.
  * @note If the `hold_on` is true, the force level will retain forever, until user removes the force level by setting the force level to `-1`.
  * @note If the `hold_on` is false, the force level can be overridden by the next event action.
+ * @note The force level set by this function can be inverted by GPIO matrix or dead-time module. So the level set here doesn't equal to the final output level.
  *
  * @param[in] gen MCPWM generator handle, allocated by `mcpwm_new_generator()`
  * @param[in] level GPIO level to be applied to MCPWM generator, specially, -1 means to remove the force level

+ 50 - 0
components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c

@@ -77,6 +77,56 @@ TEST_CASE("mcpwm_generator_force_level_hold_on", "[mcpwm]")
     TEST_ESP_OK(mcpwm_del_operator(oper));
 }
 
+// mcpwm_generator_set_force_level acts before the dead time module
+// so the value output on the generator is a combined result
+TEST_CASE("mcpwm_force_level_and_dead_time", "[mcpwm]")
+{
+    printf("create operator and generators\r\n");
+    mcpwm_oper_handle_t oper = NULL;
+    mcpwm_operator_config_t operator_config = {
+        .group_id = 0,
+    };
+    TEST_ESP_OK(mcpwm_new_operator(&operator_config, &oper));
+
+    mcpwm_gen_handle_t gen_a = NULL;
+    mcpwm_gen_handle_t gen_b = NULL;
+    const int gen_a_gpio = 0;
+    const int gen_b_gpio = 2;
+    mcpwm_generator_config_t generator_config = {
+        .gen_gpio_num = gen_a_gpio,
+        .flags.io_loop_back = true, // loop back for test
+    };
+    TEST_ESP_OK(mcpwm_new_generator(oper, &generator_config, &gen_a));
+    generator_config.gen_gpio_num = gen_b_gpio;
+    generator_config.flags.invert_pwm = true; // Inversion add to the GPIO matrix
+    TEST_ESP_OK(mcpwm_new_generator(oper, &generator_config, &gen_b));
+
+    mcpwm_dead_time_config_t dt_config = {
+        .posedge_delay_ticks = 5,
+    };
+    ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gen_a, gen_a, &dt_config));
+    dt_config = (mcpwm_dead_time_config_t) {
+        .negedge_delay_ticks = 5,
+        .flags.invert_output = true, // Inversion applied by the dead time module
+    };
+    ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(gen_b, gen_b, &dt_config));
+
+    printf("add force level to the generator, hold on");
+    for (int i = 0; i < 10; i++) {
+        TEST_ESP_OK(mcpwm_generator_set_force_level(gen_b, 0, true));
+        vTaskDelay(pdMS_TO_TICKS(10));
+        TEST_ASSERT_EQUAL(0, gpio_get_level(gen_b_gpio));
+        TEST_ESP_OK(mcpwm_generator_set_force_level(gen_b, 1, true));
+        vTaskDelay(pdMS_TO_TICKS(10));
+        TEST_ASSERT_EQUAL(1, gpio_get_level(gen_b_gpio));
+    }
+
+    printf("delete generator and operator\r\n");
+    TEST_ESP_OK(mcpwm_del_generator(gen_a));
+    TEST_ESP_OK(mcpwm_del_generator(gen_b));
+    TEST_ESP_OK(mcpwm_del_operator(oper));
+}
+
 TEST_CASE("mcpwm_generator_force_level_recovery", "[mcpwm]")
 {
     printf("create mcpwm timer\r\n");

+ 41 - 28
examples/peripherals/mcpwm/mcpwm_bldc_hall_control/main/mcpwm_bldc_hall_control_example_main.c

@@ -61,24 +61,26 @@ static void bldc_set_phase_up_vm(mcpwm_gen_handle_t (*gens)[2])
     // U+ = PWM, U- = _PWM_
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_HIGH], -1, true);
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], -1, true);
-    // V+ = 0, V- = 1
+
+    // V+ = 0, V- = 1  --[because gen_low is inverted by dead time]--> V+ = 0, V- = 0
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
-    // W+ = 0, W- = 0
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
+
+    // W+ = 0, W- = 0  --[because gen_low is inverted by dead time]--> W+ = 0, W- = 1
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
 }
 
 // W+U-
 static void bldc_set_phase_wp_um(mcpwm_gen_handle_t (*gens)[2])
 {
-    // U+ = 0, U- = 1
+    // U+ = 0, U- = 1  --[because gen_low is inverted by dead time]--> U+ = 0, U- = 0
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
 
-    // V+ = 0, V- = 0
+    // V+ = 0, V- = 0  --[because gen_low is inverted by dead time]--> V+ = 0, V- = 1
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
 
     // W+ = PWM, W- = _PWM_
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_HIGH], -1, true);
@@ -88,13 +90,13 @@ static void bldc_set_phase_wp_um(mcpwm_gen_handle_t (*gens)[2])
 // W+V-
 static void bldc_set_phase_wp_vm(mcpwm_gen_handle_t (*gens)[2])
 {
-    // U+ = 0, U- = 0
+    // U+ = 0, U- = 0  --[because gen_low is inverted by dead time]--> U+ = 0, U- = 1
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
 
-    // V+ = 0, V- = 1
+    // V+ = 0, V- = 1  --[because gen_low is inverted by dead time]--> V+ = 0, V- = 0
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
 
     // W+ = PWM, W- = _PWM_
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_HIGH], -1, true);
@@ -104,33 +106,33 @@ static void bldc_set_phase_wp_vm(mcpwm_gen_handle_t (*gens)[2])
 // V+U-
 static void bldc_set_phase_vp_um(mcpwm_gen_handle_t (*gens)[2])
 {
-    // U+ = 0, U- = 1
+    // U+ = 0, U- = 1  --[because gen_low is inverted by dead time]--> U+ = 0, U- = 0
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
 
     // V+ = PWM, V- = _PWM_
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_HIGH], -1, true);
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], -1, true);
 
-    // W+ = 0, W- = 0
+    // W+ = 0, W- = 0  --[because gen_low is inverted by dead time]--> W+ = 0, W- = 1
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
 }
 
 // V+W-
 static void bldc_set_phase_vp_wm(mcpwm_gen_handle_t (*gens)[2])
 {
-    // U+ = 0, U- = 0
+    // U+ = 0, U- = 0  --[because gen_low is inverted by dead time]--> U+ = 0, U- = 1
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
 
     // V+ = PWM, V- = _PWM_
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_HIGH], -1, true);
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], -1, true);
 
-    // W+ = 0, W- = 1
+    // W+ = 0, W- = 1  --[because gen_low is inverted by dead time]--> W+ = 0, W- = 0
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
 }
 
 // U+W- / A+C-
@@ -140,13 +142,13 @@ static void bldc_set_phase_up_wm(mcpwm_gen_handle_t (*gens)[2])
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_HIGH], -1, true);
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_U][BLDC_MCPWM_GEN_INDEX_LOW], -1, true);
 
-    // V+ = 0, V- = 0
+    // V+ = 0, V- = 0  --[because gen_low is inverted by dead time]--> V+ = 0, V- = 1
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_V][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
 
-    // W+ = 0, W- = 1
+    // W+ = 0, W- = 1  --[because gen_low is inverted by dead time]--> W+ = 0, W- = 0
     mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true);
-    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_LOW], 1, true);
+    mcpwm_generator_set_force_level(gens[BLDC_MCPWM_OP_INDEX_W][BLDC_MCPWM_GEN_INDEX_LOW], 0, true);
 }
 
 static const bldc_hall_phase_action_t s_hall_actions[] = {
@@ -255,6 +257,8 @@ void app_main(void)
     }
 
     ESP_LOGI(TAG, "Set generator actions");
+    // gen_high and gen_low output the same waveform after the following configuration
+    // we will use the dead time module to add edge delay, also make gen_high and gen_low complementary
     for (int i = 0; i < 3; i++) {
         ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(generators[i][BLDC_MCPWM_GEN_INDEX_HIGH],
                         MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
@@ -264,6 +268,15 @@ void app_main(void)
                         MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_CBC, MCPWM_GEN_ACTION_LOW)));
         ESP_ERROR_CHECK(mcpwm_generator_set_action_on_brake_event(generators[i][BLDC_MCPWM_GEN_INDEX_HIGH],
                         MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_CBC, MCPWM_GEN_ACTION_LOW)));
+
+        ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(generators[i][BLDC_MCPWM_GEN_INDEX_LOW],
+                        MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
+        ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(generators[i][BLDC_MCPWM_GEN_INDEX_LOW],
+                        MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparators[i], MCPWM_GEN_ACTION_LOW)));
+        ESP_ERROR_CHECK(mcpwm_generator_set_action_on_brake_event(generators[i][BLDC_MCPWM_GEN_INDEX_LOW],
+                        MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_CBC, MCPWM_GEN_ACTION_LOW)));
+        ESP_ERROR_CHECK(mcpwm_generator_set_action_on_brake_event(generators[i][BLDC_MCPWM_GEN_INDEX_LOW],
+                        MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_CBC, MCPWM_GEN_ACTION_LOW)));
     }
 
     ESP_LOGI(TAG, "Setup deadtime");
@@ -278,14 +291,14 @@ void app_main(void)
         .flags.invert_output = true,
     };
     for (int i = 0; i < 3; i++) {
-        ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(generators[i][BLDC_MCPWM_GEN_INDEX_HIGH], generators[i][BLDC_MCPWM_GEN_INDEX_LOW], &dt_config));
+        ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(generators[i][BLDC_MCPWM_GEN_INDEX_LOW], generators[i][BLDC_MCPWM_GEN_INDEX_LOW], &dt_config));
     }
 
     ESP_LOGI(TAG, "Turn off all the gates");
     for (int i = 0; i < 3; i++) {
-        for (int j = 0; j < 2; j++) {
-            ESP_ERROR_CHECK(mcpwm_generator_set_force_level(generators[i][j], 0, true));
-        }
+        ESP_ERROR_CHECK(mcpwm_generator_set_force_level(generators[i][BLDC_MCPWM_GEN_INDEX_HIGH], 0, true));
+        // because gen_low is inverted by dead time module, so we need to set force level to 1
+        ESP_ERROR_CHECK(mcpwm_generator_set_force_level(generators[i][BLDC_MCPWM_GEN_INDEX_LOW], 1, true));
     }
 
     ESP_LOGI(TAG, "Create Hall sensor capture channels");