mirror of
https://github.com/espressif/arduino-esp32
synced 2024-09-21 10:28:04 +00:00
feature(ledc): Add output invert option for LEDC pin + minor fixes (#9257)
* feat(ledc): Add output invert option for LEDC pin + minor fixes * docs(ledc): Document LEDC functions in header file * feat(ledc): Replace log2 with __builtin_ctz * fix(ledc): Fixing free_channel for > 8 supported channels * fix(ledc): Apply suggestions from code review Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com> * fix(ledc): Added freq check to ledcChangeFrequency * docs(ledc): Fix ledc documentation formatting * docs(migration): Add new functions to the migration guide * docs(ledc): Fix functions name and parameters --------- Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com> Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
This commit is contained in:
parent
05e2abc58b
commit
c4b55bb9f1
@ -19,6 +19,8 @@
|
||||
#include "esp32-hal-ledc.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp32-hal-periman.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
#ifdef SOC_LEDC_SUPPORT_HS_MODE
|
||||
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1)
|
||||
@ -40,7 +42,7 @@ typedef struct {
|
||||
int used_channels : LEDC_CHANNELS; // Used channels as a bits
|
||||
} ledc_periph_t;
|
||||
|
||||
ledc_periph_t ledc_handle;
|
||||
ledc_periph_t ledc_handle = {0};
|
||||
|
||||
static bool fade_initialized = false;
|
||||
|
||||
@ -58,15 +60,28 @@ static bool ledcDetachBus(void * bus){
|
||||
|
||||
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel)
|
||||
{
|
||||
if (channel >= LEDC_CHANNELS || resolution > LEDC_MAX_BIT_WIDTH)
|
||||
{
|
||||
log_e("Channel %u is not available! (maximum %u) or bit width too big (maximum %u)", channel, LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);
|
||||
if(channel >= LEDC_CHANNELS || ledc_handle.used_channels & (1UL << channel)){
|
||||
log_e("Channel %u is not available (maximum %u) or already used!", channel, LEDC_CHANNELS);
|
||||
return false;
|
||||
}
|
||||
if (freq == 0) {
|
||||
log_e("LEDC pin %u - frequency can't be zero.", pin);
|
||||
return false;
|
||||
}
|
||||
if (resolution == 0 || resolution > LEDC_MAX_BIT_WIDTH){
|
||||
log_e("LEDC pin %u - resolution is zero or it is too big (maximum %u)", pin, LEDC_MAX_BIT_WIDTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
perimanSetBusDeinit(ESP32_BUS_TYPE_LEDC, ledcDetachBus);
|
||||
ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
|
||||
if(bus != NULL && !perimanClearPinBus(pin)){
|
||||
if(bus != NULL){
|
||||
log_e("Pin %u is already attached to LEDC (channel %u, resolution %u)", pin, bus->channel, bus->channel_resolution);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!perimanClearPinBus(pin)){
|
||||
log_e("Pin %u is already attached to another bus and failed to detach", pin);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -119,12 +134,12 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
|
||||
|
||||
bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution)
|
||||
{
|
||||
uint8_t free_channel = ~ledc_handle.used_channels & (ledc_handle.used_channels+1);
|
||||
if (free_channel == 0 || resolution > LEDC_MAX_BIT_WIDTH){
|
||||
log_e("No more LEDC channels available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);
|
||||
int free_channel = ~ledc_handle.used_channels & (ledc_handle.used_channels+1);
|
||||
if (free_channel == 0){
|
||||
log_e("No more LEDC channels available! (maximum is %u channels)", LEDC_CHANNELS);
|
||||
return false;
|
||||
}
|
||||
int channel = log2(free_channel & -free_channel);
|
||||
uint8_t channel = __builtin_ctz(free_channel); // Convert the free_channel bit to channel number
|
||||
|
||||
return ledcAttachChannel(pin, freq, resolution, channel);
|
||||
}
|
||||
@ -239,9 +254,12 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution)
|
||||
{
|
||||
ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
|
||||
if(bus != NULL){
|
||||
|
||||
if(resolution > LEDC_MAX_BIT_WIDTH){
|
||||
log_e("LEDC resolution too big (maximum %u)", LEDC_MAX_BIT_WIDTH);
|
||||
if (freq == 0) {
|
||||
log_e("LEDC pin %u - frequency can't be zero.", pin);
|
||||
return 0;
|
||||
}
|
||||
if (resolution == 0 || resolution > LEDC_MAX_BIT_WIDTH){
|
||||
log_e("LEDC pin %u - resolution is zero or it is too big (maximum %u)", pin, LEDC_MAX_BIT_WIDTH);
|
||||
return 0;
|
||||
}
|
||||
uint8_t group=(bus->channel/8), timer=((bus->channel/2)%4);
|
||||
@ -265,6 +283,21 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ledcOutputInvert(uint8_t pin, bool out_invert)
|
||||
{
|
||||
ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
|
||||
if(bus != NULL){
|
||||
gpio_set_level(pin, out_invert);
|
||||
#ifdef SOC_LEDC_SUPPORT_HS_MODE
|
||||
esp_rom_gpio_connect_out_signal(pin, ((bus->channel/8 == 0) ? LEDC_HS_SIG_OUT0_IDX : LEDC_LS_SIG_OUT0_IDX) + ((bus->channel)%8), out_invert, 0);
|
||||
#else
|
||||
esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + ((bus->channel)%8), out_invert, 0);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static IRAM_ATTR bool ledcFnWrapper(const ledc_cb_param_t *param, void *user_arg)
|
||||
{
|
||||
if (param->event == LEDC_FADE_END_EVT) {
|
||||
|
@ -45,20 +45,150 @@ typedef struct {
|
||||
#endif
|
||||
} ledc_channel_handle_t;
|
||||
|
||||
//channel 0-15 resolution 1-16bits freq limits depend on resolution
|
||||
bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution);
|
||||
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel);
|
||||
bool ledcWrite(uint8_t pin, uint32_t duty);
|
||||
uint32_t ledcWriteTone(uint8_t pin, uint32_t freq);
|
||||
uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave);
|
||||
uint32_t ledcRead(uint8_t pin);
|
||||
uint32_t ledcReadFreq(uint8_t pin);
|
||||
bool ledcDetach(uint8_t pin);
|
||||
uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution);
|
||||
/**
|
||||
* @brief Attach a pin to the LEDC driver, with a given frequency and resolution.
|
||||
* Channel is automatically assigned.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param freq frequency of PWM signal
|
||||
* @param resolution resolution for LEDC pin
|
||||
*
|
||||
* @return true if configuration is successful and pin was successfully attached, false otherwise.
|
||||
*/
|
||||
bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution);
|
||||
|
||||
/**
|
||||
* @brief Attach a pin to the LEDC driver, with a given frequency, resolution and channel.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param freq frequency of PWM signal
|
||||
* @param resolution resolution for LEDC pin
|
||||
* @param channel LEDC channel to attach to
|
||||
*
|
||||
* @return true if configuration is successful and pin was successfully attached, false otherwise.
|
||||
*/
|
||||
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel);
|
||||
|
||||
/**
|
||||
* @brief Set the duty cycle of a given pin.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param duty duty cycle to set
|
||||
*
|
||||
* @return true if duty cycle was successfully set, false otherwise.
|
||||
*/
|
||||
bool ledcWrite(uint8_t pin, uint32_t duty);
|
||||
|
||||
/**
|
||||
* @brief Sets the duty to 50 % PWM tone on selected frequency.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param freq select frequency of pwm signal. If frequency is 0, duty will be set to 0.
|
||||
*
|
||||
* @return frequency if tone was successfully set.
|
||||
* If ``0`` is returned, error occurs and LEDC pin was not configured.
|
||||
*/
|
||||
uint32_t ledcWriteTone(uint8_t pin, uint32_t freq);
|
||||
|
||||
/**
|
||||
* @brief Sets the LEDC pin to specific note.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param note select note to be set (NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, NOTE_A, NOTE_Bb, NOTE_B).
|
||||
* @param octave select octave for note.
|
||||
*
|
||||
* @return frequency if note was successfully set.
|
||||
* If ``0`` is returned, error occurs and LEDC pin was not configured.
|
||||
*/
|
||||
uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave);
|
||||
|
||||
/**
|
||||
* @brief Read the duty cycle of a given LEDC pin.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
*
|
||||
* @return duty cycle of selected LEDC pin.
|
||||
*/
|
||||
uint32_t ledcRead(uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief Read the frequency of a given LEDC pin.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
*
|
||||
* @return frequency of selected LEDC pin.
|
||||
*/
|
||||
uint32_t ledcReadFreq(uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief Detach a pin from the LEDC driver.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
*
|
||||
* @return true if pin was successfully detached, false otherwise.
|
||||
*/
|
||||
bool ledcDetach(uint8_t pin);
|
||||
|
||||
/**
|
||||
* @brief Change the frequency and resolution of a given LEDC pin.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param freq frequency of PWM signal
|
||||
* @param resolution resolution for LEDC pin
|
||||
*
|
||||
* @return frequency configured for the LEDC channel.
|
||||
* If ``0`` is returned, error occurs and LEDC pin was not configured.
|
||||
*/
|
||||
uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution);
|
||||
|
||||
/**
|
||||
* @brief Sets inverting of the output signal for a given LEDC pin.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param out_invert select, if output should be inverted (true = inverting output).
|
||||
*
|
||||
* @return true if output inverting was successfully set, false otherwise.
|
||||
*/
|
||||
bool ledcOutputInvert(uint8_t pin, bool out_invert);
|
||||
|
||||
//Fade functions
|
||||
/**
|
||||
* @brief Setup and start a fade on a given LEDC pin.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param start_duty initial duty cycle of the fade
|
||||
* @param target_duty target duty cycle of the fade
|
||||
* @param max_fade_time_ms maximum fade time in milliseconds
|
||||
*
|
||||
* @return true if fade was successfully set and started, false otherwise.
|
||||
*/
|
||||
bool ledcFade(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms);
|
||||
|
||||
/**
|
||||
* @brief Setup and start a fade on a given LEDC pin with a callback function.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param start_duty initial duty cycle of the fade
|
||||
* @param target_duty target duty cycle of the fade
|
||||
* @param max_fade_time_ms maximum fade time in milliseconds
|
||||
* @param userFunc callback function to be called after fade is finished
|
||||
*
|
||||
* @return true if fade was successfully set and started, false otherwise.
|
||||
*/
|
||||
bool ledcFadeWithInterrupt(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void));
|
||||
|
||||
/**
|
||||
* @brief Setup and start a fade on a given LEDC pin with a callback function and argument.
|
||||
*
|
||||
* @param pin GPIO pin
|
||||
* @param start_duty initial duty cycle of the fade
|
||||
* @param target_duty target duty cycle of the fade
|
||||
* @param max_fade_time_ms maximum fade time in milliseconds
|
||||
* @param userFunc callback function to be called after fade is finished
|
||||
* @param arg argument to be passed to the callback function
|
||||
*
|
||||
* @return true if fade was successfully set and started, false otherwise.
|
||||
*/
|
||||
bool ledcFadeWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void*), void * arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -53,14 +53,16 @@ int8_t gpioNumberToDigitalPin(int8_t gpioNumber);
|
||||
#define i2cSlaveInit(num, sda, scl, slaveID, frequency, rx_len, tx_len) i2cSlaveInit(num, digitalPinToGPIONumber(sda), digitalPinToGPIONumber(scl), slaveID, frequency, rx_len, tx_len)
|
||||
|
||||
// cores/esp32/esp32-hal-ledc.h
|
||||
#define ledcAttach(pin, freq, resolution) ledcAttach(digitalPinToGPIONumber(pin), freq, resolution)
|
||||
#define ledcWrite(pin, duty) ledcWrite(digitalPinToGPIONumber(pin), duty)
|
||||
#define ledcWriteTone(pin, freq) ledcWriteTone(digitalPinToGPIONumber(pin), freq)
|
||||
#define ledcWriteNote(pin, note, octave) ledcWriteNote(digitalPinToGPIONumber(pin), note, octave)
|
||||
#define ledcRead(pin) ledcRead(digitalPinToGPIONumber(pin))
|
||||
#define ledcReadFreq(pin) ledcReadFreq(digitalPinToGPIONumber(pin))
|
||||
#define ledcDetach(pin) ledcDetach(digitalPinToGPIONumber(pin))
|
||||
#define ledcChangeFrequency(pin, freq, resolution) ledcChangeFrequency(digitalPinToGPIONumber(pin), freq, resolution)
|
||||
#define ledcAttach(pin, freq, resolution) ledcAttach(digitalPinToGPIONumber(pin), freq, resolution)
|
||||
#define ledcAttachChannel(pin, freq, resolution, channel) ledcAttachChannel(digitalPinToGPIONumber(pin), freq, resolution, channel)
|
||||
#define ledcWrite(pin, duty) ledcWrite(digitalPinToGPIONumber(pin), duty)
|
||||
#define ledcWriteTone(pin, freq) ledcWriteTone(digitalPinToGPIONumber(pin), freq)
|
||||
#define ledcWriteNote(pin, note, octave) ledcWriteNote(digitalPinToGPIONumber(pin), note, octave)
|
||||
#define ledcRead(pin) ledcRead(digitalPinToGPIONumber(pin))
|
||||
#define ledcReadFreq(pin) ledcReadFreq(digitalPinToGPIONumber(pin))
|
||||
#define ledcDetach(pin) ledcDetach(digitalPinToGPIONumber(pin))
|
||||
#define ledcChangeFrequency(pin, freq, resolution) ledcChangeFrequency(digitalPinToGPIONumber(pin), freq, resolution)
|
||||
#define ledcOutputInvert(pin, out_invert) ledcOutputInvert(digitalPinToGPIONumber(pin), out_invert)
|
||||
|
||||
#define ledcFade(pin, start_duty, target_duty, max_fade_time_ms) ledcFade(digitalPinToGPIONumber(pin), start_duty, target_duty, max_fade_time_ms)
|
||||
#define ledcFadeWithInterrupt(pin, start_duty, target_duty, max_fade_time_ms, userFunc) ledcFadeWithInterrupt(digitalPinToGPIONumber(pin), start_duty, target_duty, max_fade_time_ms, userFunc)
|
||||
|
@ -26,8 +26,7 @@ Arduino-ESP32 LEDC API
|
||||
ledcAttach
|
||||
**********
|
||||
|
||||
This function is used to setup LEDC pin with given frequency and resolution.
|
||||
LEDC channel will be selected automatically.
|
||||
This function is used to setup LEDC pin with given frequency and resolution. LEDC channel will be selected automatically.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
@ -35,10 +34,10 @@ LEDC channel will be selected automatically.
|
||||
|
||||
* ``pin`` select LEDC pin.
|
||||
* ``freq`` select frequency of pwm.
|
||||
* ``resolution`` select resolution for LEDC channel.
|
||||
|
||||
* ``resolution`` select resolution for LEDC channel.
|
||||
|
||||
* range is 1-14 bits (1-20 bits for ESP32).
|
||||
|
||||
|
||||
This function will return ``true`` if configuration is successful.
|
||||
If ``false`` is returned, error occurs and LEDC channel was not configured.
|
||||
|
||||
@ -49,15 +48,16 @@ This function is used to setup LEDC pin with given frequency, resolution and cha
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel);
|
||||
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, int8_t channel);
|
||||
|
||||
* ``pin`` select LEDC pin.
|
||||
* ``freq`` select frequency of pwm.
|
||||
* ``resolution`` select resolution for LEDC channel.
|
||||
* ``channel`` select LEDC channel.
|
||||
|
||||
* ``resolution`` select resolution for LEDC channel.
|
||||
|
||||
* range is 1-14 bits (1-20 bits for ESP32).
|
||||
|
||||
|
||||
* ``channel`` select LEDC channel.
|
||||
|
||||
This function will return ``true`` if configuration is successful.
|
||||
If ``false`` is returned, error occurs and LEDC channel was not configured.
|
||||
|
||||
@ -171,6 +171,21 @@ This function is used to set frequency for the LEDC pin.
|
||||
This function will return ``frequency`` configured for the LEDC channel.
|
||||
If ``0`` is returned, error occurs and the LEDC channel frequency was not set.
|
||||
|
||||
ledcOutputInvert
|
||||
****************
|
||||
|
||||
This function is used to set inverting output for the LEDC pin.
|
||||
|
||||
.. code-block:: arduino
|
||||
|
||||
bool ledcOutputInvert(uint8_t pin, bool out_invert);
|
||||
|
||||
* ``pin`` select LEDC pin.
|
||||
* ``out_invert`` select, if output should be inverted (true = inverting output).
|
||||
|
||||
This function returns ``true`` if setting inverting output was successful.
|
||||
If ``false`` is returned, an error occurred and the inverting output was not set.
|
||||
|
||||
ledcFade
|
||||
********
|
||||
|
||||
|
@ -63,8 +63,10 @@ New APIs
|
||||
********
|
||||
|
||||
* ``ledcAttach`` used to set up the LEDC pin (merged ``ledcSetup`` and ``ledcAttachPin`` functions).
|
||||
* ``timerGetFrequency`` used to get the actual frequency of the timer.
|
||||
* ``timerAttachInterruptArg`` used to attach the interrupt to a timer using arguments.
|
||||
* ``ledcOutputInvert`` used to attach the interrupt to a timer using arguments.
|
||||
* ``ledcFade`` used to set up and start a fade on a given LEDC pin.
|
||||
* ``ledcFadeWithInterrupt`` used to set up and start a fade on a given LEDC pin with an interrupt.
|
||||
* ``ledcFadeWithInterruptArg`` used to set up and start a fade on a given LEDC pin with an interrupt using arguments.
|
||||
|
||||
Changes in APIs
|
||||
***************
|
||||
|
@ -33,7 +33,7 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
while(!Serial) delay(10);
|
||||
|
||||
// Setup timer and attach timer to a led pins
|
||||
// Setup timer with given frequency, resolution and attach it to a led pin with auto-selected channel
|
||||
ledcAttach(LED_PIN, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT);
|
||||
|
||||
// Setup and start fade on led (duty from 0 to 4095)
|
||||
|
@ -26,7 +26,7 @@ void setup()
|
||||
delay(10);
|
||||
|
||||
// Initialize pins as LEDC channels
|
||||
// resolution 1-16 bits, freq limits depend on resolution
|
||||
// resolution 1-16 bits, freq limits depend on resolution, channel is automatically selected
|
||||
ledcAttach(ledR, 12000, 8); // 12 kHz PWM, 8-bit resolution
|
||||
ledcAttach(ledG, 12000, 8);
|
||||
ledcAttach(ledB, 12000, 8);
|
||||
|
Loading…
Reference in New Issue
Block a user