LPC55S06 100Hz PWM with dutycycle change

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC55S06 100Hz PWM with dutycycle change

Jump to solution
2,728 Views
francoisB
Contributor III

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.

 

SCR01.PNG

 

You can find the code here : https://pastebin.com/BHBZC0hn .

 

Thanks for helping me.

 

François

 

 

0 Kudos
1 Solution
2,660 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

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);
}

View solution in original post

10 Replies
2,715 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport
Hi,
 
I have checked your code, I think your computation of the ledLogoValue  has issue, it is your application code, pls check yourself.
 
Pls  modify the code like this, then check if the duty cycle can extend to all cycle time.
Hope it can help you
BR
XiangJun Rong
 
void SCTIMER_LED_HANDLER()
{
    sctimerIsrFlag = true;
    static uint8_t state1 = 0;
    static uint8_t state2 = 0;
    static uint8_t state3 = 0;
    logo_cycle_time++;
   if(logo_cycle_time<(sizeof(ledLogoProfilValues)/4))  logo_cycle_time=0;

 
 
    updatedDutycycle = (uint8_t)(ledLogoProfilValues[logo_cycle_time] * 100 / 3073;
 
 
    if (SCTIMER_GetStatusFlags(SCT0) & (1 << eventNumberOutput))
    {
        /* Clear interrupt flag.*/
        SCTIMER_ClearStatusFlags(SCT0, (1 << eventNumberOutput));
    }
}

 

0 Kudos
2,706 Views
francoisB
Contributor III

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). 

SCR01.PNG

 

Thanks for your reply.

 

François

 

0 Kudos
2,682 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

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);

xiangjun_rong_0-1634110720612.png

 

0 Kudos
2,675 Views
francoisB
Contributor III

It's working because you set the pwm frequency to 24kHz. Could you try with 100Hz to see if it still works please ?

0 Kudos
2,663 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

I can duplicate your issue, when the PWM frequency is 100Hz, the duty cycle is abnormal.

I will check the code later.

BR

Xiangjun Rong

Tags (1)
0 Kudos
2,661 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

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);
}

2,653 Views
francoisB
Contributor III

Thank you very much, it works !

0 Kudos
2,697 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

The range of the updatedDutycycle is from 1 to 99, do you have issue if you set the variable in the range?

BR

XiangJun Rong

0 Kudos
2,693 Views
francoisB
Contributor III

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.

 

SCR03.png

0 Kudos
2,684 Views
francoisB
Contributor III

I did some measurements with my oscilloscope. You can see in the table below the time to high for different dutycycles :

dutycycletime to HIGH (µs)
1101
5501
10318
20635
30271
40587
50222
60539
70174
80491
90127
99343
100443

 

0 Kudos