Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32C3: set_duty_hw() on ledc::Channel doesn't work #285

Closed
IsaacDynamo opened this issue Dec 4, 2022 · 2 comments · Fixed by #294
Closed

ESP32C3: set_duty_hw() on ledc::Channel doesn't work #285

IsaacDynamo opened this issue Dec 4, 2022 · 2 comments · Fixed by #294
Labels
bug Something isn't working

Comments

@IsaacDynamo
Copy link
Contributor

After creation and configuration of a ledc::Channel, as done in the example, the duty-cycle is not be updated via set_duty() or set_duty_hw().

This is because modification of some register in the LEDC peripheral, are buffered and are only applied when LEDC_PARA_UP_CHn is set.

The HAL contains a macro that does this, update_channel!(), but it is currently not public.
Instead of making it public it could also called from within set_duty() and set_duty_hw(). I think this would a bit more user friendly, and less surprising.

But after setting LEDC_PARA_UP_CHn manually, the duty-cycle still didn't update. By referencing the esp-idf source code and reconstructing their register access, I found that setting the LEDC_DUTY_START_CHn is also required. Although this is as far as I could see in the technical reference manual, not mentioned to be needed for normal PWM mode. LEDC_DUTY_START_CHn is mentioned for the more advanced fading options. My guess is that the hardware implement regular PWM just as fading with step size of zero. An therefor still needs the LEDC_DUTY_START_CHn trigger to start the "fading" action, which updates the duty-cycle.

So currently the following extra steps need to be done to updated the duty-cycle:

channel0.set_duty(80);
let raw_ledc = unsafe { &*hal::pac::LEDC::ptr() };
raw_ledc.ch0_conf1.modify(|_, w| w.duty_start().set_bit());
raw_ledc.ch0_conf0.modify(|_, w| w.para_up().set_bit());

I can work on a PR that fixes the issue for the ESP32-C3 but I don't have the hardware to test the other ESP32 variants. Let me known if/how I can help.

Here are some other usability improvements suggestions for the LEDC:

  • Allow set_duty(0) instead of returning Error::Duty. When precision is required set_duty_hw() should be used instead IMHO.
  • The addition of a trait without generic type parameter for the channels, so something like this becomes easier:
impl<'a, R, G, B> Rgb<'a, R, G, B>
where
    R: AnyChannel,
    G: AnyChannel,
    B: AnyChannel
{
    pub fn new(r: &'a R, g: &'a G, b: &'a B) -> Self {
        Self { r, g, b }
    }
}

The embedded_hal::PwmPin trait might be a good option as well.

@jessebraham jessebraham added the bug Something isn't working label Dec 5, 2022
@bjoernQ
Copy link
Contributor

bjoernQ commented Dec 6, 2022

Great find! For sure a PR would be very welcome. We also have plans to rewrite this driver since it's currently not really compile time safe - just didn't get to it

Also implementing embedded_hal::PwmPin is a great suggestion

No problem if you can't verify it on other chips than ESP32-C3 - we can (and will) test it on all supported chips. Would be nice if it at least compiles for all targets

@IsaacDynamo
Copy link
Contributor Author

The embedded_hal::PwmPin documentation that I found was apparently outdated, and currently there is no standardized trait. See embedded-hal #357.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

3 participants