SPWM WITH SCT BLOCK AND DMA

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

SPWM WITH SCT BLOCK AND DMA

577 Views
skanda19
Contributor III

Hello, 

I am trying to generate a Sine PWM signal with fewer ISR, my source code looks like this at the moment: 

#include "board.h"
 
 
/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/
 
#define SCT_PWM            LPC_SCT
#define SCT_PWM_PIN_OUT    4 /* COUT4 Generate square wave */
 
#define SCT_PWM_OUT        1 /* Index of OUT PWM */
#define SCT_PWM_RATE    512 /* PWM frequency 51.2 KHz */
 
// LED_W
#define LED_W_PORT    0
#define LED_W_PIN      19
#define LED_W_OUT      LPC_GPIO->DIR[LED_W_PORT] |= (1UL << LED_W_PIN)
#define LED_W_HI      LPC_GPIO->B[LED_W_PORT][LED_W_PIN] = true
#define LED_W_LO      LPC_GPIO->B[LED_W_PORT][LED_W_PIN] = false
#define LED_W_INP      LPC_GPIO->DIR[LED_W_PORT] &= ~(1UL << LED_W_PIN)
#define LED_W_IN      LPC_GPIO->B[LED_W_PORT][LED_W_PIN]
/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/
#define TABLE_SIZE 20
uint16_t sine_table[TABLE_SIZE] = {488,647,788,897,962,975,935,848,721,569,408,256,129,41,2,15,80,188,330,488};
/*****************************************************************************
 * Private functions
 ****************************************************************************/
 
/* Setup board specific pin muxing */
static void app_setup_pin(void)
{
Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 1, IOCON_FUNC3 | IOCON_MODE_INACT | IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 19, IOCON_FUNC0 | IOCON_MODE_INACT | IOCON_DIGITAL_EN);
}
 
/*****************************************************************************
 * Public functions
 ****************************************************************************/
 
void update_pwm()
{
    static uint16_t index = 0;
    static uint8_t counter = 0;
    if(counter == 0) {
        LPC_SCT->MATCHREL[1].L = sine_table[index] ;
        index = (index + 1) % TABLE_SIZE;
    }
    counter = (counter + 1) % 5;
 
LED_W_INP;
}
 
 
void SCT0_IRQHandler(void)
{
if (LPC_SCT->EVFLAG & (1 << 0)) 
    {
        update_pwm();
        LPC_SCT->EVFLAG = (1 << 0); // clear flag of event 0
    }
}
 
 
void STC0_Init(void)
{
/* Initialize the SCT as PWM and set frequency */
Chip_SCTPWM_Init(SCT_PWM);
NVIC_EnableIRQ(SCT0_IRQn);
Chip_SCTPWM_SetRate(SCT_PWM, SCT_PWM_RATE);
LPC_SCT->EVENT[1].STATE = 0xFFFFFFFF; // valid event on all states
LPC_SCT->EVENT[1].CTRL = (1 << 0) | (1 << 12); //  MATCH[1].L and match event
LPC_SCT->EVFLAG = (1 << 0); // clear flag of event 0 
LPC_SCT->EVEN = (1 << 0); // enable interrupt for event 0
 
}
 
int main(void)
{
int loop = 1; /* Prevents the unreachable statement warning */
 
/* Generic Initialization */
SystemCoreClockUpdate();
Board_Init();
STC0_Init();
 
 
/* Setup Board specific output pin */
app_setup_pin();
 
/* Use SCT0_OUT1 pin */
//LED_W_OUT;
Chip_SCTPWM_SetOutPin(SCT_PWM, SCT_PWM_OUT, SCT_PWM_PIN_OUT);
Chip_SCTPWM_Start(SCT_PWM);
 
 
while (loop) {
__WFI();
}
return 0;
}


This code is a modified version from the SCT example, I been able to successfully generate the modulation for the sine wave and after low pass filter I get good enough result BUT the main drawback is that it requires lots of interrupts.  
 
I want to configure the DMA to update the MATCHREL[1] to change the match value after the match register has reloaded the value 5 times (for signal integrity mainly). 


I know that I have to enable the SCT DMAREQ0 to match the event 0 and also have to match it with DMA_ITRIG_INMUX[2]. 
 
But ain't sure what would be the right configuration required on the DMA side to be able to work with the size of the array that is getting loaded into the SCT blocks. 
 
