]> rtime.felk.cvut.cz Git - arc.git/blob - arch/arm/arm_cm3/drivers/Pwm.c
842dc57f21ca6c5aab59b7b5fd4f4108b02d2784
[arc.git] / arch / arm / arm_cm3 / drivers / Pwm.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 /*\r
16  * Pwm.c\r
17  *\r
18  *  Created on: 2009-okt-02\r
19  *      Author: jonte\r
20  */\r
21 #include "Std_Types.h"\r
22 #include "Det.h"\r
23 #include "Mcu.h"\r
24 #include "Os.h"\r
25 #include "Pwm.h"\r
26 #include "stm32f10x_tim.h"\r
27 #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
28 #include "isr.h"\r
29 #include "irq.h"\r
30 #include "arc.h"\r
31 #endif\r
32 \r
33 #if defined(USE_DET)\r
34 #       define Pwm_Det_ReportError(ApiId, ErrorId) Det_ReportError( MODULE_ID_PWM, 0, ApiId, ErrorId);\r
35 #else\r
36 #   define Pwm_Det_ReportError(ApiId, ErrorId)\r
37 #endif\r
38 \r
39 #if PWM_DEV_ERROR_DETECT==STD_ON\r
40         #define PWM_VALIDATE(_exp, _apiid, _errid) \\r
41                 if (!(_exp)) { \\r
42                         Pwm_Det_ReportError( _apiid, _errid); \\r
43                         return; \\r
44                 }\r
45         #define Pwm_VALIDATE_CHANNEL(_apiid, _ch) PWM_VALIDATE( (_ch <= PWM_TOTAL_NOF_CHANNELS), _apiid, PWM_E_PARAM_CHANNEL)\r
46         #define Pwm_VALIDATE_INITIALIZED(_apiid) PWM_VALIDATE( (Pwm_ModuleState == PWM_STATE_INITIALIZED), _apiid, PWM_E_UNINIT)\r
47         #define Pwm_VALIDATE_UNINITIALIZED(_apiid) PWM_VALIDATE( (Pwm_ModuleState != PWM_STATE_INITIALIZED), _apiid, PWM_E_ALREADY_INITIALIZED)\r
48 #else\r
49         #define PWM_VALIDATE(_exp, _apiid, _errid)\r
50         #define Pwm_VALIDATE_CHANNEL(_apiid, _ch)\r
51         #define Pwm_VALIDATE_INITIALIZED(_apiid)\r
52         #define Pwm_VALIDATE_UNINITIALIZED(_apiid)\r
53 #endif\r
54 \r
55 typedef enum {\r
56         PWM_STATE_UNINITIALIZED, PWM_STATE_INITIALIZED\r
57 } Pwm_ModuleStateType;\r
58 \r
59 static Pwm_ModuleStateType Pwm_ModuleState = PWM_STATE_UNINITIALIZED;\r
60 \r
61 /* Local functions */\r
62 #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
63 static void Pwm_Isr(void);\r
64 #endif\r
65 \r
66 static TIM_TypeDef * GetTimeBaseFromChannel(Pwm_ChannelType Channel)\r
67 {\r
68         TIM_TypeDef *TIMx;\r
69 \r
70         if(Channel < PWM_CHANNEL_21){\r
71                 TIMx = (TIM_TypeDef *)TIM1_BASE;\r
72         } else if(Channel < PWM_CHANNEL_31){\r
73                 TIMx = (TIM_TypeDef *)TIM2_BASE;\r
74         } else if(Channel < PWM_CHANNEL_41){\r
75                 TIMx = (TIM_TypeDef *)TIM3_BASE;\r
76         }else if(Channel <= PWM_CHANNEL_44){\r
77                 TIMx = (TIM_TypeDef *)TIM4_BASE;\r
78         }\r
79 \r
80         return TIMx;\r
81 }\r
82 \r
83 void Pwm_Init( const Pwm_ConfigType *ConfigPtr )\r
84 {\r
85     uint8 i;\r
86     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;\r
87     TIM_OCInitTypeDef  TIM_OCInitStructure;\r
88 \r
89     Pwm_VALIDATE_UNINITIALIZED( PWM_INIT_ID );\r
90         /*\r
91          * PWM046: If development error detection is enabled for the Pwm module,\r
92          * the function Pwm_Init shall raise development error PWM_E_PARAM_CONFIG\r
93          * if ConfigPtr is a null pointer.\r
94          *\r
95          * PWM120: For pre-compile and link-time configuration variants, a NULL\r
96          * pointer shall be passed to the initialization routine. In this case the\r
97          * check for this NULL pointer has to be omitted.\r
98          */\r
99         #if PWM_STATICALLY_CONFIGURED==STD_OFF\r
100                 PWM_VALIDATE((ConfigPtr != NULL), PWM_INIT_ID, PWM_E_PARAM_CONFIG);\r
101         #endif\r
102         \r
103   for (i=0;i<PWM_NUMBER_OF_CHANNELS;i++){\r
104     TIM_TypeDef *TIMx;\r
105 \r
106     TIMx = GetTimeBaseFromChannel(ConfigPtr->Channels[i].channel);\r
107   \r
108   /* -----------------------------------------------------------------------\r
109      TIM4CLK = 72 MHz, Prescaler = 7199, TIM4 counter clock = 72 MHz\r
110      TIM4 ARR Register = 10000 => TIM4 Frequency = TIM4 counter clock/(ARR*(PSC + 1)\r
111      TIM4 Frequency = 1 Hz.\r
112      TIM4 Channel1 duty cycle = (TIM4_CCR1/ TIM4_ARR)* 100 = 12.5%\r
113      ----------------------------------------------------------------------- */\r
114 \r
115     /* Time base configuration */\r
116     TIM_TimeBaseStructure.TIM_Period = ConfigPtr->Channels[i].r.period;\r
117     TIM_TimeBaseStructure.TIM_Prescaler = ConfigPtr->Channels[i].r.prescaler;\r
118     TIM_TimeBaseStructure.TIM_ClockDivision = 0;\r
119     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;\r
120     TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);\r
121    \r
122     /* Mode configuration */\r
123     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;\r
124     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;\r
125     TIM_OCInitStructure.TIM_Pulse = ConfigPtr->Channels[i].r.duty;\r
126     if(ConfigPtr->Channels[i].r.edgePolarity == PWM_HIGH){\r
127         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;\r
128     }else{\r
129         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;\r
130     }\r
131     \r
132     if(ConfigPtr->Channels[i].channel%4 == 0){\r
133       TIM_OC1Init(TIMx, &TIM_OCInitStructure);\r
134       TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable);\r
135     } else if(ConfigPtr->Channels[i].channel%4 == 1){\r
136       TIM_OC2Init(TIMx, &TIM_OCInitStructure);\r
137       TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable);\r
138     } else if(ConfigPtr->Channels[i].channel%4 == 2){\r
139       TIM_OC3Init(TIMx, &TIM_OCInitStructure);\r
140       TIM_OC3PreloadConfig(TIMx, TIM_OCPreload_Enable);\r
141     } else if(ConfigPtr->Channels[i].channel%4 == 3){\r
142       TIM_OC4Init(TIMx, &TIM_OCInitStructure);\r
143       TIM_OC4PreloadConfig(TIMx, TIM_OCPreload_Enable);\r
144     }\r
145     \r
146     TIM_ARRPreloadConfig(TIMx, ENABLE);\r
147     \r
148     /* TIMx enable counter */\r
149     TIM_Cmd(TIMx, ENABLE);\r
150 \r
151   }\r
152 \r
153 #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
154   ISR_INSTALL_ISR2( "Pwm1", Pwm_Isr, TIM1_CC_IRQn, 6, 0 );\r
155   ISR_INSTALL_ISR2( "Pwm2", Pwm_Isr, TIM2_IRQn,    6, 0 );\r
156   ISR_INSTALL_ISR2( "Pwm3", Pwm_Isr, TIM3_IRQn,    6, 0 );\r
157   ISR_INSTALL_ISR2( "Pwm4", Pwm_Isr, TIM4_IRQn,    6, 0 );\r
158 #endif\r
159 \r
160   Pwm_ModuleState = PWM_STATE_INITIALIZED;\r
161 }\r
162 #if 0\r
163 void Pwm_DeInitChannel(Pwm_ChannelType Channel) {\r
164         Pwm_VALIDATE_CHANNEL(Channel);\r
165         Pwm_VALIDATE_INITIALIZED();\r
166 \r
167     TIM_TypeDef *TIMx;\r
168 \r
169     TIMx = GetTimeBaseFromChannel(Channel);\r
170     TIM_DeInit(TIMx);\r
171 \r
172     /*\r
173      * PWM052: The function Pwm_DeInit shall disable all notifications.\r
174      */\r
175     #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
176         Pwm_DisableNotification(Channel);\r
177     #endif\r
178 }\r
179 #endif\r
180 \r
181 void Pwm_DeInit( void )\r
182 {\r
183   Pwm_VALIDATE_INITIALIZED( PWM_DEINIT_ID );\r
184 \r
185   uint8 i;\r
186 \r
187   /*\r
188    * PWM052: The function Pwm_DeInit shall disable all notifications.\r
189    */\r
190   for (i=0;i<PWM_TOTAL_NOF_CHANNELS;i++){\r
191 #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
192       Pwm_DisableNotification(i);\r
193 #endif\r
194   }\r
195   TIM_DeInit(TIM1);\r
196   TIM_DeInit(TIM2);\r
197   TIM_DeInit(TIM3);\r
198   TIM_DeInit(TIM4);\r
199 \r
200   Pwm_ModuleState = PWM_STATE_UNINITIALIZED;\r
201 }\r
202 \r
203 void Pwm_SetDutyCycle( Pwm_ChannelType Channel, Pwm_DutyCycleType DutyCycle )\r
204 {\r
205   TIM_TypeDef *TIMx;\r
206   Pwm_VALIDATE_CHANNEL( PWM_SETDUTYCYCLE_ID, Channel );\r
207   Pwm_VALIDATE_INITIALIZED( PWM_SETDUTYCYCLE_ID );\r
208   \r
209   TIMx = GetTimeBaseFromChannel(Channel);\r
210 \r
211   /*\r
212    * PWM058: The width of the duty cycle parameter is 16 bits\r
213    *\r
214    * PWM059: The PWM module shall comply with the following scaling scheme\r
215    * for the duty cycle:\r
216    * 0x0    =   0%,\r
217    * 0x8000 = 100% */\r
218   DutyCycle = (DutyCycle * TIMx->ARR)>>15;\r
219     \r
220   if(Channel%4 == 0){\r
221     TIM_SetCompare1(TIMx,DutyCycle);\r
222   } else if(Channel%4 == 1){\r
223     TIM_SetCompare2(TIMx,DutyCycle);\r
224   } else if(Channel%4 == 2){\r
225     TIM_SetCompare3(TIMx,DutyCycle);\r
226   } else if(Channel%4 == 3){\r
227     TIM_SetCompare4(TIMx,DutyCycle);\r
228   }\r
229 }\r
230 \r
231 /*\r
232  * PWM083: The function Pwm_SetPeriodAndDuty shall be pre compile time\r
233  * changeable STD_ON/STD_OFF by the configuration parameter PwmSetPeriodAndDuty.\r
234  */\r
235 #if PWM_SET_PERIOD_AND_DUTY_API==STD_ON\r
236 void Pwm_SetPeriodAndDuty(Pwm_ChannelType Channel, Pwm_PeriodType Period,\r
237                 Pwm_DutyCycleType DutyCycle) {\r
238     TIM_TypeDef *TIMx;\r
239     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;\r
240 \r
241         Pwm_VALIDATE_INITIALIZED( PWM_SETPERIODANDDUTY_ID );\r
242         Pwm_VALIDATE_CHANNEL( PWM_SETPERIODANDDUTY_ID, Channel );\r
243 \r
244         TIMx = GetTimeBaseFromChannel(Channel);\r
245 \r
246     /* Time base configuration */\r
247     TIM_TimeBaseStructure.TIM_Period = Period;\r
248     TIM_TimeBaseStructure.TIM_Prescaler = TIMx->PSC; // get old prescaler\r
249     TIM_TimeBaseStructure.TIM_ClockDivision = 0;\r
250     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;\r
251     TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);\r
252 \r
253     Pwm_SetDutyCycle(Channel,DutyCycle);\r
254 }\r
255 #endif\r
256 \r
257 #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
258 void Pwm_DisableNotification(Pwm_ChannelType Channel) \r
259 {\r
260     TIM_TypeDef *TIMx;\r
261     uint16_t tim_it = 0;\r
262     Pwm_VALIDATE_CHANNEL( PWM_DISABLENOTIFICATION_ID, Channel );\r
263     Pwm_VALIDATE_INITIALIZED( PWM_DISABLENOTIFICATION_ID );\r
264 \r
265     TIMx = GetTimeBaseFromChannel(Channel);\r
266 \r
267     if(Channel%4 == 0){\r
268         tim_it = TIM_IT_CC1;\r
269     } else if(Channel%4 == 1){\r
270         tim_it = TIM_IT_CC2;\r
271     } else if(Channel%4 == 2){\r
272         tim_it = TIM_IT_CC3;\r
273     } else if(Channel%4 == 3){\r
274         tim_it = TIM_IT_CC4;\r
275     }\r
276 \r
277     TIM_ITConfig(TIMx, tim_it,DISABLE);\r
278 }\r
279 \r
280 void Pwm_EnableNotification(Pwm_ChannelType Channel,\r
281         Pwm_EdgeNotificationType Notification) \r
282 {\r
283     TIM_TypeDef *TIMx;\r
284     uint16_t tim_it = 0;\r
285     Pwm_VALIDATE_CHANNEL( PWM_ENABLENOTIFICATION_ID, Channel );\r
286     Pwm_VALIDATE_INITIALIZED( PWM_ENABLENOTIFICATION_ID );\r
287 \r
288     TIMx = GetTimeBaseFromChannel(Channel);\r
289 \r
290     if(Channel%4 == 0){\r
291         tim_it = TIM_IT_CC1;\r
292     } else if(Channel%4 == 1){\r
293         tim_it = TIM_IT_CC2;\r
294     } else if(Channel%4 == 2){\r
295         tim_it = TIM_IT_CC3;\r
296     } else if(Channel%4 == 3){\r
297         tim_it = TIM_IT_CC4;\r
298     }\r
299 \r
300     TIM_ITConfig(TIMx, tim_it,ENABLE);\r
301 }\r
302 \r
303 static void Pwm_Isr(void) {\r
304     ITStatus status = 0;\r
305     status = TIM_GetITStatus(TIM1, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);\r
306     if(status != 0){\r
307         TIM_ClearITPendingBit(TIM1, status);\r
308         status = 0;\r
309     }\r
310     status = TIM_GetITStatus(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);\r
311     if(status != 0){\r
312         TIM_ClearITPendingBit(TIM2, status);\r
313         status = 0;\r
314     }\r
315     status = TIM_GetITStatus(TIM3, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);\r
316     if(status != 0){\r
317         TIM_ClearITPendingBit(TIM3, status);\r
318         status = 0;\r
319     }\r
320     status = TIM_GetITStatus(TIM4, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);\r
321     if(status != 0){\r
322         TIM_ClearITPendingBit(TIM4, status);\r
323         status = 0;\r
324     }\r
325 }\r
326 #endif //PWM_NOTIFICATION_SUPPORTED==STD_ON\r
327 \r
328 void Pwm_SetOutputToIdle(Pwm_ChannelType Channel) {\r
329         TIM_TypeDef *TIMx;\r
330         Pwm_VALIDATE_CHANNEL( PWM_SETOUTPUTTOIDLE_ID, Channel );\r
331         Pwm_VALIDATE_INITIALIZED( PWM_SETOUTPUTTOIDLE_ID );\r
332 \r
333     TIMx = GetTimeBaseFromChannel(Channel);\r
334 \r
335     if(Channel%4 == 0){\r
336       TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Disable);\r
337     } else if(Channel%4 == 1){\r
338       TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Disable);\r
339     } else if(Channel%4 == 2){\r
340       TIM_OC3PreloadConfig(TIMx, TIM_OCPreload_Disable);\r
341     } else if(Channel%4 == 3){\r
342       TIM_OC4PreloadConfig(TIMx, TIM_OCPreload_Disable);\r
343     }\r
344 }\r
345 \r
346 /*\r
347  * PWM085: The function Pwm_GetOutputState shall be pre compile configurable\r
348  * STD_ON/STD_OFF by the configuration parameter PwmGetOutputState\r
349  */\r
350 #if PWM_GET_OUTPUT_STATE_API==STD_ON\r
351 /*\r
352  * PWM022: The function Pwm_GetOutputState shall read the internal state\r
353  * of the PWM output signal and return it.\r
354  */\r
355 Pwm_OutputStateType Pwm_GetOutputState(Pwm_ChannelType Channel) {\r
356 \r
357         // We need to return something, even in presence of errors\r
358         if (Channel >= PWM_TOTAL_NOF_CHANNELS) {\r
359                 Pwm_Det_ReportError( PWM_GETOUTPUTSTATE_ID, PWM_E_PARAM_CHANNEL );\r
360 \r
361                 /*\r
362                  * Accordingly to PWM025, we should return PWM_LOW on failure.\r
363                  */\r
364                 return PWM_LOW;\r
365 \r
366         } else if (Pwm_ModuleState != PWM_STATE_INITIALIZED) {\r
367                 Pwm_Det_ReportError( PWM_GETOUTPUTSTATE_ID, PWM_E_UNINIT );\r
368 \r
369                 /*\r
370                  * Accordingly to PWM025, we should return PWM_LOW on failure.\r
371                  */\r
372                 return PWM_LOW;\r
373 \r
374         }\r
375 \r
376         return PWM_LOW; // TODO: implement Pwm_GetOutputState\r
377 }\r
378 #endif\r
379 \r
380 void Pwm_GetVersionInfo(Std_VersionInfoType* VersionInfo) {\r
381         /* TODO: Implement Pwm_GetVersionInfo */\r
382 }\r