Page 1 of 1

ESP32S3 LEDC for low frequency

Posted: Thu Aug 29, 2024 12:16 am
by chr_te
Hi everyone,

I would like to e.g. blink an LED utilizing the LEDC peripheral.
When saying blinking an LED, I'm referring to something like 500 ms on, 500 ms off, i.e. 1 second PWM period with 50 % duty cycle.
Using ledcAttach I can't get much below a frequency of 200 Hz.

I am aware that documentation of the Arduino LEDC explicitly says, that it's mainly intended for controlling LED brightness. But, it would simply be so extremely convenient and elegant to have all of that purely managed by hardware. Blinking, on, off, fading purely controlled by LEDC.

Is this possible and I've just missed something, or does LEDC on the Arduino core simply not offer the possibility of ~1 Hz frequencies?

Re: ESP32S3 LEDC for low frequency

Posted: Thu Aug 29, 2024 2:05 am
by lbernstone
It can't go below 1Hz, but there's no reason you can't use it as a blinker
blinker example

Re: ESP32S3 LEDC for low frequency

Posted: Thu Aug 29, 2024 9:02 am
by chr_te
lbernstone wrote:
Thu Aug 29, 2024 2:05 am
It can't go below 1Hz, but there's no reason you can't use it as a blinker
blinker example
Thanks for the answer and I wish it worked, but it doesn't. Also, I'm using the s3, in case that changes anything.

The following program fails:

Code: Select all

#define LED_PIN 6
void setup() {
     ledcAttach(LED_PIN, 1, 12); // 1Hz, 12bit resolution
     ledcWrite(LED_PIN, 2048);
}
void loop() {
    delay(10);
}
This is the Debug output:

Code: Select all

============ Before Setup End ============
[   856][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type LEDC (9) successfully set to 0x42001f38
E (601) ledc: requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=0
[   868][E][esp32-hal-ledc.c:116] ledcAttachChannel(): ledc setup failed!
=========== After Setup Start ============


Changing to freq=256 and resolution=8, with duty 128 works perfectly fine and gets me a dimmed LED as one would expect. Here's the debug output in that case:

Code: Select all

============ Before Setup End ============
[   856][V][esp32-hal-periman.c:235] perimanSetBusDeinit(): Deinit function for type LEDC (9) successfully set to 0x42001f38
[   857][V][esp32-hal-periman.c:160] perimanSetPinBus(): Pin 6 successfully set to type LEDC (9) with bus 0x3fcec54c
[   866][I][esp32-hal-ledc.c:151] ledcAttachChannel(): LEDC attached to pin 6 (channel 0, resolution 8)
=========== After Setup Start ============

Any ideas, anyone?

Re: ESP32S3 LEDC for low frequency

Posted: Thu Aug 29, 2024 7:48 pm
by lbernstone
My laptop decided today was a good day to die, so I can't really test, but there is an example that shows you the available frequencies. 3Hz is the lowest on a S3 at 14 bit.

Re: ESP32S3 LEDC for low frequency

Posted: Thu Aug 29, 2024 11:33 pm
by chr_te
Thank you so much! Don't know how I've missed that example.

I can confirm the 3 Hz for the s3, that's as low as it will go utilizing the Arduino API:

Code: Select all

#include <Arduino.h>
#define LED_PIN 6
void setup() {
    ledcAttachChannel(LED_PIN, 3, 14, 0); // 2 Hz, 14 bit (0-16383)
    ledcWrite(LED_PIN, 8192);
}
void loop() {
}

After playing around, using directly driver/ledc.h I got down to 2 Hz. But, the convenience/simplicity of the Arduino API is lost:

Code: Select all

#include <Arduino.h>
#include "driver/ledc.h"
#include "hal/ledc_types.h"

void setup() {
    ledc_timer_config_t ledc_timer = {
        .speed_mode       = LEDC_LOW_SPEED_MODE,
        .duty_resolution  = LEDC_TIMER_14_BIT,
        .timer_num        = LEDC_TIMER_0,
        .freq_hz          = 2,
        .clk_cfg          = LEDC_AUTO_CLK
        };
    ledc_timer_config(&ledc_timer);

    ledc_channel_config_t ledc_channel = {
        .gpio_num       = 6,
        .speed_mode     = LEDC_LOW_SPEED_MODE,
        .channel        = LEDC_CHANNEL_0,
        .intr_type      = LEDC_INTR_DISABLE,
        .timer_sel      = LEDC_TIMER_0,
        .duty           = 0,
        .hpoint         = 0
    };
    ledc_channel_config(&ledc_channel);
    ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8192);
    ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
}

void loop() {
}
All in all, I'd say that purely hardware blinking a signaling LED on your pcb can be implemented that way. To the human eye, I'd say the 2 Hz would look calmer/better for that purpose.

I also want to note, that the Arduino LEDC is lacking a function to stop an ongoing fade. If you want to change e.g. the frequency while a fade is going on, you'll end up with blocked code until the fade has completely finished. This can be mitigated by using the IDF function ledc_fade_stop. For that you need to know the channel you're using and the ledc speed mode. On the s3 the speed mode always is LEDC_LOW_SPEED_MODE.

Re: ESP32S3 LEDC for low frequency

Posted: Fri Aug 30, 2024 7:45 am
by lbernstone
If your goal is just to offload the blink to hardware, the RMT driver can do that for you.

https://github.com/espressif/arduino-es ... inkRGB.ino
https://github.com/espressif/arduino-es ... -rgb-led.c