Hi,
I have tried to generate 2 PWM outputs with SCT0 of LPC55S28.
The requirements:
No luck yet with the examples or the PWM cookbook. Is this possible in theory?
Edit: The signal of SCTIMER_Out_X in the picture is actually 8MHz while it should be 4MHz.
Solved! Go to Solution.
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
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
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