纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。 Co-authored-by: Cursor <[email protected]>
277 lines
9.4 KiB
C
277 lines
9.4 KiB
C
#include "step_motor_init.h"
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "esp_check.h"
|
|
#include "esp_timer.h"
|
|
|
|
static mcpwm_timer_handle_t s_timer;
|
|
static mcpwm_oper_handle_t s_oper[2];
|
|
static mcpwm_cmpr_handle_t s_cmpr[4]; /* [0]=A+ [1]=A- [2]=B+ [3]=B- */
|
|
static mcpwm_gen_handle_t s_gen[4];
|
|
static esp_timer_handle_t s_openloop_timer;
|
|
|
|
static uint32_t s_pwm_period_ticks = STEPPER_PWM_RESOL_HZ / STEPPER_PWM_FREQ_HZ;
|
|
static bool s_running = false;
|
|
static bool s_output_enabled = false;
|
|
static bool s_openloop_running = false;
|
|
static uint8_t s_openloop_step_idx = 0;
|
|
static stepper_motor_direction_t s_direction = STEPPER_DIR_FORWARD;
|
|
static const char *TAG = "stepper_motor";
|
|
|
|
static const uint16_t s_openloop_phase_table[4][4] = {
|
|
{ STEPPER_STARTUP_DUTY_RAW, 0, STEPPER_STARTUP_DUTY_RAW, 0 },
|
|
{ 0, STEPPER_STARTUP_DUTY_RAW, STEPPER_STARTUP_DUTY_RAW, 0 },
|
|
{ 0, STEPPER_STARTUP_DUTY_RAW, 0, STEPPER_STARTUP_DUTY_RAW },
|
|
{ STEPPER_STARTUP_DUTY_RAW, 0, 0, STEPPER_STARTUP_DUTY_RAW },
|
|
};
|
|
|
|
static uint32_t duty_raw_to_ticks(uint16_t duty_raw)
|
|
{
|
|
if (duty_raw > STEPPER_DUTY_MAX) {
|
|
duty_raw = STEPPER_DUTY_MAX;
|
|
}
|
|
return ((uint64_t)duty_raw * s_pwm_period_ticks) / STEPPER_DUTY_MAX;
|
|
// return ((uint64_t)duty_raw * s_pwm_period_ticks);
|
|
// return ((uint64_t)duty_raw );
|
|
}
|
|
|
|
static void apply_openloop_phase(uint8_t step_idx)
|
|
{
|
|
const uint16_t *phase = s_openloop_phase_table[step_idx & 0x03];
|
|
stepper_motor_set_duty_raw(phase[0], phase[1], phase[2], phase[3]);
|
|
}
|
|
|
|
static void stepper_motor_step_once(stepper_motor_direction_t direction)
|
|
{
|
|
if (direction == STEPPER_DIR_FORWARD) {
|
|
s_openloop_step_idx = (uint8_t)((s_openloop_step_idx + 1) & 0x03);
|
|
} else {
|
|
s_openloop_step_idx = (uint8_t)((s_openloop_step_idx + 3) & 0x03);
|
|
}
|
|
apply_openloop_phase(s_openloop_step_idx);
|
|
}
|
|
|
|
static void openloop_timer_cb(void *arg)
|
|
{
|
|
(void)arg;
|
|
|
|
stepper_motor_step_once(s_direction);
|
|
}
|
|
|
|
void stepper_motor_output_enable(void)
|
|
{
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(s_gen[0], -1, true));
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(s_gen[1], -1, true));
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(s_gen[2], -1, true));
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(s_gen[3], -1, true));
|
|
s_output_enabled = true;
|
|
}
|
|
|
|
void stepper_motor_output_disable(void)
|
|
{
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(s_gen[0], 0, true));
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(s_gen[1], 0, true));
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(s_gen[2], 0, true));
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_force_level(s_gen[3], 0, true));
|
|
s_output_enabled = false;
|
|
}
|
|
|
|
bool stepper_motor_output_is_enabled(void)
|
|
{
|
|
return s_output_enabled;
|
|
}
|
|
|
|
stepper_motor_direction_t stepper_motor_get_direction(void)
|
|
{
|
|
return s_direction;
|
|
}
|
|
|
|
void stepper_motor_set_duty_raw(uint16_t a_plus, uint16_t a_minus, uint16_t b_plus, uint16_t b_minus)
|
|
{
|
|
if (!s_running) {
|
|
return;
|
|
}
|
|
|
|
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(s_cmpr[0], duty_raw_to_ticks(a_plus)));
|
|
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(s_cmpr[1], duty_raw_to_ticks(a_minus)));
|
|
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(s_cmpr[2], duty_raw_to_ticks(b_plus)));
|
|
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(s_cmpr[3], duty_raw_to_ticks(b_minus)));
|
|
}
|
|
|
|
void stepper_motor_openloop_start_dir(stepper_motor_direction_t direction)
|
|
{
|
|
if (s_openloop_timer == NULL) {
|
|
esp_timer_create_args_t timer_args = {
|
|
.callback = openloop_timer_cb,
|
|
.arg = NULL,
|
|
.dispatch_method = ESP_TIMER_TASK,
|
|
.name = "step_ol",
|
|
.skip_unhandled_events = true,
|
|
};
|
|
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &s_openloop_timer));
|
|
}
|
|
|
|
if (!s_running) {
|
|
return;
|
|
}
|
|
|
|
s_direction = (direction == STEPPER_DIR_REVERSE) ? STEPPER_DIR_REVERSE : STEPPER_DIR_FORWARD;
|
|
|
|
if (s_openloop_running) {
|
|
ESP_ERROR_CHECK(esp_timer_stop(s_openloop_timer));
|
|
s_openloop_running = false;
|
|
}
|
|
|
|
if (!s_output_enabled) {
|
|
stepper_motor_output_enable();
|
|
}
|
|
|
|
s_openloop_step_idx = 0;
|
|
apply_openloop_phase(s_openloop_step_idx);
|
|
|
|
const uint64_t period_us = 1000000ULL / (uint64_t)(STEPPER_OPENLOOP_STEP_HZ * 4U);
|
|
ESP_ERROR_CHECK(esp_timer_start_periodic(s_openloop_timer, period_us));
|
|
s_openloop_running = true;
|
|
ESP_LOGI(TAG,
|
|
"openloop start: dir=%s duty=%u step_hz=%u",
|
|
s_direction == STEPPER_DIR_FORWARD ? "forward" : "reverse",
|
|
STEPPER_STARTUP_DUTY_RAW,
|
|
STEPPER_OPENLOOP_STEP_HZ);
|
|
}
|
|
|
|
void stepper_motor_openloop_start(void)
|
|
{
|
|
stepper_motor_openloop_start_dir(s_direction);
|
|
}
|
|
|
|
void stepper_motor_forward(void)
|
|
{
|
|
stepper_motor_openloop_start_dir(STEPPER_DIR_FORWARD);
|
|
}
|
|
|
|
void stepper_motor_reverse(void)
|
|
{
|
|
stepper_motor_openloop_start_dir(STEPPER_DIR_REVERSE);
|
|
}
|
|
|
|
void stepper_motor_run_steps(stepper_motor_direction_t direction, uint32_t steps)
|
|
{
|
|
if (!s_running || steps == 0) {
|
|
return;
|
|
}
|
|
|
|
if (s_openloop_timer != NULL && s_openloop_running) {
|
|
ESP_ERROR_CHECK(esp_timer_stop(s_openloop_timer));
|
|
s_openloop_running = false;
|
|
}
|
|
|
|
s_direction = (direction == STEPPER_DIR_REVERSE) ? STEPPER_DIR_REVERSE : STEPPER_DIR_FORWARD;
|
|
|
|
if (!s_output_enabled) {
|
|
stepper_motor_output_enable();
|
|
}
|
|
|
|
for (uint32_t i = 0; i < steps; ++i) {
|
|
stepper_motor_step_once(s_direction);
|
|
vTaskDelay(pdMS_TO_TICKS(1000 / (STEPPER_OPENLOOP_STEP_HZ * 4U)));
|
|
}
|
|
|
|
stepper_motor_stop();
|
|
}
|
|
|
|
void stepper_motor_openloop_stop(void)
|
|
{
|
|
if (s_openloop_timer != NULL && s_openloop_running) {
|
|
ESP_ERROR_CHECK(esp_timer_stop(s_openloop_timer));
|
|
s_openloop_running = false;
|
|
}
|
|
|
|
stepper_motor_set_duty_raw(0, 0, 0, 0);
|
|
stepper_motor_output_disable();
|
|
ESP_LOGI(TAG, "openloop stop");
|
|
}
|
|
|
|
void stepper_motor_stop(void)
|
|
{
|
|
stepper_motor_openloop_stop();
|
|
}
|
|
|
|
void stepper_motor_init(void)
|
|
{
|
|
gpio_config_t gpio_cfg = {
|
|
.pin_bit_mask = (1ULL << STEPPER_PIN_A1) | (1ULL << STEPPER_PIN_A2) |
|
|
(1ULL << STEPPER_PIN_B1) | (1ULL << STEPPER_PIN_B2),
|
|
.mode = GPIO_MODE_OUTPUT,
|
|
.pull_up_en = GPIO_PULLUP_DISABLE,
|
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
.intr_type = GPIO_INTR_DISABLE,
|
|
};
|
|
ESP_ERROR_CHECK(gpio_config(&gpio_cfg));
|
|
gpio_set_level(STEPPER_PIN_A1, 0);
|
|
gpio_set_level(STEPPER_PIN_A2, 0);
|
|
gpio_set_level(STEPPER_PIN_B1, 0);
|
|
gpio_set_level(STEPPER_PIN_B2, 0);
|
|
ESP_LOGI(TAG, "Step1: GPIO done");
|
|
|
|
mcpwm_timer_config_t timer_cfg = {
|
|
.group_id = STEPPER_MCPWM_GROUP,
|
|
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
|
.resolution_hz = STEPPER_PWM_RESOL_HZ,
|
|
.period_ticks = s_pwm_period_ticks,
|
|
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
|
.flags = { .update_period_on_empty = true },
|
|
};
|
|
ESP_ERROR_CHECK(mcpwm_new_timer(&timer_cfg, &s_timer));
|
|
ESP_LOGI(TAG, "Step2: timer created | pwm=%lu Hz | period=%lu",
|
|
(unsigned long)STEPPER_PWM_FREQ_HZ,
|
|
(unsigned long)s_pwm_period_ticks);
|
|
|
|
mcpwm_operator_config_t oper_cfg = { .group_id = STEPPER_MCPWM_GROUP };
|
|
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_cfg, &s_oper[0]));
|
|
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(s_oper[0], s_timer));
|
|
ESP_ERROR_CHECK(mcpwm_new_operator(&oper_cfg, &s_oper[1]));
|
|
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(s_oper[1], s_timer));
|
|
ESP_LOGI(TAG, "Step3: operators connected");
|
|
|
|
mcpwm_comparator_config_t cmpr_cfg = { .flags.update_cmp_on_tez = true };
|
|
ESP_ERROR_CHECK(mcpwm_new_comparator(s_oper[0], &cmpr_cfg, &s_cmpr[0]));
|
|
ESP_ERROR_CHECK(mcpwm_new_comparator(s_oper[0], &cmpr_cfg, &s_cmpr[1]));
|
|
ESP_ERROR_CHECK(mcpwm_new_comparator(s_oper[1], &cmpr_cfg, &s_cmpr[2]));
|
|
ESP_ERROR_CHECK(mcpwm_new_comparator(s_oper[1], &cmpr_cfg, &s_cmpr[3]));
|
|
ESP_LOGI(TAG, "Step4: comparators created");
|
|
|
|
mcpwm_generator_config_t gen_cfg = { .gen_gpio_num = STEPPER_PIN_A1 };
|
|
ESP_ERROR_CHECK(mcpwm_new_generator(s_oper[0], &gen_cfg, &s_gen[0]));
|
|
gen_cfg.gen_gpio_num = STEPPER_PIN_A2;
|
|
ESP_ERROR_CHECK(mcpwm_new_generator(s_oper[0], &gen_cfg, &s_gen[1]));
|
|
gen_cfg.gen_gpio_num = STEPPER_PIN_B1;
|
|
ESP_ERROR_CHECK(mcpwm_new_generator(s_oper[1], &gen_cfg, &s_gen[2]));
|
|
gen_cfg.gen_gpio_num = STEPPER_PIN_B2;
|
|
ESP_ERROR_CHECK(mcpwm_new_generator(s_oper[1], &gen_cfg, &s_gen[3]));
|
|
ESP_LOGI(TAG, "Step5: generators created");
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_timer_event(s_gen[i],
|
|
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,
|
|
MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW),//MCPWM_GEN_ACTION_LOW
|
|
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
|
ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(s_gen[i],
|
|
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP,
|
|
s_cmpr[i], MCPWM_GEN_ACTION_HIGH),//
|
|
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
|
}
|
|
ESP_LOGI(TAG, "Step6: pwm actions configured");
|
|
|
|
stepper_motor_output_disable();
|
|
ESP_ERROR_CHECK(mcpwm_timer_enable(s_timer));
|
|
ESP_ERROR_CHECK(mcpwm_timer_start_stop(s_timer, MCPWM_TIMER_START_NO_STOP));
|
|
|
|
s_running = true;
|
|
stepper_motor_set_duty_raw(0, 0, 0, 0);
|
|
|
|
ESP_LOGI(TAG, "MCPWM init done, motor standby on boot");
|
|
}
|