LEDC Fade

AlexESP32
Posts: 65
Joined: Thu Oct 03, 2019 9:41 am

LEDC Fade

Postby AlexESP32 » Sat Aug 01, 2020 2:09 pm

Hello guys.

I struggle with the LEDC API and the fade functionality...

My code:

Code: Select all



#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h" // for xQueue* stuff
#include "driver/ledc.h"
#include "esp_err.h"

#define LEDC_HS_TIMER          LEDC_TIMER_0
#define LEDC_HS_MODE           LEDC_HIGH_SPEED_MODE

#define LEDC_HS_CH0_GPIO       (2)
#define LEDC_HS_CH0_CHANNEL    LEDC_CHANNEL_0
#define LEDC_HS_CH1_GPIO       (5)
#define LEDC_HS_CH1_CHANNEL    LEDC_CHANNEL_1

#define LEDC_TEST_CH_NUM       (2)
#define LEDC_TEST_DUTY         (8000)
#define LEDC_TEST_FADE_TIME    (1000)

#define GPIO_INPUT_IO_0     4
#define GPIO_INPUT_PIN_SEL  (1ULL<<GPIO_INPUT_IO_0)
#define ESP_INTR_FLAG_DEFAULT 0

static xQueueHandle gpio_evt_queue = NULL;

static bool fade_inverted = false;
static xQueueHandle evt_queue = NULL;
// ISR routine for changing fade direction of LEDC demo

int led_fade_stop = false;

static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    int abc = 2;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
    xQueueSendFromISR(evt_queue, &abc, NULL);
}

static void gpio_task_example(void* arg)
{
    uint32_t io_num;
    for(;;) {
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            led_fade_stop = 2;
            printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}

static void IRAM_ATTR toggle_fade_isr( void *dummy ) {
      fade_inverted = !fade_inverted;
  xQueueSendFromISR(evt_queue, &fade_inverted, NULL);
}

void app_main(void)
{
    gpio_config_t io_conf;

    //interrupt of rising edge
    io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
    //bit mask of the pins, use GPIO4/5 here
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //set as input mode    
    io_conf.mode = GPIO_MODE_INPUT;
    //enable pull-up mode
    io_conf.pull_up_en = 1;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    gpio_config(&io_conf);

    //change gpio intrrupt type for one pin
    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);

    //create a queue to handle gpio event from isr
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));

    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);

    //remove isr handler for gpio number.
    gpio_isr_handler_remove(GPIO_INPUT_IO_0);
    //hook isr handler for specific gpio pin again
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);

    int ch;
    evt_queue = xQueueCreate(1, sizeof(uint32_t)); // never more than one event
    ledc_timer_config_t ledc_timer = {
        .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
        .freq_hz = 5000,                      // frequency of PWM signal
        .speed_mode = LEDC_HS_MODE,           // timer mode
        .timer_num = LEDC_HS_TIMER,            // timer index
        .clk_cfg = LEDC_AUTO_CLK,              // Auto select the source clock
    };
    // Set configuration of timer0 for high speed channels
    ledc_timer_config(&ledc_timer);

    ledc_channel_config_t ledc_channel[LEDC_TEST_CH_NUM] = {
        {
            .channel    = LEDC_HS_CH0_CHANNEL,
            .duty       = 0,
            .gpio_num   = LEDC_HS_CH0_GPIO,
            .speed_mode = LEDC_HS_MODE,
            .hpoint     = 0,
            .intr_type  = LEDC_INTR_FADE_END,
            .timer_sel  = LEDC_HS_TIMER
        },
        {
            .channel    = LEDC_HS_CH1_CHANNEL,
            .duty       = 0,
            .gpio_num   = LEDC_HS_CH1_GPIO,
            .speed_mode = LEDC_HS_MODE,
            .hpoint     = 0,
            .intr_type  = LEDC_INTR_FADE_END,
            .timer_sel  = LEDC_HS_TIMER
        },
    };

    // Set LED Controller with previously prepared configuration
    for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
        ledc_channel_config(&ledc_channel[ch]);
    }

    // Initialize fade service.
    ledc_fade_func_install(ESP_INTR_FLAG_SHARED);
    ledc_isr_register(toggle_fade_isr, NULL, ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_SHARED, NULL);
        for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
            ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
                    ledc_channel[ch].channel, LEDC_TEST_DUTY, LEDC_TEST_FADE_TIME);
            ledc_fade_start(ledc_channel[ch].speed_mode,
                    ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
        }

    while (1) {
    int inverted;


    if( xQueueReceive(evt_queue, &inverted, portMAX_DELAY)) {
        if(inverted == 2)
        {
            printf("inverted == 2\n");
              /*for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
            ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
                    ledc_channel[ch].channel, 0 , LEDC_TEST_FADE_TIME);
            ledc_fade_start(ledc_channel[ch].speed_mode,
                    ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);

        
        }*/
            for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
            ledc_stop(ledc_channel[ch].speed_mode, ledc_channel[ch].channel,0);
            ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, 0);
            ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);

        }
        vTaskDelay(10 / portTICK_PERIOD_MS);
                      for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
            ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
                    ledc_channel[ch].channel, inverted == 1? 0 : LEDC_TEST_DUTY, LEDC_TEST_FADE_TIME);
            ledc_fade_start(ledc_channel[ch].speed_mode,
                    ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
        
    }

            break;
        }
            printf("Fade %s GetTickckount: %dms\n", inverted == 1? "out" : "in", xTaskGetTickCount()*1000/configTICK_RATE_HZ );
              for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
            ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
                    ledc_channel[ch].channel, inverted == 1? 0 : LEDC_TEST_DUTY, LEDC_TEST_FADE_TIME);
            ledc_fade_start(ledc_channel[ch].speed_mode,
                    ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
        
    }
     }
        vTaskDelay(1);

    }
}
First in my opinion this is maybe an error or should give some warning:
If I increase the frequency of the timer to 5000Hz the LEDC_TEST_FADE_TIME isn't 1000ms anymore. Same when the frequency is too low (10Hz)...
Maybe you can explain why this causes problems?


