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.
Tool/software: Code Composer Studio
Hello,
I have been working on a program that needs to read the duty cycle of a PWM input signal and generate an appropriate proportional output signal. The program uses Timer 0 (split into two half-width timers) to capture the rising and falling edges from the PWM signal, and Timer 1 to periodically update the proportional signal. While debugging, I discovered that while Timer 1 is not enabled, the program reads the PWM signal perfectly. When both Timers 0 and 1 are enabled, the capture times for the rising/falling edges aren't lined up as they should for the given PWM signal.
I've pasted the code below. Is there anything I can change that would fix this problem?
#include <stdint.h> #include <stdbool.h> #include "inc/tm4c123gh6pm.h" #include "inc/hw_gpio.h" #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "driverlib/pin_map.h" #include "driverlib/fpu.h" #include "driverlib/rom.h" #include "driverlib/gpio.h" #include "driverlib/qei.h" #include "driverlib/sysctl.h" #include "driverlib/uart.h" #include "utils/uartstdio.h" #include "driverlib/timer.h" #include "driverlib/interrupt.h" #include "gaitdata/gaitdata.h" #include "pwmwrite/pwmwrite.h" volatile uint32_t currentpos = 0; volatile uint32_t goalpos = 0; //as indicated by index volatile int32_t error = 0; volatile uint32_t index = 0; //keeps track of point in gait data volatile int32_t PIDsignal = 0; //signal that alters goalpwmhigh volatile uint32_t proportional = 50; //P from PID volatile uint32_t goalpwmhigh = 2048; //duty value, out of 4096 volatile uint32_t goalduty = 50; //duty in % volatile float rawgoalpos = 0; //THIS BLOCK FOR PWMREAD static volatile uint32_t periodStartTime = 0; static volatile uint32_t periodStartTimePrevious = 0; static volatile uint32_t pulseEndTime = 0; static volatile uint32_t pulseWidth = 0; static volatile uint32_t periodWidth = 1; static volatile float dutyCycle = 0; static volatile uint32_t encoderValue = 0; void timer1ISR(void) { TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT); rawgoalpos = getKneeData(index); goalpos = (float)250.0 + (float)2.88 * ((float)rawgoalpos - (float)28.5); currentpos = encoderValue; error = currentpos - goalpos; PIDsignal = proportional * error; goalpwmhigh = 2048 + PIDsignal; if (goalpwmhigh > 3696) { goalpwmhigh = 3696; } else if (goalpwmhigh < 410) { goalpwmhigh = 410; } goalduty = (float)100 * ((float)goalpwmhigh / (float)4096); setPulseWidth(50, goalduty); index++; if(index == 1000) { index = 0; } } void timerARisingISR(void) { // // CALCULATE PERIOD WIDTH // // clear interrupt source TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT); // retrieve the clock count at event trigger time periodStartTime = ((TimerValueGet(TIMER0_BASE, TIMER_A) << 16) >> 16); // if timer overflow occurred, calculate period width accordingly assuming 16 bit timer if (periodStartTime < periodStartTimePrevious) { periodWidth = periodStartTime + (65536 - periodStartTimePrevious); } // if no timer overflow since last event else { periodWidth = periodStartTime - periodStartTimePrevious; } // calculate duty cycle dutyCycle = (((float)pulseWidth/(float)periodWidth)); encoderValue = (dutyCycle*1024); UARTprintf("rising\n"); UARTprintf("periodStartTime: %u\n", periodStartTime); UARTprintf("periodStartTimePrevious: %u\n", periodStartTimePrevious); // mark current period start time as being old periodStartTimePrevious = periodStartTime; } void timerBFallingISR(void) { // clear interrupt source TimerIntClear(TIMER0_BASE, TIMER_CAPB_EVENT); // retrieve the clock count at event trigger time pulseEndTime = ((TimerValueGet(TIMER0_BASE, TIMER_B) << 16) >> 16); // if 16 bit timer overflowed, calculate pulse width accordingly if (pulseEndTime < periodStartTime) { pulseWidth = pulseEndTime + (65536 - periodStartTime); } // if timer did not overflow else { pulseWidth = pulseEndTime - periodStartTime; } UARTprintf("falling\n"); UARTprintf("pulseEndTime: %u\n", pulseEndTime); } int main(void) { //set clock to 40 MHz SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN); //enable UART0 SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); //enable GPIOF SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // TIMER0 peripheral, and GPIO ports B and F SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // Wait for the TIMER0 module to be ready while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0)) { } // configure PB6 for timer A capture GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6); GPIOPinConfigure(GPIO_PB6_T0CCP0); // configure PB7 for timer B capture GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_7); GPIOPinConfigure(GPIO_PB7_T0CCP1); // Configure TimerA as a half-width one-shot timer, and TimerB as a // half-width edge capture counter. TimerConfigure(TIMER0_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP | TIMER_CFG_B_CAP_TIME_UP)); // TIMER_CLOCK_SYSTEM: use 40MHz system clock // TIMER_CLOCK_PIOSC: use 16MHz precision internal oscillator for timing signals // It appears PIOSC might not be an option for the TM4C123GH6PM TimerClockSourceSet(TIMER0_BASE, TIMER_CLOCK_SYSTEM); // set a prescaler value for timerA and timerB to ensure that overflow occurs more slowly than PWM periods // timer frequency currently set to: 10MHz // for some reason this isn't working right now and timer is still running at 40MHz //TimerPrescaleSet(TIMER0_BASE, TIMER_BOTH, 4); // Configure TimerA to mark time of rising edge, configure TimerB to mark time of falling edge TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE); TimerControlEvent(TIMER0_BASE, TIMER_B, TIMER_EVENT_NEG_EDGE); // clear both interrupts TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT); // register timer interrupt service routines //TimerIntRegister(TIMER0_BASE, TIMER_A, *timerARisingISR); //TimerIntRegister(TIMER0_BASE, TIMER_B, *timerBFallingISR); // enable the interrupts for the two timers, A detects rising edge, B detects falling edge TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT); // enable interrupts for timerA and timerB IntEnable(INT_TIMER0A); IntEnable(INT_TIMER0B); // enable timer module 1 SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); // wait for timer module 1 to be ready while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER1)) { } // configure one full width timer, counting down TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC); // set timer 1 to run off of system clock TimerClockSourceSet(TIMER1_BASE, TIMER_CLOCK_SYSTEM); // set timer to reset at 10Hz TimerLoadSet(TIMER1_BASE, TIMER_A, SysCtlClockGet() / 100); // register the timer interrupt service routine TimerIntRegister(TIMER1_BASE, TIMER_A, *timer1ISR); // clear rollover interrupt and then enable it TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT); TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT); IntEnable(INT_TIMER1A); //configure GPIO Pins for UART 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, 921600, 16000000); GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3); GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3); IntMasterEnable(); //synchronize timer A and timer B to start on the same clock cycle TimerSynchronize(TIMER0_BASE, TIMER_0A_SYNC | TIMER_0B_SYNC); //start the timers TimerEnable(TIMER0_BASE, TIMER_BOTH); TimerEnable(TIMER1_BASE, TIMER_A); while(1) { //nothing! } }