AnsweredAssumed Answered

QN9080 - PWM problem

Question asked by Shai Berman on Feb 3, 2020
Latest reply on Feb 10, 2020 by Sebastián Del Río

Hello Team,

 

my customer has the following issue, could you please advise the below:

 

I am having a problem with using the SCTimer module on QN9080.

The interrupts do not seem to work properly, the interrupts seem to take way too much time.

I am attaching sample code and follows more details.

To use the code add the file to a new project include fsl_sctimer.h and comment out "SCTIMER_EventHandleIRQ","SCT0_IRQHandler" and finally run init on main.

 

Details:

needed output:

  • PWM output of sine wave in  488Hz with over sampling of 256

What was done:

  • Using a 32MHz clock, the needed PWM frequency is 125kHz (=clock/oversampling)
  • On SCTimer, set the limit counter to 255 (clock/desired frequency -1)
  • Set match event (SCTimer) to a value taken from lookup table at index i.
  • Set actions to clear output limit event and set the output for match event.
  • Then I set an interrupt for limit event
    • On the callback, update lookup index and load a new lookup value to the corresponding MATCHREL register

The problem

  • The resulting PWM output with a low pass (22kOhm and 10nF) was supposed to be 488Hz but was much lower.
  • I assumed the interrupts were handled slowly and so I commented out the driver ISR and rewrote it. In the end I managed to get 13Hz output.

// some how i did not managed to upload .C file so I have copy paste it here for you to review:

 

#include "stdint.h"

#include "fsl_sctimer.h"

#include "fsl_debug_console.h"

#include "pin_mux.h"

#include "fsl_gpio.h"

 

static const uint8_t lookupTable[LENGTH]={128, 131, 134, 137, 140, 143, 146, 149, 152, 156, 159, 162, 165, 168, 171, 174, 176, 179, 182, 185, 188, 191, 193, 196, 199, 201, 204, 206, 209, 211, 213, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 239, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 254, 254, 253, 253, 252, 252, 251, 250, 249, 248, 247, 246, 245, 244, 242, 241, 239, 238, 236, 235, 233, 231, 229, 227, 225, 223, 221, 219, 217, 215, 212, 210, 207, 205, 202, 200, 197, 195, 192, 189, 186, 184, 181, 178, 175, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, 138, 135, 132, 129, 126, 123, 120, 117, 113, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, 77, 74, 71, 69, 66, 63, 60, 58, 55, 53, 50, 48, 45, 43, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 19, 17, 16, 14, 13, 11, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 42, 44, 46, 49, 51, 54, 56, 59, 62, 64, 67, 70, 73, 76, 79, 81, 84, 87, 90, 93, 96, 99, 103, 106, 109, 112, 115, 118, 121, 124, 128};

static volatile uint8_t increment=1;

static volatile uint8_t oversamplingCounter=0;

static volatile uint8_t lookupIndex=0,pulsePeriod;

static volatile uint32_t periodEvent,pulseMatchReg;

void SCTIMER_EventHandleIRQ(SCT_Type *base){}

void SCT0_IRQHandler(){

if(++oversamplingCounter==0){

SCT0->SCTMATCHREL[pulseMatchReg] = (uint32_t)pulsePeriod;

pulsePeriod=lookupTable[++lookupIndex];

}

}

 

void init(){

sctimer_config_t sctimerInfo;

uint32_t sctimerClock = CLOCK_GetFreq(kCLOCK_BusClk);

SCTIMER_GetDefaultConfig(&sctimerInfo);

SCTIMER_Init(SCT, &sctimerInfo);

uint32_t period;

uint32_t pwmFreq_Hz=125000U;

uint32_t pulseEvent;

/* Set unify bit to operate in 32-bit counter mode */

SCT0->CONFIG |= SCT_CONFIG_UNIFY_MASK;

/* Calculate PWM period match value */

period = (sctimerClock / pwmFreq_Hz) - 1;

/* Calculate pulse width match value */

pulsePeriod = (uint32_t)lookupTable[0];

/* Schedule an event when we reach the PWM period */

SCTIMER_CreateAndScheduleEvent(SCT, kSCTIMER_MatchEventOnly, period, 0, kSCTIMER_Counter_L, &periodEvent);

/* Schedule an event when we reach the pulse width */

SCTIMER_CreateAndScheduleEvent(SCT, kSCTIMER_MatchEventOnly, pulsePeriod, 0, kSCTIMER_Counter_L, &pulseEvent);

/* Retrieve the match register number for the PWM pulse period */

pulseMatchReg = SCT->EVENT[pulseEvent].CTRL & SCT_EVENT_CTRL_MATCHSEL_MASK;

/* Reset the counter when we reach the PWM period */

SCTIMER_SetupCounterLimitAction(SCT, kSCTIMER_Counter_L, periodEvent);

/* For high-true level */

/* Set the initial output level to low which is the inactive state */

SCT0->OUTPUT &= ~(1U << kSCTIMER_Out_0);

/* Set the output when we reach the PWM period */

SCTIMER_SetupOutputSetAction(SCT, kSCTIMER_Out_0, periodEvent);

/* Clear the output when we reach the PWM pulse value */

SCTIMER_SetupOutputClearAction(SCT, kSCTIMER_Out_0, pulseEvent);

SCTIMER_EnableInterrupts(SCT,1<<pulseEvent);

PRINTF("%d",SCT->EVEN);

NVIC_SetPriority(SCT0_IRQn, 4);

NVIC_EnableIRQ(SCT0_IRQn);

SCTIMER_StartTimer(SCT, kSCTIMER_Counter_L);

PRINTF("PWM started.\r\n");

}

Thanks in advance

 

Best regards,

Shai Berman

Outcomes