ESP32想做个typeC充电时呼吸灯的应用,看了开发手册发现带有个LED PWM控制器,可以无需处理器干预实现硬件的PWM脉宽的自由步进,从而实现呼吸灯渐变的效果,主要参考了官方的资料,把调试的过程记录下来
如有异议,欢迎留言指正
LED PWM 控制器主要用于控制 LED,也可产生 PWM 信号用于其他设备的控制。LED_PWM控制器总共有16路通道,分为8路高速通道和8路低速通道,可以产生独立的波形来驱动 RGB LED 设备等。
LED PWM控制器最大可生成40MHz的频率,此时占空比分辨率为1,也就是50%固定脉宽;20Mhz时,占空比分辨率为3
LED PWM 控制器的高速通道和低速通道均支持硬件渐变功能【高低速定时器】,可在无需 CPU 干预的情况下自动改变 PWM 信号的占空比,也可由软件改变 PWM 信号的占空比,实现亮度和颜色渐变。此外,低速通道在 Sleep 模式下仍可运行。
LED_PWM架构:4个高速定时器与4个低速定时器分别对应8个高速通道与8个低速通道
时钟源选择器可以选择两个时钟源,分别是APB_CLK【由CPU_CLK产生】
和REF_TICK【由APB_CLK分频产生】
,下一期会单独讲下ESP32系统时钟树
时钟通过18bit的分配器进行分频,计算公式LEDC_DEV_CLK = A*B/256,A代表高10bit整数部分,B代表低8位小数部分
分配器的输出时钟作为计数器的基准时钟,计数器最大有效位为20bit,计数达到2^ LEDC_HSTIMERx_DUTY_RES – 1时,会产生溢出中断;溢出后计数值回滚到0,这也就决定了PWM通道的频率
低速通道与高速通道有两个区别
从通道图中不难发现,每个通道都有两个比较器,分别为high_level_comparator与low_level_comparator
打开idf目录下的ledc.h,路径esp-idf\components\driver\include\driver
ledc_channel_config_t
主要设置通道、输出GPIO、速度模式、定时器、占空比ledc_timer_config_t
主要设置频率、占空比分辨率、所选的定时器打开idf目录下的test_ledc.c,路径esp-idf\components\driver\test
摘取一段通过指定时间渐变的代码进行讲解,其他代码可以自行展开引用
TEST_CASE("LEDC fade with time(logic analyzer)", "[ledc][test_env=UT_T1_LEDC]")
{
#ifdef CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE
return;
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
const ledc_mode_t test_speed_mode = LEDC_HIGH_SPEED_MODE;
#elif defined CONFIG_IDF_TARGET_ESP32S2
const ledc_mode_t test_speed_mode = LEDC_LOW_SPEED_MODE;
#endif
ledc_channel_config_t ledc_ch_config = {
.gpio_num = PULSE_IO,//gpio
.speed_mode = test_speed_mode,//模式
.channel = LEDC_CHANNEL_0,//通道
.intr_type = LEDC_INTR_DISABLE,//禁用中断
.timer_sel = LEDC_TIMER_0,//time0
.duty = 0,//占空比0
.hpoint = 0,//高电平比较
};
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));//配置通道
ledc_timer_config_t ledc_time_config = {
.speed_mode = test_speed_mode,//模式
.duty_resolution = LEDC_TIMER_13_BIT,//13位分辨率
.timer_num = LEDC_TIMER_0,//定时器0
.freq_hz = 5000,//5khz
.clk_cfg = LEDC_USE_APB_CLK,//时钟源
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));//定时器配置
//initialize fade service
TEST_ESP_OK(ledc_fade_func_install(0));//安装服务
TEST_ESP_OK(ledc_set_fade_with_time(test_speed_mode, LEDC_CHANNEL_0, 4000, 1000));//1s 4000目标占空比渐变
TEST_ESP_OK(ledc_fade_start(test_speed_mode, LEDC_CHANNEL_0, LEDC_FADE_WAIT_DONE));//开始运行
vTaskDelay(1000 / portTICK_RATE_MS);
TEST_ASSERT_EQUAL_INT32(ledc_get_duty(test_speed_mode, LEDC_CHANNEL_0), 4000);//确认当前占空比
TEST_ESP_OK(ledc_set_fade_with_time(test_speed_mode, LEDC_CHANNEL_0, 0, 1000));//1s 占空比0
TEST_ESP_OK(ledc_fade_start(test_speed_mode, LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT));//开始运行
vTaskDelay(1000 / portTICK_RATE_MS);
TEST_ASSERT_EQUAL_INT32(ledc_get_duty(test_speed_mode, LEDC_CHANNEL_0), 0);//确认当前占空比
//deinitial fade service
ledc_fade_func_uninstall();//卸载服务,释放ram
}
PS:总体来说配置相对简单,在一些特定的应用场景下,也可以通过该控制器输出时钟源给外设使用,如camera、RF相关的硬件外设,节省掉电路设计中的晶振的投入