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.

Something wrong using timer to capture pulses



I config the a WTIMER as  two split timer for event capture. The two signal input are nearly same. But one of the two timers is always later to match the same match value. And the load value of the two timer is the same. All I've figured out is that one of the timer work normally while the other one went wrong when the value is close to the match value. And I wonder why. Here's the code. I am using lm4f120.

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "utils/uartstdio.h"
#include "driverlib/pwm.h"
#include "driverlib/timer.h"
#include "inc/hw_ints.h"
#include "driverlib/interrupt.h"

void right(void)
{
	TimerIntClear(WTIMER1_BASE, TIMER_CAPA_MATCH);//clear the interrupt
	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, 0);
	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_6, 0);
	UARTprintf("\nhello world, left\n");
}
void left(void)
{
	TimerIntClear(WTIMER1_BASE, TIMER_CAPB_MATCH);//clear the interrupt
	GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_5, 0);
	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_5, 0);
	UARTprintf("\nhello world, right\n");
}

//*****************************************************************************
//To init the motor's pins, start to output after the func been called 
//*****************************************************************************
void ACMotorInit(void)
{
	//Set the GPIOs
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

	GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_5);
	GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_5);
	GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_6);
	GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7);

	//The pwm pin
	//Config PB3 as T3CCP1
	GPIOPinConfigure(GPIO_PB3_T3CCP1);
	GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_3);
	//Config PB2 as T3CCP0
	GPIOPinConfigure(GPIO_PB2_T3CCP0);
	GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_2);
	//Config the timer
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);
	TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM | TIMER_CFG_B_PWM);
	TimerLoadSet(TIMER3_BASE, TIMER_B, 60000);
	TimerMatchSet(TIMER3_BASE, TIMER_B, 30000);
	TimerLoadSet(TIMER3_BASE, TIMER_A, 60000);
	TimerMatchSet(TIMER3_BASE, TIMER_A, 30000);
	TimerEnable(TIMER3_BASE, TIMER_B);
	TimerEnable(TIMER3_BASE, TIMER_A);

	//Timer counter
	//WTIMER1 PC6 PC7
	SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER1);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);

	//Config the timer
	TimerConfigure(WTIMER1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_COUNT 
			| TIMER_CFG_B_CAP_COUNT);
	//Config C6 as WT1CCP0
	GPIOPinConfigure(GPIO_PC6_WT1CCP0);
	GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_6);
	//Config C7 as WT1CCP1
	GPIOPinConfigure(GPIO_PC7_WT1CCP1);
	GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_7);

	//Event ctl
	TimerControlEvent(WTIMER1_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
	TimerControlEvent(WTIMER1_BASE, TIMER_B, TIMER_EVENT_POS_EDGE);
	//Load set
	//TimerLoadSet(WTIMER1_BASE, TIMER_A, 0);
	//TimerLoadSet(WTIMER1_BASE, TIMER_B, 0);
	//Match set
	TimerMatchSet(WTIMER1_BASE, TIMER_A, 1000);
	TimerMatchSet(WTIMER1_BASE, TIMER_B, 1000);

	//Timer int enable
	TimerIntRegister(WTIMER1_BASE, TIMER_A, right);
	TimerIntRegister(WTIMER1_BASE, TIMER_B, left);
	TimerIntEnable(WTIMER1_BASE, TIMER_CAPA_MATCH | TIMER_CAPB_MATCH);
	IntEnable(INT_WTIMER1A);
	IntEnable(INT_WTIMER1B);
	IntMasterEnable();
	//Timer enable
	//TimerEnable(WTIMER1_BASE, TIMER_A);
	//TimerEnable(WTIMER1_BASE, TIMER_B);
}

//*****************************************************************************
//The left wheel to rotate exact distance
//the uint of the distance is the number of pulse of the photogate
//dir=1 to go ahead
//TimerB->Left
//*****************************************************************************
void LeftRotate(uint8_t dir, uint32_t distance)
{
	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7, dir?(~GPIO_PIN_7):GPIO_PIN_7);
	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_6, dir?GPIO_PIN_6:(~GPIO_PIN_6));
	TimerLoadSet(WTIMER1_BASE, TIMER_B, distance+1000);
	TimerEnable(WTIMER1_BASE, TIMER_B);
}

//*****************************************************************************
//The right wheel to rotate exact distance
//the uint of the distance is the number of pulse of the photogate
//dir=1 to go ahead
//TimerA->right
//*****************************************************************************
void RightRotate(uint8_t dir, uint32_t distance)
{
	GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_5, dir?GPIO_PIN_5:~GPIO_PIN_5);
	GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_5, dir?~GPIO_PIN_5:GPIO_PIN_5);
	TimerLoadSet(WTIMER1_BASE, TIMER_A, distance+1000);
	TimerEnable(WTIMER1_BASE, TIMER_A);
}

//*****************************************************************************
//To adjust the rotate speed
//the var speed ranges from 0 to 100
//*****************************************************************************
void SpeedAdj(uint32_t speed)
{
	TimerMatchSet(TIMER3_BASE, TIMER_B, speed*100);
}

  • Hello Wen,

    When 2 or more interrupts occur the CPU will resolve the priority first and then service the interrupt. So even if the two interrupts occur together, the one with the highest priority will get services. Secondly the use of Print in ISR is not a good practice as it is Block Write and hence will delay the exit from one ISR and entry to the other ISR.

    Also there is always delay when a ISR is called as there is a PUSH-POP operation to SRAM which will take a few clock cycles.

    Regards

    Amit

  • Thanks for answering. I do understand what you mentioned. But I can't understand why this happened when the timer's value changes from 120 to 789, which is even out of the load value I set. Can you please explain that for me?

  • Hello Wen,

    In the code post the Wide Timer Load Value is commented. So it will take the default load value. Scondly the timer by default is in down count mode. Hence the count will be from Load to Match where Load has the default value of 1's. If you want it to count upto match, then you must configure it in Up Count Mode.

    Does that answer the question or am I by any chance mis-reading the question still?

    Regards

    Amit

  • The timer is not enabled untill I set the load value in the RightRotate or LeftRotate fun. The timer will start to count down when I called these fun, which is clear to me. What puzzled me is the penomenon that when one of the two timer count down to 120, the next value occured is 789, or sometimes other unexpected value. 

  • Hello Wen,

    1. Can you give a value of the "distance" variable in the functions, so that I can checl

    2. Which register and which API are you using to read the timer count?

    Regards

    Amit

  • I assume distance can be any value bigger than 1000. Actually, the match value was firstly 0. I changed it into 1000 in order to correct the deviate. And I failed. I use TimerValueGet() to get the value of the timer.

  • Hello Wen,

    Please check the following forum thread on a very similar issue:

    http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/354038/1242339.aspx#1242339

    Regards

    Amit