ESP32S3 LEDC for low frequency

chr_te
Posts: 9
Joined: Thu Apr 11, 2024 10:33 pm

ESP32S3 LEDC for low frequency

Postby chr_te » Thu Aug 29, 2024 12:16 am

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?

lbernstone
Posts: 828
Joined: Mon Jul 22, 2019 3:20 pm

Re: ESP32S3 LEDC for low frequency

Postby lbernstone » 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

chr_te
Posts: 9
Joined: Thu Apr 11, 2024 10:33 pm

Re: ESP32S3 LEDC for low frequency

Postby chr_te » Thu Aug 29, 2024 9:02 am

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?

lbernstone
Posts: 828
Joined: Mon Jul 22, 2019 3:20 pm

Re: ESP32S3 LEDC for low frequency

Postby lbernstone » Thu Aug 29, 2024 7:48 pm

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.

chr_te
Posts: 9
Joined: Thu Apr 11, 2024 10:33 pm

Re: ESP32S3 LEDC for low frequency

Postby chr_te » Thu Aug 29, 2024 11:33 pm

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.

lbernstone
Posts: 828
Joined: Mon Jul 22, 2019 3:20 pm

Re: ESP32S3 LEDC for low frequency

Postby lbernstone » Fri Aug 30, 2024 7:45 am

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

Who is online

Users browsing this forum: Majestic-12 [Bot] and 131 guests