iLLD_TC27xD  1.0
IfxGtm_Atom_PwmHl.c
Go to the documentation of this file.
1 /**
2  * \file IfxGtm_Atom_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_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  /* check that period value is not more than 24 bits */
126  if (IfxGtm_Atom_Timer_getPeriod(timer) > (0xFFFFFF - 2))
127  {
128  result = FALSE;
130  }
131 
132  /* driver.base must be at offset 0 to be compatible with the standard interface PwmHl */
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 
145 
146  driver->atom = &(timer->gtm->ATOM[config->atom]);
147  /* Only one AGC */
148  driver->agc = (Ifx_GTM_ATOM_AGC *)&driver->atom->AGC.GLB_CTRL;
149 
151 
153 
154  for (channelIndex = 0; channelIndex < config->base.channelCount; channelIndex++)
155  {
156  IfxGtm_Atom_Ch channel;
157  /* CCX */
158  channel = config->ccx[channelIndex]->channel;
159  driver->ccx[channelIndex] = channel;
160  channelMask = 1 << channel;
161  channelsMask |= channelMask;
162 
163  /* Initialize the timer part */
164  IfxGtm_Atom_Ch_configurePwmMode(driver->atom, channel, clock,
165  driver->base.inverted ? config->base.ccxActiveState :
168 
169  /* Initialize the port */
170  IfxGtm_PinMap_setAtomTout(config->ccx[channelIndex],
171  config->base.outputMode, config->base.outputDriver);
172 
173  /* COUTX */
174  channel = config->coutx[channelIndex]->channel;
175  driver->coutx[channelIndex] = channel;
176  channelMask = 1 << channel;
177  channelsMask |= channelMask;
178 
179  /* Initialize the timer part */
180  IfxGtm_Atom_Ch_configurePwmMode(driver->atom, channel, clock,
181  driver->base.inverted ?
183  : config->base.coutxActiveState,
185 
186  /* Initialize the port */
187  IfxGtm_PinMap_setAtomTout(config->coutx[channelIndex],
188  config->base.outputMode, config->base.outputDriver);
189  }
190 
191  IfxGtm_Atom_Agc_enableChannelsOutput(driver->agc, channelsMask, 0, TRUE);
192  IfxGtm_Atom_Agc_enableChannels(driver->agc, channelsMask, 0, TRUE);
193 
195 
197  IfxGtm_Atom_PwmHl_updateOff(driver, tOn); /* tOn do not need defined values */
198 
199  /* Transfer the shadow registers */
200  IfxGtm_Atom_Agc_setChannelsForceUpdate(driver->agc, channelsMask, 0, 0, 0);
201  IfxGtm_Atom_Agc_trigger(driver->agc);
202  IfxGtm_Atom_Agc_setChannelsForceUpdate(driver->agc, 0, channelsMask, 0, 0);
203 
204  /* Enable timer to update the channels */
205 
206  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
207  {
208  IfxGtm_Atom_Timer_addToChannelMask(timer, 1 << driver->ccx[channelIndex]);
209  IfxGtm_Atom_Timer_addToChannelMask(timer, 1 << driver->coutx[channelIndex]);
210  }
211 
212  return result;
213 }
214 
215 
217 {
219  config->timer = NULL_PTR;
220  config->atom = IfxGtm_Atom_0;
221  config->ccx = NULL_PTR;
222  config->coutx = NULL_PTR;
223 }
224 
225 
227 {
228  Ifx_TimerValue value = IfxStdIf_Timer_sToTick(driver->timer->base.clockFreq, deadtime);
229 
230  /* FIXME warn if dead time in out of range: > 1/2 period, ... */
231  driver->base.deadtime = value;
232 
233  return TRUE;
234 }
235 
236 
238 {
239  Ifx_TimerValue value = IfxStdIf_Timer_sToTick(driver->timer->base.clockFreq, minPulse);
240 
241  driver->base.minPulse = value + driver->base.deadtime;
242  driver->base.maxPulse = driver->timer->base.period - driver->base.minPulse;
243 
244  return TRUE;
245 }
246 
247 
249 {
250  boolean result = TRUE;
251  IfxGtm_Atom_PwmHl_Base *base = &driver->base;
252 
253  if (base->mode != mode)
254  {
255  if (mode > Ifx_Pwm_Mode_off)
256  {
257  mode = Ifx_Pwm_Mode_off;
258  result = FALSE;
259  }
260 
261  base->mode = mode;
262  driver->update = IfxGtm_Atom_PwmHl_modes[mode].update;
263 
264  if (base->mode != Ifx_Pwm_Mode_off)
265  {
266  base->inverted = IfxGtm_Atom_PwmHl_modes[mode].inverted;
267  }
268  else
269  { /* Keep previous inverted for off mode */
270  }
271 
272  if (base->inverted)
273  {
274  driver->ccxTemp = driver->coutx;
275  driver->coutxTemp = driver->ccx;
276  }
277  else
278  {
279  driver->ccxTemp = driver->ccx;
280  driver->coutxTemp = driver->coutx;
281  }
282 
283  { /* Workaround to enable the signal inversion required for center aligned inverted
284  * and right aligned modes */
285  /** \note Changing signal level may produce short circuit at the power stage,
286  * in which case the inverter must be disable during this action.*/
287 
288  /* Ifx_Pwm_Mode_centerAligned and Ifx_Pwm_Mode_LeftAligned use inverted=FALSE */
289  /* Ifx_Pwm_Mode_centerAlignedInverted and Ifx_Pwm_Mode_RightAligned use inverted=TRUE */
290  uint32 channelIndex;
291 
292  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
293  {
294  IfxGtm_Atom_Ch channel;
295 
296  channel = driver->ccx[channelIndex];
297  IfxGtm_Atom_Ch_setSignalLevel(driver->atom, channel, base->inverted
298  ? base->ccxActiveState
300 
301  channel = driver->coutx[channelIndex];
302  IfxGtm_Atom_Ch_setSignalLevel(driver->atom, channel, base->inverted
304  : base->coutxActiveState);
305  }
306  }
307  }
308 
309  return result;
310 }
311 
312 
314 {
315  driver->update(driver, tOn);
316 }
317 
318 
319 void IfxGtm_Atom_PwmHl_setupChannels(IfxGtm_Atom_PwmHl *driver, boolean *activeCh, boolean *stuckSt)
320 {
321  /* FIXME TODO */
322 }
323 
324 
326 {
327  /* *INDENT-OFF* Note: this file was indented manually by the author. */
328  /* Set the API link */
329  stdif->driver = driver;
338  IfxGtm_Atom_Timer_stdIfTimerInit(&stdif->timer, driver->timer);
339  /* *INDENT-ON* */
340 
341  return TRUE;
342 }
343 
344 
345 static void IfxGtm_Atom_PwmHl_updateCenterAligned(IfxGtm_Atom_PwmHl *driver, Ifx_TimerValue *tOn)
346 {
347  uint8 channelIndex;
348  Ifx_TimerValue period;
349  Ifx_TimerValue deadtime = driver->base.deadtime;
350 
351  period = driver->timer->base.period;
352 
353  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
354  {
355  Ifx_TimerValue x; /* x=period*dutyCycle, x=OnTime+deadTime */
356  Ifx_TimerValue cm0, cm1;
357  x = tOn[channelIndex];
358 
359  if (driver->base.inverted != FALSE)
360  {
361  x = period - x;
362  }
363  else
364  {}
365 
366  if ((x < driver->base.minPulse) || (x <= deadtime))
367  { /* For deadtime condition: avoid leading edge of top channel to occur after the trailing edge */
368  x = 0;
369  }
370  else if (x > driver->base.maxPulse)
371  {
372  x = period;
373  }
374  else
375  {}
376 
377  /* Special handling due to GTM issue */
378  if (x == period)
379  { /* 100% duty cycle */
380  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex],
381  period + 1 /* No compare event */,
382  2 /* 1st compare event (issue: expected to be 1)*/ + deadtime);
383  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex],
384  period + 2 /* No compare event, issues has been seen with +1 */,
385  2 /* 1st compare event (issue: expected to be 1)*/);
386  }
387  else if (x == 0)
388  {
389  cm0 = 1;
390  cm1 = period + 2;
391  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex], cm0, cm1);
392  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
393  }
394  else
395  { /* x% duty cycle */
396  cm1 = (period - x) / 2; // CM1
397  cm0 = (period + x) / 2; // CM0
398  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex], cm0, cm1 + deadtime);
399  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
400  }
401  }
402 }
403 
404 
405 static void IfxGtm_Atom_PwmHl_updateEdgeAligned(IfxGtm_Atom_PwmHl *driver, Ifx_TimerValue *tOn)
406 {
407  uint8 channelIndex;
408  Ifx_TimerValue period;
409  Ifx_TimerValue deadtime = driver->base.deadtime;
410 
411  period = driver->timer->base.period;
412 
413  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
414  {
415  Ifx_TimerValue x; /* x=period*dutyCycle, x=OnTime+deadTime */
416  Ifx_TimerValue cm0, cm1;
417  x = tOn[channelIndex];
418 
419  if (driver->base.inverted != FALSE)
420  {
421  x = period - x;
422  }
423  else
424  {}
425 
426  if ((x < driver->base.minPulse) || (x <= deadtime))
427  { /* For deadtime condition: avoid leading edge of top channel to occur after the trailing edge */
428  x = 0;
429  }
430  else if (x > driver->base.maxPulse)
431  {
432  x = period;
433  }
434  else
435  {}
436 
437  /* Special handling due to GTM issue */
438  if (x == period)
439  { /* 100% duty cycle */
440  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex],
441  period + 1 /* No compare event */,
442  2 /* 1st compare event (issue: expected to be 1)*/ + deadtime);
443  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex],
444  period + 2 /* No compare event, issues has been seen with +1 */,
445  2 /* 1st compare event (issue: expected to be 1)*/);
446  }
447  else if (x == 0)
448  {
449  cm0 = 1;
450  cm1 = period + 2;
451  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex], cm0, cm1);
452  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
453  }
454  else
455  { /* x% duty cycle */
456  cm1 = 2; // CM1, set to 2 due to a GTM issue. should be 1 according to spec
457  cm0 = x; // CM0, set to x+2 due to a GTM issue. should be x+1 according to spec
458  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex], cm0, cm1 + deadtime);
459  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], cm0 + deadtime, cm1);
460  }
461  }
462 }
463 
464 
465 static void IfxGtm_Atom_PwmHl_updateOff(IfxGtm_Atom_PwmHl *driver, Ifx_TimerValue *tOn)
466 {
467  uint8 channelIndex;
468  Ifx_TimerValue period;
469  period = driver->timer->base.period;
470 
471  for (channelIndex = 0; channelIndex < driver->base.channelCount; channelIndex++)
472  {
473  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->ccxTemp[channelIndex],
474  2 /* 1 will keep the previous level*/, period + 2);
475  IfxGtm_Atom_Ch_setCompareShadow(driver->atom, driver->coutxTemp[channelIndex], period + 1, 2);
476  }
477 }