1 /** mbed Microcontroller Library
2 ******************************************************************************
3 * @file pwmout_api.c
4 * @author
5 * @version V1.0.0
6 * @date 2016-08-01
7 * @brief This file provides mbed API for PWM.
8 ******************************************************************************
9 * @attention
10 *
11 * This module is a confidential and proprietary property of RealTek and
12 * possession or use of this module requires written permission of RealTek.
13 *
14 * Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
15 ******************************************************************************
16 */
17
18
19 #include "device.h"
20 #include "objects.h"
21 #include "pinmap.h"
22
23 #include "pwmout_api.h"
24
25 /** @defgroup AmebaD_Mbed_API
26 * @{
27 */
28
29 /** @addtogroup MBED_PWM
30 * @brief MBED_PWM driver modules.
31 * @{
32 */
33
34 /** @defgroup MBED_PWM_Exported_Types MBED_PWM Exported Types
35 * @{
36 */
37
38 #define PWM_TIMER 5
39 #define BIT_PWM_TIM_IDX_FLAG BIT(7)
40 #define BIT_PWM_TIM_IDX_SHIFT 7
41
42 /**
43 * @brief Table elements express the pin to PWM channel number, they are:
44 * {pinName, km0_pin2chan, km4_pin2chan}
45 */
46 const u32 pin2chan[19][3] = {
47 {PA_12, 0, 0},
48 {PA_13, 1, 1},
49 {PA_23, 2, 2},
50 {PA_24, 3, 3},
51 {PA_25, 4, 4},
52 {PA_26, 5, 5},
53 {PA_28, 0, 6},
54 {PA_30, 1, 7},
55 {PB_4, 2, 8},
56 {PB_5, 3, 9},
57 {PB_18, 4, 10},
58 {PB_19, 5, 11},
59 {PB_20, 0, 12},
60 {PB_21, 1, 13},
61 {PB_22, 2, 14},
62 {PB_23, 3, 15},
63 {PB_24, 4, 16},
64 {PB_25, 5, 17},
65 {PB_7, 5, 17}
66 };
67
68 u8 timer5_start = 0;
69 u8 timer05_start = 0;
70 u8 km4_ch_start[18] = {0};
71 u8 km0_ch_start[6] = {0};
72 u8 prescaler = 0;
73 RTIM_TypeDef* PWM_TIM[2] = {TIMM05, TIM5};
74 /**
75 * @}
76 */
77
78 /** @defgroup MBED_PWM_Exported_Functions MBED_PWM Exported Functions
79 * @{
80 */
81
82 /**
83 * @brief Return PWM channel number according to pin name.
84 * @param pin: The pin to be told.
85 * @retval value: PWM channel number corresponding to the pin.
86 */
pwmout_pin2chan(PinName pin)87 u32 pwmout_pin2chan(PinName pin)
88 {
89 int i = 0;
90 for(;i < 19;i++){
91 if(pin2chan[i][0] == pin){
92 return (pin2chan[i][2] | BIT_PWM_TIM_IDX_FLAG);
93 }
94 }
95 return NC;
96 }
97
98 /**
99 * @brief Initializes the TIM5/TIMM05 device, include TIM5/TIMM05 registers and function.
100 * @param obj: PWM object define in application software.
101 * @retval none
102 */
pwmout_timer5_init(pwmout_t * obj)103 void pwmout_timer5_init(pwmout_t* obj)
104 {
105 RTIM_TimeBaseInitTypeDef TIM_InitStruct;
106 RTIM_TimeBaseStructInit(&TIM_InitStruct);
107 TIM_InitStruct.TIM_Idx = PWM_TIMER;
108
109 RTIM_TimeBaseInit(PWM_TIM[obj->pwm_idx >>BIT_PWM_TIM_IDX_SHIFT], &TIM_InitStruct, TIMER5_IRQ, NULL, (u32)&TIM_InitStruct);
110 RTIM_Cmd(PWM_TIM[obj->pwm_idx >>BIT_PWM_TIM_IDX_SHIFT], ENABLE);
111
112 if (obj->pwm_idx & BIT_PWM_TIM_IDX_FLAG) {
113 timer5_start = 1;
114 } else {
115 timer05_start = 1;
116 }
117 }
118
119 /**
120 * @brief Initializes the PWM function/registers of the specified pin with default parameters.
121 * @param obj: PWM object define in application software.
122 * @param pin: the pinname of specified channel to be set.
123 * @retval none
124 * @note
125 * - default period: 1638us
126 * - default pulse width: 102us
127 * - default duty cycle: 6.227%
128 */
pwmout_init(pwmout_t * obj,PinName pin)129 void pwmout_init(pwmout_t* obj, PinName pin)
130 {
131 u32 pwm_chan;
132 TIM_CCInitTypeDef TIM_CCInitStruct;
133 uint8_t pwm_tim_idx;
134
135 pwm_chan = pwmout_pin2chan(pin);
136 if(pwm_chan == NC)
137 DBG_8195A("PinName error: pwm channel of PinName doesn't exist!\n");
138
139 obj->pwm_idx = pwm_chan;
140 obj->period = 0x10000 * (prescaler + 1) / 40;
141 obj->pulse = 0x1000 * (prescaler + 1) / 40;
142
143 pwm_tim_idx = obj->pwm_idx >> BIT_PWM_TIM_IDX_SHIFT;
144 pwm_chan = pwm_chan & (~BIT_PWM_TIM_IDX_FLAG);
145
146 if(pwm_tim_idx && (!timer5_start)) {
147 pwmout_timer5_init(obj);
148 }else if ((!pwm_tim_idx) && (!timer05_start)) {
149 pwmout_timer5_init(obj);
150 }
151
152 RTIM_CCStructInit(&TIM_CCInitStruct);
153 RTIM_CCxInit(PWM_TIM[pwm_tim_idx], &TIM_CCInitStruct, pwm_chan);
154 RTIM_CCxCmd(PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Enable);
155
156 if ((obj->pwm_idx & BIT_PWM_TIM_IDX_FLAG)) {
157 Pinmux_Config(pin, PINMUX_FUNCTION_PWM_HS);
158 } else {
159 Pinmux_Config(pin, PINMUX_FUNCTION_PWM_LP);
160 }
161
162 if (obj->pwm_idx & BIT_PWM_TIM_IDX_FLAG) {
163 km4_ch_start[pwm_chan] = 1;
164 } else {
165 km0_ch_start[pwm_chan] = 1;
166 }
167
168 }
169
170
171 /**
172 * @brief Deinitializes the PWM device of the specified channel.
173 * @param obj: PWM object define in application software.
174 * @retval none
175 * @note If all channels are released, TIM5/TIMM05 will also be disabled.
176 */
pwmout_free(pwmout_t * obj)177 void pwmout_free(pwmout_t* obj)
178 {
179 /* disable pwm channel */
180 uint8_t pwm_chan = obj->pwm_idx & (~BIT_PWM_TIM_IDX_FLAG);
181 uint8_t pwm_tim_idx = obj->pwm_idx >> BIT_PWM_TIM_IDX_SHIFT;;
182
183
184 if(pwm_tim_idx && km4_ch_start[pwm_chan]){
185 km4_ch_start[pwm_chan] = 0;
186 RTIM_CCxCmd(PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Disable);
187
188 /* stop timer5 if no pwm channels starts */
189 for(pwm_chan = 0;pwm_chan < 18;pwm_chan++){
190 if(km4_ch_start[pwm_chan]){
191 return;
192 }
193 }
194
195 RTIM_Cmd(PWM_TIM[pwm_tim_idx], DISABLE);
196 timer5_start = 0;
197 } else if (!(pwm_tim_idx) && km0_ch_start[pwm_chan]) {
198 km0_ch_start[pwm_chan] = 0;
199 RTIM_CCxCmd(PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Disable);
200 /* stop timer05 if no pwm channels starts */
201 for(pwm_chan = 0;pwm_chan < 6;pwm_chan++){
202 if(km0_ch_start[pwm_chan]){
203 return;
204 }
205 }
206
207 RTIM_Cmd(PWM_TIM[pwm_tim_idx], DISABLE);
208 timer05_start = 0;
209 }
210
211 return;
212 }
213
214 /**
215 * @brief Set the duty cycle of the specified channel.
216 * @param obj: PWM object define in application software.
217 * @param percent: The duty cycle value to be set.
218 * @retval none
219 */
pwmout_write(pwmout_t * obj,float percent)220 void pwmout_write(pwmout_t* obj, float percent) //write duty-cycle
221 {
222 u32 ccrx;
223
224 if (percent < (float)0.0) {
225 percent = 0.0;
226 }
227 else if (percent > (float)1.0) {
228 percent = 1.0;
229 }
230
231 obj->pulse = (percent * obj->period);
232
233 ccrx = (u32)(obj->pulse * 40 / (prescaler + 1)) & 0x0000ffff;
234
235 RTIM_CCRxSet(PWM_TIM[obj->pwm_idx >>BIT_PWM_TIM_IDX_SHIFT], ccrx, obj->pwm_idx & (~BIT_PWM_TIM_IDX_FLAG));
236 }
237
238 /**
239 * @brief Get the duty cycle value of the specified channel.
240 * @param obj: PWM object define in application software.
241 * @retval : the duty cycle value of the specified channel.
242 */
pwmout_read(pwmout_t * obj)243 float pwmout_read(pwmout_t* obj) //read duty-cycle
244 {
245 float value = 0;
246 if (obj->period > 0) {
247 value = (float)obj->pulse / (float)obj->period;
248 }
249 return ((value > 1.0) ? (1.0) : (value));
250 }
251
252 /**
253 * @brief Set the period of the specified channel in seconds.
254 * @param obj: PWM object define in application software.
255 * @param seconds: The period value to be set in seconds.
256 * @retval none
257 */
pwmout_period(pwmout_t * obj,float seconds)258 void pwmout_period(pwmout_t* obj, float seconds)
259 {
260 pwmout_period_us(obj, (int)(seconds * 1000000.0f));
261 }
262
263 /**
264 * @brief Set the period of the specified channel in millseconds.
265 * @param obj: PWM object define in application software.
266 * @param ms: The period value to be set in millseconds.
267 * @retval none
268 */
pwmout_period_ms(pwmout_t * obj,int ms)269 void pwmout_period_ms(pwmout_t* obj, int ms)
270 {
271 pwmout_period_us(obj, (int)(ms * 1000));
272 }
273
274 /**
275 * @brief Set the period of the specified channel in microseconds.
276 * @param obj: PWM object define in application software.
277 * @param us: The period value to be set in microseconds.
278 * @retval none
279 */
pwmout_period_us(pwmout_t * obj,int us)280 void pwmout_period_us(pwmout_t* obj, int us)
281 {
282 u32 arr;
283 float dc = pwmout_read(obj);
284 u32 tmp = us * 40 / (prescaler + 1);
285
286 if(tmp > 0x10000){
287 prescaler = us * 40 / 0x10000;
288 RTIM_PrescalerConfig(PWM_TIM[obj->pwm_idx >>BIT_PWM_TIM_IDX_SHIFT], prescaler, TIM_PSCReloadMode_Update);
289 }
290
291 obj->period = us;
292 arr = us * 40 / (prescaler + 1) - 1;
293
294 RTIM_ChangePeriod(PWM_TIM[obj->pwm_idx >>BIT_PWM_TIM_IDX_SHIFT], arr);
295 pwmout_write(obj, dc);
296 }
297
298 /**
299 * @brief Set the pulse width of the specified channel in seconds.
300 * @param obj: PWM object define in application software.
301 * @param seconds: The pulse width value to be set in seconds.
302 * @retval none
303 */
pwmout_pulsewidth(pwmout_t * obj,float seconds)304 void pwmout_pulsewidth(pwmout_t* obj, float seconds)
305 {
306 pwmout_pulsewidth_us(obj, (int)(seconds * 1000000.0f));
307 }
308
309 /**
310 * @brief Set the pulse width of the specified channel in milliseconds.
311 * @param obj: PWM object define in application software.
312 * @param ms: The pulse width value to be set in milliseconds.
313 * @retval none
314 */
pwmout_pulsewidth_ms(pwmout_t * obj,int ms)315 void pwmout_pulsewidth_ms(pwmout_t* obj, int ms)
316 {
317 pwmout_pulsewidth_us(obj, ms * 1000);
318 }
319
320 /**
321 * @brief Set the pulse width of the specified channel in microseconds.
322 * @param obj: PWM object define in application software.
323 * @param us: The pulse width value to be set in microseconds.
324 * @retval none
325 */
pwmout_pulsewidth_us(pwmout_t * obj,int us)326 void pwmout_pulsewidth_us(pwmout_t* obj, int us)
327 {
328 u32 ccrx;
329
330 obj->pulse = (float)us;
331 ccrx = (u32)(obj->pulse * 40 / (prescaler + 1)) & 0x0000ffff;
332 RTIM_CCRxSet(PWM_TIM[obj->pwm_idx >>BIT_PWM_TIM_IDX_SHIFT], ccrx, obj->pwm_idx & (~BIT_PWM_TIM_IDX_FLAG));
333 }
334
335 /**
336 * @brief Enable the specified channel to output PWM.
337 * @param obj: PWM object define in application software.
338 * @retval none
339 */
pwmout_start(pwmout_t * obj)340 void pwmout_start(pwmout_t* obj)
341 {
342 RTIM_CCxCmd(PWM_TIM[obj->pwm_idx >>BIT_PWM_TIM_IDX_SHIFT], obj->pwm_idx & (~BIT_PWM_TIM_IDX_FLAG), TIM_CCx_Enable);
343 }
344
345 /**
346 * @brief Disable the specified channel to output PWM.
347 * @param obj: PWM object define in application software.
348 * @retval none
349 */
pwmout_stop(pwmout_t * obj)350 void pwmout_stop(pwmout_t* obj)
351 {
352 RTIM_CCxCmd(PWM_TIM[obj->pwm_idx >>BIT_PWM_TIM_IDX_SHIFT], obj->pwm_idx & (~BIT_PWM_TIM_IDX_FLAG), TIM_CCx_Disable);
353 }
354 /**
355 * @}
356 */
357
358 /**
359 * @}
360 */
361
362 /**
363 * @}
364 */
365
366