SimpleFOClibrary 2.4.0
Loading...
Searching...
No Matches
efr32_pwm.cpp
Go to the documentation of this file.
1#if defined(ARDUINO_ARCH_SILABS)
2
3#include <pinDefinitions.h>
4#include <em_device.h>
5#include <em_gpio.h>
6#include <em_bus.h>
7#include <em_cmu.h>
8#include "efr32_pwm.h"
9
10static CMU_Clock_TypeDef _getTimerClock(TIMER_TypeDef *timer) {
11#if defined(_CMU_HFCLKSEL_MASK) || defined(_CMU_CMD_HFCLKSEL_MASK)
12 CMU_Clock_TypeDef timerClock = cmuClock_HF;
13#elif defined(_CMU_SYSCLKCTRL_MASK)
14 CMU_Clock_TypeDef timerClock = cmuClock_SYSCLK;
15#else
16#error "Unknown root of clock tree"
17#endif
18
19 switch ((uint32_t)timer) {
20#if defined(TIMER0_BASE)
21 case TIMER0_BASE:
22 timerClock = cmuClock_TIMER0;
23 break;
24#endif
25#if defined(TIMER1_BASE)
26 case TIMER1_BASE:
27 timerClock = cmuClock_TIMER1;
28 break;
29#endif
30#if defined(TIMER2_BASE)
31 case TIMER2_BASE:
32 timerClock = cmuClock_TIMER2;
33 break;
34#endif
35#if defined(TIMER3_BASE)
36 case TIMER3_BASE:
37 timerClock = cmuClock_TIMER3;
38 break;
39#endif
40#if defined(TIMER4_BASE)
41 case TIMER4_BASE:
42 timerClock = cmuClock_TIMER4;
43 break;
44#endif
45#if defined(TIMER5_BASE)
46 case TIMER5_BASE:
47 timerClock = cmuClock_TIMER5;
48 break;
49#endif
50#if defined(TIMER6_BASE)
51 case TIMER6_BASE:
52 timerClock = cmuClock_TIMER6;
53 break;
54#endif
55#if defined(WTIMER0_BASE)
56 case WTIMER0_BASE:
57 timerClock = cmuClock_WTIMER0;
58 break;
59#endif
60#if defined(WTIMER1_BASE)
61 case WTIMER1_BASE:
62 timerClock = cmuClock_WTIMER1;
63 break;
64#endif
65#if defined(WTIMER2_BASE)
66 case WTIMER2_BASE:
67 timerClock = cmuClock_WTIMER2;
68 break;
69#endif
70#if defined(WTIMER3_BASE)
71 case WTIMER3_BASE:
72 timerClock = cmuClock_WTIMER3;
73 break;
74#endif
75 default:
76 break;
77 }
78 return timerClock;
79}
80
81void pwmHiConfig(
82 EFR32PwmInstance *inst,
83 TIMER_TypeDef *timer,
84 const int pin,
85 const uint8_t channel
86) {
87 if (!inst) return;
88
89 inst->h.timer = timer;
90 inst->h.port = getSilabsPortFromArduinoPin(pinToPinName(pin));
91 inst->h.pin = getSilabsPinFromArduinoPin(pinToPinName(pin));
92 inst->h.channel = channel;
93}
94
95void pwmHiInit(
96 EFR32PwmInstance *inst,
97 EFR32PwmConfig *config,
98 prevTimerInitCCFn fn,
99 void *params
100) {
101 if (!inst || !config) return;
102
103 // Enable Timer Clock
104 CMU_Clock_TypeDef timerClock = _getTimerClock(inst->h.timer);
105 CMU_ClockEnable(timerClock, true);
106
107 // Set PWM pin as output
108 CMU_ClockEnable(cmuClock_GPIO, true);
109 GPIO_PinModeSet((GPIO_Port_TypeDef)inst->h.port,
110 inst->h.pin,
111 gpioModePushPull,
112 config->polarity);
113
114 // Set CC channel parameters
115 TIMER_InitCC_TypeDef initCC = TIMER_INITCC_DEFAULT;
116 initCC.mode = timerCCModePWM;
117 if (config->outInvert) initCC.outInvert = true;
118 if (fn) fn(&initCC, params);
119
120 TIMER_InitCC(inst->h.timer, inst->h.channel, &initCC);
121
122 volatile uint32_t *routeRegister = &GPIO->TIMERROUTE[TIMER_NUM(inst->h.timer)].CC0ROUTE;
123 routeRegister += inst->h.channel;
124 *routeRegister = (inst->h.port << _GPIO_TIMER_CC0ROUTE_PORT_SHIFT)
125 | (inst->h.pin << _GPIO_TIMER_CC0ROUTE_PIN_SHIFT);
126
127 // Configure TIMER frequency
128 uint32_t top = (CMU_ClockFreqGet(timerClock) / (config->frequency)) - 1U;
129 TIMER_TopSet(inst->h.timer, top);
130
131 // Set initial duty cycle to 0%
132 TIMER_CompareSet(inst->h.timer, inst->h.channel, 0U);
133}
134
135void pwmHiDeinit(
136 EFR32PwmInstance *inst
137) {
138 if (!inst) return;
139
140 pwmHiOff(inst);
141
142 volatile uint32_t *routeRegister = &GPIO->TIMERROUTE[TIMER_NUM(inst->h.timer)].CC0ROUTE;
143 routeRegister += inst->h.channel;
144 *routeRegister = 0;
145
146 TIMER_Reset(inst->h.timer);
147 GPIO_PinModeSet((GPIO_Port_TypeDef)inst->h.port,
148 inst->h.pin,
149 gpioModeDisabled,
150 0);
151 CMU_Clock_TypeDef timerClock = _getTimerClock(inst->h.timer);
152 CMU_ClockEnable(timerClock, false);
153}
154
155void pwmHiOn(
156 EFR32PwmInstance *inst
157) {
158 if (!inst) return;
159 GPIO->TIMERROUTE_SET[TIMER_NUM(inst->h.timer)].ROUTEEN = 1 << (inst->h.channel + _GPIO_TIMER_ROUTEEN_CC0PEN_SHIFT);
160}
161
162void pwmHiOff(
163 EFR32PwmInstance *inst
164) {
165 if (!inst) return;
166 GPIO->TIMERROUTE_CLR[TIMER_NUM(inst->h.timer)].ROUTEEN = 1 << (inst->h.channel + _GPIO_TIMER_ROUTEEN_CC0PEN_SHIFT);
167}
168
169void pwmHiSetDutyCycle(
170 EFR32PwmInstance *inst,
171 float percent
172) {
173 if (!inst || (percent > 100.0f)) return;
174 uint32_t top = TIMER_TopGet(inst->h.timer);
175 volatile bool outInvert = inst->h.timer->CC[inst->h.channel].CTRL & TIMER_CC_CTRL_OUTINV;
176 if (outInvert) percent = 100 - percent;
177 TIMER_CompareBufSet(inst->h.timer, inst->h.channel, (uint32_t) (top * percent) / 100);
178}
179
180float pwmHiGetDutyCycle(
181 EFR32PwmInstance *inst
182) {
183 if (!inst) return 0;
184 uint32_t top = TIMER_TopGet(inst->h.timer);
185 uint32_t compare = TIMER_CaptureGet(inst->h.timer, inst->h.channel);
186 volatile bool outInvert = inst->h.timer->CC[inst->h.channel].CTRL & TIMER_CC_CTRL_OUTINV;
187 float percent = (float)((compare * 100) / top);
188 return outInvert ? (100 - percent) : percent;
189}
190
191void pwmLoConfig(
192 EFR32PwmInstance *inst,
193 const int pin
194) {
195 if (!inst) return;
196 inst->l.port = getSilabsPortFromArduinoPin(pinToPinName(pin));
197 inst->l.pin = getSilabsPinFromArduinoPin(pinToPinName(pin));
198}
199
200void pwmLoInit(
201 EFR32PwmInstance *inst
202) {
203 if (!inst) return;
204
205 // Low side PWM
206 CMU_ClockEnable(cmuClock_GPIO, true);
207 GPIO_PinModeSet((GPIO_Port_TypeDef)inst->l.port,
208 inst->l.pin,
209 gpioModePushPull,
210 0);
211
212 volatile uint32_t *routeRegister = &GPIO->TIMERROUTE[TIMER_NUM(inst->h.timer)].CDTI0ROUTE;
213 routeRegister += inst->h.channel;
214 *routeRegister = (inst->l.port << _GPIO_TIMER_CDTI0ROUTE_PORT_SHIFT)
215 | (inst->l.pin << _GPIO_TIMER_CDTI0ROUTE_PIN_SHIFT);
216}
217
218void pwmLoDeinit(
219 EFR32PwmInstance *inst
220) {
221 if (!inst) return;
222
223 pwmLoOff(inst);
224
225 volatile uint32_t *routeRegister = &GPIO->TIMERROUTE[TIMER_NUM(inst->h.timer)].CDTI0ROUTE;
226 routeRegister += inst->h.channel;
227 *routeRegister = 0;
228
229 GPIO_PinModeSet((GPIO_Port_TypeDef)inst->l.port,
230 inst->l.pin,
231 gpioModeDisabled,
232 0);
233}
234
235void pwmLoOn(
236 EFR32PwmInstance *inst
237) {
238 if (!inst) return;
239 GPIO->TIMERROUTE_SET[TIMER_NUM(inst->h.timer)].ROUTEEN |= 1 << (inst->h.channel + _GPIO_TIMER_ROUTEEN_CCC0PEN_SHIFT);
240}
241
242void pwmLoOff(
243 EFR32PwmInstance *inst
244) {
245 if (!inst) return;
246 GPIO->TIMERROUTE_CLR[TIMER_NUM(inst->h.timer)].ROUTEEN |= 1 << (inst->h.channel + _GPIO_TIMER_ROUTEEN_CCC0PEN_SHIFT);
247}
248
249void pwmInit(
250 EFR32PwmInstance *inst,
251 EFR32PwmConfig *config,
252 prevTimerInitCCFn fn,
253 void *params
254) {
255 if (!inst || !config) return;
256 pwmHiInit(inst, config, fn, params);
257 pwmLoInit(inst);
258}
259
260void pwmDeinit(
261 EFR32PwmInstance *inst
262) {
263 if (!inst) return;
264 pwmHiDeinit(inst);
265 pwmLoDeinit(inst);
266}
267
268void pwmOff(EFR32PwmInstance *inst) {
269 if (!inst) return;
270 pwmHiOff(inst);
271 pwmLoOff(inst);
272}
273
274void pwmOn(EFR32PwmInstance *inst) {
275 if (!inst) return;
276 pwmHiOn(inst);
277 pwmLoOn(inst);
278}
279
280void pwmStart(EFR32PwmInstance *inst, prevTimerInitFn fn, void *params) {
281 if (!inst) return;
282
283 // Initialize TIMER
284 TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
285 if (fn) fn(&timerInit, params);
286 TIMER_Init(inst->h.timer, &timerInit);
287}
288
289void pwmDeadTimeInit(
290 EFR32PwmInstance *inst,
291 EFR32PwmDeadTimeConfig *config
292) {
293 if (!inst || !config) return;
294
295 // Enable Timer Clock
296 CMU_Clock_TypeDef timerClock = _getTimerClock(inst->h.timer);
297 CMU_ClockEnable(timerClock, true);
298
299 unsigned int dtiTime = (CMU_ClockFreqGet(timerClock) / 1e3f) * config->deadTimeNs / 1e6f;
300 if (dtiTime > 64) dtiTime = SILABBS_DEFAULT_DEAD_TIME;
301
302 TIMER_InitDTI_TypeDef initDTI = TIMER_INITDTI_DEFAULT;
303 initDTI.riseTime = dtiTime;
304 initDTI.fallTime = dtiTime;
305 initDTI.outputsEnableMask = config->outputMask;
306
307 TIMER_InitDTI(inst->h.timer, &initDTI);
308}
309
310#endif
GenericCurrentSenseParams * params