callbackmicrocontrolleresp32arduino-esp32isr

getting "undefined reference to ledc_cb_register" error


I'm trying to use a callback function with the led controller of esp32, however I'm unable to compile the code. I'm not sure if something is missing or the code has errors, as I have a limited understanding of pointers or coding in general.

I'm using the Arduino framework, however when I hover over the ledc_cb_register text, VSCode will popup some more details/definition of this function, so I would expect that it does see the reference to it.

relevant esp32 documentation: docs.espressif.com

I'm trying to copy the following example, but make it a bit simpler (using only one channel): github It seems this example can be compiled on my side too, but this uses espidf framework.

trying the following code (many lines are not shown here for simplicity)

static bool cb_ledc_fade_end_event(const ledc_cb_param_t *param, void *user_arg)
{
portBASE_TYPE taskAwoken = pdFALSE;

if (param->event == LEDC_FADE_END_EVT) {
    isFading = false;
}

return (taskAwoken == pdTRUE);
}

[...]

void setup() {    
ledc_timer_config_t ledc_timer = {
    .speed_mode = LEDC_HIGH_SPEED_MODE,       // timer mode
    .duty_resolution = LEDC_TIMER_13_BIT,     // resolution of PWM duty
    .timer_num = LEDC_TIMER_0,                // timer index
    .freq_hz = LED_frequency,                 // frequency of PWM signal
    .clk_cfg = LEDC_AUTO_CLK,                 // Auto select the source clock
};
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

ledc_channel_config_t ledc_channel = {
          .gpio_num   = LED_PIN,
          .speed_mode = LEDC_HIGH_SPEED_MODE,
          .channel    = LEDC_CHANNEL_0,
          .timer_sel  = LEDC_TIMER_0,
          .duty       = 4000,
          .hpoint     = 0,
          //.flags.output_invert = 0
      };

ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));

ledc_fade_func_install(0);

ledc_cbs_t callbacks = {
    .fade_cb = cb_ledc_fade_end_event
};


ledc_cb_register(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, &callbacks, 0);

and getting the following error message:

[..]/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\esp32dev\src\main.cpp.o:(.literal._Z5setupv+0x78): undefined reference to 'ledc_cb_register(ledc_mode_t, ledc_channel_t, ledc_cbs_t*, void*)'
[..]/.platformio/packages/toolchain-xtensa-esp32@8.4.0+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\esp32dev\src\main.cpp.o: in function 'setup()':
[..]\PlatformIO\Projects\asdf/src/main.cpp:272: undefined reference to 'ledc_cb_register(ledc_mode_t, ledc_channel_t, ledc_cbs_t*, void*)'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\esp32dev\firmware.elf] Error 1

Solution

  • According to the docs, it seems to be a feature that was added in v4.4.4 but the latest Arduino core (2.0.6) is build on v4.4.3.

    If you are not on the latest Arduino core, try updating that first and see if it works. If not, then you just have to wait until the Arduino core is updated to use ESP IDF v4.4.4.

    Of course, you can use ledc_isr_register(...) to register an ISR handler for the interrupt.

    Best of luck!

    Update: I realized that the problem (at least on my side when testing it) was that there is an error in the ledc.h file, where they forgot to add ledc_cb_register in an extern "C" block.

    I manually patched it by moving the

    #ifdef __cplusplus
    }
    #endif
    

    part, which was located after the ledc_set_fade_step_and_start function, below ledc_cb_register instead.

    So, the end of my ledc.h file looks like this now:

    ...
    esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num, ledc_fade_mode_t fade_mode);
    
    
    /**
     * @brief LEDC callback registration function
     * ...
     */
    esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg);
    #ifdef __cplusplus
    }
    #endif