LEDC Output Value - Register Access

lm_mrsh
Posts: 1
Joined: Mon Dec 02, 2019 11:14 am

LEDC Output Value - Register Access

Postby lm_mrsh » Mon Dec 02, 2019 11:54 am

Hi,

In my project I need to be able to read the current output state of a PWM pin (configured using LEDC). I've looked through the datasheet and can't seem to find a register which holds this value.

I'd like to avoid a digitalRead as I'm running a time critical loop, and want this to be programmatically as efficient as possible. I've also had very mixed results with using a hardware interrupt, which triggers spuriously when the PWM signal is at 0 V. As such, directly accessing the value within the registers of the device is preferable to looping the signal back round to an input.

Does anybody know if this is possible?

Thanks in advance.

michalk
Posts: 20
Joined: Wed Mar 24, 2021 7:09 pm

Re: LEDC Output Value - Register Access

Postby michalk » Tue Jul 27, 2021 3:51 pm

Any luck with this? I need to do the exact same thing in order to sample a current reading when the drive line is asserted.

Maxzillian
Posts: 8
Joined: Fri Apr 01, 2022 3:06 pm

Re: LEDC Output Value - Register Access

Postby Maxzillian » Thu Nov 02, 2023 10:02 pm

Pretty late to this party, but I found a solution. After you make your call to ledc_channel_config() you need to set the GPIO direction as input/output. Unfortunately setting the direction will break the IOMUX mapping for the pin so you must then restore the mapping using esp_rom_gpio_connect_out_signal(). With the GPIO now configured as an input/output you can monitor its state using gpio_get_level() or by directly monitoring the input register (GPIO_IN_REG).

So the pseudo code looks like this:

Code: Select all

#include <driver/gpio.h>
#include <driver/ledc.h>
#include "soc/ledc_periph.h"
#include "esp_rom_gpio.h"

// Prepare and then apply the LEDC PWM channel configuration
ledc_channel_config_t _ledc_channel_config = {
    .gpio_num          = this->Pin,
    .speed_mode        = this->speedMode,
    .channel           = this->ledc_channel,
    .intr_type         = hal::pwm::dflt_intrType,
    .timer_sel         = this->ledc_timer,
    .duty              = 0, // Set duty to 0%
    .hpoint            = 0,
    {
        .output_invert = 0
    }
};
ESP_ERROR_CHECK(ledc_channel_config(&_ledc_channel_config));

// set to be an input as well to allow for output diagnostics
// this will reset the IOMUX routing to GPIO so it has to be restored to LEDC
gpio_set_direction(this->Pin, GPIO_MODE_INPUT_OUTPUT); 
esp_rom_gpio_connect_out_signal(
    this->Pin,
    ledc_periph_signal[this->speedMode].sig_out0_idx + this->ledc_channel,
    _ledc_channel_config.flags.output_invert,
    0
);
Maybe there's a better way to remap the LEDC peripheral function to the GPIO pin, but that method worked for me.

edit: It occurred to me that this is the Arduino flavor of the forum. The above example is written for the ESP-IDF, but the concept is all the same.
Last edited by Maxzillian on Mon Nov 06, 2023 9:47 pm, edited 1 time in total.

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

Re: LEDC Output Value - Register Access

Postby lbernstone » Fri Nov 03, 2023 5:25 pm

The timer registers are shown in the technical reference manual. You will need to calculate the frequency from the clock and divider. I assure you it is much easier and faster to store this when you set it, and just reference that value than querying the hardware to read this setting.

Screenshot from 2023-11-03 07-18-39.png
Screenshot from 2023-11-03 07-18-39.png (177.58 KiB) Viewed 2938 times

In v3.0.0, arduino-esp32 will use the peripheral manager (tied to the IDF HAL), so this info can be read directly from the manager. https://docs.espressif.com/projects/ard ... l#ledcread

Maxzillian
Posts: 8
Joined: Fri Apr 01, 2022 3:06 pm

Re: LEDC Output Value - Register Access

Postby Maxzillian » Sat Nov 04, 2023 2:24 pm

I think you're misunderstanding what I'm aiming to do. In my case I have an input configured to measure the output state of a driver being controlled by PWM. By checking if the output is low while I'm commanding it to be high I can detect a driver failure or a short-to-ground.

I could check the counter values and calculate what the pin should be at, but with what I proposed a single register read can tell me right away what the output state should be. Since my output checking code is operating in an ISR I opted for what could be performed the quickest.

Who is online

Users browsing this forum: No registered users and 52 guests