• 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 <stdlib.h>
17 #include <stdio.h>
18 #include "hcs_macro.h"
19 #include "hdf_config_macro.h"
20 #include "hdf_device_desc.h"
21 #include "pwm_if.h"
22 #include "pwm_core.h"
23 #include "hdf_log.h"
24 #include "driver/mcpwm.h"
25 #include "driver/ledc.h"
26 
27 #define PERIOD_NUM 1000000000
28 #define PERIOD2FREQUENCY(period) (PERIOD_NUM / (period))
29 #define MCPWM_GENERATOR(cmpr) ((cmpr) % 2)
30 #define NUM_8192 8192
31 #define GET_ESP_DUTY_CYCLE_PERCENT(duty, period) (int)(NUM_8192 * (1.0 * (duty) / (period)))
32 
33 #define UNIT_MAX_OUTPUT 6 // 每个PWM单元最大输出的个数
34 #define CONFIG_2_PWM_NUM(unit, signal_port) (((unit)*UNIT_MAX_OUTPUT) + (signal_port))
35 #define PWM_NUM_2_CONFIG(pwm_num, unit, signal_port) \
36     do {                                             \
37         (unit) = (pwm_num) / UNIT_MAX_OUTPUT;        \
38         (signal_port) = (pwm_num) % UNIT_MAX_OUTPUT; \
39     } while (0)
40 
41 typedef struct _PwmDeviceConfig {
42     int channel;
43     int pwm_timer;
44     int freq_hz;
45     int gpio_pin;
46     ledc_timer_config_t ledc_timer_config;
47     ledc_channel_config_t ledc_channel_config;
48 } PwmDeviceConfig;
49 
50 static int32_t PwmDevSetConfig(struct PwmDev *pwm, struct PwmConfig *config);
51 static int32_t PwmDevOpen(struct PwmDev *pwm);
52 static int32_t PwmDevClose(struct PwmDev *pwm);
53 
54 struct PwmMethod g_pwmmethod = {
55     .setConfig = PwmDevSetConfig,
56     .open = PwmDevOpen,
57     .close = PwmDevClose,
58 };
59 
60 #define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
61 #define PLATFORM_PWM_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), pwm_config)
62 
63 #define PWM_FIND_CONFIG(node, name, resource)                                               \
64     do {                                                                                    \
65         if (strcmp(HCS_PROP(node, match_attr), name) == 0) {                                \
66             (resource)->channel = GetChannelFromStr(HCS_PROP(node, channel));               \
67             (resource)->pwm_timer = GetTimerFromStr(HCS_PROP(node, timer));                 \
68             (resource)->freq_hz = HCS_PROP(node, freq_hz);                                  \
69             (resource)->gpio_pin = GetPinIndexFromStr(HCS_PROP(node, gpio_pin));            \
70             (resource)->ledc_timer_config.duty_resolution = LEDC_TIMER_13_BIT;              \
71             (resource)->ledc_timer_config.clk_cfg = LEDC_AUTO_CLK;                          \
72             (resource)->ledc_timer_config.timer_num = (resource)->pwm_timer;                \
73             (resource)->ledc_timer_config.speed_mode = LEDC_LOW_SPEED_MODE;                 \
74             (resource)->ledc_channel_config.channel = (resource)->channel;                  \
75             (resource)->ledc_channel_config.gpio_num = (resource)->gpio_pin;                \
76             (resource)->ledc_channel_config.speed_mode = LEDC_LOW_SPEED_MODE;               \
77             (resource)->ledc_channel_config.hpoint = 0;                                     \
78             (resource)->ledc_channel_config.timer_sel = (resource)->pwm_timer;              \
79             HDF_LOGD("<---------- %s ------------>", name);                                 \
80             HDF_LOGD("channel = %s [%d]", HCS_PROP(node, channel), (resource)->channel);    \
81             HDF_LOGD("pwm_timer = %s [%d]", HCS_PROP(node, timer), (resource)->pwm_timer);  \
82             HDF_LOGD("freq_hz = %dHz", (resource)->freq_hz);                                \
83             HDF_LOGD("gpio_pin = %s [%d]", HCS_PROP(node, gpio_pin), (resource)->gpio_pin); \
84             result = HDF_SUCCESS;                                                           \
85         }                                                                                   \
86     } while (0)
87 
88 #define NUM_10 10
89 
GetPinIndexFromStr(const char * str)90 static int GetPinIndexFromStr(const char *str)
91 {
92     if (str == NULL || strlen(str) < 10) {
93         HDF_LOGE("pin index config is illegal!");
94         return GPIO_NUM_NC;
95     }
96 
97     char *ptr_nun = &str[9];
98     int level = strlen(ptr_nun); // 获取下标位数
99     int pin_index = 0;           // GPIO号
100     for (int i = 0; i < level; i++) {
101         if (i != 0) {
102             pin_index = NUM_10 * pin_index;
103         }
104         int num = ptr_nun[i] - '0';
105         if (num >= NUM_10) { // 字符非法
106             HDF_LOGE("pin index config is illegal!");
107             return GPIO_NUM_NC;
108         }
109         pin_index += num;
110     }
111     return pin_index;
112 }
113 
GetTimerFromStr(const char * str)114 static int GetTimerFromStr(const char *str)
115 {
116     if (!strcmp(str, "LEDC_TIMER_0")) {
117         return LEDC_TIMER_0;
118     } else if (!strcmp(str, "LEDC_TIMER_1")) {
119         return LEDC_TIMER_1;
120     } else if (!strcmp(str, "LEDC_TIMER_2")) {
121         return LEDC_TIMER_2;
122     } else if (!strcmp(str, "LEDC_TIMER_3")) {
123         return LEDC_TIMER_3;
124     }
125     HDF_LOGE("pwm_timer is illegal! must be LEDC_TIMER_0-LEDC_TIMER_03.");
126     return LEDC_TIMER_MAX;
127 }
128 
GetChannelFromStr(const char * str)129 static int GetChannelFromStr(const char *str)
130 {
131     if (!strcmp(str, "LEDC_CHANNEL_0")) {
132         return LEDC_CHANNEL_0;
133     } else if (!strcmp(str, "LEDC_CHANNEL_1")) {
134         return LEDC_CHANNEL_1;
135     } else if (!strcmp(str, "LEDC_CHANNEL_2")) {
136         return LEDC_CHANNEL_2;
137     } else if (!strcmp(str, "LEDC_CHANNEL_3")) {
138         return LEDC_CHANNEL_3;
139     } else if (!strcmp(str, "LEDC_CHANNEL_4")) {
140         return LEDC_CHANNEL_4;
141     } else if (!strcmp(str, "LEDC_CHANNEL_5")) {
142         return LEDC_CHANNEL_5;
143     } else if (!strcmp(str, "LEDC_CHANNEL_6")) {
144         return LEDC_CHANNEL_6;
145     } else if (!strcmp(str, "LEDC_CHANNEL_7")) {
146         return LEDC_CHANNEL_7;
147     }
148     HDF_LOGE("channel is illegal! must be LEDC_CHANNEL 0-7.");
149     return LEDC_CHANNEL_MAX;
150 }
151 
GetPwmDeviceResource(PwmDeviceConfig * device,const char * deviceMatchAttr)152 static uint32_t GetPwmDeviceResource(PwmDeviceConfig *device, const char *deviceMatchAttr)
153 {
154     int32_t result = HDF_FAILURE;
155     if (device == NULL || deviceMatchAttr == NULL) {
156         HDF_LOGE("%s: device or deviceMatchAttr is NULL", __func__);
157         return HDF_ERR_INVALID_PARAM;
158     }
159 
160     HCS_FOREACH_CHILD_VARGS(PLATFORM_PWM_CONFIG, PWM_FIND_CONFIG, deviceMatchAttr, device);
161 
162     if (result != HDF_SUCCESS) {
163         HDF_LOGE("resourceNode %s is NULL\r\n", deviceMatchAttr);
164     }
165 
166     return result;
167 }
168 
AttachPwmDevice(struct PwmDev * host,struct HdfDeviceObject * device)169 static int32_t AttachPwmDevice(struct PwmDev *host, struct HdfDeviceObject *device)
170 {
171     int32_t ret;
172     PwmDeviceConfig *pwmDevice = NULL;
173     if (device == NULL || host == NULL) {
174         HDF_LOGE("%s: param is NULL\r\n", __func__);
175         return HDF_ERR_INVALID_PARAM;
176     }
177     pwmDevice = (PwmDeviceConfig *)OsalMemAlloc(sizeof(PwmDeviceConfig));
178     if (pwmDevice == NULL) {
179         HDF_LOGE("%s: OsalMemAlloc pwmDevice error\r\n", __func__);
180         return HDF_ERR_MALLOC_FAIL;
181     }
182     ret = GetPwmDeviceResource(pwmDevice, device->deviceMatchAttr);
183     if (ret != HDF_SUCCESS) {
184         (void)OsalMemFree(pwmDevice);
185         return HDF_FAILURE;
186     }
187 
188     PwmSetPriv(host, pwmDevice);
189     host->num = pwmDevice->channel;
190 
191     return HDF_SUCCESS;
192 }
193 
194 static int32_t PwmDriverBind(struct HdfDeviceObject *device);
195 static int32_t PwmDriverInit(struct HdfDeviceObject *device);
196 static void PwmDriverRelease(struct HdfDeviceObject *device);
197 
198 struct HdfDriverEntry g_pwmDriverEntry = {
199     .moduleVersion = 1,
200     .moduleName = "ESP32U4_HDF_PLATFORM_PWM",
201     .Bind = PwmDriverBind,
202     .Init = PwmDriverInit,
203     .Release = PwmDriverRelease,
204 };
205 HDF_INIT(g_pwmDriverEntry);
206 
PwmDriverBind(struct HdfDeviceObject * device)207 static int32_t PwmDriverBind(struct HdfDeviceObject *device)
208 {
209     struct PwmDev *devService = NULL;
210     if (device == NULL) {
211         HDF_LOGE("hdfDevice object is null!\r\n");
212         return HDF_FAILURE;
213     }
214 
215     devService = (struct PwmDev *)OsalMemCalloc(sizeof(struct PwmDev));
216     if (devService == NULL) {
217         HDF_LOGE("malloc pwmDev failed\n");
218     }
219     device->service = &devService->service;
220     devService->device = device;
221 
222     return HDF_SUCCESS;
223 }
224 
PwmDriverInit(struct HdfDeviceObject * device)225 static int32_t PwmDriverInit(struct HdfDeviceObject *device)
226 {
227     int32_t ret;
228     struct PwmDev *host = NULL;
229 
230     if (device == NULL) {
231         HDF_LOGE("%s: device is NULL\r\n", __func__);
232         return HDF_ERR_INVALID_OBJECT;
233     }
234 
235     host = (struct PwmDev *)device->service;
236     if (host == NULL) {
237         HDF_LOGE("%s: host is NULL\r\n", __func__);
238         return HDF_ERR_MALLOC_FAIL;
239     }
240 
241     ret = AttachPwmDevice(host, device);
242     if (ret != HDF_SUCCESS) {
243         HDF_LOGE("%s:attach error\r\n", __func__);
244         return HDF_DEV_ERR_ATTACHDEV_FAIL;
245     }
246 
247     host->method = &g_pwmmethod;
248     ret = PwmDeviceAdd(device, host);
249     if (ret != HDF_SUCCESS) {
250         PwmDeviceRemove(device, host);
251         OsalMemFree(host->device);
252         OsalMemFree(host);
253         return HDF_DEV_ERR_NO_DEVICE;
254     }
255 
256     return HDF_SUCCESS;
257 }
258 
PwmDriverRelease(struct HdfDeviceObject * device)259 static void PwmDriverRelease(struct HdfDeviceObject *device)
260 {
261     struct PwmDev *host = NULL;
262     if (device == NULL || device->service == NULL) {
263         HDF_LOGE("device is null\r\n");
264         return;
265     }
266     host = (struct PwmDev *)device->service;
267     if (host != NULL && host->device != NULL) {
268         host->method = NULL;
269         OsalMemFree(host->device);
270         OsalMemFree(host);
271         host->device = NULL;
272         host = NULL;
273     }
274     device->service = NULL;
275     host = NULL;
276     return;
277 }
278 
PwmDevSetConfig(struct PwmDev * pwm,struct PwmConfig * config)279 static int32_t PwmDevSetConfig(struct PwmDev *pwm, struct PwmConfig *config)
280 {
281     int ret;
282     if (pwm == NULL || config == NULL) {
283         HDF_LOGE("%s: PwmDev* pwm or struct PwmConfig *config is NULL!", __FUNCTION__);
284         return HDF_ERR_INVALID_PARAM;
285     }
286     PwmDeviceConfig *pwmDevice = (PwmDeviceConfig *)PwmGetPriv(pwm);
287     if (pwmDevice == NULL) {
288         HDF_LOGE("%s: PwmDeviceConfig* pwmDevice is NULL", __FUNCTION__);
289         return HDF_ERR_INVALID_PARAM;
290     }
291     if (config->status == PWM_ENABLE_STATUS) {                                          // 使能PWM
292         if (pwmDevice->ledc_timer_config.freq_hz != PERIOD2FREQUENCY(config->period)) { // 周期有频率变化
293             pwmDevice->ledc_timer_config.freq_hz = PERIOD2FREQUENCY(config->period);
294             ledc_timer_config(&pwmDevice->ledc_timer_config); // 重新配置周期
295             printf("\r\n------->config freq_hz = %d [period = %d]\r\n",
296                    pwmDevice->ledc_timer_config.freq_hz, config->period);
297             printf("speed_mode = %d\r\n", pwmDevice->ledc_timer_config.speed_mode);
298             printf("timer_num = %d\r\n", pwmDevice->ledc_timer_config.timer_num);
299             printf("clk_cfg = %d\r\n", pwmDevice->ledc_timer_config.clk_cfg);
300             printf("duty_resolution = %d\r\n", pwmDevice->ledc_timer_config.duty_resolution);
301         }
302         if (pwmDevice->ledc_channel_config.duty != GET_ESP_DUTY_CYCLE_PERCENT(config->duty, config->period)) {
303             pwmDevice->ledc_channel_config.duty = GET_ESP_DUTY_CYCLE_PERCENT(config->duty, config->period);
304             printf("\r\n------->config ledc_duty = %d [duty=%d <--> period=%d]\r\n",
305                    pwmDevice->ledc_channel_config.duty, config->duty, config->period);
306             printf("gpio_num = %d\r\n", pwmDevice->ledc_channel_config.gpio_num);
307             printf("speed_mode = %d\r\n", pwmDevice->ledc_channel_config.speed_mode);
308             printf("channel = %d\r\n", pwmDevice->ledc_channel_config.channel);
309             printf("timer_sel = %d\r\n", pwmDevice->ledc_channel_config.timer_sel);
310             printf("hpoint = %d\r\n", pwmDevice->ledc_channel_config.hpoint);
311         }
312     } else if (config->status == PWM_DISABLE_STATUS) { // 失能PWM
313         ledc_stop(pwmDevice->ledc_timer_config.speed_mode, pwmDevice->channel, config->polarity);
314         printf("------->pwm output stop, set level = %d\r\n", config->polarity);
315     }
316     return HDF_SUCCESS;
317 }
318 
PwmDevOpen(struct PwmDev * pwm)319 static int32_t PwmDevOpen(struct PwmDev *pwm)
320 {
321     if (pwm == NULL) {
322         HDF_LOGE("%s: PwmDev* pwm is NULL", __FUNCTION__);
323         return HDF_ERR_INVALID_PARAM;
324     }
325 
326     PwmDeviceConfig *pwmDevice = (PwmDeviceConfig *)PwmGetPriv(pwm);
327     if (pwmDevice == NULL) {
328         HDF_LOGE("%s: PwmDeviceConfig* pwmDevice is NULL", __FUNCTION__);
329         return HDF_ERR_INVALID_PARAM;
330     }
331     return HDF_SUCCESS;
332 }
333 
PwmDevClose(struct PwmDev * pwm)334 static int32_t PwmDevClose(struct PwmDev *pwm)
335 {
336     HDF_LOGI("——> Enter %s", __FUNCTION__);
337     return HDF_SUCCESS;
338 }