1 /* -------------------------------- Arctic Core ------------------------------
\r
2 * Arctic Core - the open source AUTOSAR platform http://arccore.com
\r
4 * Copyright (C) 2009 ArcCore AB <contact@arccore.com>
\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
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
14 * -------------------------------- Arctic Core ------------------------------*/
\r
18 * Created on: 2009-okt-02
\r
21 #include "Std_Types.h"
\r
26 #include "stm32f10x_tim.h"
\r
27 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
33 #if defined(USE_DET)
\r
34 # define Pwm_Det_ReportError(ApiId, ErrorId) Det_ReportError( MODULE_ID_PWM, 0, ApiId, ErrorId);
\r
36 # define Pwm_Det_ReportError(ApiId, ErrorId)
\r
39 #if PWM_DEV_ERROR_DETECT==STD_ON
\r
40 #define PWM_VALIDATE(_exp, _apiid, _errid) \
\r
42 Pwm_Det_ReportError( _apiid, _errid); \
\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
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
56 PWM_STATE_UNINITIALIZED, PWM_STATE_INITIALIZED
\r
57 } Pwm_ModuleStateType;
\r
59 static Pwm_ModuleStateType Pwm_ModuleState = PWM_STATE_UNINITIALIZED;
\r
61 /* Local functions */
\r
62 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
63 static void Pwm_Isr(void);
\r
66 static TIM_TypeDef * GetTimeBaseFromChannel(Pwm_ChannelType Channel)
\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
83 void Pwm_Init( const Pwm_ConfigType *ConfigPtr )
\r
86 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
\r
87 TIM_OCInitTypeDef TIM_OCInitStructure;
\r
89 Pwm_VALIDATE_UNINITIALIZED( PWM_INIT_ID );
\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
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
99 #if PWM_STATICALLY_CONFIGURED==STD_OFF
\r
100 PWM_VALIDATE((ConfigPtr != NULL), PWM_INIT_ID, PWM_E_PARAM_CONFIG);
\r
103 for (i=0;i<PWM_NUMBER_OF_CHANNELS;i++){
\r
106 TIMx = GetTimeBaseFromChannel(ConfigPtr->Channels[i].channel);
\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
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
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
129 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
\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
146 TIM_ARRPreloadConfig(TIMx, ENABLE);
\r
148 /* TIMx enable counter */
\r
149 TIM_Cmd(TIMx, ENABLE);
\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
160 Pwm_ModuleState = PWM_STATE_INITIALIZED;
\r
163 void Pwm_DeInitChannel(Pwm_ChannelType Channel) {
\r
164 Pwm_VALIDATE_CHANNEL(Channel);
\r
165 Pwm_VALIDATE_INITIALIZED();
\r
169 TIMx = GetTimeBaseFromChannel(Channel);
\r
173 * PWM052: The function Pwm_DeInit shall disable all notifications.
\r
175 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
176 Pwm_DisableNotification(Channel);
\r
181 void Pwm_DeInit( void )
\r
183 Pwm_VALIDATE_INITIALIZED( PWM_DEINIT_ID );
\r
188 * PWM052: The function Pwm_DeInit shall disable all notifications.
\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
200 Pwm_ModuleState = PWM_STATE_UNINITIALIZED;
\r
203 void Pwm_SetDutyCycle( Pwm_ChannelType Channel, Pwm_DutyCycleType DutyCycle )
\r
206 Pwm_VALIDATE_CHANNEL( PWM_SETDUTYCYCLE_ID, Channel );
\r
207 Pwm_VALIDATE_INITIALIZED( PWM_SETDUTYCYCLE_ID );
\r
209 TIMx = GetTimeBaseFromChannel(Channel);
\r
212 * PWM058: The width of the duty cycle parameter is 16 bits
\r
214 * PWM059: The PWM module shall comply with the following scaling scheme
\r
215 * for the duty cycle:
\r
218 DutyCycle = (DutyCycle * TIMx->ARR)>>15;
\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
232 * PWM083: The function Pwm_SetPeriodAndDuty shall be pre compile time
\r
233 * changeable STD_ON/STD_OFF by the configuration parameter PwmSetPeriodAndDuty.
\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
239 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
\r
241 Pwm_VALIDATE_INITIALIZED( PWM_SETPERIODANDDUTY_ID );
\r
242 Pwm_VALIDATE_CHANNEL( PWM_SETPERIODANDDUTY_ID, Channel );
\r
244 TIMx = GetTimeBaseFromChannel(Channel);
\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
253 Pwm_SetDutyCycle(Channel,DutyCycle);
\r
257 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
258 void Pwm_DisableNotification(Pwm_ChannelType Channel)
\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
265 TIMx = GetTimeBaseFromChannel(Channel);
\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
277 TIM_ITConfig(TIMx, tim_it,DISABLE);
\r
280 void Pwm_EnableNotification(Pwm_ChannelType Channel,
\r
281 Pwm_EdgeNotificationType Notification)
\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
288 TIMx = GetTimeBaseFromChannel(Channel);
\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
300 TIM_ITConfig(TIMx, tim_it,ENABLE);
\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
307 TIM_ClearITPendingBit(TIM1, status);
\r
310 status = TIM_GetITStatus(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);
\r
312 TIM_ClearITPendingBit(TIM2, status);
\r
315 status = TIM_GetITStatus(TIM3, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);
\r
317 TIM_ClearITPendingBit(TIM3, status);
\r
320 status = TIM_GetITStatus(TIM4, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4);
\r
322 TIM_ClearITPendingBit(TIM4, status);
\r
326 #endif //PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
328 void Pwm_SetOutputToIdle(Pwm_ChannelType Channel) {
\r
330 Pwm_VALIDATE_CHANNEL( PWM_SETOUTPUTTOIDLE_ID, Channel );
\r
331 Pwm_VALIDATE_INITIALIZED( PWM_SETOUTPUTTOIDLE_ID );
\r
333 TIMx = GetTimeBaseFromChannel(Channel);
\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
347 * PWM085: The function Pwm_GetOutputState shall be pre compile configurable
\r
348 * STD_ON/STD_OFF by the configuration parameter PwmGetOutputState
\r
350 #if PWM_GET_OUTPUT_STATE_API==STD_ON
\r
352 * PWM022: The function Pwm_GetOutputState shall read the internal state
\r
353 * of the PWM output signal and return it.
\r
355 Pwm_OutputStateType Pwm_GetOutputState(Pwm_ChannelType Channel) {
\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
362 * Accordingly to PWM025, we should return PWM_LOW on failure.
\r
366 } else if (Pwm_ModuleState != PWM_STATE_INITIALIZED) {
\r
367 Pwm_Det_ReportError( PWM_GETOUTPUTSTATE_ID, PWM_E_UNINIT );
\r
370 * Accordingly to PWM025, we should return PWM_LOW on failure.
\r
376 return PWM_LOW; // TODO: implement Pwm_GetOutputState
\r
380 void Pwm_GetVersionInfo(Std_VersionInfoType* VersionInfo) {
\r
381 /* TODO: Implement Pwm_GetVersionInfo */
\r