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

LEDC: Add examples/ledc_check.c for check freq and duty (Issue report). (IDFGH-14067) #14882

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions examples/peripherals/ledc/ledc_check/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ledc)
2 changes: 2 additions & 0 deletions examples/peripherals/ledc/ledc_check/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
idf_component_register(SRCS "ledc_check.c"
INCLUDE_DIRS ".")
132 changes: 132 additions & 0 deletions examples/peripherals/ledc/ledc_check/main/ledc_check.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* LEDC (LED Controller) basic checks example

This code is in the Public Domain (or CC0 licensed, at your option.)

Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <math.h>
#include "driver/ledc.h"
#include "esp_err.h"

#include "freertos/FreeRTOS.h"
#include "esp_clk_tree.h"

#define CHECK_SET 0 // 1
#if CHECK_SET != 0
#warning Add to the esp-idf//components//esp_driver_ledc//include//driver//ledc.h
uint32_t ledc_calculate_divisor(uint32_t src_clk_freq, int freq_hz, uint32_t precision);
#endif

#define CHECK_ALL 0 // 1 // Set CHECK_ALL to 1 for test all frequencies from 1Hz to 40MHz
#define FDIV 1 // 2 // 5 // Test not all frequencies, but more frequencies
#define DELAY_ms 500 // 3000

// #undef ESP_ERROR_CHECK
// #define ESP_ERROR_CHECK(err) do {if (err != ESP_OK) {printf("freq=%lu, err=%d, LINE=%d\n", freq, err, __LINE__);} } while (0);

#define LEDC_OUTPUT_IO (26) // Define the output GPIO
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_MODE LEDC_HIGH_SPEED_MODE // LEDC_LOW_SPEED_MODE //
#define LEDC_CHANNEL LEDC_CHANNEL_0

#define LEDC_DUTY ((1UL << timer.duty_resolution) / 2) // 50%
/* Warning:
* For ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32C6, ESP32H2, ESP32P4 targets,
* when LEDC_DUTY_RES selects the maximum duty resolution (i.e. value equal to SOC_LEDC_TIMER_BIT_WIDTH),
* 100% duty cycle is not reachable (duty cannot be set to (2 ** SOC_LEDC_TIMER_BIT_WIDTH)).
*/

#define FREQ_PERCENT (10)
#define DUTY_PERCENT (10)

ledc_timer_config_t timer;
ledc_channel_config_t channel;

static void check(uint32_t freq)
{
printf("freq=%lu \t", freq);

// Set the LEDC peripheral configuration
uint32_t src_clk_freq;
ESP_ERROR_CHECK(esp_clk_tree_src_get_freq_hz(LEDC_USE_APB_CLK, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &src_clk_freq));
// Prepare and then apply the LEDC PWM timer configuration
timer = (ledc_timer_config_t) {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = ledc_find_suitable_duty_resolution(src_clk_freq, freq),
.freq_hz = freq,
.clk_cfg = LEDC_USE_APB_CLK
};
ESP_ERROR_CHECK(ledc_timer_config(&timer));

// Prepare and then apply the LEDC PWM channel configuration
channel = (ledc_channel_config_t) {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_OUTPUT_IO,
.duty = LEDC_DUTY,
.hpoint = 0
};
ESP_ERROR_CHECK(ledc_channel_config(&channel));

#if CHECK_SET
uint32_t divider = ledc_calculate_divisor(src_clk_freq, timer.freq_hz, 0x1 << timer.duty_resolution);
ESP_ERROR_CHECK(ledc_timer_set(timer.speed_mode, timer.timer_num, divider, timer.duty_resolution, timer.clk_cfg));

// Set duty
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
// Update duty to apply the new value
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
#endif

vTaskDelay((2000 / freq) / portTICK_PERIOD_MS);

uint32_t get_freq = ledc_get_freq(LEDC_MODE, LEDC_CHANNEL);
float freq_percent = 100.0 * fabs((float)timer.freq_hz - get_freq) / timer.freq_hz;
uint32_t get_duty = ledc_get_duty(LEDC_MODE, LEDC_CHANNEL);
float duty_percent = 100.0 * fabs((float)channel.duty - get_duty) / channel.duty;

//if ((timer.freq_hz != get_freq) || (channel.duty != get_duty)) {
if ((freq_percent >= FREQ_PERCENT) || (duty_percent >= DUTY_PERCENT)) {
printf("%6.2f%% timer.freq_hz=%lu, get_freq=%lu, \t\t %6.2f%% channel.duty=%lu, get_duty=%lu \t\t timer.duty_resolution=%u\n",
freq_percent, timer.freq_hz, get_freq,
duty_percent, channel.duty, get_duty,
timer.duty_resolution);
} else {
printf("\n");
}
}

void app_main(void)
{
uint32_t freq;
for (freq = 1; freq <= 40000000; freq += 1) {
#if CHECK_ALL != 1
if (freq > 10000000) {
freq += 10000000 / FDIV - 1;
} else if (freq > 1000000) {
freq += 1000000 / FDIV - 1;
} else if (freq > 100000) {
freq += 100000 / FDIV - 1;
} else if (freq > 10000) {
freq += 10000 / FDIV - 1;
} else if (freq > 1000) {
freq += 1000 / FDIV - 1;
} else if (freq > 100) {
freq += 100 / FDIV - 1;
} else if (freq > 10) {
freq += 10 / FDIV - 1;
}
#endif

check(freq);

vTaskDelay(DELAY_ms / portTICK_PERIOD_MS);
}
printf("END.\n");
}
Loading