can someone of tech support help get a general direction based on the code I have provided ???


thanks.  
0 Kudos
Reply
5 Replies

510 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

Pls refer to the application note an11538.pdf which I attached.

I suppose that you should follow up the procedures:

1)use the code in AN so that you can output a PWM signal via PWM output pin without interrupt and DMA involved.

2)have the SCT to generate interrupt, in the ISR, update the PWM duty cycle  with sine-table as you have done without DMA involved. You can see the variable duty cycle of PWM via scope.

3)disable SCT interrupt, use DMA to update the PWM duty cycle. While you have to enable DMA interrupt after a sine cycle has completed, in the DMA ISR, assign the sine-table address to the DMA source address.

For the SCT module, you can use register access as the AN, for the DMA, you can call the SDK function.

Hope it can help you

BR

XiangJun Rong

 

0 Kudos
Reply

504 Views
skanda19
Contributor III

Thanks for replying, would it be possible to update the Duty Cycle of the SCT without any interrupt ? even without the DMA interrupt that you suggested ???

0 Kudos
Reply

497 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

Of course, it is impossible to update duty cycle without interrupt.

I just give you suggestion from simplicity to complexity.

Can you output PWM signal now?

Hope it can help you

BR

XiangJun Rong

0 Kudos
Reply

491 Views
skanda19
Contributor III

understood, Yes, let me share the script. 

At this time the program will have the trigger by hardware set and creating the request for the interruption. I am having an issue were I can only transfer the first item of the buffer instead of the whole thing. 

so the program generates a PWM output and only transfers one item from the buffer.  

please see attachment. 

0 Kudos
Reply

562 Views
skanda19
Contributor III

This is the code I have developed so far:

 

 
#include "board.h"
 
 
/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/
 
#define SCT_PWM            LPC_SCT
#define SCT_PWM_PIN_OUT    4 /* COUT4 Generate square wave */
 
#define SCT_PWM_OUT        1 /* Index of OUT PWM */
#define SCT_PWM_RATE    51200 /* PWM frequency 51.2 KHz */
 
#define SCT_PWM_CHANNEL 0  // Definir el canal del SCT para el PWM
#define SIZE_SINE_TABLE (sizeof(sine_table) / sizeof(sine_table[0]))
 
 
volatile bool dmaDone;
 
 
 
// LED_W
#define LED_W_PORT    0
#define LED_W_PIN      19
#define LED_W_OUT      LPC_GPIO->DIR[LED_W_PORT] |= (1UL << LED_W_PIN)
#define LED_W_HI      LPC_GPIO->B[LED_W_PORT][LED_W_PIN] = true
#define LED_W_LO      LPC_GPIO->B[LED_W_PORT][LED_W_PIN] = false
#define LED_W_INP      LPC_GPIO->DIR[LED_W_PORT] &= ~(1UL << LED_W_PIN)
#define LED_W_IN      LPC_GPIO->B[LED_W_PORT][LED_W_PIN]
/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/
#define TABLE_SIZE 20
uint16_t sine_table[TABLE_SIZE] = {488,647,788,897,962,975,935,848,721,569,408,256,129,41,2,15,80,188,330,488};
/*****************************************************************************
 * Private functions
 ****************************************************************************/
 
/* Setup board specific pin muxing */
static void app_setup_pin(void)
{
Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 1, IOCON_FUNC3 | IOCON_MODE_INACT | IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 19, IOCON_FUNC0 | IOCON_MODE_INACT | IOCON_DIGITAL_EN);
}
 
/*****************************************************************************
 * Public functions
 ****************************************************************************/
 
void update_pwm()
{
    static uint16_t index = 0;
    static uint8_t counter = 0;
    if(counter == 0) {
        LPC_SCT->MATCHREL[1].L = sine_table[index] ;
        index = (index + 1) % TABLE_SIZE;
    }
    counter = (counter + 1) % 5;
 
LED_W_INP;
}
 
 
void SCT0_IRQHandler(void)
{
if (LPC_SCT->EVFLAG & (1 << 0)) 
    {
        update_pwm();
        LPC_SCT->EVFLAG = (1 << 0); // clear flag of event 0
    }
}
 
 
void STC0_Init(void)
{
/* Initialize the SCT as PWM and set frequency */
Chip_SCTPWM_Init(SCT_PWM);
NVIC_EnableIRQ(SCT0_IRQn);
Chip_SCTPWM_SetRate(SCT_PWM, SCT_PWM_RATE);
LPC_SCT->EVENT[1].STATE = 0xFFFFFFFF; // valid event on all states
LPC_SCT->EVENT[1].CTRL = (1 << 0) | (1 << 12); //  MATCH[1].L and match event
LPC_SCT->EVFLAG = (1 << 0); // clear flag of event 0 
LPC_SCT->EVEN = (1 << 0); // enable interrupt for event 0
LPC_SCT->DMAREQ0 |= (1 << 1);
}
 
