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.

Problems with PWM

Hello all,

I'm using the TM4C123GXL to try and generate a PWM signal corresponding to a sine wave, as triggered by a button press. I'm using repetitions for each "sample" of the sine wave and I'm trying to change the pulse-width each time I've used the sample 5 times.

The code I've written so far is:

#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include <stdio.h>
#include <stdlib.h>
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/debug.h"
#include "driverlib/pwm.h"
#include "driverlib/pin_map.h"
#include "driverlib/interrupt.h"
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#define TARGET_IS_BLIZZARD_RB1
#include "driverlib/rom.h"

#define PI 3.1415926535897932384
#define N 64
#define PWM_FREQUENCY 200000

volatile uint32_t ui32Load;
volatile uint32_t ui32PWMClock;
volatile uint32_t ui32Adjust;
volatile uint32_t sample_counter = 0;
volatile uint32_t ZOH_counter = 1;
volatile float x[N];
volatile uint32_t button_flag = 0;

int main(void)
{
	volatile float fs = 100.0;
	volatile float f_sine = 10.0;
	uint32_t i;

	ROM_FPULazyStackingEnable();
	ROM_FPUEnable();
	ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
	ROM_SysCtlPWMClockSet(SYSCTL_PWMDIV_2);

	for (i = 0; i < N; i++)
	{
		x[i] = 0.95 * sinf(2 * PI * (f_sine / fs) * i);
	}

	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
	HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01;
	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;
	ROM_GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_DIR_MODE_IN);
	GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);

	GPIOIntClear(GPIO_PORTF_BASE, GPIO_PIN_0);
	GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_FALLING_EDGE);
	GPIOIntEnable(GPIO_PORTF_BASE, GPIO_PIN_0);
	ROM_IntEnable(INT_GPIOF);

	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	ROM_GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0);
	ROM_GPIOPinConfigure(GPIO_PD0_M1PWM0);

	ui32PWMClock = SysCtlClockGet() / 2;
	ui32Load = (ui32PWMClock / PWM_FREQUENCY) - 1;
	PWMGenConfigure(PWM1_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN);
	PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0, ui32Load);

	ROM_PWMGenIntClear(PWM1_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO);
	ROM_PWMGenIntTrigEnable(PWM1_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO);
	ROM_PWMIntEnable(PWM1_BASE, PWM_INT_GEN_0);
	ROM_IntEnable(INT_PWM1_0);

	ROM_IntMasterEnable();

	while(1)
	{
		if(button_flag == 1)
		{
			ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, (uint32_t)(roundf((ui32Load + 1) / 2)));
			ROM_PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT, true);
			ROM_PWMGenEnable(PWM1_BASE, PWM_GEN_0);

			while (sample_counter < N)
			{
			}

			ROM_PWMGenDisable(PWM1_BASE, PWM_GEN_0);
			ROM_PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT, false);
			button_flag = 0;
			sample_counter = 0;
			ZOH_counter = 1;
		}
	}
}

void Switch0IntHandler(void)
{
	GPIOIntClear(GPIO_PORTF_BASE, GPIO_PIN_0);
	button_flag = 1;
}

void PWM1Gen0IntHandler(void)
{
	ROM_PWMGenIntClear(PWM1_BASE, PWM_GEN_0, PWM_INT_CNT_ZERO);
	ZOH_counter++;
	if(ZOH_counter == 5)
	{
		sample_counter++;
		ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, (uint32_t)(roundf((ui32Load + 1)*((x[sample_counter] + 1) / 2))));
		ZOH_counter = 0;
	}
}

I have three questions regarding the above code's performance.

1. I'm getting problems with the first pulse each time I press the button. 

The first time I press the button, I get a chain of pulses starting with this: 

So I'm getting an unwanted extra first pulse.

The second time pressing the button, and the ones following that, give me:

Zoom-in on the first pulses:

So I'm getting a pulse adjacent to the first one I actually want (and it also has different width than the first intended one), and it apparently starts when the line enabling the output (PWMOutputState) is executed. 

2. I'm having issues using extreme duty-cycle values- if I hadn't multiplied the sine wave to generate by 0.95 I'd have duty cycle values corresponding to 98 PWM clock cycles, for example, and for some reason this gives me a pulse having a duty cycle of 100%- that is, I don't see the pulse go to '0'. Is this some kind of known issue, or is there something wrong with the code?

3.  I've tried setting the pulse width differently instead of attenuating the sine wave, by using the following line in the PWM int handler instead of the existing one:

ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, (uint32_t)(roundf((ui32Load + 1)*(0.45 * x[sample_counter] + 0.5)));

What this gave me was chains of 6-7 repetitions instead of the 5 I had intended to get - is this due to the longer time it takes to calculate the new width, or something of the sort?

I'd appreciate any help- thanks in advance!

Avner

  • Hello Avner

    I think you are using immediate load instead of load on timeout. That would be the cause of the issue where the PWM Duty Cycle seems to be different for the first pulse after a change.

    Ours (and other vendors) DC output from PWM tends to have issues at the extreme ends of the DC. But that should be for DC where only 1-2 clock is involved and not early enough at 95%. 100% condition is not possible.

    Note that the condition is ZOH_counter is set for compare of 5. Hence it will count from 0 to 5 (which is 6 interrupts).

    Regards
    Amit