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