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.
I want to capture time of negative edges on clock signal, and look at the period for multiple clock cycles. At moment I have a 68kHz clock with even mark space generated via PWM on PB0, this works fine, However I want to measure the period of say twenty clock cycles, in order to generate a synchronous sub clock. Using timer0A as capture, but can't get it to work. Project started off as a variant of the timer example, coupled with the LED drive at 1Hz via timer1, which works if I comment out the timer0 code. If I don't the code compiles and runs, but appears to constantly run into the timer0 interrupt. I did not set a value for the timer0A overflow as I left it to default 0xFFFF, which should be adequate given the clock speed. Can someone advise what I am doing wrong or missing. I am new to the Tiva C series, but much more familiar with the MSP430 timers, with which I have coded some complex quite functionality.
Code:
// include file references
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
//#include "inc/hw_types.h"
//#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
// constant defines
#define RED_LED GPIO_PIN_1
#define BLUE_LED GPIO_PIN_2
#define GREEN_LED GPIO_PIN_3
// variable defines
unsigned char toggleRED_LED = 0x00; // value for RED LED toggle
unsigned char toggleBLUE_LED = 0x04; // value for BLUE LED toggle
unsigned long timer1APeriod = 0; // value for timer 1A period
unsigned short timer2APeriod = 0;
unsigned short timer2AHalfPeriod = 0;
unsigned short currentClockCapture = 0; // value at negative edge
unsigned short lastClockCapture = 0; // value at last negative edge
//*****************************************************************************
//
// The interrupt handler for the first timer interrupt.
//
//*****************************************************************************
void Timer0IntHandler(void)
{
ROM_TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT); // clear the timer interrupt
currentClockCapture = ROM_TimerValueGet(TIMER0_BASE, TIMER_A);
lastClockCapture = currentClockCapture;
}
//*****************************************************************************
//
// The interrupt handler for the second timer interrupt.
//
//*****************************************************************************
void Timer1IntHandler(void)
{
ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT); // clear the timer interrupt
toggleBLUE_LED ^= 0x04;
ROM_GPIOPinWrite(GPIO_PORTF_BASE, BLUE_LED, toggleBLUE_LED);
toggleRED_LED ^= 0x02;
ROM_GPIOPinWrite(GPIO_PORTF_BASE, RED_LED, toggleRED_LED);
}
//*****************************************************************************
//
// This example application demonstrates the use of the timers to generate
// periodic interrupts and drive LEDs
//
//*****************************************************************************
int main(void)
{
ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);// sys clock to run at 80 Mhz from PLL with 16MHz crystal
timer1APeriod = SysCtlClockGet() - 1; // 1 Hz - SysCtlClockGet() divided by x, gives count for x Hz period
timer2APeriod = (SysCtlClockGet()/68000) - 1; // 68 kHz
timer2AHalfPeriod = (SysCtlClockGet()/136000) - 1; // 68/2 kHz
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // enable GPIO port B
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // enable GPIO port F
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // enable timer peripheral
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); // enable timer peripheral
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2); // enable timer peripheral
ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED);// enable the GPIO pins as output for the tri colour LED
ROM_GPIOPinConfigure(GPIO_PB0_T2CCP0 | GPIO_PB6_T0CCP0);// configure for peripherals
ROM_GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_6);// enable the GPIO pins for timer
ROM_TimerConfigure(TIMER0_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME));// timer0A configured 16 bit time capture
ROM_TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_NEG_EDGE);
ROM_IntEnable(INT_TIMER0A); // interrupt enabled for the timer0A
ROM_TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT); // interrupt setup for the timer0 capture events
ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC); // timer1A configured 32 bit periodic
ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, timer1APeriod);
ROM_IntEnable(INT_TIMER1A); // interrupt enabled for the timer0A
ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT); // interrupt setup for the timer0A timeouts
ROM_TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);// timer2A configured 16 bit PWM
ROM_TimerLoadSet(TIMER2_BASE, TIMER_A, timer2APeriod);
ROM_TimerMatchSet(TIMER2_BASE, TIMER_A, timer2AHalfPeriod);
ROM_IntMasterEnable(); // enable processor interrupts
ROM_TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);
ROM_TimerEnable(TIMER0_BASE, TIMER_A); // enable the timer0A
ROM_TimerEnable(TIMER1_BASE, TIMER_A); // enable the timer1A
ROM_TimerEnable(TIMER2_BASE, TIMER_A); // enable the timer2A
while(1); // loop forever while the timers run
}
OK comments everywhere, just helps me resolve code issues when switching from one project to another, micro to another, and long periods in between sorting hardware out
dBell
Hello David,
The 68KHz PWM pulse basically means a ned edge will come every 14us. Hence whenever you stop the core with the debugger, the chances are that you would be in the timer-0 interrupt loop
A simple check would be remove the input PWM signal and then check if it remains in the Interrupt Handler or not.
From initialization perspective it looks pretty clean, except that the IntEnable should be always be done after TimerIntEnable is done which should be done after TimerIntClear. This removes any stray interrupt from a previous run.
TimerIntClear
TimerIntEnable
IntEnable
Regards
Amit
Amit
Moving the Master Interrupt enable to just before the while(1), seems to have stopped the interrupt firing all the time when the 68kHz clock is removed from PB6. More work to do in debug to confirm the timer values are reported OK when the clock is re connected. In the datasheet tm4c123gh6pm.pdf section 11.3.2.4 Input Edge-Time Mode, we are told the capture values reside in GPTMTnR register, can you advise which ROM_ call I need to access this and pass it to a user register, such as currentClockCapture in the code. At moment I use currentClockCapture = ROM_TimerValueGet(TIMER0_BASE, TIMER_A); and this I presume returns the TAR value, not the captured timer value.
dBell
Hello David,
You are correct. The ROM_TimerValueGet is the correct API to use,
Regards
Amit
Amit Ashara said:From initialization perspective it looks pretty clean, except that the IntEnable should be always be done after TimerIntEnable is done which should be done after TimerIntClear. This removes any stray interrupt from a previous run.
TimerIntClear
TimerIntEnable
IntEnable
Amit's writing is perfectly clear above - yet he made the time/effort to really "drive the point home" with the sequential (program like) listing - as well.
Bravo - that care, attention to detail saves countless users lost time/effort - and goes far to enable clients to reach production sooner - rather than later - thus boosting Sales...
Amit
Thanks for the order info regards the interrupt settings and enables. I have now updated the code and still have problems. I hope you can help. The files are still the same as the original timer example except that I have updated to Compiler V5.1.5 and put the original setup_ccs.c back and removed the tm4c.... linker and tm4c...setup_ccs.c files from the project. The two interrupts are named as in the timer example. The problem I have is that when I remove the comments from the code below, the timer2 output does not work properly, so the capture won't work either. At this stage all I need to do is get the capture working properly. I have had it working once, however stopping and starting the code then stopped the timer2 PWM output. I have spent some time trying to get this to work, so perhaps someone else can see a mistake or something missing / wrong. Once fixed we will move on to using the capture count to create two synchronous sub clocks on two other timer channels.
revised code:
//*****************************************************************************
//
// This application produces 68kHz clock using timer2A in PWM mode and
// captures its time period using timer0A capture. The GREEN_LED of the
// tricolour LED illuminates if clock period samples properly, this allows
// any error glitches to be detected by monitoring PF3 with a logic analyser
//
// RED and BLUE LEDs are toggled at 1s interval by timer1A in periodic mode
//
//*****************************************************************************
// include file references
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
//#include "inc/hw_types.h"
//#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
// constant defines
#define RED_LED GPIO_PIN_1
#define BLUE_LED GPIO_PIN_2
#define GREEN_LED GPIO_PIN_3
#define CLOCK_OUT GPIO_PIN_0
#define CLOCK_SAMPLE GPIO_PIN_6
#define PWM GPIO_PB0_T2CCP0
#define CAPTURE GPIO_PB6_T0CCP0
// variable defines
uint32_t timer1APeriod = 0; // value for timer 1A period
uint16_t timer2APeriod = 0;
uint16_t timer2AHalfPeriod = 0;
uint16_t currentClockCapture = 0; // value at negative edge
uint16_t lastClockCapture = 0; // value at last negative edge
uint16_t masterClockPeriod = 0; // master clock period sampled
uint8_t error = 0;
uint32_t RED_LEDtoggle = 0x00000000; // value for RED toggle
uint32_t BLUE_LEDtoggle = 0x00000004; // value for BLUE toggle
uint32_t GREEN_LEDtoggle = 0x00000000;
//*****************************************************************************
//
// interrupt handler for the first timer interrupt
// capture negative edge of 68kHz clock and report period in multiples of 12ns
//
//*****************************************************************************
void Timer0IntHandler(void)
{
TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT); // clear the timer interrupt
currentClockCapture = TimerValueGet(TIMER0_BASE, TIMER_A);
masterClockPeriod = lastClockCapture - currentClockCapture;
lastClockCapture = currentClockCapture;
}
//*****************************************************************************
//
// interrupt handler for the second timer interrupt
// toggles RED_LED and BLUE_LED drive at 1s intervals
//
//*****************************************************************************
void Timer1IntHandler(void)
{
TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT); // clear the timer interrupt
RED_LEDtoggle ^= 0x00000002;
GPIOPinWrite(GPIO_PORTF_BASE, RED_LED|GREEN_LED, RED_LEDtoggle);
BLUE_LEDtoggle ^= 0x00000004;
GPIOPinWrite(GPIO_PORTF_BASE, BLUE_LED|GREEN_LED, BLUE_LEDtoggle);
}
//*****************************************************************************
//
// application demonstrates the use of the timers to generate
// periodic interrupts and drive LEDs
// port PB0 is used as output for a 68kHz clock signal generated by timer2A
//
//*****************************************************************************
int main(void)
{
SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);// system clock to run at 80 MHz from PLL with 16MHz xtal
timer1APeriod = SysCtlClockGet() - 1; // 1 Hz - SysCtlClockGet() divided by x, gives count for x Hz period
timer2APeriod = (SysCtlClockGet()/68000) - 1; // 68 kHz
timer2AHalfPeriod = (SysCtlClockGet()/136000) - 1; // 68/2 kHz
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // enable the GPIO port
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // enable the GPIO port
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // enable the timer peripherals
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); // enable the timer peripherals
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2); // enable the timer peripherals
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED);// configure the GPIO pins
GPIOPinConfigure(PWM); // configure for peripherals
// GPIOPinConfigure(PWM | CAPTURE); // configure for peripherals
GPIOPinTypeTimer(GPIO_PORTB_BASE, CLOCK_OUT); // enable the GPIO pins for timer
// GPIOPinTypeTimer(GPIO_PORTB_BASE, (CLOCK_OUT | CLOCK_SAMPLE));// enable the GPIO pins for timer
IntMasterEnable(); // enable processor interrupts
// IntPrioritySet(INT_TIMER0A, 0x00);
// IntPrioritySet(INT_TIMER1A, 0x40);
// TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME);// timer0A configured 32 bit time capture
// TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_NEG_EDGE);
// TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);
// IntEnable(INT_TIMER0A); // interrupt enabled for the timer0A
TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC); // timer1A configured 32 bit periodic
TimerLoadSet(TIMER1_BASE, TIMER_A, timer1APeriod);
TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT); // interrupt setup for the timer1A timeouts
IntEnable(INT_TIMER1A); // interrupt enabled for the timer1A
TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);// timer2A configured 16 bit PWM with output on PB0
TimerLoadSet(TIMER2_BASE, TIMER_A, timer2APeriod);
TimerMatchSet(TIMER2_BASE, TIMER_A, timer2AHalfPeriod);
// TimerEnable(TIMER0_BASE, TIMER_A); // enable the timer0A
TimerEnable(TIMER2_BASE, TIMER_A); // enable the timer2A
TimerEnable(TIMER1_BASE, TIMER_A); // enable the timer1A
while(1) // loop forever while the timers run
{
if (masterClockPeriod == 0x0498) // GREEN_LED goes off if not this value
{
GPIOPinWrite(GPIO_PORTF_BASE, GREEN_LED, 0x00000008);
error = 0;
}
else
{
GPIOPinWrite(GPIO_PORTF_BASE, GREEN_LED, 0x00000000);
error = 1;
}
}
}
The watch window has the following visible:
timer1APeriod unsigned int 79999999 0x20000100
timer2APeriod unsigned short 0x0497 (Hex) 0x20000104
timer2AHalfPeriod unsigned short 0x024B (Hex) 0x20000106
RED_LEDtoggle unsigned int 0 0x20000110
BLUE_LEDtoggle unsigned int 4 0x20000114
currentClockCapture unsigned short 0x0000 (Hex) 0x20000108
lastClockCapture unsigned short 0x0000 (Hex) 0x2000010A
error unsigned char 1 (Decimal) 0x2000010E
masterClockPeriod unsigned short 0x0000 (Hex) 0x2000010C
Hello David.
The configuration is of Timer-1 and Timer-2 but the Interrupt handler is for Timer-0 and Timer-1, shouldn't it be for Timer-1 and Timer-2?
Also please attach the code for the startup.c
Regards
Amit
Hi,
In function GPIOPinConfigure(), param ui32PinConfig is the pin configuration value, specified as only one of the GPIO_P??_??? values. Only one peripheral function at a time can be associated with a GPIO pin, and each peripheral function should only be associated with a single GPIO pin at a time.
Petrei
Thanks for advising about the GPIO_PB0_T2CCP0 not being a bit packing constant, I think that may have given me the unpredictable debug performance.
For now the 68kHz clock is generated by PWM so will be synchronous to the system clock, due to this the masterClockPeriod test actually works 100% of the time, I fully understand that with jitter or noise or temperature effects a clock source can change. In fact the clock source we are measuring will be external when the project is finished, so we will need to take the asyncronous nature including frequency drift into account, when creating additional sub clocks. We have done all this before successfully with an MSP430.
Regards blinking LED, when this code works it does not blink, however it is only used as an indicator of the capture value being correct. The true test is using a logic analyzer or oscilloscope on the LED drive pin PF3, and I can report that PF3 is high all the time and there are no glitches.
Separating the two GPIOPinConfigure lines seems to have made the code work, however when I exit the debug, reset the processor on the LaunchPad, I now find that I can't get the Timer1 interrupt to work, that was toggling the LED READ and BLUE. Even when I reflash the LaunchPad and run in debug again. Odd. In the past it was the PWM output that went AWOL after the first debug session.
dBell
Hi David,
Good to know your capture code works. About the Timer1 problem: wouldn't be better to use the SysTick timer for 1 second instead Timer1? Also you commented out the interrupt priority settings - maybe you set a higher prio for timer1?
Petrei
HI David
your code will be general debugging is fine .But while i download into Tiva c launchpad over after they d'not show any output.if any file required to enable in startup.c file.if its required plz send what file we enable details.
Hello CSReddy,
The startup.c is required for the interrupt, sp and pc vectors. The file that David had needs to be added to the CCS project. What is the exact issue that you face when downloading to the flash? Does it go into a bus fault, etc. Also do mention which device you are using e.g. TM4C123 or TM4C129?
Regards
Amit