LPC55S28 SCTimer two PWM outputs with different frequencies

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

LPC55S28 SCTimer two PWM outputs with different frequencies

Jump to solution
1,254 Views
vanska
Contributor II

Hi,

I have tried to generate 2 PWM outputs with SCT0 of LPC55S28.

The requirements:

  • No CPU load (callbacks)
  • Outputs must be synchronized
  • Output X must have a frequency of output Y times 4
  • Duty cycle of both outputs must be 50 %

No luck yet with the examples or the PWM cookbook. Is this possible in theory?

2 PWM outputs with different frequencies2 PWM outputs with different frequencies

Edit: The signal of SCTIMER_Out_X in the picture is actually 8MHz while it should be 4MHz.

Labels (2)
0 Kudos
1 Solution
1,232 Views
vanska
Contributor II

Got it working. The resolution is not that good with MHz frequencies, though.

Here's one solution that might require some refactoring:

uint32_t pwmFrequency = frequency * 4;
uint32_t sctClock = CLOCK_GetFreq(kCLOCK_BusClk) / (((base->CTRL & SCT_CTRL_PRE_L_MASK) >> SCT_CTRL_PRE_L_SHIFT) + 1U);

uint32_t period = (sctClock / pwmFrequency) - 1U;	// edge aligned PWM
uint32_t pulsePeriod = (period * 50U) / 100U;		// pulse width match value

base->MATCHREL_ACCESS16BIT[0].MATCHRELL = (uint16_t)(period * 4);	// match value for 1MHz

for (uint8_t i = 1; i < 8; i++)
{
	// Match values for the rest of the events
	base->MATCHREL_ACCESS16BIT[i].MATCHRELL = (uint16_t)((uint16_t)(i/2) * period + (i%2) * pulsePeriod);
}

for (uint8_t i = 0; i < 8; i++)
{
	base->EV[i].STATE = 0xFFFFFFFF;                 // all states
	base->EV[i].CTRL = (i << 0) | (1 << 12);        // match i condition only
}

base->OUT[2].SET = (1 << 0);                        // event 0 will set SCT0_OUT2
base->OUT[2].CLR = (1 << 4);                        // event 4 will clear SCT0_OUT2
base->OUT[3].SET = 0x55;                            // even events (0, 2, 4, 6) will set SCT0_OUT3
base->OUT[3].CLR = 0xAA;                            // odd events (1, 3, 5, 7) will clear SCT0_OUT3

base->CTRL &= ~(SCT_CTRL_HALT_L_MASK);              // start/unhalt timer by clearing bit 2 of CTRL register

View solution in original post

0 Kudos
2 Replies
633 Views
laugechristense
Contributor II

I realize I am late for the party but I found a more flexible solution.
I used it to generate a 1MHz 50% dutycycle signal synchronized to a kHz 20% dutycyle.
I used the peripherals perspective in mcuxpresso, so it is hard to share source code, but the setup is as follows:
SCT clock is 16 MHz, using a prescaler of 8, the counter frequency is 2 MHz.

event 0:
match event with match value 0
action: toggle sct output 1

event 1
match event with match value 400
action: clear sct output 2

event 2
match event with match value 1999
action: set sct output 2 and limit counter (restart it from zero).

in the source code, add the following line before starting the timer:
SCT0->EV[0].CTRL |= SCT_EV_CTRL_MATCHMEM(1);
This means that the event 0 fires every clock after the initial match. since the match is set to 0 it just toggles the output at 1MHz from the the timer is started.

event 1 and event 2 control the second output and are responsible for limiting the timer.
They can be set almost independently of event0.

summary:
Choose a prescaler to get a counter frequency twice as fast as the fastest signal, by using the MATCHMEM setting of event 0.
Use two indenpendent events to set the second pwm channel and limit the counter.

 

Cheers,

Lauge

 

0 Kudos
1,233 Views
vanska
Contributor II

Got it working. The resolution is not that good with MHz frequencies, though.

Here's one solution that might require some refactoring:

uint32_t pwmFrequency = frequency * 4;
uint32_t sctClock = CLOCK_GetFreq(kCLOCK_BusClk) / (((base->CTRL & SCT_CTRL_PRE_L_MASK) >> SCT_CTRL_PRE_L_SHIFT) + 1U);

uint32_t period = (sctClock / pwmFrequency) - 1U;	// edge aligned PWM
uint32_t pulsePeriod = (period * 50U) / 100U;		// pulse width match value

base->MATCHREL_ACCESS16BIT[0].MATCHRELL = (uint16_t)(period * 4);	// match value for 1MHz

for (uint8_t i = 1; i < 8; i++)
{
	// Match values for the rest of the events
	base->MATCHREL_ACCESS16BIT[i].MATCHRELL = (uint16_t)((uint16_t)(i/2) * period + (i%2) * pulsePeriod);
}

for (uint8_t i = 0; i < 8; i++)
{
	base->EV[i].STATE = 0xFFFFFFFF;                 // all states
	base->EV[i].CTRL = (i << 0) | (1 << 12);        // match i condition only
}

base->OUT[2].SET = (1 << 0);                        // event 0 will set SCT0_OUT2
base->OUT[2].CLR = (1 << 4);                        // event 4 will clear SCT0_OUT2
base->OUT[3].SET = 0x55;                            // even events (0, 2, 4, 6) will set SCT0_OUT3
base->OUT[3].CLR = 0xAA;                            // odd events (1, 3, 5, 7) will clear SCT0_OUT3

base->CTRL &= ~(SCT_CTRL_HALT_L_MASK);              // start/unhalt timer by clearing bit 2 of CTRL register
0 Kudos