Hello,
I am trying to determine the PWM pulse width value on 4 pins: PF0, PF1, PF2, PF3. Right now I am using PF1 to generate PWM (works great). Originally I used 32-bit timers Timer0 and Timer1 to read pulse width on PF0 and PF2 and that worked well. Since I need a total of 4 pins I decided to split Timer0 and Timer1 into split 16-bit timers. The moment I do that my code stops working. I am not getting the proper value anymore. Testing showed that the interrupt handler works properly, ISR determines which pin caused interrupt properly, pulse width calculation is correct. I think the timers setup causes problems. I would appreciate any help, thank you.
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_timer.h"
#include "inc/tm4c123ge6pm.h" // Definitions for the interrupt and register assignments.
#include "inc/hw_gpio.h"
#include "driverlib/fpu.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom.h"
#include "driverlib/pin_map.h"
#include "driverlib/uart.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"
#include "driverlib/pwm.h"
#include "utils/uartstdio.h"
void ConfigureUART(void);
void ConfigureTimers(void);
void ConfigurePWM(void);
void ConfigureGPIO(void);
void IntDefaultHandler(void);
void InputPF0(void);
void InputPF1(void);
void InputPF2(void);
void InputPF3(void);
void print_float(double v);
uint32_t systemClock;
// PF0 is tied to timer 0A
volatile float pulseWidth0 = 0;
volatile uint32_t timer0AValue = 0;
// PF1 is tied to timer 0B
volatile float pulseWidth1 = 0;
volatile uint32_t timer0BValue = 0;
// PF2 is tied to timer 1A
volatile float pulseWidth2 = 0;
volatile uint32_t timer1AValue = 0;
// PF3 is tied to timer 1B
volatile float pulseWidth3 = 0;
volatile uint32_t timer1BValue = 0;
double timerPeriod;
int main(void)
{
volatile uint32_t load;
volatile uint32_t dutyCycle;
volatile uint32_t pwmClock;
uint32_t pwmFrequency = 1000; // sets PWM frequency to Hz
// System clock, 200/10 = 20 MHz
SysCtlClockSet(SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |SYSCTL_OSC_MAIN);
systemClock = SysCtlClockGet();
timerPeriod = (double)1/systemClock;
// Configuring PWM clock
SysCtlPWMClockSet(SYSCTL_PWMDIV_64);
pwmClock = SysCtlClockGet() / 64;
load = ((pwmClock/pwmFrequency) - 1); // setting PWM period
dutyCycle = load/2; // 50% duty cycle
ConfigurePWM();
ConfigureUART();
ConfigureTimers();
ConfigureGPIO();
// Set PWM period
PWMGenPeriodSet(PWM1_BASE, PWM_GEN_2, load);
// PWM duty cycle
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_5_BIT, dutyCycle);
while(1)
{
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_5, dutyCycle);
}
}
void ConfigurePWM(void)
{
// Enable the peripherals
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1); // Module 1
// Configure pins as PWM
GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_1);
GPIOPinConfigure(GPIO_PF1_M1PWM5);
// Configure the PWM generator
PWMGenConfigure(PWM1_BASE, PWM_GEN_2, PWM_GEN_MODE_DOWN);
// Turn on output pin
PWMOutputState(PWM1_BASE, PWM_OUT_5_BIT, true);
// Enable PWM generator
PWMGenEnable(PWM1_BASE, PWM_GEN_2);
}
// Have to attach PF1
void ConfigureGPIO(void)
{
// Configuring PF0, PF1, PF2, PF3 as inputs and attaching interrupt to them
// PF1 is removed for now since it generates PWM
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
// Wait for the peripheral to be ready
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)){}
// Unlock the pins on port F
HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
HWREG(GPIO_PORTF_BASE + GPIO_O_CR) = 0xFF;
GPIOIntRegister(GPIO_PORTF_BASE, IntDefaultHandler);
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3);
GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_BOTH_EDGES);
GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_0 | GPIO_INT_PIN_2 | GPIO_INT_PIN_3);
}
void ConfigureUART(void)
{
// Enable the GPIO Peripheral used by the UART.
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
// Enable UART0
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
// Configure GPIO Pins for UART mode.
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
// Use the internal 16MHz oscillator as the UART clock source.
UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
// Initialize the UART for console I/O.
UARTStdioConfig(0, 115200, 16000000);
}
void ConfigureTimers(void)
{
// Timer 0 is 32-bits split into 16-bit timer A and 16-bit timer B
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0)){}
TimerConfigure(TIMER0_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP | TIMER_CFG_B_PERIODIC_UP));
// Timer 1 is 32-bits split into 16-bit timer A and 16-bit timer B
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER1)){}
TimerConfigure(TIMER1_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP | TIMER_CFG_B_PERIODIC_UP));
}
void IntDefaultHandler(void)
{
uint32_t status = 0;
status = GPIOIntStatus(GPIO_PORTF_BASE, true);
// Clear interrupt flag
GPIOIntClear(GPIO_PORTF_BASE,status);
// Check which pin triggered the interrupt
if((status & GPIO_INT_PIN_0) == GPIO_INT_PIN_0)
{
InputPF0();
}
if((status & GPIO_INT_PIN_1) == GPIO_INT_PIN_1)
{
InputPF1();
}
if((status & GPIO_INT_PIN_2) == GPIO_INT_PIN_2)
{
InputPF2();
}
if((status & GPIO_INT_PIN_3) == GPIO_INT_PIN_3)
{
InputPF3();
}
}
void InputPF0(void)
{
// Check the input pin state
if ( GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_0) == GPIO_PIN_0) // rising edge
{
HWREG(TIMER0_BASE + TIMER_O_TAV) = 0; // load 0 to the timer
TimerEnable(TIMER0_BASE,TIMER_A); //start timer to record
}
else // falling edge
{
TimerDisable(TIMER0_BASE,TIMER_A); //stop timer
timer0AValue = TimerValueGet(TIMER0_BASE,TIMER_A); //record value
pulseWidth0 = (double)(timerPeriod*timer0AValue*1000000); // PWM width in us
}
UARTprintf("\nTimer PF0 = %d\n", timer0AValue);
print_float(pulseWidth0);
}
void InputPF1(void)
{
// Check the input pin state
if ( GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_1) == GPIO_PIN_1) // rising edge
{
HWREG(TIMER0_BASE + TIMER_O_TBV) = 0; // load 0 to the timer
TimerEnable(TIMER0_BASE,TIMER_B); //start timer to record
}
else // falling edge
{
TimerDisable(TIMER0_BASE,TIMER_B); //stop timer
timer0BValue = TimerValueGet(TIMER0_BASE,TIMER_B); //record value
pulseWidth1 = (double)(timerPeriod*timer0BValue*1000000); // PWM width in us
}
UARTprintf("\nTimer PF1 = %d\n", timer0BValue);
print_float(pulseWidth1);
}
void InputPF2(void)
{
// Check the input pin state
if ( GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_2) == GPIO_PIN_2) // rising edge
{
HWREG(TIMER1_BASE + TIMER_O_TAV) = 0; // load 0 to the timer
TimerEnable(TIMER1_BASE,TIMER_A); //start timer to record
}
else // falling edge
{
TimerDisable(TIMER1_BASE,TIMER_A); //stop timer
timer1AValue = TimerValueGet(TIMER1_BASE,TIMER_A); //record value
pulseWidth2 = (double)(timerPeriod*timer1AValue*1000000); // PWM width in us
}
UARTprintf("\nTimer PF2 = %d\n", timer1AValue);
print_float(pulseWidth2);
}
void InputPF3(void)
{
// Check the input pin state
if ( GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_3) == GPIO_PIN_3) // rising edge
{
HWREG(TIMER1_BASE + TIMER_O_TBV) = 0; // load 0 to the timer
TimerEnable(TIMER1_BASE,TIMER_B); //start timer to record
}
else // falling edge
{
TimerDisable(TIMER1_BASE,TIMER_B); //stop timer
timer1BValue = TimerValueGet(TIMER1_BASE,TIMER_B); //record value
pulseWidth3 = (double)(timerPeriod*timer1BValue*1000000); // PWM width in us
}
UARTprintf("\nTimer PF3 = %d\n", timer1BValue);
print_float(pulseWidth3);
}
void print_float(double v)
{
int decimal = 2;
int i = 1;
int intPart, fractPart;
for (;decimal!=0; i*=10, decimal--);
intPart = (int)v;
fractPart = (int)((v-(double)(int)v)*i);
if(fractPart < 0) fractPart *= -1;
UARTprintf("%i.%i us\n\r", intPart, fractPart);
}