iLLD_TC27xC  1.0
IfxGtm_Atom_PwmHl.c
Go to the documentation of this file.
1 /**
2  * \file IfxGtm_Atom_PwmHl.c
3  * \brief _ATOM 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_Atom_PwmHl.h"
30 #include "_Utilities/Ifx_Assert.h"
31 #include "stddef.h"
32 
33 /** \addtogroup IfxLld_Gtm_Atom_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 ATOM PWM driver
51  * \param tOn T on
52  * \return None
53  */
54 static void IfxGtm_Atom_PwmHl_updateCenterAligned(IfxGtm_Atom_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 ATOM PWM driver
58  * \param tOn T on
59  * \return None
60  */
61 static void IfxGtm_Atom_PwmHl_updateEdgeAligned(IfxGtm_Atom_PwmHl *driver, Ifx_TimerValue *tOn);
62 
63 /** \brief Set the outputs to inactive
64  * \param driver GTM ATOM PWM driver
65  * \param tOn T on
66  * \return None
67  */
68 static void IfxGtm_Atom_PwmHl_updateOff(IfxGtm_Atom_PwmHl *driver, Ifx_TimerValue *tOn);
69 
70 /** \} */
71 
72 /******************************************************************************/
73 /*------------------------Private Variables/Constants-------------------------*/
74 /******************************************************************************/
75 
76 static const IfxGtm_Atom_PwmHl_Mode IfxGtm_Atom_PwmHl_modes[5] = {
77  {FALSE, &IfxGtm_Atom_PwmHl_updateCenterAligned}, // Ifx_Pwm_Mode_centerAligned
78  {TRUE, &IfxGtm_Atom_PwmHl_updateCenterAligned}, // Ifx_Pwm_Mode_centerAlignedInverted
79  {FALSE, &IfxGtm_Atom_PwmHl_updateEdgeAligned }, // Ifx_Pwm_Mode_leftAligned
80  {TRUE, &IfxGtm_Atom_PwmHl_updateEdgeAligned }, // Ifx_Pwm_Mode_rightAligned
81  {FALSE, &IfxGtm_Atom_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 
123  IfxGtm_Atom_Timer *timer = config->timer;
124 
125  /* driver.base must be at offset 0 to be compatible with the standard interface PwmHl */
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 
138 
139  driver->atom = &(timer->gtm->ATOM[config->atom]);
140  /* Only one AGC */
141  driver->agc = (Ifx_GTM_ATOM_AGC *)&driver->atom->AGC.GLB_CTRL;
142 
144 
146 
147  for (channelIndex = 0; channelIndex < config->base.channelCount; channelIndex++)
148  {
149  IfxGtm_Atom_Ch channel;
150  /* CCX */
151  channel = config->ccx[channelIndex]->channel;
152  driver->ccx[channelIndex] = channel;
153  channelMask = 1 << channel;
154  channelsMask |= channelMask;
155 
156  /* Initialize the timer part */
157  IfxGtm_Atom_Ch_configurePwmMode(driver->atom, channel, clock,
158  driver->base.inverted ? config->base.ccxActiveState :
161 
162  /* Initialize the port */
163  IfxGtm_PinMap_setAtomTout(config->ccx[channelIndex],
164  config->base.outputMode, config->base.outputDriver);
165 
166  /* COUTX */
167  channel = config->coutx[channelIndex]->channel;
168  driver->coutx[channelIndex] = channel;
169  channelMask = 1 << channel;
170  channelsMask |= channelMask;
171 
172  /* Initialize the timer part */
173  IfxGtm_Atom_Ch_configurePwmMode(driver->atom, channel, clock,
174  driver->base.inverted ?
176  : config->base.coutxActiveState,
178 
179  /* Initialize the port */
180  IfxGtm_PinMap_setAtomTout(config->coutx[channelIndex],
181  config->base.outputMode, config->base.outputDriver);
182  }
183 
184  IfxGtm_Atom_Agc_enableChannelsOutput(driver->agc, channelsMask, 0, TRUE);
185  IfxGtm_Atom_Agc_enableChannels(driver->agc, channelsMask, 0, TRUE);
186 
188 
190  IfxGtm_Atom_PwmHl_updateOff(driver, tOn); /* tOn do not need defined values */
191 
192  /* Transfer the shadow registers */
193  IfxGtm_Atom_Agc_setChannelsForceUpdate(driver->agc, channelsMask, 0, 0, 0);
194  IfxGtm_Atom_Agc_trigger(driver->agc);
195  IfxGtm_Atom_Agc_setChannelsForceUpdate(driver->agc, 0, channelsMask, 0, 0);
196 
197  /* Enable timer to update the channels */
198 
199  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
200  {
201  IfxGtm_Atom_Timer_addToChannelMask(timer, 1 << driver->ccx[channelIndex]);
202  IfxGtm_Atom_Timer_addToChannelMask(timer, 1 << driver->coutx[channelIndex]);
203  }
204 
205  return result;
206 }
207 
208 
210 {
212  config->timer = NULL_PTR;
213  config->atom = IfxGtm_Atom_0;
214  config->ccx = NULL_PTR;
215  config->coutx = NULL_PTR;
216 }
217 
218 
220 {
221  Ifx_TimerValue value = IfxStdIf_Timer_sToTick(driver->timer->base.clockFreq, deadtime);
222 
223  /* FIXME warn if dead time in out of range: > 1/2 period, ... */
224  driver->base.deadtime = value;
225 
226  return TRUE;
227 }
228 
229 
231 {
232  Ifx_TimerValue value = IfxStdIf_Timer_sToTick(driver->timer->base.clockFreq, minPulse);
233 
234  driver->base.minPulse = value + driver->base.deadtime;
235  driver->base.maxPulse = driver->timer->base.period - driver->base.minPulse;
236 
237  return TRUE;
238 }
239 
240 
242 {
243  boolean result = TRUE;
244  IfxGtm_Atom_PwmHl_Base *base = &driver->base;
245 
246  if (base->mode != mode)
247  {
248  if (mode > Ifx_Pwm_Mode_off)
249  {
250  mode = Ifx_Pwm_Mode_off;
251  result = FALSE;
252  }
253 
254  base->mode = mode;
255  driver->update = IfxGtm_Atom_PwmHl_modes[mode].update;
256 
257  if (base->mode != Ifx_Pwm_Mode_off)
258  {
259  base->inverted = IfxGtm_Atom_PwmHl_modes[mode].inverted;
260  }
261  else
262  { /* Keep previous inverted for off mode */
263  }
264 
265  if (base->inverted)
266  {
267  driver->ccxTemp = driver->coutx;
268  driver->coutxTemp = driver->ccx;
269  }
270  else
271  {
272  driver->ccxTemp = driver->ccx;
273  driver->coutxTemp = driver->coutx;
274  }
275 
276  { /* Workaround to enable the signal inversion required for center aligned inverted
277  * and right aligned modes */
278  /** \note Changing signal level may produce short circuit at the power stage,
279  * in which case the inverter must be disable during this action.*/
280 
281  /* Ifx_Pwm_Mode_centerAligned and Ifx_Pwm_Mode_LeftAligned use inverted=FALSE */
282  /* Ifx_Pwm_Mode_centerAlignedInverted and Ifx_Pwm_Mode_RightAligned use inverted=TRUE */
283  uint32 channelIndex;
284 
285  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
286  {
287  IfxGtm_Atom_Ch channel;
288 
289  channel = driver->ccx[channelIndex];
290  IfxGtm_Atom_Ch_setSignalLevel(driver->atom, channel, base->inverted
291  ? base->ccxActiveState
293 
294  channel = driver->coutx[channelIndex];
295  IfxGtm_Atom_Ch_setSignalLevel(driver->atom, channel, base->inverted
297  : base->coutxActiveState);
298  }
299  }
300  }
301 
302  return result;
303 }
304 
305 
307 {
308  driver->update(driver, tOn);
309 }
310 
311 
312 void IfxGtm_Atom_PwmHl_setupChannels(IfxGtm_Atom_PwmHl *driver, boolean *activeCh, boolean *stuckSt)
313 {
314  /* FIXME TODO */
315 }
316 
317 
319 {
320  /* *INDENT-OFF* Note: this file was indented manually by the author. */
321  /* Set the API link */
322  stdif->driver = driver;
331  IfxGtm_Atom_Timer_stdIfTimerInit(&stdif->timer, driver->timer);
332  /* *INDENT-ON* */
333 
334  return TRUE;
335 }
336 
337 
338 static void IfxGtm_Atom_PwmHl_updateCenterAligned(IfxGtm_Atom_PwmHl *driver, Ifx_TimerValue *tOn)
339 {
340  uint8 channelIndex;
341  Ifx_TimerValue period;
342  Ifx_TimerValue deadtime = driver->base.deadtime;
343 
344  period = driver->timer->base.period;
345 
346  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
347  {
348  Ifx_TimerValue x; /* x=period*dutyCycle, x=OnTime+deadTime */
349  Ifx_TimerValue cm0, cm1;
350  x = tOn[channelIndex];
351 
352  if (driver->base.inverted != FALSE)
353  {
354  x = period - x;
355  }
356  else
357  {}
358 
359  if ((x < driver->base.minPulse) || (x <= deadtime))
360  { /* For deadtime condition: avoid leading edge of top channel to occur after the trailing edge */
361  x = 0;
362  }
363  else if (x > driver->base.maxPulse)
364  {
365  x = period;
366  }
367  else
368  {}
369 
370  /* Special handling due to GTM issue */
371  if (x == period)
372  { /* 100% duty cycle */
373  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex],
374  period + 1 /* No compare event */,
375  2 /* 1st compare event (issue: expected to be 1)*/ + deadtime);
376  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex],
377  period + 2 /* No compare event, issues has been seen with +1 */,
378  2 /* 1st compare event (issue: expected to be 1)*/);
379  }
380  else if (x == 0)
381  {
382  cm0 = 1;
383  cm1 = period + 2;
384  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex], cm0, cm1);
385  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
386  }
387  else
388  { /* x% duty cycle */
389  cm1 = (period - x) / 2; // CM1
390  cm0 = (period + x) / 2; // CM0
391  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex], cm0, cm1 + deadtime);
392  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
393  }
394  }
395 }
396 
397 
398 static void IfxGtm_Atom_PwmHl_updateEdgeAligned(IfxGtm_Atom_PwmHl *driver, Ifx_TimerValue *tOn)
399 {
400  uint8 channelIndex;
401  Ifx_TimerValue period;
402  Ifx_TimerValue deadtime = driver->base.deadtime;
403 
404  period = driver->timer->base.period;
405 
406  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
407  {
408  Ifx_TimerValue x; /* x=period*dutyCycle, x=OnTime+deadTime */
409  Ifx_TimerValue cm0, cm1;
410  x = tOn[channelIndex];
411 
412  if (driver->base.inverted != FALSE)
413  {
414  x = period - x;
415  }
416  else
417  {}
418 
419  if ((x < driver->base.minPulse) || (x <= deadtime))
420  { /* For deadtime condition: avoid leading edge of top channel to occur after the trailing edge */
421  x = 0;
422  }
423  else if (x > driver->base.maxPulse)
424  {
425  x = period;
426  }
427  else
428  {}
429 
430  /* Special handling due to GTM issue */
431  if (x == period)
432  { /* 100% duty cycle */
433  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex],
434  period + 1 /* No compare event */,
435  2 /* 1st compare event (issue: expected to be 1)*/ + deadtime);
436  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex],
437  period + 2 /* No compare event, issues has been seen with +1 */,
438  2 /* 1st compare event (issue: expected to be 1)*/);
439  }
440  else if (x == 0)
441  {
442  cm0 = 1;
443  cm1 = period + 2;
444  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex], cm0, cm1);
445  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
446  }
447  else
448  { /* x% duty cycle */
449  cm1 = 2; // CM1, set to 2 due to a GTM issue. should be 1 according to spec
450  cm0 = x; // CM0, set to x+2 due to a GTM issue. should be x+1 according to spec
451  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex], cm0, cm1 + deadtime);
452  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
453  }
454  }
455 }
456 
457 
458 static void IfxGtm_Atom_PwmHl_updateOff(IfxGtm_Atom_PwmHl *driver, Ifx_TimerValue *tOn)
459 {
460  uint8 channelIndex;
461  Ifx_TimerValue period;
462  period = driver->timer->base.period;
463 
464  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
465  {
466  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex],
467  2 /* 1 will keep the previous level*/, period + 2);
468  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], period + 1, 2);
469  }
470 }