1 /*
2 * Copyright (c) 2006-2024 RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-12-18 hywing Initial version.
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "fsl_pwm.h"
14
15 #ifdef RT_USING_PWM
16
17 #define BOARD_PWM_BASEADDR (FLEXPWM0)
18 #define PWM_SRC_CLK_FREQ (CLOCK_GetFreq(kCLOCK_BusClk))
19 #define FLEX_PWM_CLOCK_DEVIDER (kPWM_Prescale_Divide_2)
20 #define FLEX_PWM_FAULT_LEVEL true
21
22 typedef struct
23 {
24 struct rt_device_pwm pwm_device;
25 pwm_submodule_t submodule;
26 pwm_module_control_t control;
27 pwm_channels_t channel;
28 pwm_clock_prescale_t prescale;
29 char *name;
30 } mcx_pwm_obj_t;
31
32 static mcx_pwm_obj_t mcx_pwm_list[]=
33 {
34 #ifdef BSP_USING_PWM0
35 {
36 .submodule = kPWM_Module_0,
37 .control = kPWM_Control_Module_0,
38 .channel = kPWM_PwmA,
39 .prescale = FLEX_PWM_CLOCK_DEVIDER,
40 .name = "pwm0",
41 },
42 #endif
43 #ifdef BSP_USING_PWM1
44 {
45 .submodule = kPWM_Module_1,
46 .control = kPWM_Control_Module_1,
47 .channel = kPWM_PwmA,
48 .prescale = FLEX_PWM_CLOCK_DEVIDER,
49 .name = "pwm1",
50 },
51 #endif
52 #ifdef BSP_USING_PWM2
53 {
54 .submodule = kPWM_Module_2,
55 .control = kPWM_Control_Module_2,
56 .channel = kPWM_PwmA,
57 .prescale = FLEX_PWM_CLOCK_DEVIDER,
58 .name = "pwm2",
59 },
60 #endif
61 };
62
mcx_drv_pwm_get(mcx_pwm_obj_t * pwm,struct rt_pwm_configuration * configuration)63 static rt_err_t mcx_drv_pwm_get(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration)
64 {
65 return RT_EOK;
66 }
67
mcx_drv_pwm_set(mcx_pwm_obj_t * pwm,struct rt_pwm_configuration * configuration)68 static rt_err_t mcx_drv_pwm_set(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration)
69 {
70 uint8_t dutyCyclePercent = configuration->pulse * 100 / configuration->period;
71 pwm_signal_param_t pwmSignal[1];
72 uint32_t pwmFrequencyInHz = 1000000000 / configuration->period;
73
74 pwmSignal[0].pwmChannel = pwm->channel;
75 pwmSignal[0].level = kPWM_HighTrue;
76 pwmSignal[0].dutyCyclePercent = dutyCyclePercent;
77 pwmSignal[0].deadtimeValue = 0;
78 pwmSignal[0].faultState = kPWM_PwmFaultState0;
79 pwmSignal[0].pwmchannelenable = true;
80
81 PWM_SetupPwm(BOARD_PWM_BASEADDR, pwm->submodule, pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz, PWM_SRC_CLK_FREQ);
82 PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, pwm->submodule, pwm->channel, kPWM_SignedCenterAligned, dutyCyclePercent);
83 PWM_SetPwmLdok(BOARD_PWM_BASEADDR, pwm->control, true);
84
85 return 0;
86 }
87
mcx_drv_pwm_enable(mcx_pwm_obj_t * pwm,struct rt_pwm_configuration * configuration)88 static rt_err_t mcx_drv_pwm_enable(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration)
89 {
90 PWM_StartTimer(BOARD_PWM_BASEADDR, pwm->control);
91 return 0;
92 }
93
mcx_drv_pwm_disable(mcx_pwm_obj_t * pwm,struct rt_pwm_configuration * configuration)94 static rt_err_t mcx_drv_pwm_disable(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration)
95 {
96 PWM_StopTimer(BOARD_PWM_BASEADDR, pwm->control);
97 return 0;
98 }
99
mcx_drv_pwm_control(struct rt_device_pwm * device,int cmd,void * args)100 static rt_err_t mcx_drv_pwm_control(struct rt_device_pwm *device, int cmd, void *args)
101 {
102 mcx_pwm_obj_t *pwm = device->parent.user_data;
103 struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)args;
104
105 switch (cmd)
106 {
107 case PWM_CMD_ENABLE:
108 return mcx_drv_pwm_enable(pwm, configuration);
109
110 case PWM_CMD_DISABLE:
111 return mcx_drv_pwm_disable(pwm, configuration);
112
113 case PWM_CMD_SET:
114 return mcx_drv_pwm_set(pwm, configuration);
115
116 case PWM_CMD_GET:
117 return mcx_drv_pwm_get(pwm, configuration);
118
119 default:
120 return -RT_EINVAL;
121 }
122
123 return RT_EOK;
124 }
125
126 static struct rt_pwm_ops mcx_pwm_ops =
127 {
128 .control = mcx_drv_pwm_control,
129 };
130
mcx_pwm_init(void)131 int mcx_pwm_init(void)
132 {
133 rt_err_t ret;
134 pwm_config_t pwmConfig;
135 pwm_fault_param_t faultConfig;
136 PWM_GetDefaultConfig(&pwmConfig);
137 pwmConfig.prescale = FLEX_PWM_CLOCK_DEVIDER;
138 pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
139
140 int i;
141 for (i = 0; i < sizeof(mcx_pwm_list) / sizeof(mcx_pwm_list[0]); i++)
142 {
143 pwm_config_t pwmConfig;
144 pwm_fault_param_t faultConfig;
145 PWM_GetDefaultConfig(&pwmConfig);
146 pwmConfig.prescale = mcx_pwm_list[i].prescale;
147 pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
148 if (PWM_Init(BOARD_PWM_BASEADDR, mcx_pwm_list[i].submodule, &pwmConfig) == kStatus_Fail)
149 {
150 rt_kprintf("PWM Init Failed\n");
151 }
152 ret = rt_device_pwm_register(&mcx_pwm_list[i].pwm_device, mcx_pwm_list[i].name, &mcx_pwm_ops, &mcx_pwm_list[i]);
153 }
154
155 /*
156 * config->faultClearingMode = kPWM_Automatic;
157 * config->faultLevel = false;
158 * config->enableCombinationalPath = true;
159 * config->recoverMode = kPWM_NoRecovery;
160 */
161 PWM_FaultDefaultConfig(&faultConfig);
162 faultConfig.faultLevel = FLEX_PWM_FAULT_LEVEL;
163
164 /* Sets up the PWM fault protection */
165 PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_0, &faultConfig);
166 PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_1, &faultConfig);
167 PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_2, &faultConfig);
168 PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_3, &faultConfig);
169
170 /* Set PWM fault disable mapping for submodule 0/1/2 */
171 PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA, kPWM_faultchannel_0,
172 kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);
173 PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_1, kPWM_PwmA, kPWM_faultchannel_0,
174 kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);
175 PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_2, kPWM_PwmA, kPWM_faultchannel_0,
176 kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);
177
178
179 /* Set the load okay bit for all submodules to load registers from their buffer */
180 PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2, true);
181
182 return ret;
183 }
184
185 INIT_DEVICE_EXPORT(mcx_pwm_init);
186
187 #endif /* RT_USING_PWM */
188