Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MCPWM persists state after cleanup (IDFGH-11895) #12980

Closed
3 tasks done
RemiNV opened this issue Jan 15, 2024 · 2 comments
Closed
3 tasks done

MCPWM persists state after cleanup (IDFGH-11895) #12980

RemiNV opened this issue Jan 15, 2024 · 2 comments
Assignees
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Bug bugs in IDF

Comments

@RemiNV
Copy link

RemiNV commented Jan 15, 2024

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

v5.3-dev-1353-gb3f7e2c8a4

Espressif SoC revision.

ESP32-H2 (revision v0.1)

Operating System used.

Linux

How did you build your project?

VS Code IDE

If you are using Windows, please specify command line type.

None

Development Kit.

ESP32-H2-DevKitM-1

Power Supply used.

USB

What is the expected behavior?

After setting up MCPWM (timer, operator, comparator, generator) as in the mcpwm servo example, then cleaning up each item with mcpwm_del_X, the procedure can be repeated to control another device on a different pin.

What is the actual behavior?

After setting up MCPWM (timer, operator, comparator, generator) as in the mcpwm servo example, then cleaning up each item with mcpwm_del_X, if another set of (timer, operator, comparator, generator) is recreated to control another servo on a different pin, the first servo will also be affected.

Steps to reproduce.

Modify mcpwm_servo_control_example_main.c with the following code. This sets up MCPWM to move a servo on pin 10, waits for a second, and cleans up the (timer, operator, comparator, generator). Then it waits for 5 seconds, and does the same thing for a servo on pin 11.

Expected behavior:

  • First servo moves
  • 6 seconds wait
  • Second servo moves
  • 6 seconds wait
  • First servo moves ...

Actual behavior:

  • First servo moves
  • 6 seconds wait
  • Both servos move
  • 12 seconds wait
  • Both servos move
  • 12 seconds wait ...
/*
 * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/mcpwm_prelude.h"

static const char *TAG = "example";

// Please consult the datasheet of your servo before changing the following parameters
#define SERVO_MIN_PULSEWIDTH_US 400  // Minimum pulse width in microsecond
#define SERVO_MAX_PULSEWIDTH_US 2600  // Maximum pulse width in microsecond
#define SERVO_MIN_DEGREE        -130   // Minimum angle
#define SERVO_MAX_DEGREE        130    // Maximum angle

#define SERVO_TIMEBASE_RESOLUTION_HZ 1000000  // 1MHz, 1us per tick
#define SERVO_TIMEBASE_PERIOD        20000    // 20000 ticks, 20ms

#define GPIO_SERVO_1 10
#define GPIO_SERVO_2 11

static inline uint32_t example_angle_to_compare(int angle)
{
    return (angle - SERVO_MIN_DEGREE) * (SERVO_MAX_PULSEWIDTH_US - SERVO_MIN_PULSEWIDTH_US) / (SERVO_MAX_DEGREE - SERVO_MIN_DEGREE) + SERVO_MIN_PULSEWIDTH_US;
}

void move_servo_and_cleanup(int init_angle, int gpio)
{
    ESP_LOGI(TAG, "Create timer and operator");
    mcpwm_timer_handle_t timer = NULL;
    mcpwm_timer_config_t timer_config = {
        .group_id = 0,
        .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
        .resolution_hz = SERVO_TIMEBASE_RESOLUTION_HZ,
        .period_ticks = SERVO_TIMEBASE_PERIOD,
        .count_mode = MCPWM_TIMER_COUNT_MODE_UP,
    };
    ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config, &timer));

    mcpwm_oper_handle_t oper = NULL;
    mcpwm_operator_config_t operator_config = {
        .group_id = 0, // operator must be in the same group to the timer
    };
    ESP_ERROR_CHECK(mcpwm_new_operator(&operator_config, &oper));

    ESP_LOGI(TAG, "Connect timer and operator");
    ESP_ERROR_CHECK(mcpwm_operator_connect_timer(oper, timer));

    ESP_LOGI(TAG, "Create comparator and generator from the operator");
    mcpwm_cmpr_handle_t comparator = NULL;
    mcpwm_comparator_config_t comparator_config = {
        .flags.update_cmp_on_tez = true,
    };
    ESP_ERROR_CHECK(mcpwm_new_comparator(oper, &comparator_config, &comparator));

    mcpwm_gen_handle_t generator = NULL;
    mcpwm_generator_config_t generator_config = {
        .gen_gpio_num = gpio,
    };
    ESP_ERROR_CHECK(mcpwm_new_generator(oper, &generator_config, &generator));

    // set the initial compare value
    ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparator, example_angle_to_compare(init_angle)));

    ESP_LOGI(TAG, "Set generator action on timer and compare event");
    // go high on counter empty
    ESP_ERROR_CHECK(mcpwm_generator_set_action_on_timer_event(generator,
                    MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH)));
    // go low on compare threshold
    ESP_ERROR_CHECK(mcpwm_generator_set_action_on_compare_event(generator,
                    MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator, MCPWM_GEN_ACTION_LOW)));
 
    ESP_LOGI(TAG, "Enable and start timer");
    ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
    ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));

    vTaskDelay(pdMS_TO_TICKS(1000));

    ESP_ERROR_CHECK(mcpwm_del_generator(generator));
    ESP_ERROR_CHECK(mcpwm_del_comparator(comparator));
    ESP_ERROR_CHECK(mcpwm_del_operator(oper));
    ESP_ERROR_CHECK(mcpwm_timer_disable(timer));
    ESP_ERROR_CHECK(mcpwm_del_timer(timer));
}

void app_main(void)
{
    int angle = SERVO_MIN_DEGREE;
    // Move each servo in sequence
    while (1) {
        move_servo_and_cleanup(angle, GPIO_SERVO_1);
        vTaskDelay(pdMS_TO_TICKS(5000));
        move_servo_and_cleanup(angle, GPIO_SERVO_2);
        angle = -angle;
        vTaskDelay(pdMS_TO_TICKS(5000));
    }
}

Debug Logs.

No response

More Information.

It seems that there is some problem where setting up MCPWM, and cleaning it up with mcpwm_del_X, does not actually fully clean it up and it affects subsequent setups ?

@RemiNV RemiNV added the Type: Bug bugs in IDF label Jan 15, 2024
@espressif-bot espressif-bot added the Status: Opened Issue is new label Jan 15, 2024
@github-actions github-actions bot changed the title MCPWM persists state after cleanup MCPWM persists state after cleanup (IDFGH-11895) Jan 15, 2024
@RemiNV
Copy link
Author

RemiNV commented Jan 15, 2024

I found that calling gpio_reset_pin(gpio) after deleting the timer resolves the issue, but it seems that this should be handled by deleting the generator ? Or at least be documented as a necessary cleanup step. I am also not sure whether that is the only missing cleanup, or if there is other state left.

@suda-morris
Copy link
Collaborator

Hi @RemiNV thanks for reporting. Yes, I also think we need to reset the GPIO in mcpwm_del_generator

@espressif-bot espressif-bot added Status: In Progress Work is in progress Status: Reviewing Issue is being reviewed Status: Done Issue is done internally Resolution: NA Issue resolution is unavailable and removed Status: Opened Issue is new Status: In Progress Work is in progress Status: Reviewing Issue is being reviewed labels Jan 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

3 participants