Page 1 of 1

Spontaneous activation of PWM (LEDC)

Posted: Sun Mar 03, 2024 9:04 am
by GrandfatherPikhto
Question for the experts (has anyone come across this?)
Task: a +3.5V pulse arrives at the processor pin (10-50 us). Based on a pulse arriving at the pin, you need to launch a 100 kHz PWM packet with a length of about 20-100 μs. The problem is that even when the GPIO is turned off (on the input pin), i.e., the PWM trigger function is disabled, spontaneous triggering begins on the LEDC channels with a frequency of approximately 1 time per second.
Two channels are configured for PWM, both at a frequency of 100 kHz. But! Even after the ledc_stop(...) command, the PWM switches on approximately once a second on the corresponding PWM pin. Moreover, when the PWM duty is reset, the controller for some reason “remembers” the previous settings.
In this situation, only the ledc_timer_pause() function helps.. But the problem is that after ledc_timer_resume() (the packet should be quite short), the ledc_timer_stop() call sometimes does not implemented immediately and the PWM package is “smeared”

Code: Select all

[Codebox=c file=Untitled.c]
#include "common.h"

#define LEDC_TIMER              LEDC_TIMER_0
#define LEDC_MODE               LEDC_HIGH_SPEED_MODE // LEDC_HIGH_SPEED_MODE
#define LEDC_GPIO_0             GPIO_NUM_23
#define LEDC_GPIO_1             GPIO_NUM_22
#define LEDC_DUTY_0             0x7E
#define LEDC_DUTY_1             0x7E
#define LEDC_DUTY_RES_0         LEDC_TIMER_8_BIT
#define LEDC_DUTY_RES_1         LEDC_TIMER_8_BIT
#define LEDC_DUTY_FREQ_0        100000
#define LEDC_DUTY_FREQ_1        100000
#define LEDC_CHANNEL_OUTPUT_0   LEDC_CHANNEL_0
#define LEDC_CHANNEL_OUTPUT_1   LEDC_CHANNEL_1
#define LEDC_INVERT_OUTPUT_0    (0)
#define LEDC_INVERT_OUTPUT_1    (0)

static uint32_t s_duty_resolution = 0;

// static uint32_t s_frequency = 100000;
// static ledc_timer_bit_t s_duty_resolution = LEDC_TIMER_9_BIT;
static uint32_t _calc_duty_resolution () {
    uint32_t clk_src_hz = 0;
    ESP_ERROR_CHECK(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)TIMER_SRC_CLK_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_hz)); 
    return ledc_find_suitable_duty_resolution(clk_src_hz, LEDC_DUTY_FREQ_0);
}

static void _config_ledc_timer (void) {
    s_duty_resolution = _calc_duty_resolution ();
    ledc_timer_config_t ledc_timer = {
        .speed_mode       = LEDC_MODE,
        .timer_num        = LEDC_TIMER,
        .duty_resolution  = LEDC_DUTY_RES_0,
        .freq_hz          = LEDC_DUTY_FREQ_0,  // Set output frequency at 5 kHz
        .clk_cfg          = LEDC_AUTO_CLK
    };
    ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
} 

static void _config_ledc_channel (void) {
    // Prepare and then apply the LEDC PWM channel configuration
    ledc_channel_config_t ledc_channel = {
        .speed_mode     = LEDC_MODE,
        .channel        = LEDC_CHANNEL_OUTPUT_0,
        .timer_sel      = LEDC_TIMER,
        .intr_type      = LEDC_INTR_DISABLE,
        .gpio_num       = LEDC_GPIO_0,
        .duty           = 0, // Set duty to 0%
        .hpoint         = 0,
		.flags = {
			.output_invert = LEDC_INVERT_OUTPUT_0,
		},
    };
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
}

void pause_pwm (void) {
    ESP_ERROR_CHECK(ledc_set_duty_and_update(LEDC_MODE, LEDC_CHANNEL_0, 0, 0UL));
    ESP_ERROR_CHECK(ledc_timer_pause(LEDC_MODE, LEDC_TIMER));
}

void resume_pwm (void) {
    ESP_ERROR_CHECK(ledc_timer_resume(LEDC_MODE, LEDC_TIMER));
    ESP_ERROR_CHECK(ledc_set_duty_and_update(LEDC_MODE, LEDC_CHANNEL_0, LEDC_DUTY_0, 0UL));
}

void init_pwm (void) {
    _config_ledc_timer   ();
    _config_ledc_channel ();
    ledc_fade_func_install(ESP_INTR_FLAG_EDGE);
    ESP_ERROR_CHECK(ledc_set_duty_and_update(LEDC_MODE, LEDC_CHANNEL_0, 0, 0UL));
    ESP_ERROR_CHECK(ledc_timer_pause(LEDC_MODE, LEDC_TIMER));
}
[/Codebox]