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