Opis:
Kontroler PWM może wygenerować do 16 kanałów. Do każdego z nich można osobno wygenerować sygnał o podanym okresie i wypełnieniu. Układ działa na 80 MHz zegarze APB. Osiem z nich może wykorzystywać 8 MHz oscylator. Każdy z kanałów może być konfigurowalny z 20 bitowego timera z ustawianym zakresem odliczania. Dokładność obliczeń wykonana jest na 16 bitach z 1ms okresem.
Programowanie:
Przedstawiony kod testowałem na dwóch wyprowadzeniach (GPIO19 oraz GPIO16) jednak powinien on działać bez problemu na innych wyprowadzeniach. Spowodowane jest to tym, ze można jego wyprowadzenia jak i kanały PWM bezpośrednio przerzucać pomiędzy pinami.
Program poniżej pozwala na uruchomienie wybranych timerów wraz z wybranym kanałem PWM.
- static void pwmInitial(uint8_t timer, uint8_t channel, uint8_t gpioPinNumber)
- {
- /* Config timer, in else if to have different settings in define */
- if(timer == LEDC_TIMER_0){
- timer_Conf(timer, LEDC_TIMER_12_BIT, 1000, LEDC_HIGH_SPEED_MODE);
- }
- else if(timer == LEDC_TIMER_1){
- timer_Conf(timer, LEDC_TIMER_12_BIT, 1000, LEDC_HIGH_SPEED_MODE);
- }
- else if(timer == LEDC_TIMER_2){
- timer_Conf(timer, LEDC_TIMER_12_BIT, 1000, LEDC_HIGH_SPEED_MODE);
- }
- else if(timer == LEDC_TIMER_3){
- timer_Conf(timer, LEDC_TIMER_12_BIT, 1000, LEDC_HIGH_SPEED_MODE);
- }
- /* Config PWM, in else if functions for set different settings for different channels */
- if(channel == LEDC_CHANNEL_0){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_1){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_2){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_3){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_4){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_5){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_6){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_7){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- }
Funkcja wywołuje pod funkcje statyczne które ustawiają przesłane parametry. Zostały one przedstawione poniżej:
- static void timer_Conf(ledc_timer_t timer, ledc_timer_bit_t bit_num, uint32_t freq, ledc_mode_t speed_mode)
- {
- ledc_timer_config_t timer_conf = {0};
- timer_conf.bit_num = bit_num;
- timer_conf.freq_hz = freq;
- timer_conf.speed_mode = speed_mode;
- timer_conf.timer_num = timer;
- ledc_timer_config(&timer_conf);
- }
- static void pwmChannel_Conf(ledc_channel_t channel, uint32_t duty, uint8_t gpioPinNumber, ledc_intr_type_t intr_type,
- ledc_mode_t speed_mode, ledc_timer_t timer)
- {
- ledc_channel_config_t ledc_conf;
- ledc_conf.channel = channel;
- ledc_conf.duty = duty;
- ledc_conf.gpio_num = (int)gpioPinNumber;
- ledc_conf.intr_type = intr_type;
- ledc_conf.speed_mode = speed_mode;
- ledc_conf.timer_sel = timer;
- ledc_channel_config(&ledc_conf);
- ledc_set_duty(speed_mode, channel, 0);
- ledc_update_duty(speed_mode, channel);
- }
Pierwsza funkcja powyżej odpowiada za konfiguracje timera podanymi parametrami. Najpierw tworzy się strukturę do której dane zostają przypisane po czym zapisuje się ustawienia po przez podanie do funkcji ledc_timer_config informacji o ustawieniach. Podobnie działa funkcja następna czyli pwmChannel_Conf. Odpowiada ona za konfiguracje kanału PWM zadanymi parametrami.
Ustawienie wartosci na konretnym porcie PWM odbywa sie po wywolaniu nastepujacej funkcji:
- void pwmSetValue(uint8_t channel, uint16_t duty)
- {
- ledc_set_duty(LEDC_HIGH_SPEED_MODE, channel, duty);
- ledc_update_duty(LEDC_HIGH_SPEED_MODE, channel);
- }
Ponizej zalaczam plik .c oraz plik .h:
.c:
- /*
- * Calculations:
- * f = (Clock Speed)/(Divisor * precision)
- * Divisor = (Clock Speed)/(f * precision)
- */
- #include "pwm_ctrl.h"
- static void pwmInitial(uint8_t timer, uint8_t channel, uint8_t gpioPinNumber);
- static void timer_Conf(ledc_timer_t timer, ledc_timer_bit_t bit_num, uint32_t freq, ledc_mode_t speed_mode);
- static void pwmChannel_Conf(ledc_channel_t channel, uint32_t duty, uint8_t gpioPinNumber, ledc_intr_type_t intr_type,
- ledc_mode_t speed_mode, ledc_timer_t timer);
- void pwmInit(void)
- {
- pwmInitial(LEDC_TIMER_0, LEDC_CHANNEL_0, 19);
- }
- void pwmSetValue(uint8_t channel, uint16_t duty)
- {
- ledc_set_duty(LEDC_HIGH_SPEED_MODE, channel, duty);
- ledc_update_duty(LEDC_HIGH_SPEED_MODE, channel);
- }
- /* ================= STATIC FUNCTIONS ================= */
- static void pwmInitial(uint8_t timer, uint8_t channel, uint8_t gpioPinNumber)
- {
- /* Config timer, in else if to have different settings in define */
- if(timer == LEDC_TIMER_0){
- timer_Conf(timer, LEDC_TIMER_12_BIT, 1000, LEDC_HIGH_SPEED_MODE);
- }
- else if(timer == LEDC_TIMER_1){
- timer_Conf(timer, LEDC_TIMER_12_BIT, 1000, LEDC_HIGH_SPEED_MODE);
- }
- else if(timer == LEDC_TIMER_2){
- timer_Conf(timer, LEDC_TIMER_12_BIT, 1000, LEDC_HIGH_SPEED_MODE);
- }
- else if(timer == LEDC_TIMER_3){
- timer_Conf(timer, LEDC_TIMER_12_BIT, 1000, LEDC_HIGH_SPEED_MODE);
- }
- /* Config PWM, in else if functions for set different settings for different channels */
- if(channel == LEDC_CHANNEL_0){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_1){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_2){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_3){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_4){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_5){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_6){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- else if(channel == LEDC_CHANNEL_7){
- pwmChannel_Conf(channel, 1024, gpioPinNumber, LEDC_INTR_DISABLE, LEDC_HIGH_SPEED_MODE, timer);
- }
- }
- static void timer_Conf(ledc_timer_t timer, ledc_timer_bit_t bit_num, uint32_t freq, ledc_mode_t speed_mode)
- {
- ledc_timer_config_t timer_conf = {0};
- timer_conf.bit_num = bit_num;
- timer_conf.freq_hz = freq;
- timer_conf.speed_mode = speed_mode;
- timer_conf.timer_num = timer;
- ledc_timer_config(&timer_conf);
- }
- static void pwmChannel_Conf(ledc_channel_t channel, uint32_t duty, uint8_t gpioPinNumber, ledc_intr_type_t intr_type,
- ledc_mode_t speed_mode, ledc_timer_t timer)
- {
- ledc_channel_config_t ledc_conf;
- ledc_conf.channel = channel;
- ledc_conf.duty = duty;
- ledc_conf.gpio_num = (int)gpioPinNumber;
- ledc_conf.intr_type = intr_type;
- ledc_conf.speed_mode = speed_mode;
- ledc_conf.timer_sel = timer;
- ledc_channel_config(&ledc_conf);
- ledc_set_duty(speed_mode, channel, 0);
- ledc_update_duty(speed_mode, channel);
- }
.h:
- #ifndef MAIN_PWM_CTRL_H_
- #define MAIN_PWM_CTRL_H_
- #include <driver/ledc.h>
- #include <esp_err.h>
- #include <esp_event.h>
- #include <esp_event_loop.h>
- #include <esp_log.h>
- #include <esp_system.h>
- void pwmInit(void);
- void pwmSetValue(uint8_t channel, uint16_t duty);
- #endif /* MAIN_PWM_CTRL_H_ */
Wszystkie dodatkowe informacje można przeczytać pod tym linkiem.
Bibliotekę można znaleźć w folderze ESP32 na dysku Google pod tym linkiem.