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.

Using timer to generate precise pulses

Other Parts Discussed in Thread: TM4C1294NCPDT, ENERGIA

Hello, 

I'm trying to use a TM4C1294NCPDT to generate very precise interrupt-driven pulses using the hardware timers, and I'm not having much luck. I have the following code in an Energia sketch to (I hope) set up Timer 0A in 16-bit mode driven by the PIOSC clock at 16 MHz (?) with a prescale to get 1 microsecond ticks, and the timer configured for one-shot operation with a load of 10000 to get a 10 ms pulse. One external interrupt turns output on starts the timer and the timer's interrupt stops the timer and turns the output off. 

The code I have is not working as I intended, and I'm not smart enough to understand the TM4C1294NCPDT's datasheet for the timers. A few pointers on what I'm doing wrong would be greatly appreciated. 

#include "Energia.h"
#include <driverlib/timer.h>
#include <driverlib/sysctl.h>

void setup()
{
	Serial.begin(19200);

	pinMode(PB_3, INPUT_PULLDOWN);
	pinMode(PD_3, OUTPUT);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
	while (!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0));
	TimerConfigure(TIMER0_BASE, TIMER_CFG_A_ONE_SHOT);
	TimerClockSourceSet(TIMER0_BASE, TIMER_CLOCK_PIOSC);
	TimerPrescaleSet(TIMER0_BASE, TIMER_A, 16);
	TimerIntRegister(TIMER0_BASE, TIMER_A, lightOff);
	//TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
	TimerLoadSet(TIMER0_BASE, TIMER_A, 10000);

	attachInterrupt(PB_3, lightOn, RISING);
}

void loop()
{

}

void lightOff()
{
	digitalWrite(PD_3, LOW);
	TimerDisable(TIMER0_BASE, TIMER_A);
	TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
}

void lightOn()
{
	digitalWrite(PD_3, HIGH);
	TimerEnable(TIMER0_BASE, TIMER_A);
	TimerIntEnable(TIMER0_BASE, TIMER_A);
}

  • Hello Rudolph

    Why not use the PWM Mode of the timer to control LED lighting? Where the Output from the timer is independent of the interrupt and depends only on the counter values and match values.

    Regards,
    Amit
  • Hi Amit,

    The reason I can't use PWM because this is for an industrial lighting system with a smart camera driving the pulse. The camera generates a trigger pulse when it wants to take an image, and those pulses can be very sporadic and sometimes stay off for several seconds. Basically the light pulses need to be in response to a (potentially) very irregular external input.

    -Rudy
  • Hello Rudolph,

    Thanks for the clarification. Since I am not an expert at Energia, this is what I will suggest

    1. TimerClockSourceSet(TIMER0_BASE, TIMER_CLOCK_PIOSC); is not to be used on TM4C129 as it has a bug and errata already mentions this
    2. The Interrupt enable for Timer and the GPIO has not been done. This requires the use of IntEnable API Call.

    Regards
    Amit
  • Amit,

    The Timer interrupt enable is done inside the GPIO interrupt handler. The GPIO's interrupt is enabled by the Energia "attachInterrupt" function.

    Now, when I change the code above to use TIMER_CLOCK_SYSTEM and a prescale of 121 to get 1 us period timer, and keeping all other code the same, I get a very strange output:

    My output pulse is a 3.3 us wide, and 3.3 us delayed from the input pulse. Also, I get one of these delayed output pulses on both edges of the trigger signal, even though I only have rising edge selected for the external interrupt.

    -Rudy
  • Hello Rudy,

    The Timer Interrupt in the NVIC is not enabled by the TimerIntEnable. For that it requires IntEnable(INT_TIMER0A)

    To check the problem of dual edge trigger, you would need to get the register settings done for the GPIO to see if it is correctly configured.

    Regards
    Amit
  • Amit,

    Adding IntEnable(INT_TIMER0A) had no effect on the output. And changing "attachInterrupt" to

    GPIOIntRegister(GPIO_PORTB_BASE, lightOn);
    GPIOIntTypeSet(GPIO_PORTB_BASE, GPIO_INT_PIN_3, GPIO_RISING_EDGE);
    GPIOIntEnable(GPIO_PORTB_BASE, GPIO_INT_PIN_3);

    Turned my output into a constant pulse train that continued after the first trigger. And yes, I did have GPIOIntClear in my external interrupt handler. 

    Is the TM4C1294NCPDT system clock 120MHz as I believe? 

  • Hello Rudolph

    Yes, TM4C1294NCPDT has a maximum clock frequency of 120MHz.

    As for the constant pulse train the only explanation would be that somehow the PB3 is seeing edges which is causing the interrupt to trip. Can you connect an external pull down in the board you have.

    Regards
    Amit
  • Hi Amit,

    Sorry for the long delay, I was working on other projects. What it turns out is that I was missing TimerIntClear in my timer interrupt handlers. Without that, it wasn't firing repeatedly so much as just acting weird.

    After adding that simple function call, everything now works beautifully. Thank you for the help.
  • Hello Rudolph,

    Great. Even I had got biased by looking at the code multiple times.

    Regards
    Amit
  • Hi Rudolph,

    If you are using TM4C1294 you don´t need to use an ISR to handle a GPIO output to control your light, consider to use the new behaviour "ACT" of TIMER to control CCP pin, you can configure your TIMER with "TIMER_CFG_A_ACT_SETCLRTO" #define and your GPIO_PL4_T0CCP0 will SET at TIMER1 start and CLEAR at TIME_OUT. Consult your "timer.h" to more options and the datasheet of this device
    Think about it!!!

    Best regards
  • Tales,

    Unfortunately I didn't do the board layout for this device, and I have to use certain pins for output. Now these are, coincidentally, timer CCP pins. However two of the three pins I have to manage are Timer 3 CCP 0 and 1. I'm not sure if I can use Timer 3 A & B to manage them separately; Table 13-1 on the TM4C1294NCPDT datasheet references even and odd CCP pins, and I don't see how a pin can be both even and odd. 

    -Rudy

  • Hello Rudy,

    You can use Timer A and B separately only in 16 bit mode. In such a case A is the even pin and B is the odd pin.

    Regards
    Amit
  • Amit,

    In that case I'll try to convert my current code to the SETCLRTO and see how that works out.

    -Rudy
  • Well, I couldn't get the SETCLRTO to work. Also, while the output pins I have to work with are timer CCP pins, two of them are for the same timer. Right now, I have one hardware timer per driver channel which keeps things separate and organized.

    The GPIO interrupt system I'm using may be less efficient, but the outputs scope out very precise and perfectly consistent, so I'm happy.
  • Hello Rudolph,

    I understand that the code is working fine, but would like to understand what did not work?

    Regards
    Amit
  • I changed TimerConfigure to TIMER_CFG_A_SETCLRTO and then used the code

    GPIOPinTypeTimer(GPIO_PORTM_BASE, GPIO_PIN_0);
    GPIOPinConfigure(GPIO_PM0_T2CCP0);

    And PM2 wasn't being set. I didn't want to make too many radical changes to a system that worked, so at that point I gave up rolled back to the previous system.

    I may give this another shot from scratch on an EK-TM4C1294 eval board and then port it over if I can get that working. 

  • Hello Rudolph,

    The configuration of the GPIO is correct for the timer function. May be something in the timer configuration itself.

    Regards
    Amit
  • Hi Rudolph

    The timer may be configured like this:

    TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_ONE_SHOT | TIMER_CFG_A_ACT_SETCLRTO);

    Tales Amorim