• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *    http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <securec.h>
17 
18 #include "iot_errno.h"
19 #include "iot_pwm.h"
20 
21 #include "driver/ledc.h"
22 #include "esp_err.h"
23 
24 #define CLK_40M (40000000)
25 #define DUTY_MIN (0)
26 #define DUTY_MAX (100)
27 #define DUTY_RES_MIN (128)
28 #define LEDC_OUTPUT_IO (5)
29 #define LEDC_TIMER LEDC_TIMER_0
30 
31 #define NUM2 2
32 #define DUTY_RESOLUTION_MAX (NUM2 << ((LEDC_TIMER_BIT_MAX) - 1))
33 #if SOC_LEDC_SUPPORT_HS_MODE
34 #define LEDC_MODE LEDC_HIGH_SPEED_MODE
35 #else
36 #define LEDC_MODE LEDC_LOW_SPEED_MODE
37 #endif
38 
39 typedef enum {
40     PWM_UNINIT = 0,
41     PWM_INIT = 1
42 } pwm_status_e;
43 
44 typedef struct {
45     pwm_status_e pwm_state;
46     ledc_channel_config_t pwm_attr;
47 } pwm_driver_data_t;
48 
49 static pwm_driver_data_t g_pwm[LEDC_CHANNEL_MAX] = {0};
50 
PwmDutyCalc(uint8_t TimerBit,uint32_t duty)51 static unsigned int PwmDutyCalc(uint8_t TimerBit, uint32_t duty)
52 {
53     return ((((NUM2 >> TimerBit) - 1) * duty) / DUTY_MAX);
54 }
55 
InitPwm(ledc_channel_t num,ledc_channel_config_t * pwm_conf)56 static void InitPwm(ledc_channel_t num, ledc_channel_config_t *pwm_conf)
57 {
58     assert(num < LEDC_CHANNEL_MAX);
59     assert(pwm_conf != NULL);
60     pwm_conf->speed_mode = LEDC_MODE;
61     pwm_conf->channel = num;
62     pwm_conf->timer_sel = LEDC_TIMER;
63     pwm_conf->intr_type = LEDC_INTR_DISABLE;
64     pwm_conf->gpio_num = LEDC_OUTPUT_IO;
65     pwm_conf->duty = 0;
66     pwm_conf->hpoint = 0;
67 }
68 
ESPErrToHoErr(esp_err_t ret)69 static uint32_t ESPErrToHoErr(esp_err_t ret)
70 {
71     if (ret == ESP_OK) {
72         return IOT_SUCCESS;
73     } else {
74         return IOT_FAILURE;
75     }
76 }
77 
IoTPwmInit(unsigned int port)78 unsigned int IoTPwmInit(unsigned int port)
79 {
80     if (port >= LEDC_CHANNEL_MAX) {
81         return IOT_FAILURE;
82     }
83 
84     pwm_driver_data_t *pwm = &g_pwm[port];
85     if (pwm->pwm_state == PWM_INIT) {
86         return IOT_FAILURE;
87     }
88 
89     pwm->pwm_state = PWM_INIT;
90     InitPwm((ledc_channel_t)port, &(pwm->pwm_attr));
91     return IOT_SUCCESS;
92 }
93 
IoTPwmDeinit(unsigned int port)94 unsigned int IoTPwmDeinit(unsigned int port)
95 {
96     if (port >= LEDC_CHANNEL_MAX) {
97         return IOT_FAILURE;
98     }
99 
100     pwm_driver_data_t *pwm = &g_pwm[port];
101     if (pwm->pwm_state == PWM_UNINIT) {
102         return IOT_FAILURE;
103     }
104 
105     memset_s(pwm, sizeof(pwm_driver_data_t), 0, sizeof(pwm_driver_data_t));
106     return IOT_SUCCESS;
107 }
108 
IoTPwmStart(unsigned int port,unsigned short duty,unsigned int freq)109 unsigned int IoTPwmStart(unsigned int port, unsigned short duty, unsigned int freq)
110 {
111     if (port >= LEDC_CHANNEL_MAX) {
112         return IOT_FAILURE;
113     }
114 
115     pwm_driver_data_t *pwm = &g_pwm[port];
116     if (pwm->pwm_state == PWM_UNINIT) {
117         return IOT_FAILURE;
118     }
119 
120     if ((freq == 0) || (duty >= DUTY_MAX) || (duty == DUTY_MIN)) {
121         return IOT_FAILURE;
122     }
123 
124     uint32_t DutyResolution = CLK_40M / freq;
125     if (DutyResolution < DUTY_RES_MIN || DutyResolution > DUTY_RESOLUTION_MAX) {
126         return IOT_FAILURE;
127     }
128 
129     uint8_t TimerBit = 0;
130     while (DutyResolution) {
131         DutyResolution = DutyResolution >> 1;
132         TimerBit++;
133     }
134 
135     ledc_timer_config_t ledc_timer = {
136         .speed_mode = LEDC_MODE,
137         .timer_num = LEDC_TIMER,
138         .duty_resolution = (TimerBit - 1),
139         .freq_hz = freq,
140         .clk_cfg = LEDC_AUTO_CLK};
141 
142     esp_err_t ret = ledc_timer_config(&ledc_timer);
143     if (ret != ESP_OK) {
144         return IOT_FAILURE;
145     }
146 
147     ret = ledc_channel_config(&(pwm->pwm_attr));
148     if (ret != ESP_OK) {
149         return IOT_FAILURE;
150     }
151 
152     uint32_t PwmDuty = PwmDutyCalc(TimerBit, duty);
153     ret = ledc_set_duty(LEDC_MODE, port, PwmDuty);
154     if (ret != ESP_OK) {
155         return IOT_FAILURE;
156     }
157 
158     ret = ledc_update_duty(LEDC_MODE, port);
159     return ESPErrToHoErr(ret);
160 }
161 
IoTPwmStop(unsigned int port)162 unsigned int IoTPwmStop(unsigned int port)
163 {
164     if (port >= LEDC_CHANNEL_MAX) {
165         return IOT_FAILURE;
166     }
167 
168     pwm_driver_data_t *pwm = &g_pwm[port];
169     if (pwm->pwm_state == PWM_UNINIT) {
170         return IOT_FAILURE;
171     }
172 
173     esp_err_t ret = ledc_stop(LEDC_MODE, port, 0);
174     return ESPErrToHoErr(ret);
175 }
176