iLLD_TC27xC  1.0
IfxGtm_Tom_PwmHl.c
Go to the documentation of this file.
1 /**
2  * \file IfxGtm_Tom_PwmHl.c
3  * \brief _TOM PWMHL details
4  *
5  * \version iLLD_0_1_0_10
6  * \copyright Copyright (c) 2013 Infineon Technologies AG. All rights reserved.
7  *
8  *
9  * IMPORTANT NOTICE
10  *
11  *
12  * Infineon Technologies AG (Infineon) is supplying this file for use
13  * exclusively with Infineon's microcontroller products. This file can be freely
14  * distributed within development tools that are supporting such microcontroller
15  * products.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
18  * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
20  * INFINEON SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
21  * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
22  *
23  */
24 
25 /******************************************************************************/
26 /*----------------------------------Includes----------------------------------*/
27 /******************************************************************************/
28 
29 #include "IfxGtm_Tom_PwmHl.h"
30 #include "_Utilities/Ifx_Assert.h"
31 #include "stddef.h"
32 
33 /** \addtogroup IfxLld_Gtm_Tom_PwmHl_PwmHl_StdIf_Functions
34  * \{ */
35 /******************************************************************************/
36 /*------------------------Inline Function Prototypes--------------------------*/
37 /******************************************************************************/
38 
39 /** \brief Inverts the active state
40  * \param activeState Active state
41  * \return State
42  */
44 
45 /******************************************************************************/
46 /*-----------------------Private Function Prototypes--------------------------*/
47 /******************************************************************************/
48 
49 /** \brief Updates the x output duty cycle in center aligned and center aligned inverted modes
50  * \param driver GTM TOM PWM driver
51  * \param tOn T on
52  * \return None
53  */
54 static void IfxGtm_Tom_PwmHl_updateCenterAligned(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn);
55 
56 /** \brief Updates the x output duty cycle in edge aligned modes (left and right aligned)
57  * \param driver GTM TOM PWM driver
58  * \param tOn T on
59  * \return None
60  */
61 static void IfxGtm_Tom_PwmHl_updateEdgeAligned(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn);
62 
63 /** \brief Set the outputs to inactive
64  * \param driver GTM TOM PWM driver
65  * \param tOn T on
66  * \return None
67  */
68 static void IfxGtm_Tom_PwmHl_updateOff(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn);
69 
70 /** \} */
71 
72 /******************************************************************************/
73 /*------------------------Private Variables/Constants-------------------------*/
74 /******************************************************************************/
75 
76 static const IfxGtm_Tom_PwmHl_Mode IfxGtm_Tom_PwmHl_modes[5] = {
77  {FALSE, IfxGtm_Tom_PwmHl_updateCenterAligned}, // Ifx_Pwm_Mode_centerAligned
78  {TRUE, IfxGtm_Tom_PwmHl_updateCenterAligned}, // Ifx_Pwm_Mode_centerAlignedInverted
79  {FALSE, IfxGtm_Tom_PwmHl_updateEdgeAligned }, // Ifx_Pwm_Mode_leftAligned
80  {TRUE, IfxGtm_Tom_PwmHl_updateEdgeAligned }, // Ifx_Pwm_Mode_rightAligned
81  {FALSE, IfxGtm_Tom_PwmHl_updateOff } // Ifx_Pwm_Mode_off
82 };
83 
84 /******************************************************************************/
85 /*---------------------Inline Function Implementations------------------------*/
86 /******************************************************************************/
87 
89 {
91 }
92 
93 
94 /******************************************************************************/
95 /*-------------------------Function Implementations---------------------------*/
96 /******************************************************************************/
97 
99 {
100  return IfxStdIf_Timer_tickToS(driver->timer->base.clockFreq, driver->base.deadtime);
101 }
102 
103 
105 {
106  return IfxStdIf_Timer_tickToS(driver->timer->base.clockFreq, driver->base.minPulse - driver->base.deadtime);
107 }
108 
109 
111 {
112  return driver->base.mode;
113 }
114 
115 
117 {
118  boolean result = TRUE;
119  uint16 channelMask;
120  uint16 channelsMask = 0;
121  uint32 channelIndex;
122  uint16 maskShift = 0;
123  IfxGtm_Tom_Timer *timer = config->timer;
124 
125  /* driver.base must be at offset 0 to be compatible with the standard interface PwmHl */
126  IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, offsetof(IfxGtm_Tom_PwmHl, base) == 0);
127 
128  driver->base.mode = Ifx_Pwm_Mode_init;
129  driver->timer = timer;
130  driver->base.setMode = 0;
131  driver->base.inverted = FALSE;
132  driver->base.ccxActiveState = config->base.ccxActiveState;
133  driver->base.coutxActiveState = config->base.coutxActiveState;
134  driver->base.channelCount = config->base.channelCount;
135 
136  IfxGtm_Tom_PwmHl_setDeadtime(driver, config->base.deadtime);
137  IfxGtm_Tom_PwmHl_setMinPulse(driver, config->base.minPulse);
138 
139  driver->tom = &(timer->gtm->TOM[config->tom]);
140 
141  /* config->ccx[0] is used for the definition of the TGC */
142  if (config->ccx[0]->channel <= 7)
143  {
144  driver->tgc = IfxGtm_Tom_Ch_getTgcPointer(driver->tom, 0);
145  }
146  else
147  {
148  driver->tgc = IfxGtm_Tom_Ch_getTgcPointer(driver->tom, 1);
149  }
150 
151  maskShift = (config->ccx[0]->channel <= 7) ? 0 : 8;
152 
154 
156 
157  for (channelIndex = 0; channelIndex < config->base.channelCount; channelIndex++)
158  {
159  IfxGtm_Tom_Ch channel;
160  /* CCX */
161  channel = config->ccx[channelIndex]->channel;
162  driver->ccx[channelIndex] = channel;
163  channelMask = 1 << (channel - maskShift);
164  channelsMask |= channelMask;
165 
166  /* Initialize the timer part */
167  /* FIXME add IfxGtm_Tom_Ch_configurePwmMode() and use it */
168  IfxGtm_Tom_Ch_setClockSource(driver->tom, channel, clock);
169  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, driver->base.inverted
170  ? config->base.ccxActiveState
174 
175  /*Initialize the port */
176  IfxGtm_PinMap_setTomTout(config->ccx[channelIndex],
177  config->base.outputMode, config->base.outputDriver);
178 
179  /* COUTX */
180  channel = config->coutx[channelIndex]->channel;
181  driver->coutx[channelIndex] = channel;
182  channelMask = 1 << (channel - maskShift);
183  channelsMask |= channelMask;
184 
185  /* Initialize the timer part */
186  /* FIXME add IfxGtm_Tom_Ch_configurePwmMode() and use it */
187  IfxGtm_Tom_Ch_setClockSource(driver->tom, channel, clock);
188  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, driver->base.inverted
190  : config->base.coutxActiveState);
193 
194  /*Initialize the port */
195  IfxGtm_PinMap_setTomTout(config->coutx[channelIndex],
196  config->base.outputMode, config->base.outputDriver);
197  }
198 
199  IfxGtm_Tom_Tgc_enableChannelsOutput(driver->tgc, channelsMask, 0, TRUE);
200  IfxGtm_Tom_Tgc_enableChannels(driver->tgc, channelsMask, 0, TRUE);
201 
203 
205  IfxGtm_Tom_PwmHl_updateOff(driver, tOn); /* tOn do not need defined values */
206 
207  /* Transfer the shadow registers */
208  IfxGtm_Tom_Tgc_setChannelsForceUpdate(driver->tgc, channelsMask, 0, 0, 0);
209  IfxGtm_Tom_Tgc_trigger(driver->tgc);
210  IfxGtm_Tom_Tgc_setChannelsForceUpdate(driver->tgc, 0, channelsMask, 0, 0);
211 
212  /* Enable timer to update the channels */
213  maskShift = (config->ccx[0]->channel <= 7) ? 0 : 8;
214 
215  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
216  {
217  IfxGtm_Tom_Timer_addToChannelMask(timer, 1 << (driver->ccx[channelIndex] - maskShift));
218  IfxGtm_Tom_Timer_addToChannelMask(timer, 1 << (driver->coutx[channelIndex] - maskShift));
219  }
220 
221  return result;
222 }
223 
224 
226 {
228  config->timer = NULL_PTR;
229  config->tom = IfxGtm_Tom_0;
230  config->ccx = NULL_PTR;
231  config->coutx = NULL_PTR;
232 }
233 
234 
236 {
237  Ifx_TimerValue value = IfxStdIf_Timer_sToTick(driver->timer->base.clockFreq, deadtime);
238 
239  /* FIXME warn if dead time in out of range: > 1/2 period, ... */
240  driver->base.deadtime = value;
241 
242  return TRUE;
243 }
244 
245 
247 {
248  Ifx_TimerValue value = IfxStdIf_Timer_sToTick(driver->timer->base.clockFreq, minPulse);
249 
250  driver->base.minPulse = value + driver->base.deadtime;
251  driver->base.maxPulse = driver->timer->base.period - driver->base.minPulse;
252 
253  return TRUE;
254 }
255 
256 
258 {
259  boolean result = TRUE;
260  IfxGtm_Tom_PwmHl_Base *base = &driver->base;
261 
262  if (base->mode != mode)
263  {
264  if (mode > Ifx_Pwm_Mode_off)
265  {
266  mode = Ifx_Pwm_Mode_off;
267  result = FALSE;
268  }
269 
270  base->mode = mode;
271  driver->update = IfxGtm_Tom_PwmHl_modes[mode].update;
272 
273  if (base->mode != Ifx_Pwm_Mode_off)
274  {
275  base->inverted = IfxGtm_Tom_PwmHl_modes[mode].inverted;
276  }
277  else
278  { /* Keep previous inverted for off mode */
279  }
280 
281  if (base->inverted)
282  {
283  driver->ccxTemp = driver->coutx;
284  driver->coutxTemp = driver->ccx;
285  }
286  else
287  {
288  driver->ccxTemp = driver->ccx;
289  driver->coutxTemp = driver->coutx;
290  }
291 
292  { /* Workaround to enable the signal inversion required for center aligned inverted
293  * and right aligned modes */
294  /** \note that changing signal level may produce short circuit at the power stage,
295  * in which case the inverter must be disable during this action. */
296 
297  /* Ifx_Pwm_Mode_centerAligned and Ifx_Pwm_Mode_LeftAligned use inverted=FALSE */
298  /* Ifx_Pwm_Mode_centerAlignedInverted and Ifx_Pwm_Mode_RightAligned use inverted=TRUE */
299  uint32 channelIndex;
300 
301  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
302  {
303  IfxGtm_Tom_Ch channel;
304 
305  channel = driver->ccx[channelIndex];
306  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, base->inverted
307  ? base->ccxActiveState
309 
310  channel = driver->coutx[channelIndex];
311  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, base->inverted
313  : base->coutxActiveState);
314  }
315  }
316  }
317 
318  return result;
319 }
320 
321 
323 {
324  driver->update(driver, tOn);
325 }
326 
327 
328 void IfxGtm_Tom_PwmHl_setupChannels(IfxGtm_Tom_PwmHl *driver, boolean *activeCh, boolean *stuckSt)
329 {
330  /* FIXME TODO */
331 }
332 
333 
335 {
336  /* *INDENT-OFF* Note: this file was indented manually by the author. */
337  /* Set the API link */
338  stdif->driver = driver;
347  IfxGtm_Tom_Timer_stdIfTimerInit(&stdif->timer, driver->timer);
348  /* *INDENT-ON* */
349 
350  return TRUE;
351 }
352 
353 
354 static void IfxGtm_Tom_PwmHl_updateCenterAligned(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn)
355 {
356  uint8 channelIndex;
357  Ifx_TimerValue period;
358  Ifx_TimerValue deadtime = driver->base.deadtime;
359 
360  period = driver->timer->base.period;
361 
362  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
363  {
364  Ifx_TimerValue x; /* x=period*dutyCycle, x=OnTime+deadTime */
365  Ifx_TimerValue cm0, cm1;
366  x = tOn[channelIndex];
367 
368  if (driver->base.inverted != FALSE)
369  {
370  x = period - x;
371  }
372  else
373  {}
374 
375  if ((x < driver->base.minPulse) || (x <= deadtime))
376  { /* For deadtime condition: avoid leading edge of top channel to occur after the trailing edge */
377  x = 0;
378  }
379  else if (x > driver->base.maxPulse)
380  {
381  x = period;
382  }
383  else
384  {}
385 
386  /* Special handling due to GTM issue */
387  if (x == period)
388  { /* 100% duty cycle */
389  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex],
390  period + 1 /* No compare event */,
391  2 /* 1st compare event (issue: expected to be 1) */ + deadtime);
392  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex],
393  period + 2 /* No compare event, issues has been seen with +1 */,
394  2 /* 1st compare event (issue: expected to be 1) */);
395  }
396  else if (x == 0)
397  {
398  cm0 = 1;
399  cm1 = period + 2;
400  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex], cm0, cm1);
401  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
402  }
403  else
404  { /* x% duty cycle */
405  cm1 = (period - x) / 2; // CM1 /* FIXME issue if CM1 <= 1, should be limited for up to AB step at least */
406  cm0 = (period + x) / 2; // CM0
407  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex], cm0, cm1 + deadtime);
408  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
409  }
410  }
411 }
412 
413 
414 static void IfxGtm_Tom_PwmHl_updateEdgeAligned(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn)
415 {
416  uint8 channelIndex;
417  Ifx_TimerValue period;
418  Ifx_TimerValue deadtime = driver->base.deadtime;
419 
420  period = driver->timer->base.period;
421 
422  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
423  {
424  Ifx_TimerValue x; /* x=period*dutyCycle, x=OnTime+deadTime */
425  Ifx_TimerValue cm0, cm1;
426  x = tOn[channelIndex];
427 
428  if (driver->base.inverted != FALSE)
429  {
430  x = period - x;
431  }
432  else
433  {}
434 
435  if ((x < driver->base.minPulse) || (x <= deadtime))
436  { /* For deadtime condition: avoid leading edge of top channel to occur after the trailing edge */
437  x = 0;
438  }
439  else if (x > driver->base.maxPulse)
440  {
441  x = period;
442  }
443  else
444  {}
445 
446  /* Special handling due to GTM issue */
447  if (x == period)
448  { /* 100% duty cycle */
449  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex],
450  period + 1 /* No compare event */,
451  2 /* 1st compare event (issue: expected to be 1) */ + deadtime);
452  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex],
453  period + 2 /* No compare event, issues has been seen with +1 */,
454  2 /* 1st compare event (issue: expected to be 1) */);
455  }
456  else if (x == 0)
457  {
458  cm0 = 1;
459  cm1 = period + 2;
460  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex], cm0, cm1);
461  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
462  }
463  else
464  { /* x% duty cycle */
465  cm1 = 2; // CM1, set to 2 due to a GTM issue. should be 1 according to spec
466  cm0 = x; // CM0, set to x+2 due to a GTM issue. should be x+1 according to spec
467  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex], cm0, cm1 + deadtime);
468  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
469  }
470  }
471 }
472 
473 
474 static void IfxGtm_Tom_PwmHl_updateOff(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn)
475 {
476  uint8 channelIndex;
477  Ifx_TimerValue period;
478 
479  period = driver->timer->base.period;
480 
481  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
482  {
483  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex],
484  2 /* 1 will keep the previous level */, period + 2);
485  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], period + 1, 2);
486  }
487 }