void DMA_IRQHandler(void)
{
    if ((Chip_DMA_GetIntStatus(LPC_DMA) & DMA_INTSTAT_ACTIVEERRINT) != 0) {
        Chip_DMA_DisableChannel(LPC_DMA, DMA_CH21);
        while ((Chip_DMA_GetBusyChannels(LPC_DMA) & (1 << DMA_CH21)) != 0) {}
        Chip_DMA_AbortChannel(LPC_DMA, DMA_CH21);
        Chip_DMA_ClearErrorIntChannel(LPC_DMA, DMA_CH21);
        Chip_DMA_EnableChannel(LPC_DMA, DMA_CH21);
 
    }
 
    Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_CH21);
 
    dmaDone = true;
}
 
int main(void)
{
    int loop = 1; /* Prevents the unreachable statement warning */
    DMA_CHDESC_T sct_pwm_dma_descriptor;  
    /* Generic Initialization */
    SystemCoreClockUpdate();
    Board_Init();
    STC0_Init();
 
    /* Setup Board specific output pin */
    app_setup_pin();
    
    /* Use SCT0_OUT1 pin */
    //LED_W_OUT;
    Chip_SCTPWM_SetOutPin(SCT_PWM, SCT_PWM_OUT, SCT_PWM_PIN_OUT);
    Chip_SCTPWM_Start(SCT_PWM);
    
    Chip_DMA_Init(LPC_DMA);
    Chip_DMA_Enable(LPC_DMA);
    Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
 
    // Configura el canal de DMA
    Chip_DMA_EnableChannel(LPC_DMA, DMA_CH21);
    Chip_DMA_EnableIntChannel(LPC_DMA, DMA_CH21);
    Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_CH21,
        (DMA_CFG_PERIPHREQEN | DMA_CFG_TRIGTYPE_EDGE | DMA_CFG_TRIGPOL_HIGH |
        DMA_CFG_BURSTPOWER_16 | DMA_CFG_CHPRIORITY(0)));
 
    sct_pwm_dma_descriptor.source = DMA_ADDR(&sine_table[SIZE_SINE_TABLE]);
    sct_pwm_dma_descriptor.dest = DMA_ADDR(&(LPC_SCT->MATCHREL[1].L));
    sct_pwm_dma_descriptor.next = DMA_ADDR(&sine_table[SIZE_SINE_TABLE]);
 
    NVIC_EnableIRQ(DMA_IRQn);
 
    while (loop) {
        __WFI();
        
        // Configura el descriptor de transferencia y válida el canal
        Chip_DMA_SetupTranChannel(LPC_DMA, DMA_CH21, &sct_pwm_dma_descriptor);
        Chip_DMA_SetValidChannel(LPC_DMA, DMA_CH21);
 
        // Configura la transferencia de datos y dispara el DMA
        Chip_DMA_SetupChannelTransfer(LPC_DMA, DMA_CH21,
            (DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTA | DMA_XFERCFG_SWTRIG | DMA_XFERCFG_RELOAD|
            DMA_XFERCFG_WIDTH_16 | DMA_XFERCFG_SRCINC_1 | DMA_XFERCFG_DSTINC_0 |
            DMA_XFERCFG_XFERCOUNT(SIZE_SINE_TABLE)));
 
        while (dmaDone == false) {}; // Espera a que se complete la transferencia DMA
    }
    return 0;
}


I see on debug mode that on register DAMREQ0 and bit DRQ0 is set, the description says if I can see this bit set there's probably some issue with the configuration on the DMA side. 


would you be able to help me catch the mistake on the configuration of the DMA side ???


I am complete newbie with DMA. 
 
 
thanks. 
0 Kudos
Reply