iLLD_TC27xD  1.0
IfxGtm_Tom_PwmHl.c
Go to the documentation of this file.
1 /**
2  * \file IfxGtm_Tom_PwmHl.c
3  * \brief GTM PWMHL details
4  *
5  * \version iLLD_1_0_0_11_0
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  // check that period value is less than 16 bits
126  if (IfxGtm_Tom_Timer_getPeriod(timer) > (0xFFFF - 2))
127  {
128  result = FALSE;
130  }
131 
132  /* driver.base must be at offset 0 to be compatible with the standard interface PwmHl */
133  IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, offsetof(IfxGtm_Tom_PwmHl, base) == 0);
134 
135  driver->base.mode = Ifx_Pwm_Mode_init;
136  driver->timer = timer;
137  driver->base.setMode = 0;
138  driver->base.inverted = FALSE;
139  driver->base.ccxActiveState = config->base.ccxActiveState;
140  driver->base.coutxActiveState = config->base.coutxActiveState;
141  driver->base.channelCount = config->base.channelCount;
142 
143  IfxGtm_Tom_PwmHl_setDeadtime(driver, config->base.deadtime);
144  IfxGtm_Tom_PwmHl_setMinPulse(driver, config->base.minPulse);
145 
146  driver->tom = &(timer->gtm->TOM[config->tom]);
147 
148  /* config->ccx[0] is used for the definition of the TGC */
149  if (config->ccx[0]->channel <= 7)
150  {
151  driver->tgc = IfxGtm_Tom_Ch_getTgcPointer(driver->tom, 0);
152  }
153  else
154  {
155  driver->tgc = IfxGtm_Tom_Ch_getTgcPointer(driver->tom, 1);
156  }
157 
158  maskShift = (config->ccx[0]->channel <= 7) ? 0 : 8;
159 
161 
163 
164  for (channelIndex = 0; channelIndex < config->base.channelCount; channelIndex++)
165  {
166  IfxGtm_Tom_Ch channel;
167  /* CCX */
168  channel = config->ccx[channelIndex]->channel;
169  driver->ccx[channelIndex] = channel;
170  channelMask = 1 << (channel - maskShift);
171  channelsMask |= channelMask;
172 
173  /* Initialize the timer part */
174  /* FIXME add IfxGtm_Tom_Ch_configurePwmMode() and use it */
175  IfxGtm_Tom_Ch_setClockSource(driver->tom, channel, clock);
176 
177  /* Initialize the SOUR reset value and enable the channel */
178  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, !driver->base.inverted
179  ? config->base.ccxActiveState
181  IfxGtm_Tom_Tgc_enableChannels(driver->tgc, channelMask, 0, TRUE); /* Write the SOUR outout with !SL */
182  IfxGtm_Tom_Tgc_enableChannelsOutput(driver->tgc, channelMask, 0, TRUE);
183 
184  /* Set the SL to the required level for run time */
185  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, driver->base.inverted
186  ? config->base.ccxActiveState
191 
192  /*Initialize the port */
193  IfxGtm_PinMap_setTomTout(config->ccx[channelIndex],
194  config->base.outputMode, config->base.outputDriver);
195  IfxPort_setPinState(config->ccx[channelIndex]->pin.port, config->ccx[channelIndex]->pin.pinIndex, config->base.ccxActiveState ? IfxPort_State_low : IfxPort_State_high);
196 
197  /* COUTX */
198  channel = config->coutx[channelIndex]->channel;
199  driver->coutx[channelIndex] = channel;
200  channelMask = 1 << (channel - maskShift);
201  channelsMask |= channelMask;
202 
203  /* Initialize the timer part */
204  /* FIXME add IfxGtm_Tom_Ch_configurePwmMode() and use it */
205  IfxGtm_Tom_Ch_setClockSource(driver->tom, channel, clock);
206 
207  /* Initialize the SOUR reset value, SL and enable the channel */
208  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, driver->base.inverted
210  : config->base.coutxActiveState);
211  IfxGtm_Tom_Tgc_enableChannels(driver->tgc, channelMask, 0, TRUE);
212  IfxGtm_Tom_Tgc_enableChannelsOutput(driver->tgc, channelMask, 0, TRUE);
213 
217 
218  /*Initialize the port */
219  IfxGtm_PinMap_setTomTout(config->coutx[channelIndex],
220  config->base.outputMode, config->base.outputDriver);
221  IfxPort_setPinState(config->coutx[channelIndex]->pin.port, config->coutx[channelIndex]->pin.pinIndex, config->base.coutxActiveState ? IfxPort_State_low : IfxPort_State_high);
222  }
223 
225 
227  IfxGtm_Tom_PwmHl_updateOff(driver, tOn); /* tOn do not need defined values */
228 
229  /* Transfer the shadow registers */
230  IfxGtm_Tom_Tgc_setChannelsForceUpdate(driver->tgc, channelsMask, 0, 0, 0);
231  IfxGtm_Tom_Tgc_trigger(driver->tgc); /* FIXME this seems to have no effect, to be checked */
232  IfxGtm_Tom_Tgc_setChannelsForceUpdate(driver->tgc, 0, channelsMask, 0, 0);
233 
234  /* Enable timer to update the channels */
235  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
236  {
237  IfxGtm_Tom_Timer_addToChannelMask(timer, driver->ccx[channelIndex]);
238  IfxGtm_Tom_Timer_addToChannelMask(timer, driver->coutx[channelIndex]);
239  }
240 
241  return result;
242 }
243 
244 
246 {
248  config->timer = NULL_PTR;
249  config->tom = IfxGtm_Tom_0;
250  config->ccx = NULL_PTR;
251  config->coutx = NULL_PTR;
252 }
253 
254 
256 {
257  Ifx_TimerValue value = IfxStdIf_Timer_sToTick(driver->timer->base.clockFreq, deadtime);
258 
259  /* FIXME warn if dead time in out of range: > 1/2 period, ... */
260  driver->base.deadtime = value;
261 
262  return TRUE;
263 }
264 
265 
267 {
268  Ifx_TimerValue value = IfxStdIf_Timer_sToTick(driver->timer->base.clockFreq, minPulse);
269 
270  driver->base.minPulse = value + driver->base.deadtime;
271  driver->base.maxPulse = driver->timer->base.period - driver->base.minPulse;
272 
273  return TRUE;
274 }
275 
276 
278 {
279  boolean result = TRUE;
280  IfxGtm_Tom_PwmHl_Base *base = &driver->base;
281 
282  if (base->mode != mode)
283  {
284  if (mode > Ifx_Pwm_Mode_off)
285  {
286  mode = Ifx_Pwm_Mode_off;
287  result = FALSE;
288  }
289 
290  base->mode = mode;
291  driver->update = IfxGtm_Tom_PwmHl_modes[mode].update;
292 
293  if (base->mode != Ifx_Pwm_Mode_off)
294  {
295  base->inverted = IfxGtm_Tom_PwmHl_modes[mode].inverted;
296  }
297  else
298  { /* Keep previous inverted for off mode */
299  }
300 
301  if (base->inverted)
302  {
303  driver->ccxTemp = driver->coutx;
304  driver->coutxTemp = driver->ccx;
305  }
306  else
307  {
308  driver->ccxTemp = driver->ccx;
309  driver->coutxTemp = driver->coutx;
310  }
311 
312  { /* Workaround to enable the signal inversion required for center aligned inverted
313  * and right aligned modes */
314  /** \note that changing signal level may produce short circuit at the power stage,
315  * in which case the inverter must be disable during this action. */
316 
317  /* Ifx_Pwm_Mode_centerAligned and Ifx_Pwm_Mode_LeftAligned use inverted=FALSE */
318  /* Ifx_Pwm_Mode_centerAlignedInverted and Ifx_Pwm_Mode_RightAligned use inverted=TRUE */
319  uint32 channelIndex;
320 
321  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
322  {
323  IfxGtm_Tom_Ch channel;
324 
325  channel = driver->ccx[channelIndex];
326  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, base->inverted
327  ? base->ccxActiveState
329 
330  channel = driver->coutx[channelIndex];
331  IfxGtm_Tom_Ch_setSignalLevel(driver->tom, channel, base->inverted
333  : base->coutxActiveState);
334  }
335  }
336  }
337 
338  return result;
339 }
340 
341 
343 {
344  driver->update(driver, tOn);
345 }
346 
347 
348 void IfxGtm_Tom_PwmHl_setupChannels(IfxGtm_Tom_PwmHl *driver, boolean *activeCh, boolean *stuckSt)
349 {
350  /* FIXME TODO */
351 }
352 
353 
355 {
356  /* *INDENT-OFF* Note: this file was indented manually by the author. */
357  /* Set the API link */
358  stdif->driver = driver;
367  IfxGtm_Tom_Timer_stdIfTimerInit(&stdif->timer, driver->timer);
368  /* *INDENT-ON* */
369 
370  return TRUE;
371 }
372 
373 
374 static void IfxGtm_Tom_PwmHl_updateCenterAligned(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn)
375 {
376  uint8 channelIndex;
377  Ifx_TimerValue period;
378  Ifx_TimerValue deadtime = driver->base.deadtime;
379 
380  period = driver->timer->base.period;
381 
382  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
383  {
384  Ifx_TimerValue x; /* x=period*dutyCycle, x=OnTime+deadTime */
385  Ifx_TimerValue cm0, cm1;
386  x = tOn[channelIndex];
387 
388  if (driver->base.inverted != FALSE)
389  {
390  x = period - x;
391  }
392  else
393  {}
394 
395  if ((x < driver->base.minPulse) || (x <= deadtime))
396  { /* For deadtime condition: avoid leading edge of top channel to occur after the trailing edge */
397  x = 0;
398  }
399  else if (x > driver->base.maxPulse)
400  {
401  x = period;
402  }
403  else
404  {}
405 
406  /* Special handling due to GTM issue */
407  if (x == period)
408  { /* 100% duty cycle */
409  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex],
410  period + 1 /* No compare event */,
411  2 /* 1st compare event (issue: expected to be 1) */ + deadtime);
412  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex],
413  period + 2 /* No compare event, issues has been seen with +1 */,
414  2 /* 1st compare event (issue: expected to be 1) */);
415  }
416  else if (x == 0)
417  {
418  cm0 = 1;
419  cm1 = period + 2;
420  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex], cm0, cm1);
421  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
422  }
423  else
424  { /* x% duty cycle */
425  cm1 = (period - x) / 2; // CM1 /* FIXME issue if CM1 <= 1, should be limited for up to AB step at least */
426  cm0 = (period + x) / 2; // CM0
427  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex], cm0, cm1 + deadtime);
428  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
429  }
430  }
431 }
432 
433 
434 static void IfxGtm_Tom_PwmHl_updateEdgeAligned(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn)
435 {
436  uint8 channelIndex;
437  Ifx_TimerValue period;
438  Ifx_TimerValue deadtime = driver->base.deadtime;
439 
440  period = driver->timer->base.period;
441 
442  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
443  {
444  Ifx_TimerValue x; /* x=period*dutyCycle, x=OnTime+deadTime */
445  Ifx_TimerValue cm0, cm1;
446  x = tOn[channelIndex];
447 
448  if (driver->base.inverted != FALSE)
449  {
450  x = period - x;
451  }
452  else
453  {}
454 
455  if ((x < driver->base.minPulse) || (x <= deadtime))
456  { /* For deadtime condition: avoid leading edge of top channel to occur after the trailing edge */
457  x = 0;
458  }
459  else if (x > driver->base.maxPulse)
460  {
461  x = period;
462  }
463  else
464  {}
465 
466  /* Special handling due to GTM issue */
467  if (x == period)
468  { /* 100% duty cycle */
469  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex],
470  period + 1 /* No compare event */,
471  2 /* 1st compare event (issue: expected to be 1) */ + deadtime);
472  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex],
473  period + 2 /* No compare event, issues has been seen with +1 */,
474  2 /* 1st compare event (issue: expected to be 1) */);
475  }
476  else if (x == 0)
477  {
478  cm0 = 1;
479  cm1 = period + 2;
480  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex], cm0, cm1);
481  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
482  }
483  else
484  { /* x% duty cycle */
485  cm1 = 2; // CM1, set to 2 due to a GTM issue. should be 1 according to spec
486  cm0 = x; // CM0, set to x+2 due to a GTM issue. should be x+1 according to spec
487  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex], cm0, cm1 + deadtime);
488  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
489  }
490  }
491 }
492 
493 
494 static void IfxGtm_Tom_PwmHl_updateOff(IfxGtm_Tom_PwmHl *driver, Ifx_TimerValue *tOn)
495 {
496  uint8 channelIndex;
497  Ifx_TimerValue period;
498 
499  period = driver->timer->base.period;
500 
501  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
502  {
503  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->ccxTemp[channelIndex],
504  2 /* 1 will keep the previous level */, period + 2);
505  IfxGtm_Tom_Ch_setCompareShadow(driver->tom, driver->coutxTemp[channelIndex], period + 1, 2);
506  }
507 }