📄 ect_pwm.c
字号:
/*
*********************************************************************************************************
* BOARD SUPPORT PACKAGE (BSP)
* Frescale MC9S12
*
* File : bsp.c
* By : Eric Shufro
* Data : 2/25/2007
* Description : This file contains the source code necessary to implement Freescale application
* note AN2612, initially written by G.More/M.Gallop, on 1/10/03. AN2612 describes
* a method for implementing PWM channels in software via the ECT / TIM module on
* MC9S12 derivates that either do not have a hardware PWM, or do not have enough
* PWM channels to suite your application. The original source code provided in
* AN2612 required additional changes in order to provide portable data types,
* variable clock and ECT prescaler settings, and error checking.
*********************************************************************************************************
*/
#include <ect_pwm.h>
/*
*********************************************************************************************************
* MACROS
*********************************************************************************************************
*/
#ifdef TIOS_IOS0_MASK /* These macros configure the software PWM for the number */
#define ECT_NBR_CHANNELS 8 /* of possible ECT channels. This value is determined by */
#else /* checking the processor include file for TIOS_IOS0_MASK */
#define ECT_NBR_CHANNELS 4 /* which is only defined on parts that have 8 ECT channels. */
#define TCTL2 TCTL1 /* Ensure compilation on 4 channel devices, define TCTL2 */
#endif /* to ensure compilation. Else, only channels 4-7 exist */
#define ECT_DIS 0 /* Indexes into the ECT_PWM_DisLast[][index] array */
#define ECT_LAST 1
/*
*********************************************************************************************************
* GLOBALS
*********************************************************************************************************
*/
CPU_INT32U Period[8];
CPU_INT32U Mark[8];
CPU_INT32U Space[8];
CPU_BOOLEAN ECT_PWM_DisLast[8][2]; /* [channel][0] = Disable Bit, [channel][1] = Last Bit */
/*
*********************************************************************************************************
* ECT_PWM_Init()
*
* Description : This function initializes an ECT compare channel for use as a software PWM channel.
* The specified channel number must be valid and not already running. This
* function must be called before calling ECT_PWM_CfgChannel(). This function
* DOES NOT start the specified PWM channel.
*
* Arguments : channel, The ECT and SW PWM channel to configure (0-7)
* or (4-7) depending on the derivative
*
* pol The output pin polarity after the 1st toggle
* ECT_PWM_POL_LOW = Init output pin to 0, toggle thereafter
* ECT_PWM_POL_HIGH = Init output pin to 1, toggle thereafter
*
* Returns : ECT_PWM_ERR_NONE, No error has occured.
* ECT_PWM_ERR_CHA, Error. An invalid channel number was specified
* ECT_PWM_ERR_RESV, Error. The reserved channel number was specified
* ECT_PWM_ERR_POL, Error. An invalid polarity setting was specified
* ECT_PWM_ERR_RUN, Error. The specified channel is already running.
*********************************************************************************************************
*/
CPU_INT08U ECT_PWM_Init (CPU_INT08U channel, CPU_INT08U pol)
{
CPU_INT08U omn_bit;
CPU_INT08U oln_bit;
CPU_INT16U *ptcn;
if (channel > 7) {
return (ECT_PWM_ERR_CHA); /* Channel number > 7 is invalid */
}
if ((ECT_NBR_CHANNELS == 4) && (channel < 4)) { /* Only 4 channels, 4-7, supported on this derivative */
return (ECT_PWM_ERR_CHA);
}
if ((channel == 7) && (ECT_PWM_ERR_RESV > 0)) {
return (ECT_PWM_ERR_RESV); /* Invalid channel number. Channel 7 is reserved */
}
if ((pol != ECT_PWM_POL_LOW) && (pol != ECT_PWM_POL_HIGH)) { /* Return an error if an invalid polarity is specified */
return (ECT_PWM_ERR_POL);
}
if ((TIE & (1 << channel)) > 0) { /* Is PWM already running? If so return an error since the */
return (ECT_PWM_ERR_RUN); /* must be safely stopped before changing channel settings */
}
/* Initialize the PWM parameters */
ECT_PWM_DisLast[channel][ECT_DIS] = 0; /* PWM channel is not disabled */
TIOS |= (1 << channel); /* Set desired ECT channel to output compare mode */
if (channel >= 4) { /* Determine initial polarity of PWM channel */
oln_bit = ((channel - 4) * 2); /* Determine OLn bit position of desired channel */
omn_bit = (oln_bit + 1); /* Determine OMn bit position of desired channel */
TCTL1 &= ~((1 << omn_bit) | (1 << oln_bit)); /* Clear pin polarity bits */
TCTL1 |= (1 << omn_bit) | (pol << oln_bit); /* Set the initial pin polarity after the first compare */
} else {
oln_bit = (channel * 2); /* Determine OLn bit position of desired channel */
omn_bit = (oln_bit + 1); /* Determine OMn bit position of desired channel */
TCTL2 &= ~((1 << omn_bit) | (1 << oln_bit)); /* Clear pin polarity bits */
TCTL2 |= (1 << omn_bit) | (pol << oln_bit); /* Set the initial pin polarity after the first compare */
}
TSCR1 |= (TSCR1_TEN_MASK | /* Ensure that the ECT timer is running, */
TSCR1_TSWAI_MASK); /* timer runs in wait mode, */
return (ECT_PWM_ERR_NONE); /* Return without error */
}
/*
*********************************************************************************************************
* ECT_PWM_CfgChannel()
*
* Description : This function starts the specified PWM channel. The specified channel number
* must be valid, and may already be in the running state. This function may
* be called multiple times during runtime in order to change the running
* characteristics of the specified PWM channel. A call to ECT_PWM_Init() must
* occur for the specified channel before calling this function.
*
* Arguments : channel, The ECT and SW PWM channel to configure (0-7)
* or (4-7) depending on the derivative
*
* duty The desired duty cycle, values 0 - 100, in percent.
*
* frq_hz, The desired PWM channel frequency.
*
* Returns : ECT_PWM_ERR_NONE, No error has occured.
* ECT_PWM_ERR_CHA, Error. An invalid channel number was specified
* ECT_PWM_ERR_RESV, Error. The reserved channel number was specified
* ECT_PWM_ERR_DUTY, Error. An invalid duty cycle was specified.
* ECT_PWM_ERR_FRQ, Error. The specified PWM frequency is not obtainable
* given the current bus frequency and prescaler values.
*
* Notes : 1) For values of duty close to 0 or 100, it may be impossible to acheive an interrupt
* since the current ECT / TIM counter (TNCT) + Space[channel] or + Mark[channel]
* may be too close to the current value of TCNT when either Space[channel] or
* Mark[channel] are close to 0 (eg 0% or 100% duty cycle). Therefore, setting
* TCNT + 0 for example would NOT cause another interrupt right after the current
* interrupt because changing the value of the match register, TCn takes time, and
* the counter will have already passed the current match or small future match
* value. This results in an extended Mark or Space period that is highly excessive
* in length. Example:
*
* if TCNT = 100, and the next match value is set to 101, after writing
* 101 to the TCn register, TCNT may equal 108. The next match occurs after
* 65535 - 108 + 101 ticks.
*
* Therefore, values close to 0 or 100 % duty cycle are considered OFF values
* for the PWM, where the final state of the pin is either logic level LOW for
* values near 0% duty cycle, or logic level HIGH for values near 100% duty cycle.
*********************************************************************************************************
*/
CPU_INT08U ECT_PWM_CfgChannel (CPU_INT08U channel, CPU_INT08U duty, CPU_INT16U frq_hz)
{
CPU_INT32U busclk_frq;
CPU_INT32U ECT_curr_frq;
CPU_INT08U ECT_prescaler;
if (channel > 7) {
return (ECT_PWM_ERR_CHA); /* Channel number > 7 is invalid */
}
if ((ECT_NBR_CHANNELS == 4) && (channel < 4)) { /* Only 4 channels, 4-7, supported on this derivative */
return (ECT_PWM_ERR_CHA);
}
if ((channel == 7) && (ECT_PWM_ERR_RESV > 0)) {
return (ECT_PWM_ERR_RESV); /* Invalid channel number. Channel 7 is reserved */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -