这个官方示例用于配置mcpwm来读取霍尔传感器并驱动电机,我由于改为利用MT6701来读取磁场角度,因此根据此示例修改,以先用于能够正常输出pwm波,修改代码如下(只删除了有关霍尔传感器和通用定时器的那段用于传感器捕获的代码,并且将输出通道有六路缩减为三路):
/*this mcpwm example is used to drive an BLDC with miniFOC driver board in DengFOC
* the first step is to output pwm pause successfully
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "driver/mcpwm_prelude.h"
#include "driver/gpio.h"
#define BLDC_MCPWM_TIMER_RESOLUTION_HZ 10000000 // 10MHz, 1 tick = 0.1us
#define BLDC_MCPWM_PERIOD 500 // 50us, 20KHz
#define BLDC_SPIN_DIRECTION_CCW false // define the spin direction
#define BLDC_SPEED_UPDATE_PERIOD_US 200000 // 200ms
#define BLDC_EN_GPIO 10 // 1 to enable, 0 to disable
#define BLDC_FAULT_GPIO 11 // input gpio, when error occured this gpio will detect 0, 1 is normal
#define BLDC_PWM_U_GPIO 12
#define BLDC_PWM_V_GPIO 13
#define BLDC_PWM_W_GPIO 14
#define BLDC_MCPWM_OP_INDEX_U 0
#define BLDC_MCPWM_OP_INDEX_V 1
#define BLDC_MCPWM_OP_INDEX_W 2
#define BLDC_MCPWM_GEN_INDEX_HIGH 0
#define BLDC_MCPWM_GEN_INDEX_LOW 1
static const char *TAG = "example";
void task1_output_pwm(void *pvParam)
{
ESP_LOGI(TAG, "start configuring pwm...");
ESP_LOGI(TAG, "Enable EN_GPIO..."); //
gpio_config_t en_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << BLDC_EN_GPIO,
};
ESP_ERROR_CHECK(gpio_config(&en_config));
gpio_set_level(BLDC_EN_GPIO, 0);
ESP_LOGI(TAG, "Create MCPWM timer");
mcpwm_timer_handle_t timer = NULL;
mcpwm_timer_config_t timer_config = {
.group_id = 0,
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
.resolution_hz = BLDC_MCPWM_TIMER_RESOLUTION_HZ,
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
.period_ticks = BLDC_MCPWM_PERIOD,
};
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config, &timer));
ESP_LOGI(TAG, "Create MCPWM operator");
mcpwm_oper_handle_t operators[3];
mcpwm_operator_config_t operator_config = {
.group_id = 0,
};
for (int i = 0; i < 3; ++i)
{
ESP_ERROR_CHECK(mcpwm_new_operator(&operator_config, &operators[i]));
}
ESP_LOGI(TAG, "Connect operators to the same timer");
for (int i = 0; i < 3; ++i)
{
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(operators[i], timer));
}
ESP_LOGI(TAG, "Create comparators");
mcpwm_cmpr_handle_t comparators[3];
mcpwm_comparator_config_t compare_config = {
.flags.update_cmp_on_tez = true,
};
for (int i = 0; i < 3; ++i)
{
ESP_ERROR_CHECK(mcpwm_new_comparator(operators[i], &compare_config, &comparators[i]));
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparators[i], 0));
}
ESP_LOGI(TAG, "Create over current fault detector");
mcpwm_fault_handle_t over_cur_fault = NULL;
mcpwm_gpio_fault_config_t gpio_fault_config = {
.gpio_num = BLDC_FAULT_GPIO,
.group_id = 0,
.flags.active_level = 0, // 0 to error occur, 1 to normal
.flags.pull_up = true, // internally pull up
};
ESP_ERROR_CHECK(mcpwm_new_gpio_fault(&gpio_fault_config, &over_cur_fault));
// error callback handle function enable
ESP_LOGI(TAG, "Set brake mode on the fault event");
mcpwm_brake_config_t brake_config = {
.brake_mode = MCPWM_OPER_BRAKE_MODE_CBC,
.fault = over_cur_fault,
.flags.cbc_recover_on_tez = true,
};
for (int i = 0; i < 3; ++i)
{
ESP_ERROR_CHECK(mcpwm_operator_set_brake_on_fault(operators[i], &brake_config));
}
ESP_LOGI(TAG, "CreatePWM generators");
mcpwm_gen_handle_t generators[3] = {};
mcpwm_generator_config_t gen_config = {};
const int gen_gpios[3] = {
BLDC_PWM_U_GPIO,
BLDC_PWM_V_GPIO,
BLDC_PWM_W_GPIO,
};
for (int i = 0; i < 3; ++i)
{
gen_config.gen_gpio_num = gen_gpios[i];
ESP_ERROR_CHECK(mcpwm_new_generator(operators[i], &gen_config, &generators[i]));
}
ESP_LOGI(TAG, "Set generator actions");
for (int i = 0; i < 3; ++i)
{
ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(generators[i],
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],
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],
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],
MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_CBC, MCPWM_GEN_ACTION_LOW)));
}
ESP_LOGI(TAG, "Setup deadtime");
mcpwm_dead_time_config_t dt_config = {
.posedge_delay_ticks = 5,
};
for (int i = 0; i < 3; ++i)
{
ESP_ERROR_CHECK(mcpwm_generator_set_dead_time(generators[i], generators[i], &dt_config));
}
ESP_LOGI(TAG, "Turn off all the gates");
for (int i = 0; i < 3; i++)
{
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(generators[i], 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, "Enable MOSFET gate");
gpio_set_level(BLDC_EN_GPIO, 1);
ESP_LOGI(TAG, "Start the MCPWM timer");
ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
for (int i = 0; i < 3; i++)
{
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparators[i], 250));
}
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t task1_Handle = NULL;
xTaskCreate(task1_output_pwm, "task1", 4096, NULL, 10, &task1_Handle);
}
并且在最后通过如下语句来修改并测试引脚是否能输出正确的电压(手边无示波器):
for (int i = 0; i < 3; i++)
{
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparators[i], 250));
}
但是,在烧录运行之后,发现,无论设置占空比为多少,引脚输出电压皆为0,经检查发现,是由于设置了如下语句:
for (int i = 0; i < 3; i++)
{
to re-enable the capibility of setting duty
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(generators[i], 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, "Turn off all the gates");
for (int i = 0; i < 3; i++) {
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));
}
该代码用于在关闭所用的生成器通道,等到配置完毕后再打开,但是,mcpwm_generator_set_force_level这个函数在官方中的手册中是这样说的
设置为true之后想要移除这个强制操作,必须将level重设置为-1,而由于我并未使用六路三相的输出方式,所以没有移植使用下列代码
// U+V-
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 --[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], 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], 1, true);
}
导致在后续代码中并未将level设为-1,从而导致了检测错误,仅以此篇博客记录。