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
26 #include "mpc55xx.h"
\r
30 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
36 #if defined(CFG_MPC5604B)
\r
37 #define PWM_RUNTIME_CHANNEL_COUNT 56
\r
38 #define CHANNELS_OK (Channel <= PWM_MAX_CHANNEL-1)
\r
39 #elif defined(CFG_MPC5606S)
\r
40 #define PWM_RUNTIME_CHANNEL_COUNT 48
\r
41 #define CHANNELS_OK (((Channel <= PWM_MAX_CHANNEL-1) && (Channel >= 40)) || ((Channel <= 23) && (Channel >= 16)))
\r
43 #define PWM_RUNTIME_CHANNEL_COUNT 16
\r
44 #define CHANNELS_OK (Channel < 16)
\r
47 const Pwm_ConfigType* PwmConfigPtr = NULL;
\r
50 PWM_STATE_UNINITIALIZED, PWM_STATE_INITIALIZED
\r
51 } Pwm_ModuleStateType;
\r
53 static Pwm_ModuleStateType Pwm_ModuleState = PWM_STATE_UNINITIALIZED;
\r
55 // Run-time variables
\r
57 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
58 Pwm_EdgeNotificationType NotificationState;
\r
60 } Pwm_ChannelStructType;
\r
62 // We use Pwm_ChannelType as index here
\r
63 Pwm_ChannelStructType ChannelRuntimeStruct[PWM_RUNTIME_CHANNEL_COUNT];
\r
66 /* Local functions */
\r
67 Std_ReturnType Pwm_ValidateInitialized(Pwm_APIServiceIDType apiId)
\r
69 Std_ReturnType result = E_OK;
\r
70 if( Pwm_ModuleState == PWM_STATE_UNINITIALIZED )
\r
72 #if PWM_DEV_ERROR_DETECT==STD_ON
\r
73 Det_ReportError(PWM_MODULE_ID,0, apiId,PWM_E_UNINIT);
\r
80 Std_ReturnType Pwm_ValidateChannel(Pwm_ChannelType Channel,Pwm_APIServiceIDType apiId)
\r
82 Std_ReturnType result = E_OK;
\r
85 #if PWM_DEV_ERROR_DETECT==STD_ON
\r
86 Det_ReportError(PWM_MODULE_ID,0, apiId,PWM_E_PARAM_CHANNEL);
\r
93 void Pwm_InitChannel(Pwm_ChannelType Channel);
\r
94 #if PWM_DE_INIT_API==STD_ON
\r
95 void Pwm_DeInitChannel(Pwm_ChannelType Channel);
\r
98 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
99 static void Pwm_Isr(void);
\r
102 static void calcPeriodTicksAndPrescaler(
\r
103 const Pwm_ChannelConfigurationType* channelConfig,
\r
104 uint16_t* ticks, Pwm_ChannelPrescalerType* prescaler) {
\r
106 uint32_t pre_global = 0;
\r
109 #if defined(CFG_MPC560X)
\r
110 Pwm_ChannelType channel = channelConfig->channel;
\r
112 if(channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {
\r
113 f_in = McuE_GetPeripheralClock( PERIPHERAL_CLOCK_EMIOS_0 );
\r
114 pre_global = EMIOS_0.MCR.B.GPRE;
\r
116 f_in = McuE_GetPeripheralClock( PERIPHERAL_CLOCK_EMIOS_1 );
\r
117 pre_global = EMIOS_1.MCR.B.GPRE;
\r
120 f_in = McuE_GetPeripheralClock( PERIPHERAL_CLOCK_EMIOS );
\r
121 pre_global = EMIOS.MCR.B.GPRE;
\r
124 uint32_t f_target = channelConfig->frequency;
\r
126 Pwm_ChannelPrescalerType pre;
\r
127 uint32_t ticks_temp;
\r
129 if (channelConfig->prescaler == PWM_CHANNEL_PRESCALER_AUTO) {
\r
130 // Go from lowest to highest prescaler
\r
131 for (pre = PWM_CHANNEL_PRESCALER_1; pre < PWM_CHANNEL_PRESCALER_4; ++pre) {
\r
132 ticks_temp = f_in / (f_target * (pre_global + 1) * (pre + 1)); // Calc ticks
\r
133 if (ticks_temp > 0xffff) {
\r
134 ticks_temp = 0xffff; // Prescaler too low
\r
136 break; // Prescaler ok
\r
140 pre = channelConfig->prescaler; // Use config setting
\r
141 ticks_temp = f_in / (f_target * pre_global * (pre+1)); // Calc ticks
\r
142 if (ticks_temp > 0xffff) {
\r
143 ticks_temp = 0xffff; // Prescaler too low
\r
147 (*ticks) = (uint16_t) ticks_temp;
\r
148 (*prescaler) = pre;
\r
152 static void configureChannel(const Pwm_ChannelConfigurationType* channelConfig){
\r
154 Pwm_ChannelType channel = channelConfig->channel;
\r
155 volatile struct EMIOS_tag *emiosHw;
\r
157 #if defined(CFG_MPC560X)
\r
158 if(channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {
\r
159 emiosHw = &EMIOS_0;
\r
161 emiosHw = &EMIOS_1;
\r
162 channel -= PWM_NUMBER_OF_EACH_EMIOS;
\r
168 #if defined (CFG_MPC560X)
\r
169 emiosHw->CH[channel].CCR.B.MODE = channelConfig->mode;
\r
170 emiosHw->CH[channel].CCR.B.DMA = 0;
\r
171 emiosHw->CH[channel].CCR.B.BSL = channelConfig->clksrc;
\r
172 emiosHw->CH[channel].CCR.B.ODIS = 0;
\r
174 emiosHw->CH[channel].CCR.B.MODE = PWM_EMIOS_OPWM;
\r
175 emiosHw->CH[channel].CCR.B.DMA = 0;
\r
176 emiosHw->CH[channel].CCR.B.BSL = 3;
\r
177 emiosHw->CH[channel].CCR.B.ODIS = 0;
\r
180 Pwm_ChannelPrescalerType prescaler; uint16_t period_ticks;
\r
181 calcPeriodTicksAndPrescaler( channelConfig, &period_ticks, &prescaler );
\r
183 emiosHw->CH[channel].CBDR.R = period_ticks;
\r
184 emiosHw->CH[channel].CCR.B.UCPRE = prescaler;
\r
185 #if defined (CFG_MPC560X)
\r
186 emiosHw->CH[channel].CCR.B.UCPEN = 1;
\r
188 emiosHw->CH[channel].CCR.B.UCPREN = 1;
\r
191 // 0 A match on comparator A clears the output flip-flop, while a match on comparator B sets it
\r
192 // 1 A match on comparator A sets the output flip-flop, while a match on comparator B clears it
\r
193 // A duty cycle of X % should give a signal with state 'channelConfig->polarity' during
\r
194 // X % of the period time.
\r
195 emiosHw->CH[channel].CCR.B.EDPOL = (channelConfig->polarity == PWM_LOW) ? 1 : 0;
\r
198 void Pwm_Init(const Pwm_ConfigType* ConfigPtr) {
\r
199 Pwm_ChannelType channel_iterator;
\r
203 if( Pwm_ModuleState == PWM_STATE_INITIALIZED ) {
\r
204 #if PWM_DEV_ERROR_DETECT==STD_ON
\r
205 Det_ReportError(PWM_MODULE_ID,0,PWM_INIT_ID,PWM_E_ALREADY_INITIALIZED);
\r
210 #if defined(CFG_MPC5606S) && !defined(CFG_MPC5604B)
\r
211 CGM.AC1_SC.R = 0x03000000; /* MPC56xxS: Select aux. set 1 clock to be FMPLL0 */
\r
212 CGM.AC2_SC.R = 0x03000000; /* MPC56xxS: Select aux. set 2 clock to be FMPLL0 */
\r
215 #if PWM_DEV_ERROR_DETECT==STD_ON
\r
217 * PWM046: If development error detection is enabled for the Pwm module,
\r
218 * the function Pwm_Init shall raise development error PWM_E_PARAM_CONFIG
\r
219 * if ConfigPtr is a null pointer.
\r
221 * PWM120: For pre-compile and link-time configuration variants, a NULL
\r
222 * pointer shall be passed to the initialization routine. In this case the
\r
223 * check for this NULL pointer has to be omitted.
\r
225 #if PWM_STATICALLY_CONFIGURED==STD_OFF
\r
226 if (ConfigPtr == NULL) {
\r
227 Det_ReportError(PWM_MODULE_ID,0,PWM_INIT_ID,PWM_E_PARAM_CONFIG);
\r
233 PwmConfigPtr = ConfigPtr;
\r
235 #if defined(CFG_MPC560X)
\r
236 /* Clock scaler uses system clock (~64MHz) as source, so prescaler 64 => 1MHz. */
\r
237 EMIOS_0.MCR.B.GPRE = PWM_PRESCALER_EMIOS_0 - 1;
\r
238 EMIOS_1.MCR.B.GPRE = PWM_PRESCALER_EMIOS_1 - 1;
\r
240 /* Enable eMIOS clock */
\r
241 EMIOS_0.MCR.B.GPREN = 1;
\r
242 EMIOS_1.MCR.B.GPREN = 1;
\r
244 /* Stop channels when in debug mode */
\r
245 EMIOS_0.MCR.B.FRZ = PWM_FREEZE_ENABLE;
\r
246 EMIOS_1.MCR.B.FRZ = PWM_FREEZE_ENABLE;
\r
248 /* Use global time base */
\r
249 EMIOS_0.MCR.B.GTBE = 1;
\r
250 EMIOS_1.MCR.B.GTBE = 1;
\r
252 /* Clock scaler uses system clock (~64MHz) as source, so prescaler 64 => 1MHz. */
\r
253 EMIOS.MCR.B.GPRE = PWM_PRESCALER - 1;
\r
255 /* Enable eMIOS clock */
\r
256 EMIOS.MCR.B.GPREN = 1;
\r
258 /* Stop channels when in debug mode */
\r
259 EMIOS.MCR.B.FRZ = PWM_FREEZE_ENABLE;
\r
261 /* Use global time base */
\r
262 EMIOS.MCR.B.GTBE = 1;
\r
265 Pwm_ModuleState = PWM_STATE_INITIALIZED;
\r
267 for (channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++) {
\r
268 const Pwm_ChannelConfigurationType* channelConfig = &ConfigPtr->Channels[channel_iterator];
\r
269 Pwm_ChannelType channel = channelConfig->channel;
\r
271 configureChannel( channelConfig );
\r
273 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
275 * PWM052: The function Pwm_Init shall disable all notifications.
\r
277 * This is now implemented in the configuration macro.
\r
279 // Pwm_DisableNotification(channel);
\r
282 #if defined(CFG_MPC5604B)
\r
287 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F0_F1),PWM_ISR_PRIORITY, 0);
\r
291 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F2_F3),PWM_ISR_PRIORITY, 0);
\r
295 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F4_F5),PWM_ISR_PRIORITY, 0);
\r
299 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F6_F7),PWM_ISR_PRIORITY, 0);
\r
303 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F8_F9),PWM_ISR_PRIORITY, 0);
\r
307 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F10_F11),PWM_ISR_PRIORITY, 0);
\r
311 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F12_F13),PWM_ISR_PRIORITY, 0);
\r
315 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F14_F15),PWM_ISR_PRIORITY, 0);
\r
319 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F16_F17),PWM_ISR_PRIORITY, 0);
\r
323 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F18_F19),PWM_ISR_PRIORITY, 0);
\r
327 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F20_F21),PWM_ISR_PRIORITY, 0);
\r
331 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F22_F23),PWM_ISR_PRIORITY, 0);
\r
335 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F24_F25),PWM_ISR_PRIORITY, 0);
\r
339 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F26_F27),PWM_ISR_PRIORITY, 0);
\r
343 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F0_F1),PWM_ISR_PRIORITY, 0);
\r
347 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F2_F3),PWM_ISR_PRIORITY, 0);
\r
351 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F4_F5),PWM_ISR_PRIORITY, 0);
\r
355 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F6_F7),PWM_ISR_PRIORITY, 0);
\r
359 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F8_F9),PWM_ISR_PRIORITY, 0);
\r
363 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F10_F11),PWM_ISR_PRIORITY, 0);
\r
367 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F12_F13),PWM_ISR_PRIORITY, 0);
\r
371 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F14_F15),PWM_ISR_PRIORITY, 0);
\r
375 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F16_F17),PWM_ISR_PRIORITY, 0);
\r
379 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F18_F19),PWM_ISR_PRIORITY, 0);
\r
383 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F20_F21),PWM_ISR_PRIORITY, 0);
\r
387 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F22_F23),PWM_ISR_PRIORITY, 0);
\r
391 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F24_F25),PWM_ISR_PRIORITY, 0);
\r
395 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F26_F27),PWM_ISR_PRIORITY, 0);
\r
400 #elif defined(CFG_MPC5606S)
\r
404 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F16_F17),PWM_ISR_PRIORITY, 0);
\r
407 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F16_F17),PWM_ISR_PRIORITY, 0);
\r
410 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F18_F19),PWM_ISR_PRIORITY, 0);
\r
413 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F18_F19),PWM_ISR_PRIORITY, 0);
\r
416 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F20_F21),PWM_ISR_PRIORITY, 0);
\r
419 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F20_F21),PWM_ISR_PRIORITY, 0);
\r
422 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F22_F23),PWM_ISR_PRIORITY, 0);
\r
425 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F22_F23),PWM_ISR_PRIORITY, 0);
\r
428 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F16_F17),PWM_ISR_PRIORITY, 0);
\r
431 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F16_F17),PWM_ISR_PRIORITY, 0);
\r
434 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F18_F19),PWM_ISR_PRIORITY, 0);
\r
437 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F18_F19),PWM_ISR_PRIORITY, 0);
\r
440 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F20_F21),PWM_ISR_PRIORITY, 0);
\r
443 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F20_F21),PWM_ISR_PRIORITY, 0);
\r
446 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F22_F23),PWM_ISR_PRIORITY, 0);
\r
449 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F22_F23),PWM_ISR_PRIORITY, 0);
\r
458 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F0),PWM_ISR_PRIORITY, 0);
\r
461 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F1),PWM_ISR_PRIORITY, 0);
\r
464 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F2),PWM_ISR_PRIORITY, 0);
\r
467 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F3),PWM_ISR_PRIORITY, 0);
\r
470 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F4),PWM_ISR_PRIORITY, 0);
\r
473 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F5),PWM_ISR_PRIORITY, 0);
\r
476 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F6),PWM_ISR_PRIORITY, 0);
\r
479 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F7),PWM_ISR_PRIORITY, 0);
\r
482 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F8),PWM_ISR_PRIORITY, 0);
\r
485 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F9),PWM_ISR_PRIORITY, 0);
\r
488 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F10),PWM_ISR_PRIORITY, 0);
\r
491 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F11),PWM_ISR_PRIORITY, 0);
\r
494 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F12),PWM_ISR_PRIORITY, 0);
\r
497 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F13),PWM_ISR_PRIORITY, 0);
\r
500 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F14),PWM_ISR_PRIORITY, 0);
\r
503 ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F15),PWM_ISR_PRIORITY, 0);
\r
514 #if PWM_DE_INIT_API==STD_ON
\r
516 void inline Pwm_DeInitChannel(Pwm_ChannelType Channel) {
\r
517 Pwm_SetOutputToIdle(Channel);
\r
519 #if defined(CFG_MPC5516)
\r
520 // Set the disable bit for this channel
\r
521 EMIOS.UCDIS.R |= (1 << (31 - Channel));
\r
522 #elif defined(CFG_MPC560X)
\r
523 // Set the disable bit for this channel
\r
524 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1)
\r
526 EMIOS_0.UCDIS.R |= (1 << (Channel));
\r
530 EMIOS_1.UCDIS.R |= (1 << (Channel-PWM_NUMBER_OF_EACH_EMIOS));
\r
535 * PWM052: The function Pwm_DeInit shall disable all notifications.
\r
537 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
538 Pwm_DisableNotification(Channel);
\r
542 void Pwm_DeInit() {
\r
543 Pwm_ChannelType channel_iterator;
\r
545 if(E_OK != Pwm_ValidateInitialized(PWM_DEINIT_ID))
\r
550 for (channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++) {
\r
551 Pwm_ChannelType channel = PwmConfigPtr->Channels[channel_iterator].channel;
\r
552 Pwm_DeInitChannel(channel);
\r
556 #if defined(CFG_MPC5516) || defined(CFG_MPC5567)
\r
557 EMIOS.MCR.B.MDIS = 1;
\r
558 #elif defined(CFG_MPC560X)
\r
559 EMIOS_0.MCR.B.MDIS = 1;
\r
560 EMIOS_1.MCR.B.MDIS = 1;
\r
563 Pwm_ModuleState = PWM_STATE_UNINITIALIZED;
\r
569 * PWM083: The function Pwm_SetPeriodAndDuty shall be pre compile time
\r
570 * changeable ON/OFF by the configuration parameter PwmSetPeriodAndDuty.
\r
572 #if PWM_SET_PERIOD_AND_DUTY_API==STD_ON
\r
573 void Pwm_SetPeriodAndDuty(Pwm_ChannelType Channel, Pwm_PeriodType Period,
\r
574 Pwm_DutyCycleType DutyCycle) {
\r
576 if ((E_OK != Pwm_ValidateInitialized(PWM_SETPERIODANDDUTY_ID)) ||
\r
577 (E_OK != Pwm_ValidateChannel(Channel, PWM_SETPERIODANDDUTY_ID)))
\r
582 for (Pwm_ChannelType channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++)
\r
584 if(Channel == PwmConfigPtr->Channels[channel_iterator].channel){
\r
585 if(PwmConfigPtr->ChannelClass[channel_iterator] != PWM_VARIABLE_PERIOD){
\r
586 #if PWM_DEV_ERROR_DETECT==STD_ON
\r
587 Det_ReportError(PWM_MODULE_ID,0, PWM_SETPERIODANDDUTY_ID, PWM_E_PERIOD_UNCHANGEABLE);
\r
595 volatile struct EMIOS_tag *emiosHw;
\r
596 #if defined(CFG_MPC560X)
\r
597 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {
\r
598 emiosHw = &EMIOS_0;
\r
600 emiosHw = &EMIOS_1;
\r
601 Channel -= PWM_NUMBER_OF_EACH_EMIOS;
\r
607 uint16 leading_edge_position = (uint16) (((uint32) Period * (uint32) DutyCycle) >> 15);
\r
609 /* Timer instant for leading edge */
\r
610 emiosHw->CH[Channel].CADR.R = leading_edge_position;
\r
612 /* Timer instant for the period to restart */
\r
613 emiosHw->CH[Channel].CBDR.R = Period;
\r
619 * PWM013: The function Pwm_SetDutyCycle shall set the duty cycle of the PWM
\r
622 * @param Channel PWM channel to use. 0 <= Channel < PWM_NUMBER_OF_CHANNELS <= 16
\r
623 * @param DutyCycle 0 <= DutyCycle <= 0x8000
\r
625 #if PWM_SET_DUTY_CYCLE_API==STD_ON
\r
626 void Pwm_SetDutyCycle(Pwm_ChannelType Channel, Pwm_DutyCycleType DutyCycle)
\r
628 if ((E_OK != Pwm_ValidateInitialized(PWM_SETDUTYCYCLE_ID)) ||
\r
629 (E_OK != Pwm_ValidateChannel(Channel, PWM_SETDUTYCYCLE_ID)))
\r
633 volatile struct EMIOS_tag *emiosHw;
\r
634 #if defined(CFG_MPC560X)
\r
635 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {
\r
636 emiosHw = &EMIOS_0;
\r
638 emiosHw = &EMIOS_1;
\r
639 Channel -= PWM_NUMBER_OF_EACH_EMIOS;
\r
645 uint16 leading_edge_position = (uint16) ((emiosHw->CH[Channel].CBDR.R
\r
646 * (uint32) DutyCycle) >> 15);
\r
648 /* Timer instant for leading edge */
\r
651 * PWM017: The function Pwm_SetDutyCycle shall update the duty cycle at
\r
652 * the end of the period if supported by the implementation and configured
\r
653 * with PwmDutycycleUpdatedEndperiod. [ This is achieved in hardware since
\r
654 * the A and B registers are double buffered ]
\r
656 * PWM014: The function Pwm_SetDutyCycle shall set the output state according
\r
657 * to the configured polarity parameter [which is already set from
\r
658 * Pwm_InitChannel], when the duty parameter is 0% [=0] or 100% [=0x8000].
\r
660 emiosHw->CH[Channel].CADR.R = leading_edge_position;
\r
664 #if PWM_SET_OUTPUT_TO_IDLE_API == STD_ON
\r
665 void Pwm_SetOutputToIdle(Pwm_ChannelType Channel)
\r
667 if ((E_OK != Pwm_ValidateInitialized(PWM_SETOUTPUTTOIDLE_ID)) ||
\r
668 (E_OK != Pwm_ValidateChannel(Channel, PWM_SETOUTPUTTOIDLE_ID)))
\r
672 volatile struct EMIOS_tag *emiosHw;
\r
673 #if defined(CFG_MPC560X)
\r
674 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {
\r
675 emiosHw = &EMIOS_0;
\r
677 emiosHw = &EMIOS_1;
\r
678 Channel -= PWM_NUMBER_OF_EACH_EMIOS;
\r
684 emiosHw->CH[Channel].CADR.R = 0;
\r
688 * PWM085: The function Pwm_GetOutputState shall be pre compile configurable
\r
689 * ON/OFF by the configuration parameter PwmGetOutputState
\r
691 #if PWM_GET_OUTPUT_STATE_API==STD_ON
\r
693 * PWM022: The function Pwm_GetOutputState shall read the internal state
\r
694 * of the PWM output signal and return it.
\r
696 Pwm_OutputStateType Pwm_GetOutputState(Pwm_ChannelType Channel)
\r
698 if ((E_OK != Pwm_ValidateInitialized(PWM_GETOUTPUTSTATE_ID)) ||
\r
699 (E_OK != Pwm_ValidateChannel(Channel, PWM_GETOUTPUTSTATE_ID)))
\r
704 volatile struct EMIOS_tag *emiosHw;
\r
705 #if defined(CFG_MPC560X)
\r
706 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {
\r
707 emiosHw = &EMIOS_0;
\r
709 emiosHw = &EMIOS_1;
\r
710 Channel -= PWM_NUMBER_OF_EACH_EMIOS;
\r
716 return (Pwm_OutputStateType)emiosHw->CH[Channel].CSR.B.UCOUT;
\r
720 #if PWM_NOTIFICATION_SUPPORTED==STD_ON
\r
722 void Pwm_DisableNotification(Pwm_ChannelType Channel)
\r
724 if ((E_OK != Pwm_ValidateInitialized(PWM_DISABLENOTIFICATION_ID)) ||
\r
725 (E_OK != Pwm_ValidateChannel(Channel, PWM_DISABLENOTIFICATION_ID)))
\r
730 volatile struct EMIOS_tag *emiosHw;
\r
731 #if defined(CFG_MPC560X)
\r
732 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {
\r
733 emiosHw = &EMIOS_0;
\r
735 emiosHw = &EMIOS_1;
\r
736 Channel -= PWM_NUMBER_OF_EACH_EMIOS;
\r
742 // Disable flags on this channel
\r
743 emiosHw->CH[Channel].CCR.B.FEN = 0;
\r
746 void Pwm_EnableNotification(Pwm_ChannelType Channel,Pwm_EdgeNotificationType Notification)
\r
748 if ((E_OK != Pwm_ValidateInitialized(PWM_ENABLENOTIFICATION_ID)) ||
\r
749 (E_OK != Pwm_ValidateChannel(Channel, PWM_ENABLENOTIFICATION_ID)))
\r
754 volatile struct EMIOS_tag *emiosHw;
\r
755 #if defined(CFG_MPC560X)
\r
756 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {
\r
757 emiosHw = &EMIOS_0;
\r
759 emiosHw = &EMIOS_1;
\r
760 Channel -= PWM_NUMBER_OF_EACH_EMIOS;
\r
766 ChannelRuntimeStruct[Channel].NotificationState = Notification;
\r
768 emiosHw->CH[Channel].CCR.B.FEN = 1;
\r
771 static void Pwm_Isr(void)
\r
773 // Find out which channel that triggered the interrupt
\r
774 #if defined (CFG_MPC5516)
\r
775 uint32_t flagmask = EMIOS.GFLAG.R;
\r
776 #elif defined(CFG_MPC5567)
\r
777 uint32_t flagmask = EMIOS.GFR.R;
\r
780 #if defined(CFG_MPC5516) || defined(CFG_MPC5567)
\r
781 // There are 24 channels specified in the global flag register, but
\r
782 // we only listen to the first 16 as only these support OPWfM
\r
783 for (Pwm_ChannelType channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++)
\r
785 Pwm_ChannelType emios_ch = PwmConfigPtr->Channels[channel_iterator].channel;
\r
787 if (flagmask & (1 << emios_ch))
\r
789 if (PwmConfigPtr->NotificationHandlers[channel_iterator] != NULL && EMIOS.CH[emios_ch].CCR.B.FEN)
\r
791 Pwm_EdgeNotificationType notification = ChannelRuntimeStruct[emios_ch].NotificationState;
\r
792 if (notification == PWM_BOTH_EDGES ||
\r
794 notification == EMIOS.CH[emios_ch].CSR.B.UCOUT)
\r
796 PwmConfigPtr->NotificationHandlers[channel_iterator]();
\r
801 EMIOS.CH[emios_ch].CSR.B.FLAG = 1;
\r
804 #elif defined(CFG_MPC560X)
\r
805 uint32_t flagmask_0 = EMIOS_0.GFR.R;
\r
806 uint32_t flagmask_1 = EMIOS_1.GFR.R;
\r
808 for (Pwm_ChannelType channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++)
\r
811 Pwm_ChannelType emios_ch = PwmConfigPtr->Channels[channel_iterator].channel;
\r
813 if (flagmask_0 & (1 << emios_ch))
\r
815 if (PwmConfigPtr->NotificationHandlers[channel_iterator] != NULL && EMIOS_0.CH[emios_ch].CCR.B.FEN)
\r
817 Pwm_EdgeNotificationType notification = ChannelRuntimeStruct[emios_ch].NotificationState;
\r
818 if (notification == PWM_BOTH_EDGES ||
\r
820 notification == EMIOS_0.CH[emios_ch].CSR.B.UCOUT)
\r
822 PwmConfigPtr->NotificationHandlers[channel_iterator]();
\r
827 EMIOS_0.CH[emios_ch].CSR.B.FLAG = 1;
\r
829 else if (flagmask_1 & (1 << emios_ch - PWM_NUMBER_OF_EACH_EMIOS ))
\r
831 if (PwmConfigPtr->NotificationHandlers[channel_iterator] != NULL && EMIOS_1.CH[emios_ch - PWM_NUMBER_OF_EACH_EMIOS].CCR.B.FEN)
\r
833 Pwm_EdgeNotificationType notification = ChannelRuntimeStruct[emios_ch].NotificationState;
\r
834 if (notification == PWM_BOTH_EDGES ||
\r
835 notification == EMIOS_1.CH[emios_ch - PWM_NUMBER_OF_EACH_EMIOS].CSR.B.UCOUT)
\r
837 PwmConfigPtr->NotificationHandlers[channel_iterator]();
\r
842 EMIOS_1.CH[emios_ch - PWM_NUMBER_OF_EACH_EMIOS].CSR.B.FLAG = 1;
\r
849 #endif /* PWM_NOTIFICATION_SUPPORED == STD_ON */
\r