This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Phase shifted PWM on TIVA tm4c123gh6pm



Hello

I am trying to have 4 PWM waveforms in 2 sets, each set has two complimentary signals with a deadband and the two sets are phase shifted. The duty cycle of both the PWM generators are 50% and I need to control the phase shift.

The way I am trying to achieve this is to have the first set with an up/down pwm counter with a period of switching frequency. For the second phase shifted I have a down counter with twice the switching frequency and I want to toggle the output at the compare value. I am trying to write to HWREG PWMGENA but it seems to have no effect. Code below.

/*
 * main.c
 */

#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include <time.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_hibernate.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/hibernate.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/uart.h"
#include "driverlib/pwm.h"
#include "utils/uartstdio.h"
#include "utils/cmdline.h"
#include "drivers/rgb.h"
#include "drivers/buttons.h"
#include "dab_data.h"

duty_t duty;

int main(void) {

    FPUEnable();
    FPUStackingEnable();

    SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

    SysCtlPWMClockSet(SYSCTL_PWMDIV_1);

    duty.period1 = SysCtlClockGet()/100000;
    duty.deadband1 = duty.period1 * 5/100;
    duty.cycle1 = duty.period1 >> 1;
    duty.period2 = duty.period1 >> 1;
    duty.deadband2 = duty.period2 * 5/100;
    duty.cycle2 = duty.period2 >> 1;

    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    GPIOPinConfigure(GPIO_PB6_M0PWM0);
    GPIOPinConfigure(GPIO_PB7_M0PWM1);

    GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_6);
    GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_7);

    PWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_UP_DOWN |
            PWM_GEN_MODE_NO_SYNC);

    PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, duty.period1);

    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0, duty.cycle1);

    PWMDeadBandEnable(PWM0_BASE, PWM_GEN_0, duty.deadband1>>1,
            duty.deadband1>>1);

    PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT | PWM_OUT_1_BIT , true);

    PWMGenEnable(PWM0_BASE, PWM_GEN_0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    GPIOPinConfigure(GPIO_PA6_M1PWM2);
    GPIOPinConfigure(GPIO_PA7_M1PWM3);

    GPIOPinTypePWM(GPIO_PORTA_BASE, GPIO_PIN_6);
    GPIOPinTypePWM(GPIO_PORTA_BASE, GPIO_PIN_7);

    PWMGenConfigure(PWM1_BASE, PWM_GEN_1, PWM_GEN_MODE_DOWN |
            PWM_GEN_MODE_NO_SYNC);

    PWMGenPeriodSet(PWM1_BASE, PWM_GEN_1, duty.period2);
    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2, duty.cycle2);

    PWMDeadBandEnable(PWM1_BASE, PWM_GEN_1, duty.deadband2 >> 1,
            duty.deadband2 >> 1);

    PWMOutputState(PWM1_BASE, PWM_OUT_2_BIT | PWM_OUT_3_BIT , true);

    HWREG(PWM1_BASE+PWM_GEN_1+0x064) = 0x440;
    PWMGenEnable(PWM1_BASE, PWM_GEN_1);

    while(1)
    {

    }

    return 0;
}

Could someone please help me out here.

Thank you gain

  • Can you verify with a debugger that writing 0x440 to PWMGENA register did occur? Make sure your register address passed is correct. You have (PWM1_BASE+PWM_GEN_1+0x064) as PWMGENA constrol register, that seems odd to me. PWMGENA offset is 0x60 according to the datasheet.

    Angela

  • Hello Angela,

    Thank you for your reply.  I want my phase shift on the second module. So it is PWMGENB control. Anyway, I don't know why it wasn't working. I had a look at the PWM.c tivaware library files and modified it first verify that I was writing to the correct register and then I just changed the line to actual address(instead of PWM1_BASE) and it seems to work fine.

    HWREG(0x40029080 + 0x00000024) |= 0x440;

    I made a small blog post about it at https://sites.google.com/site/narasimhaweb/projects/phase-shifted-pwm-on-tiva-c-series-microcontrollers-with-dead-time-control in case someone else comes along with the same issue.

    P.S. Also, I don't know why but the same program does not work when I call the functions from ROM. Not sure whats going on there. Maybe there is a bug. For now,  I have no problem with the extra memory usage.

  • Hi,

    I am trying to drive a brushless DC motor, therefore I need 3 pwm signals shifted by 120 degres. In other words, the period divided by three. How can I do that? I have read the datasheet, but I did not understand the purpose of the HWREG.

    I would be really glad if you could give me an advice.

    Thank you,

    Feliphe

  • Hello Feliphe

    HWREG is a macro that is defined in hw_types.h in inc directory of the TivaWare installation, that is used to access an address in the device. The address is the parameter parsed to the macro.

    Regards
    Amit
  • Thank you Amit,

    Do you know where the HWREG fits when the subject is shifting a three phase pwm signal?

    Regards,

    Feliphe
  • Hello Feliphe,

    HWREG is a macro that can be used for accessing any valid address in the uC's address space. With respect to a 3 phase PWM signal, you would need to specify where it is being used in the application software.

    Regards
    Amit