Hello everyone,
Working on an LPC55S06-EVK for future developments on LPC5506, I'm trying to output a 100Hz PWM with dutycycle change (following a gaussian curve). I'm using the example "sctimer_pwm_with_dutycycle_change". It's working with the 24kHz pwm frequency but not with 100Hz (nor 1kHz). It never reaches 100% dutycycle (even if I pass 100 to the variable updatedDutycycle, see image below). As you can see in the video attached to this post, the pwm "jumps back" instead of going to full dutycyle.
You can find the code here : https://pastebin.com/BHBZC0hn .
Thanks for helping me.
François
已解决! 转到解答。
Hi,
Finally, I get the root cause of the issue, the sctimer driver has problem.
Pls use the following code I modified, I have tested, it works well.
the cause of the issue is that the pulsePeriod variable is 0x75300 at most in 100Hz PWM signal, when it use the macro SCT_MATCHREL_RELOADn_L(pulsePeriod); high half word 0x7 will be removed, it results problem obviously. But when the pulsePeriod is less than 0xFFFF, no problem.
#if 0
base->MATCH[pulseMatchReg] = SCT_MATCH_MATCHn_L(pulsePeriod);
base->MATCHREL[pulseMatchReg] = SCT_MATCHREL_RELOADn_L(pulsePeriod);
#else
base->MATCH[pulseMatchReg] = pulsePeriod;
base->MATCHREL[pulseMatchReg] = pulsePeriod;
#endif
Pls modify the function in fsl_sctimer.c
BR
XiangJun Rong
/*!
* brief Updates the duty cycle of an active PWM signal.
*
* Before calling this function, the counter is set to operate as one 32-bit counter (unify bit is set to 1).
*
* param base SCTimer peripheral base address
* param output The output to configure
* param dutyCyclePercent New PWM pulse width; the value should be between 0 to 100
* param event Event number associated with this PWM signal. This was returned to the user by the
* function SCTIMER_SetupPwm().
*/
void SCTIMER_UpdatePwmDutycycle(SCT_Type *base, sctimer_out_t output, uint8_t dutyCyclePercent, uint32_t event)
{
assert(dutyCyclePercent <= 100U);
assert((uint32_t)output < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS);
assert(1U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK));
uint32_t periodMatchReg, pulseMatchReg;
uint32_t pulsePeriod = 0, period;
/* Retrieve the match register number for the PWM period */
periodMatchReg = base->EV[event].CTRL & SCT_EV_CTRL_MATCHSEL_MASK;
/* Retrieve the match register number for the PWM pulse period */
pulseMatchReg = base->EV[event + 1U].CTRL & SCT_EV_CTRL_MATCHSEL_MASK;
period = base->MATCH[periodMatchReg];
/* Calculate pulse width and period match value:
* For EdgeAlignedPwm, "pulsePeriod = 0" results in 0% dutycyle, "pulsePeriod = period - 1U" results in 100%
* dutycyle. For CenterAlignedPwm, , "pulsePeriod = 0" results in 0% dutycyle, "pulsePeriod = period + 2U"
* results in 100% dutycyle.
*/
pulsePeriod = (uint32_t)(((uint64_t)period * dutyCyclePercent) / 100U);
if (dutyCyclePercent == 100U)
{
if (0U == (base->CTRL & SCT_CTRL_BIDIR_L_MASK))
{
pulsePeriod = period + 2U;
}
else
{
pulsePeriod = period - 1U;
}
}
/* Stop the counter before updating match register */
SCTIMER_StopTimer(base, (uint32_t)kSCTIMER_Counter_U);
/* Update dutycycle */
//////////Rong wrote, pls modify
#if 0
base->MATCH[pulseMatchReg] = SCT_MATCH_MATCHn_L(pulsePeriod);
base->MATCHREL[pulseMatchReg] = SCT_MATCHREL_RELOADn_L(pulsePeriod);
#else
base->MATCH[pulseMatchReg] = pulsePeriod;
base->MATCHREL[pulseMatchReg] = pulsePeriod;
#endif
/* Restart the counter */
SCTIMER_StartTimer(base, (uint32_t)kSCTIMER_Counter_U);
}
Hi,
My application code is not the issue because when I try this code :
void SCTIMER_LED_HANDLER()
{
sctimerIsrFlag = true;
updatedDutycycle = 100;
if (SCTIMER_GetStatusFlags(SCT0) & (1 << eventNumberOutput))
{
/* Clear interrupt flag.*/
SCTIMER_ClearStatusFlags(SCT0, (1 << eventNumberOutput));
}
}
So the dutycycle is set to 100 (thus 100%), the issue is still there (as shown in the screenshot below).
Thanks for your reply.
François
Hi,
when the updatedDutycycle1 is set up as 99, the screenshot is like the following Fig, obviously, it is correct.
BR
XiangJun Rong
volatile uint8_t updatedDutycycle = 10U;
volatile uint8_t updatedDutycycle1;
updatedDutycycle1=99;
/* Update PWM duty cycle */
SCTIMER_UpdatePwmDutycycle(SCT0, DEMO_SCTIMER_OUT, updatedDutycycle1, eventNumberOutput);
Hi,
Finally, I get the root cause of the issue, the sctimer driver has problem.
Pls use the following code I modified, I have tested, it works well.
the cause of the issue is that the pulsePeriod variable is 0x75300 at most in 100Hz PWM signal, when it use the macro SCT_MATCHREL_RELOADn_L(pulsePeriod); high half word 0x7 will be removed, it results problem obviously. But when the pulsePeriod is less than 0xFFFF, no problem.
#if 0
base->MATCH[pulseMatchReg] = SCT_MATCH_MATCHn_L(pulsePeriod);
base->MATCHREL[pulseMatchReg] = SCT_MATCHREL_RELOADn_L(pulsePeriod);
#else
base->MATCH[pulseMatchReg] = pulsePeriod;
base->MATCHREL[pulseMatchReg] = pulsePeriod;
#endif
Pls modify the function in fsl_sctimer.c
BR
XiangJun Rong
/*!
* brief Updates the duty cycle of an active PWM signal.
*
* Before calling this function, the counter is set to operate as one 32-bit counter (unify bit is set to 1).
*
* param base SCTimer peripheral base address
* param output The output to configure
* param dutyCyclePercent New PWM pulse width; the value should be between 0 to 100
* param event Event number associated with this PWM signal. This was returned to the user by the
* function SCTIMER_SetupPwm().
*/
void SCTIMER_UpdatePwmDutycycle(SCT_Type *base, sctimer_out_t output, uint8_t dutyCyclePercent, uint32_t event)
{
assert(dutyCyclePercent <= 100U);
assert((uint32_t)output < (uint32_t)FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS);
assert(1U == (base->CONFIG & SCT_CONFIG_UNIFY_MASK));
uint32_t periodMatchReg, pulseMatchReg;
uint32_t pulsePeriod = 0, period;
/* Retrieve the match register number for the PWM period */
periodMatchReg = base->EV[event].CTRL & SCT_EV_CTRL_MATCHSEL_MASK;
/* Retrieve the match register number for the PWM pulse period */
pulseMatchReg = base->EV[event + 1U].CTRL & SCT_EV_CTRL_MATCHSEL_MASK;
period = base->MATCH[periodMatchReg];
/* Calculate pulse width and period match value:
* For EdgeAlignedPwm, "pulsePeriod = 0" results in 0% dutycyle, "pulsePeriod = period - 1U" results in 100%
* dutycyle. For CenterAlignedPwm, , "pulsePeriod = 0" results in 0% dutycyle, "pulsePeriod = period + 2U"
* results in 100% dutycyle.
*/
pulsePeriod = (uint32_t)(((uint64_t)period * dutyCyclePercent) / 100U);
if (dutyCyclePercent == 100U)
{
if (0U == (base->CTRL & SCT_CTRL_BIDIR_L_MASK))
{
pulsePeriod = period + 2U;
}
else
{
pulsePeriod = period - 1U;
}
}
/* Stop the counter before updating match register */
SCTIMER_StopTimer(base, (uint32_t)kSCTIMER_Counter_U);
/* Update dutycycle */
//////////Rong wrote, pls modify
#if 0
base->MATCH[pulseMatchReg] = SCT_MATCH_MATCHn_L(pulsePeriod);
base->MATCHREL[pulseMatchReg] = SCT_MATCHREL_RELOADn_L(pulsePeriod);
#else
base->MATCH[pulseMatchReg] = pulsePeriod;
base->MATCHREL[pulseMatchReg] = pulsePeriod;
#endif
/* Restart the counter */
SCTIMER_StartTimer(base, (uint32_t)kSCTIMER_Counter_U);
}
I tried yesterday by setting updatedDutyCycle to 99 when it was 100, did not work.
Then I just tried to force it to 99 as you asked but the issue's still there.
Could it be a clock issue ?
Edit :
Something strange happens when I set dutycylcle to 99, the time to high is shorter than the time to high when I put 80.
I did some measurements with my oscilloscope. You can see in the table below the time to high for different dutycycles :
dutycycle | time to HIGH (µs) |
1 | 101 |
5 | 501 |
10 | 318 |
20 | 635 |
30 | 271 |
40 | 587 |
50 | 222 |
60 | 539 |
70 | 174 |
80 | 491 |
90 | 127 |
99 | 343 |
100 | 443 |