Then there are some more questions:

Why is there no fade_stop functionality so I can stop the fading immediately?
Is there any reason? I would like to stop and start the fading at every time...
For example I want to stop fading and after that i want to set the value of the LED with ledc_set_duty & ledc_update_duty.

Thank you ;)

AlexESP32
Posts: 65
Joined: Thu Oct 03, 2019 9:41 am

Re: LEDC Fade

Postby AlexESP32 » Tue Aug 04, 2020 7:54 am

Also I want to know:

Maybe someone can explain me the output of the 4 variants:
1. Channel0 & Channel1 = .intr_type = LEDC_INTR_FADE_END
2. Channel0 & Channel1 = //.intr_type = LEDC_INTR_FADE_END
3. Channel0 .intr_type = LEDC_INTR_FADE_END & Channel1 = //.intr_type = LEDC_INTR_FADE_END
4. Channel1 .intr_type = LEDC_INTR_FADE_END & Channel0 = //.intr_type = LEDC_INTR_FADE_END

The output is at 2. point:

Code: Select all

config timer
config channel
func install
------- 0
fade
isr routine counter:
param = 1

and at point 1. / 3. / 4.

Code: Select all

config timer
config channel
func install
-------isr routine counter:
 0
fade
param = 1
isr routine counter:
param = 2
Why occurs the isr although the fading didn't even start? :)

Thank you ;)

Code: Select all

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/ledc.h"
#include "esp_err.h"

#define LEDC_HS_TIMER          LEDC_TIMER_0
#define LEDC_HS_MODE           LEDC_HIGH_SPEED_MODE

#define LEDC_HS_CH0_GPIO       (2)
#define LEDC_HS_CH0_CHANNEL    LEDC_CHANNEL_0

#define LEDC_HS_CH1_GPIO       (18)
#define LEDC_HS_CH1_CHANNEL    LEDC_CHANNEL_1

#define LEDC_TEST_DUTY         (4000)
#define LEDC_TEST_FADE_TIME    (1000)

QueueHandle_t xQueue = NULL;

ledc_timer_config_t ledc_timer = {
	.duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
	.freq_hz = 1000,                      // frequency of PWM signal
	.speed_mode = LEDC_HS_MODE,           // timer mode
	.timer_num = LEDC_HS_TIMER            // timer index
};

ledc_channel_config_t ledc_channel1 = {
	.channel    = LEDC_HS_CH0_CHANNEL,
	.duty       = 0,
	.gpio_num   = LEDC_HS_CH0_GPIO,
	.speed_mode = LEDC_HS_MODE,
	//.intr_type  = LEDC_INTR_FADE_END,
	.timer_sel  = LEDC_HS_TIMER
};

ledc_channel_config_t ledc_channel2 = {
	.channel    = LEDC_HS_CH1_CHANNEL,
	.duty       = 0,
	.gpio_num   = LEDC_HS_CH1_GPIO,
	.speed_mode = LEDC_HS_MODE,
	//.intr_type  = LEDC_INTR_FADE_END,
	.timer_sel  = LEDC_HS_TIMER
};

void IRAM_ATTR ledc_isr_routine(void *param) {
	static uint32_t counter = 0;
	counter++;
	ets_printf("isr routine counter: \n", counter);
	xQueueSendFromISR(xQueue, &counter, 0);
}


void app_main()
{
	xQueue = xQueueCreate(5, sizeof(uint32_t));
	
    // Set configuration of timer0 for high speed channels
	printf("config timer\n");
    ledc_timer_config(&ledc_timer);

    // Set LED Controller with previously prepared configuration
	printf("config channel\n");
	ledc_channel_config(&ledc_channel1);
	ledc_channel_config(&ledc_channel2);

    // Initialize fade service.
	printf("func install\n");
	// Initialize fade service.
	ledc_fade_func_install(ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_SHARED);
	uint32_t param = 0; 
	// enable ISR routine
	printf("------- %d\n",ledc_isr_register(ledc_isr_routine, NULL, ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_SHARED, NULL));
	
	uint32_t duty = LEDC_TEST_DUTY;
	
    while (1) {
		
		if(param == 0)
		{
		printf("fade\n");
		ledc_set_fade_with_time(ledc_channel1.speed_mode, ledc_channel1.channel, duty, LEDC_TEST_FADE_TIME);
		ledc_fade_start(ledc_channel1.speed_mode, ledc_channel1.channel, LEDC_FADE_NO_WAIT);
		
		ledc_set_fade_with_time(ledc_channel2.speed_mode, ledc_channel2.channel, duty, LEDC_TEST_FADE_TIME);
		ledc_fade_start(ledc_channel2.speed_mode, ledc_channel2.channel, LEDC_FADE_NO_WAIT);			
		}

		xQueueReceive(xQueue, &param, portMAX_DELAY);
		printf("param = %d\n", param);		
	}
}

AlexESP32
Posts: 65
Joined: Thu Oct 03, 2019 9:41 am

Re: LEDC Fade

Postby AlexESP32 » Wed Aug 05, 2020 1:18 pm

Nobody can help me?

AlexESP32
Posts: 65
Joined: Thu Oct 03, 2019 9:41 am

Re: LEDC Fade

Postby AlexESP32 » Tue Aug 18, 2020 8:34 am

The question is still there...

colman
Posts: 37
Joined: Mon May 30, 2016 7:41 am

Re: LEDC Fade

Postby colman » Wed May 04, 2022 2:19 am

I also need to stop the fading immediately, there is no ledc_fade_stop function in idf v4.4.1.

redpanda
Posts: 13
Joined: Thu Feb 04, 2021 8:42 am

Re: LEDC Fade

Postby redpanda » Wed May 04, 2022 8:40 am

Would like to know the proper way to stop the fade once it is started.

glrtheil
Posts: 61
Joined: Tue Dec 07, 2021 2:48 pm

Re: LEDC Fade

Postby glrtheil » Mon May 09, 2022 2:46 pm

Set the LED duty to whatever value you want, and update. The fade will stop.

Code: Select all

// turn LED off
ledc_set_duty(ledc_channel[0].speed_mode, ledc_channel[0].channel, 0);
ledc_update_duty(ledc_channel[0].speed_mode, ledc_channel[0].channel);
Also ensure that your fade_start is done with LEDC_FADE_NO_WAIT so that the fade is asynchronous and can be stopped.

Code: Select all

ledc_fade_start(ledc_channel[0].speed_mode, ledc_channel[0].channel, LEDC_FADE_NO_WAIT);

Who is online

Users browsing this forum: No registered users and 123 guests