]> rtime.felk.cvut.cz Git - arc.git/blob - arch/ppc/mpc55xx/drivers/Pwm.c
Merge with 3ecb6845e742978827406b7da6f77dc350e6b55b
[arc.git] / arch / ppc / mpc55xx / 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 \r
17 \r
18 \r
19 #include <assert.h>\r
20 #include <string.h>\r
21 \r
22 #include "Pwm.h"\r
23 #include "MemMap.h"\r
24 #include "Det.h"\r
25 \r
26 #include "mpc55xx.h"\r
27 \r
28 #include "Os.h"\r
29 #include "Mcu.h"\r
30 #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
31 #include "isr.h"\r
32 #include "irq.h"\r
33 #include "arc.h"\r
34 #endif\r
35 \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_MPC5606B)\r
40         #define PWM_RUNTIME_CHANNEL_COUNT       64\r
41     #define CHANNELS_OK (Channel <= PWM_MAX_CHANNEL-1)\r
42 #elif defined(CFG_MPC5606S)\r
43         #define PWM_RUNTIME_CHANNEL_COUNT       48\r
44     #define CHANNELS_OK (((Channel <= PWM_MAX_CHANNEL-1) && (Channel >= 40)) || ((Channel <= 23) && (Channel >= 16)))\r
45 #else\r
46         #define PWM_RUNTIME_CHANNEL_COUNT       16\r
47         #define CHANNELS_OK (Channel < 16)\r
48 #endif\r
49 \r
50 const Pwm_ConfigType* PwmConfigPtr = NULL;\r
51 \r
52 typedef enum {\r
53         PWM_STATE_UNINITIALIZED, PWM_STATE_INITIALIZED\r
54 } Pwm_ModuleStateType;\r
55 \r
56 static Pwm_ModuleStateType Pwm_ModuleState = PWM_STATE_UNINITIALIZED;\r
57 \r
58 // Run-time variables\r
59 typedef struct {\r
60         #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
61                 Pwm_EdgeNotificationType NotificationState;\r
62         #endif\r
63 } Pwm_ChannelStructType;\r
64 \r
65 // We use Pwm_ChannelType as index here\r
66 Pwm_ChannelStructType ChannelRuntimeStruct[PWM_RUNTIME_CHANNEL_COUNT];\r
67 \r
68 \r
69 /* Local functions */\r
70 Std_ReturnType Pwm_ValidateInitialized(Pwm_APIServiceIDType apiId)\r
71 {\r
72         Std_ReturnType result = E_OK;\r
73     if( Pwm_ModuleState == PWM_STATE_UNINITIALIZED )\r
74     {\r
75 #if PWM_DEV_ERROR_DETECT==STD_ON\r
76         Det_ReportError(PWM_MODULE_ID,0, apiId,PWM_E_UNINIT);\r
77         result = E_NOT_OK;\r
78 #endif\r
79     }\r
80     return result;\r
81 }\r
82 \r
83 Std_ReturnType Pwm_ValidateChannel(Pwm_ChannelType Channel,Pwm_APIServiceIDType apiId)\r
84 {\r
85         Std_ReturnType result = E_OK;\r
86     if( !CHANNELS_OK  )\r
87     {\r
88 #if PWM_DEV_ERROR_DETECT==STD_ON\r
89         Det_ReportError(PWM_MODULE_ID,0, apiId,PWM_E_PARAM_CHANNEL);\r
90         result = E_NOT_OK;\r
91 #endif\r
92     }\r
93     return result;\r
94 }\r
95 \r
96 void Pwm_InitChannel(Pwm_ChannelType Channel);\r
97 #if PWM_DE_INIT_API==STD_ON\r
98 void Pwm_DeInitChannel(Pwm_ChannelType Channel);\r
99 #endif\r
100 \r
101 #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
102 static void Pwm_Isr(void);\r
103 #endif\r
104 \r
105 static void calcPeriodTicksAndPrescaler(\r
106                                 const Pwm_ChannelConfigurationType* channelConfig,\r
107                                 uint16_t* ticks, Pwm_ChannelPrescalerType* prescaler) {\r
108 \r
109         uint32_t pre_global = 0;\r
110         uint32_t f_in = 0;\r
111 \r
112 #if defined(CFG_MPC560X)\r
113         Pwm_ChannelType channel = channelConfig->channel;\r
114 \r
115         if(channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {\r
116                 f_in = McuE_GetPeripheralClock( PERIPHERAL_CLOCK_EMIOS_0 );\r
117                 pre_global = EMIOS_0.MCR.B.GPRE;\r
118         } else {\r
119                 f_in = McuE_GetPeripheralClock( PERIPHERAL_CLOCK_EMIOS_1 );\r
120                 pre_global = EMIOS_1.MCR.B.GPRE;\r
121         }\r
122 #else\r
123         f_in = McuE_GetPeripheralClock( PERIPHERAL_CLOCK_EMIOS );\r
124         pre_global = EMIOS.MCR.B.GPRE;\r
125 #endif\r
126 \r
127   uint32_t f_target = channelConfig->frequency;\r
128 \r
129   Pwm_ChannelPrescalerType pre;\r
130   uint32_t ticks_temp;\r
131 \r
132   if (channelConfig->prescaler == PWM_CHANNEL_PRESCALER_AUTO) {\r
133     // Go from lowest to highest prescaler\r
134     for (pre = PWM_CHANNEL_PRESCALER_1; pre < PWM_CHANNEL_PRESCALER_4; ++pre) {\r
135       ticks_temp = f_in / (f_target * (pre_global + 1) * (pre + 1)); // Calc ticks\r
136       if (ticks_temp > 0xffff) {\r
137         ticks_temp = 0xffff;  // Prescaler too low\r
138       } else {\r
139         break;                // Prescaler ok\r
140       }\r
141     }\r
142   } else {\r
143     pre = channelConfig->prescaler; // Use config setting\r
144     ticks_temp = f_in / (f_target * pre_global * (pre+1)); // Calc ticks\r
145     if (ticks_temp > 0xffff) {\r
146       ticks_temp = 0xffff;  // Prescaler too low\r
147     }\r
148   }\r
149 \r
150   (*ticks) = (uint16_t) ticks_temp;\r
151   (*prescaler) = pre;\r
152 }\r
153 \r
154 \r
155 static void configureChannel(const Pwm_ChannelConfigurationType* channelConfig){\r
156 \r
157         Pwm_ChannelType channel = channelConfig->channel;\r
158         volatile struct EMIOS_tag *emiosHw;\r
159 \r
160 #if defined(CFG_MPC560X)\r
161         if(channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {\r
162                 emiosHw = &EMIOS_0;\r
163         } else {\r
164                 emiosHw = &EMIOS_1;\r
165                 channel -= PWM_NUMBER_OF_EACH_EMIOS;\r
166         }\r
167 #else\r
168         emiosHw = &EMIOS;\r
169 #endif\r
170 \r
171 #if defined (CFG_MPC560X)\r
172         emiosHw->CH[channel].CCR.B.MODE = channelConfig->mode;\r
173         emiosHw->CH[channel].CCR.B.DMA = 0;\r
174         emiosHw->CH[channel].CCR.B.BSL = channelConfig->clksrc;\r
175         emiosHw->CH[channel].CCR.B.ODIS = 0;\r
176 #else\r
177         emiosHw->CH[channel].CCR.B.MODE = PWM_EMIOS_OPWM;\r
178         emiosHw->CH[channel].CCR.B.DMA = 0;\r
179         emiosHw->CH[channel].CCR.B.BSL = 3;\r
180         emiosHw->CH[channel].CCR.B.ODIS = 0;\r
181 #endif\r
182 \r
183         Pwm_ChannelPrescalerType prescaler;  uint16_t period_ticks;\r
184         calcPeriodTicksAndPrescaler( channelConfig, &period_ticks, &prescaler );\r
185 \r
186         emiosHw->CH[channel].CBDR.R = period_ticks;\r
187         emiosHw->CH[channel].CCR.B.UCPRE = prescaler;\r
188 #if defined (CFG_MPC560X)\r
189         emiosHw->CH[channel].CCR.B.UCPEN = 1;\r
190 #else\r
191         emiosHw->CH[channel].CCR.B.UCPREN = 1;\r
192 #endif\r
193 \r
194         // 0 A match on comparator A clears the output flip-flop, while a match on comparator B sets it\r
195         // 1 A match on comparator A sets the output flip-flop, while a match on comparator B clears it\r
196         // A duty cycle of X % should give a signal with state 'channelConfig->polarity' during\r
197         // X % of the period time.\r
198         emiosHw->CH[channel].CCR.B.EDPOL = (channelConfig->polarity == PWM_LOW) ? 1 : 0;\r
199 }\r
200 \r
201 void Pwm_Init(const Pwm_ConfigType* ConfigPtr) {\r
202     Pwm_ChannelType channel_iterator;\r
203 \r
204     /** @req PWM118 */\r
205     /** @req PWM121 */\r
206     if( Pwm_ModuleState == PWM_STATE_INITIALIZED ) {\r
207 #if PWM_DEV_ERROR_DETECT==STD_ON\r
208         Det_ReportError(PWM_MODULE_ID,0,PWM_INIT_ID,PWM_E_ALREADY_INITIALIZED);\r
209 #endif\r
210         return;\r
211     }\r
212 \r
213     #if defined(CFG_MPC5606S) && !defined(CFG_MPC560XB)\r
214                 CGM.AC1_SC.R = 0x03000000; /* MPC56xxS: Select aux. set 1 clock to be FMPLL0 */\r
215                 CGM.AC2_SC.R = 0x03000000; /* MPC56xxS: Select aux. set 2 clock to be FMPLL0 */\r
216         #endif\r
217         \r
218     #if PWM_DEV_ERROR_DETECT==STD_ON\r
219         /*\r
220          * PWM046: If development error detection is enabled for the Pwm module,\r
221          * the function Pwm_Init shall raise development error PWM_E_PARAM_CONFIG\r
222          * if ConfigPtr is a null pointer.\r
223          *\r
224          * PWM120: For pre-compile and link-time configuration variants, a NULL\r
225          * pointer shall be passed to the initialization routine. In this case the\r
226          * check for this NULL pointer has to be omitted.\r
227          */\r
228         #if PWM_STATICALLY_CONFIGURED==STD_OFF\r
229             if (ConfigPtr == NULL) {\r
230                 Det_ReportError(PWM_MODULE_ID,0,PWM_INIT_ID,PWM_E_PARAM_CONFIG);\r
231                 return;\r
232             }\r
233         #endif\r
234     #endif\r
235 \r
236     PwmConfigPtr = ConfigPtr;\r
237 \r
238         #if defined(CFG_MPC560X)\r
239                 /* Clock scaler uses system clock (~64MHz) as source, so prescaler 64 => 1MHz. */\r
240                 EMIOS_0.MCR.B.GPRE = PWM_PRESCALER_EMIOS_0 - 1;\r
241                 EMIOS_1.MCR.B.GPRE = PWM_PRESCALER_EMIOS_1 - 1;\r
242 \r
243                 /* Enable eMIOS clock */\r
244                 EMIOS_0.MCR.B.GPREN = 1;\r
245                 EMIOS_1.MCR.B.GPREN = 1;\r
246 \r
247                 /* Stop channels when in debug mode */\r
248                 EMIOS_0.MCR.B.FRZ = PWM_FREEZE_ENABLE;\r
249                 EMIOS_1.MCR.B.FRZ = PWM_FREEZE_ENABLE;\r
250 \r
251                 /* Use global time base */\r
252                 EMIOS_0.MCR.B.GTBE = 1;\r
253                 EMIOS_1.MCR.B.GTBE = 1;\r
254         #else\r
255                 /* Clock scaler uses system clock (~64MHz) as source, so prescaler 64 => 1MHz. */\r
256                 EMIOS.MCR.B.GPRE = PWM_PRESCALER - 1;\r
257 \r
258                 /* Enable eMIOS clock */\r
259                 EMIOS.MCR.B.GPREN = 1;\r
260 \r
261                 /* Stop channels when in debug mode */\r
262                 EMIOS.MCR.B.FRZ = PWM_FREEZE_ENABLE;\r
263 \r
264                 /* Use global time base */\r
265                 EMIOS.MCR.B.GTBE = 1;\r
266         #endif\r
267 \r
268     Pwm_ModuleState = PWM_STATE_INITIALIZED;\r
269 \r
270     for (channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++) {\r
271         const Pwm_ChannelConfigurationType* channelConfig = &ConfigPtr->Channels[channel_iterator];\r
272         Pwm_ChannelType channel = channelConfig->channel;\r
273 \r
274         configureChannel( channelConfig );\r
275 \r
276         #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
277                 /*\r
278                  * PWM052: The function Pwm_Init shall disable all notifications.\r
279                  *\r
280                  * This is now implemented in the configuration macro.\r
281                  */\r
282                 // Pwm_DisableNotification(channel);\r
283 \r
284                 // Install ISR\r
285                         #if defined(CFG_MPC560XB)\r
286                                 switch(channel)\r
287                                 {\r
288                                 case 0:\r
289                                 case 1:\r
290                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F0_F1),PWM_ISR_PRIORITY, 0);\r
291                                         break;\r
292                                 case 2:\r
293                                 case 3:\r
294                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F2_F3),PWM_ISR_PRIORITY, 0);\r
295                                         break;\r
296                                 case 4:\r
297                                 case 5:\r
298                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F4_F5),PWM_ISR_PRIORITY, 0);\r
299                                         break;\r
300                                 case 6:\r
301                                 case 7:\r
302                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F6_F7),PWM_ISR_PRIORITY, 0);\r
303                                         break;\r
304                                 case 8:\r
305                                 case 9:\r
306                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F8_F9),PWM_ISR_PRIORITY, 0);\r
307                                         break;\r
308                                 case 10:\r
309                                 case 11:\r
310                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F10_F11),PWM_ISR_PRIORITY, 0);\r
311                                         break;\r
312                                 case 12:\r
313                                 case 13:\r
314                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F12_F13),PWM_ISR_PRIORITY, 0);\r
315                                         break;\r
316                                 case 14:\r
317                                 case 15:\r
318                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F14_F15),PWM_ISR_PRIORITY, 0);\r
319                                         break;\r
320                                 case 16:\r
321                                 case 17:\r
322                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F16_F17),PWM_ISR_PRIORITY, 0);\r
323                                         break;\r
324                                 case 18:\r
325                                 case 19:\r
326                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F18_F19),PWM_ISR_PRIORITY, 0);\r
327                                         break;\r
328                                 case 20:\r
329                                 case 21:\r
330                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F20_F21),PWM_ISR_PRIORITY, 0);\r
331                                         break;\r
332                                 case 22:\r
333                                 case 23:\r
334                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F22_F23),PWM_ISR_PRIORITY, 0);\r
335                                         break;\r
336                                 case 24:\r
337                                 case 25:\r
338                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F24_F25),PWM_ISR_PRIORITY, 0);\r
339                                         break;\r
340                                 case 26:\r
341                                 case 27:\r
342                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F26_F27),PWM_ISR_PRIORITY, 0);\r
343                                         break;\r
344                                 case 28:\r
345                                 case 29:\r
346                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F0_F1),PWM_ISR_PRIORITY, 0);\r
347                                         break;\r
348                                 case 30:\r
349                                 case 31:\r
350                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F2_F3),PWM_ISR_PRIORITY, 0);\r
351                                         break;\r
352                                 case 32:\r
353                                 case 33:\r
354                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F4_F5),PWM_ISR_PRIORITY, 0);\r
355                                         break;\r
356                                 case 34:\r
357                                 case 35:\r
358                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F6_F7),PWM_ISR_PRIORITY, 0);\r
359                                         break;\r
360                                 case 36:\r
361                                 case 37:\r
362                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F8_F9),PWM_ISR_PRIORITY, 0);\r
363                                         break;\r
364                                 case 38:\r
365                                 case 39:\r
366                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F10_F11),PWM_ISR_PRIORITY, 0);\r
367                                         break;\r
368                                 case 40:\r
369                                 case 41:\r
370                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F12_F13),PWM_ISR_PRIORITY, 0);\r
371                                         break;\r
372                                 case 42:\r
373                                 case 43:\r
374                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F14_F15),PWM_ISR_PRIORITY, 0);\r
375                                         break;\r
376                                 case 44:\r
377                                 case 45:\r
378                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F16_F17),PWM_ISR_PRIORITY, 0);\r
379                                         break;\r
380                                 case 46:\r
381                                 case 47:\r
382                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F18_F19),PWM_ISR_PRIORITY, 0);\r
383                                         break;\r
384                                 case 48:\r
385                                 case 49:\r
386                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F20_F21),PWM_ISR_PRIORITY, 0);\r
387                                         break;\r
388                                 case 50:\r
389                                 case 51:\r
390                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F22_F23),PWM_ISR_PRIORITY, 0);\r
391                                         break;\r
392                                 case 52:\r
393                                 case 53:\r
394                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F24_F25),PWM_ISR_PRIORITY, 0);\r
395                                         break;\r
396                                 case 54:\r
397                                 case 55:\r
398                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F26_F27),PWM_ISR_PRIORITY, 0);\r
399                                         break;\r
400                                 default:\r
401                                         break;\r
402                                 }\r
403                         #elif defined(CFG_MPC5606S)\r
404                                 switch(channel)\r
405                                 {\r
406                                 case 16:\r
407                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F16_F17),PWM_ISR_PRIORITY, 0);\r
408                                         break;\r
409                                 case 17:\r
410                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F16_F17),PWM_ISR_PRIORITY, 0);\r
411                             break;\r
412                                 case 18:\r
413                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F18_F19),PWM_ISR_PRIORITY, 0);\r
414                                         break;\r
415                                 case 19:\r
416                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F18_F19),PWM_ISR_PRIORITY, 0);\r
417                             break;\r
418                                 case 20:\r
419                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F20_F21),PWM_ISR_PRIORITY, 0);\r
420                                         break;\r
421                                 case 21:\r
422                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F20_F21),PWM_ISR_PRIORITY, 0);\r
423                             break;\r
424                                 case 22:\r
425                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F22_F23),PWM_ISR_PRIORITY, 0);\r
426                                         break;\r
427                                 case 23:\r
428                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_0_GFR_F22_F23),PWM_ISR_PRIORITY, 0);\r
429                             break;\r
430                                 case 40:\r
431                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F16_F17),PWM_ISR_PRIORITY, 0);\r
432                                         break;\r
433                                 case 41:\r
434                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F16_F17),PWM_ISR_PRIORITY, 0);\r
435                             break;\r
436                                 case 42:\r
437                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F18_F19),PWM_ISR_PRIORITY, 0);\r
438                                         break;\r
439                                 case 43:\r
440                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F18_F19),PWM_ISR_PRIORITY, 0);\r
441                             break;\r
442                                 case 44:\r
443                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F20_F21),PWM_ISR_PRIORITY, 0);\r
444                                         break;\r
445                                 case 45:\r
446                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F20_F21),PWM_ISR_PRIORITY, 0);\r
447                             break;\r
448                                 case 46:\r
449                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F22_F23),PWM_ISR_PRIORITY, 0);\r
450                                         break;\r
451                                 case 47:\r
452                                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMIOS_1_GFR_F22_F23),PWM_ISR_PRIORITY, 0);\r
453                             break;\r
454                                 default:\r
455                                         break;\r
456                             }\r
457                         #else\r
458                                 switch(channel)\r
459                                 {\r
460                                 case 0:\r
461                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F0),PWM_ISR_PRIORITY, 0);\r
462                                         break;\r
463                                 case 1:\r
464                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F1),PWM_ISR_PRIORITY, 0);\r
465                                         break;\r
466                                 case 2:\r
467                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F2),PWM_ISR_PRIORITY, 0);\r
468                                         break;\r
469                                 case 3:\r
470                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F3),PWM_ISR_PRIORITY, 0);\r
471                                         break;\r
472                                 case 4:\r
473                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F4),PWM_ISR_PRIORITY, 0);\r
474                                         break;\r
475                                 case 5:\r
476                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F5),PWM_ISR_PRIORITY, 0);\r
477                                         break;\r
478                                 case 6:\r
479                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F6),PWM_ISR_PRIORITY, 0);\r
480                                         break;\r
481                                 case 7:\r
482                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F7),PWM_ISR_PRIORITY, 0);\r
483                                         break;\r
484                                 case 8:\r
485                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F8),PWM_ISR_PRIORITY, 0);\r
486                                         break;\r
487                                 case 9:\r
488                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F9),PWM_ISR_PRIORITY, 0);\r
489                                         break;\r
490                                 case 10:\r
491                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F10),PWM_ISR_PRIORITY, 0);\r
492                                         break;\r
493                                 case 11:\r
494                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F11),PWM_ISR_PRIORITY, 0);\r
495                                         break;\r
496                                 case 12:\r
497                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F12),PWM_ISR_PRIORITY, 0);\r
498                                         break;\r
499                                 case 13:\r
500                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F13),PWM_ISR_PRIORITY, 0);\r
501                                         break;\r
502                                 case 14:\r
503                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F14),PWM_ISR_PRIORITY, 0);\r
504                                         break;\r
505                                 case 15:\r
506                         ISR_INSTALL_ISR2("PwmIsr", Pwm_Isr, (IrqType)(EMISOS200_FLAG_F15),PWM_ISR_PRIORITY, 0);\r
507                                         break;\r
508                                 default:\r
509                                         break;\r
510                             }\r
511                 #endif\r
512 \r
513                 #endif\r
514     }\r
515 }\r
516 \r
517 #if PWM_DE_INIT_API==STD_ON\r
518 \r
519 void inline Pwm_DeInitChannel(Pwm_ChannelType Channel) {\r
520     Pwm_SetOutputToIdle(Channel);\r
521 \r
522         #if defined(CFG_MPC5516)\r
523         // Set the disable bit for this channel\r
524         EMIOS.UCDIS.R |= (1 << (31 - Channel));\r
525     #elif defined(CFG_MPC560X)\r
526         // Set the disable bit for this channel\r
527         if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1)\r
528         {\r
529                 EMIOS_0.UCDIS.R |= (1 << (Channel));\r
530         }\r
531         else\r
532         {\r
533                 EMIOS_1.UCDIS.R |= (1 << (Channel-PWM_NUMBER_OF_EACH_EMIOS));\r
534         }\r
535         #endif\r
536 \r
537     /*\r
538      * PWM052: The function Pwm_DeInit shall disable all notifications.\r
539      */\r
540     #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
541         Pwm_DisableNotification(Channel);\r
542     #endif\r
543 }\r
544 \r
545 void Pwm_DeInit() {\r
546         Pwm_ChannelType channel_iterator;\r
547 \r
548         if(E_OK != Pwm_ValidateInitialized(PWM_DEINIT_ID))\r
549         {\r
550                 return;\r
551         }\r
552 \r
553         for (channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++) {\r
554                 Pwm_ChannelType channel = PwmConfigPtr->Channels[channel_iterator].channel;\r
555                 Pwm_DeInitChannel(channel);\r
556         }\r
557 \r
558         // Disable module\r
559         #if defined(CFG_MPC5516) || defined(CFG_MPC5567)\r
560                 EMIOS.MCR.B.MDIS = 1;\r
561     #elif defined(CFG_MPC560X)\r
562                 EMIOS_0.MCR.B.MDIS = 1;\r
563                 EMIOS_1.MCR.B.MDIS = 1;\r
564         #endif\r
565 \r
566         Pwm_ModuleState = PWM_STATE_UNINITIALIZED;\r
567 }\r
568 #endif\r
569 \r
570 \r
571 /*\r
572  * PWM083: The function Pwm_SetPeriodAndDuty shall be pre compile time\r
573  * changeable ON/OFF by the configuration parameter PwmSetPeriodAndDuty.\r
574  */\r
575 #if PWM_SET_PERIOD_AND_DUTY_API==STD_ON\r
576         void Pwm_SetPeriodAndDuty(Pwm_ChannelType Channel, Pwm_PeriodType Period,\r
577                         Pwm_DutyCycleType DutyCycle) {\r
578 \r
579                 if ((E_OK != Pwm_ValidateInitialized(PWM_SETPERIODANDDUTY_ID)) ||\r
580                         (E_OK != Pwm_ValidateChannel(Channel, PWM_SETPERIODANDDUTY_ID)))\r
581                 {\r
582                         return;\r
583                 }\r
584 \r
585                 for (Pwm_ChannelType channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++)\r
586                 {\r
587                         if(Channel == PwmConfigPtr->Channels[channel_iterator].channel){\r
588                                 if(PwmConfigPtr->ChannelClass[channel_iterator] != PWM_VARIABLE_PERIOD){\r
589                 #if PWM_DEV_ERROR_DETECT==STD_ON\r
590                                         Det_ReportError(PWM_MODULE_ID,0, PWM_SETPERIODANDDUTY_ID, PWM_E_PERIOD_UNCHANGEABLE);\r
591                 #endif\r
592                                         return;\r
593                                 }\r
594                                 break;\r
595                         }\r
596                 }\r
597 \r
598                 volatile struct EMIOS_tag *emiosHw;\r
599 #if defined(CFG_MPC560X)\r
600                 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {\r
601                         emiosHw = &EMIOS_0;\r
602                 } else {\r
603                         emiosHw = &EMIOS_1;\r
604                         Channel -= PWM_NUMBER_OF_EACH_EMIOS;\r
605                 }\r
606 #else\r
607                 emiosHw = &EMIOS;\r
608 #endif\r
609 \r
610                 uint16 leading_edge_position = (uint16) (((uint32) Period * (uint32) DutyCycle) >> 15);\r
611 \r
612                 /* Timer instant for leading edge */\r
613                 emiosHw->CH[Channel].CADR.R = leading_edge_position;\r
614 \r
615                 /* Timer instant for the period to restart */\r
616                 emiosHw->CH[Channel].CBDR.R = Period;\r
617         }\r
618 #endif\r
619 \r
620 \r
621 /**\r
622  * PWM013: The function Pwm_SetDutyCycle shall set the duty cycle of the PWM\r
623  * channel.\r
624  *\r
625  * @param Channel PWM channel to use. 0 <= Channel < PWM_NUMBER_OF_CHANNELS <= 16\r
626  * @param DutyCycle 0 <= DutyCycle <= 0x8000\r
627  */\r
628 #if PWM_SET_DUTY_CYCLE_API==STD_ON\r
629 void Pwm_SetDutyCycle(Pwm_ChannelType Channel, Pwm_DutyCycleType DutyCycle)\r
630 {\r
631         if ((E_OK != Pwm_ValidateInitialized(PWM_SETDUTYCYCLE_ID)) ||\r
632                 (E_OK != Pwm_ValidateChannel(Channel, PWM_SETDUTYCYCLE_ID)))\r
633         {\r
634                 return;\r
635         }\r
636         volatile struct EMIOS_tag *emiosHw;\r
637 #if defined(CFG_MPC560X)\r
638         if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {\r
639                 emiosHw = &EMIOS_0;\r
640         } else {\r
641                 emiosHw = &EMIOS_1;\r
642                 Channel -= PWM_NUMBER_OF_EACH_EMIOS;\r
643         }\r
644 #else\r
645         emiosHw = &EMIOS;\r
646 #endif\r
647 \r
648         uint16 leading_edge_position = (uint16) ((emiosHw->CH[Channel].CBDR.R\r
649                                 * (uint32) DutyCycle) >> 15);\r
650 \r
651         /* Timer instant for leading edge */\r
652 \r
653         /*\r
654          * PWM017: The function Pwm_SetDutyCycle shall update the duty cycle at\r
655          * the end of the period if supported by the implementation and configured\r
656          * with PwmDutycycleUpdatedEndperiod. [ This is achieved in hardware since\r
657          * the A and B registers are double buffered ]\r
658          *\r
659          * PWM014: The function Pwm_SetDutyCycle shall set the output state according\r
660          * to the configured polarity parameter [which is already set from\r
661          * Pwm_InitChannel], when the duty parameter is 0% [=0] or 100% [=0x8000].\r
662          */\r
663         emiosHw->CH[Channel].CADR.R = leading_edge_position;\r
664 }\r
665 #endif\r
666 \r
667 #if  PWM_SET_OUTPUT_TO_IDLE_API == STD_ON\r
668         void Pwm_SetOutputToIdle(Pwm_ChannelType Channel)\r
669         {\r
670                 if ((E_OK != Pwm_ValidateInitialized(PWM_SETOUTPUTTOIDLE_ID)) ||\r
671                         (E_OK != Pwm_ValidateChannel(Channel, PWM_SETOUTPUTTOIDLE_ID)))\r
672                 {\r
673                         return;\r
674                 }\r
675                 volatile struct EMIOS_tag *emiosHw;\r
676         #if defined(CFG_MPC560X)\r
677                 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {\r
678                         emiosHw = &EMIOS_0;\r
679                 } else {\r
680                         emiosHw = &EMIOS_1;\r
681                         Channel -= PWM_NUMBER_OF_EACH_EMIOS;\r
682                 }\r
683         #else\r
684                 emiosHw = &EMIOS;\r
685         #endif\r
686 \r
687                 emiosHw->CH[Channel].CADR.R = 0;\r
688     }\r
689 #endif\r
690 /*\r
691  * PWM085: The function Pwm_GetOutputState shall be pre compile configurable\r
692  * ON/OFF by the configuration parameter PwmGetOutputState\r
693  */\r
694 #if PWM_GET_OUTPUT_STATE_API==STD_ON\r
695         /*\r
696          * PWM022: The function Pwm_GetOutputState shall read the internal state\r
697          * of the PWM output signal and return it.\r
698          */\r
699         Pwm_OutputStateType Pwm_GetOutputState(Pwm_ChannelType Channel)\r
700         {\r
701                 if ((E_OK != Pwm_ValidateInitialized(PWM_GETOUTPUTSTATE_ID)) ||\r
702                         (E_OK != Pwm_ValidateChannel(Channel, PWM_GETOUTPUTSTATE_ID)))\r
703                 {\r
704                         return PWM_LOW;\r
705                 }\r
706 \r
707                 volatile struct EMIOS_tag *emiosHw;\r
708         #if defined(CFG_MPC560X)\r
709                 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {\r
710                         emiosHw = &EMIOS_0;\r
711                 } else {\r
712                         emiosHw = &EMIOS_1;\r
713                         Channel -= PWM_NUMBER_OF_EACH_EMIOS;\r
714                 }\r
715         #else\r
716                 emiosHw = &EMIOS;\r
717         #endif\r
718 \r
719                 return (Pwm_OutputStateType)emiosHw->CH[Channel].CSR.B.UCOUT;\r
720         }\r
721 #endif\r
722 \r
723 #if PWM_NOTIFICATION_SUPPORTED==STD_ON\r
724 \r
725         void Pwm_DisableNotification(Pwm_ChannelType Channel)\r
726         {\r
727                 if ((E_OK != Pwm_ValidateInitialized(PWM_DISABLENOTIFICATION_ID)) ||\r
728                         (E_OK != Pwm_ValidateChannel(Channel, PWM_DISABLENOTIFICATION_ID)))\r
729                 {\r
730                         return;\r
731                 }\r
732 \r
733                 volatile struct EMIOS_tag *emiosHw;\r
734         #if defined(CFG_MPC560X)\r
735                 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {\r
736                         emiosHw = &EMIOS_0;\r
737                 } else {\r
738                         emiosHw = &EMIOS_1;\r
739                         Channel -= PWM_NUMBER_OF_EACH_EMIOS;\r
740                 }\r
741         #else\r
742                 emiosHw = &EMIOS;\r
743         #endif\r
744 \r
745                 // Disable flags on this channel\r
746                 emiosHw->CH[Channel].CCR.B.FEN = 0;\r
747         }\r
748 \r
749         void Pwm_EnableNotification(Pwm_ChannelType Channel,Pwm_EdgeNotificationType Notification)\r
750         {\r
751                 if ((E_OK != Pwm_ValidateInitialized(PWM_ENABLENOTIFICATION_ID)) ||\r
752                         (E_OK != Pwm_ValidateChannel(Channel, PWM_ENABLENOTIFICATION_ID)))\r
753                 {\r
754                         return;\r
755                 }\r
756 \r
757                 volatile struct EMIOS_tag *emiosHw;\r
758         #if defined(CFG_MPC560X)\r
759                 if(Channel <= PWM_NUMBER_OF_EACH_EMIOS-1) {\r
760                         emiosHw = &EMIOS_0;\r
761                 } else {\r
762                         emiosHw = &EMIOS_1;\r
763                         Channel -= PWM_NUMBER_OF_EACH_EMIOS;\r
764                 }\r
765         #else\r
766                 emiosHw = &EMIOS;\r
767         #endif\r
768 \r
769                 ChannelRuntimeStruct[Channel].NotificationState = Notification;\r
770 \r
771                 emiosHw->CH[Channel].CCR.B.FEN = 1;\r
772         }\r
773 \r
774         static void Pwm_Isr(void)\r
775         {\r
776                 // Find out which channel that triggered the interrupt\r
777                 #if defined (CFG_MPC5516)\r
778                         uint32_t flagmask = EMIOS.GFLAG.R;\r
779                 #elif defined(CFG_MPC5567)\r
780                         uint32_t flagmask = EMIOS.GFR.R;\r
781         #endif\r
782 \r
783         #if defined(CFG_MPC5516) || defined(CFG_MPC5567)\r
784                         // There are 24 channels specified in the global flag register, but\r
785                         // we only listen to the first 16 as only these support OPWfM\r
786                         for (Pwm_ChannelType channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++)\r
787                         {\r
788                                 Pwm_ChannelType emios_ch = PwmConfigPtr->Channels[channel_iterator].channel;\r
789 \r
790                                 if (flagmask & (1 << emios_ch))\r
791                                 {\r
792                                         if (PwmConfigPtr->NotificationHandlers[channel_iterator] != NULL && EMIOS.CH[emios_ch].CCR.B.FEN)\r
793                                         {\r
794                                                 Pwm_EdgeNotificationType notification = ChannelRuntimeStruct[emios_ch].NotificationState;\r
795                                                 if (notification == PWM_BOTH_EDGES ||\r
796 \r
797                                                                 notification == EMIOS.CH[emios_ch].CSR.B.UCOUT)\r
798                                                 {\r
799                                                         PwmConfigPtr->NotificationHandlers[channel_iterator]();\r
800                                                 }\r
801                                         }\r
802 \r
803                                         // Clear interrupt\r
804                                         EMIOS.CH[emios_ch].CSR.B.FLAG = 1;\r
805                                 }\r
806                         }\r
807         #elif defined(CFG_MPC560X)\r
808                         uint32_t flagmask_0 = EMIOS_0.GFR.R;\r
809                         uint32_t flagmask_1 = EMIOS_1.GFR.R;\r
810 \r
811                         for (Pwm_ChannelType channel_iterator = 0; channel_iterator < PWM_NUMBER_OF_CHANNELS; channel_iterator++)\r
812                         {\r
813 \r
814                                 Pwm_ChannelType emios_ch = PwmConfigPtr->Channels[channel_iterator].channel;\r
815 \r
816                                 if (flagmask_0 & (1 << emios_ch))\r
817                                 {\r
818                                         if (PwmConfigPtr->NotificationHandlers[channel_iterator] != NULL && EMIOS_0.CH[emios_ch].CCR.B.FEN)\r
819                                         {\r
820                                                 Pwm_EdgeNotificationType notification = ChannelRuntimeStruct[emios_ch].NotificationState;\r
821                                                 if (notification == PWM_BOTH_EDGES ||\r
822 \r
823                                                                 notification == EMIOS_0.CH[emios_ch].CSR.B.UCOUT)\r
824                                                 {\r
825                                                         PwmConfigPtr->NotificationHandlers[channel_iterator]();\r
826                                                 }\r
827                                         }\r
828 \r
829                                         // Clear interrupt\r
830                                         EMIOS_0.CH[emios_ch].CSR.B.FLAG = 1;\r
831                                 }\r
832                                 else if (flagmask_1 & (1 << emios_ch - PWM_NUMBER_OF_EACH_EMIOS ))\r
833                                 {\r
834                                         if (PwmConfigPtr->NotificationHandlers[channel_iterator] != NULL && EMIOS_1.CH[emios_ch - PWM_NUMBER_OF_EACH_EMIOS].CCR.B.FEN)\r
835                                         {\r
836                                                 Pwm_EdgeNotificationType notification = ChannelRuntimeStruct[emios_ch].NotificationState;\r
837                                                 if (notification == PWM_BOTH_EDGES ||\r
838                                                                 notification == EMIOS_1.CH[emios_ch - PWM_NUMBER_OF_EACH_EMIOS].CSR.B.UCOUT)\r
839                                                         {\r
840                                                         PwmConfigPtr->NotificationHandlers[channel_iterator]();\r
841                                                         }\r
842                                                 }\r
843 \r
844                                         // Clear interrupt\r
845                                         EMIOS_1.CH[emios_ch - PWM_NUMBER_OF_EACH_EMIOS].CSR.B.FLAG = 1;\r
846                                 }\r
847                         }\r
848 \r
849                 #endif\r
850         }\r
851 \r
852 #endif /* PWM_NOTIFICATION_SUPPORED == STD_ON */\r