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.

TM4C1294 TIVA C Series timers, and seconds

Hallo community,

Sine its my first time using the Launchpad im trying to figure out how interrupt controled timing works.
So basically i want to measure time from when I turn on a Led to where i press a button.
I have understood the basics of timers and I cant get it to calculate the time properly.
Here is what I did in Code:

Note, The turning on and off of the LEDS is for debug reasons only.

---------------------------------------------------------------------------------------------------------------------------------------

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>


#include "inc/hw_ssi.h"
#include "inc/hw_types.h"
#include "driverlib/ssi.h"

#include "inc/tm4c1294ncpdt.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/systick.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/uart.h"
#include "time.h"
#include "driverlib/timer.h"


#define TIMEOUT 0xFFFFFFFF
#define F_CPU 16000000	// 16MHz
volatile uint32_t ButtonTime = 0;
volatile uint32_t ButtonTimeinms = 0;

void ISR_Button_interrupt(void)
{


	GPIOIntClear(GPIO_PORTJ_BASE,GPIO_PIN_0);
	TimerDisable(TIMER1_BASE,TIMER_BOTH);
	ButtonTime=TIMEOUT-TimerValueGet(TIMER1_BASE, TIMER_A);
	ButtonTimeinms = (ButtonTime*1000) / F_CPU;


	TimerLoadSet(TIMER1_BASE,TIMER_A,TIMEOUT);


}
void init_interrupt(void)
{
    GPIOIntRegister(GPIO_PORTJ_BASE, ISR_Button_interrupt);
    GPIOIntTypeSet(GPIO_PORTJ_BASE, GPIO_PIN_0, GPIO_FALLING_EDGE);
    GPIOIntEnable(GPIO_PORTJ_BASE, GPIO_PIN_0);

}

void init(void)
{
	uint32_t oldpadconfig_strength;
	uint32_t oldpadconfig_type;
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
	TimerClockSourceSet(TIMER1_BASE,TIMER_CLOCK_SYSTEM);
	TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
	TimerUpdateMode(TIMER1_BASE,TIMER_A,TIMER_UP_LOAD_IMMEDIATE);
	TimerLoadSet(TIMER1_BASE,TIMER_A,TIMEOUT);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
	GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_0);
	GPIOPadConfigGet(GPIO_PORTJ_BASE, GPIO_PIN_0,&oldpadconfig_strength,&oldpadconfig_type);
	GPIOPadConfigSet(GPIO_PORTJ_BASE, GPIO_PIN_0,oldpadconfig_strength,GPIO_PIN_TYPE_STD_WPU);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
	GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_4);


}

uint8_t GetUsrSW1(void) {
	return (uint8_t) GPIOPinRead(GPIO_PORTJ_BASE, GPIO_PIN_0);
}

void delay(int s)
{
	SysCtlDelay(s*40000); /*in milliseconds*/
}


void main(void)
{
	int status = 0;




	init();
	init_interrupt();

	if (GetUsrSW1()== 1) {
		status = 1;
		GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,1);
			while (GetUsrSW1()==1);
		}

		while (status == 1){
			GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,0);
			delay(250);
			GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,1);
			TimerEnable(TIMER1_BASE,TIMER_BOTH);
			delay(1000);
			GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,0);
			delay(100);
			GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,1);
			delay(100);
			

		}



}

  • Hello Benjamin,

    I am a little confused looking at your code.

    In the main loop, you are checking the status of USR_SW1 using polling method. You also configure the GPIO interrupt on the falling edge for USR_SW1.

    Why do you need to use both of these? Why can't you pick one of the two methods (either polling or interrupt)?

    Thanks,
    Sai
  • Hello Sai,

    I have to use interrupts since it is mandatory for the project I have to hand in.
    And since I understand polling better i used it to get as far as I could

    Kindest regards,

    Benjamin

  • Hello Benjamin,

    Looks like the purpose of the assignment is to use interrupts. Using both (interrupts and polling) unnecessarily complicates the logic.

    I would recommend that you use Interrupts (as that is a requirement) to accomplish your assignment.

    Thanks,
    Sai
  • Hello Sai,
    So what would I have to change to get the correct timing in milliseconds?

    Kindest regards,
    Ben
  • Hi

    So your only question is what should be the load value?

    Well if you want the timer to generate a interrupt every 1ms then:

    Load_value= 80000000/1000.

    So its the system clock divided by the interrupt frequency.

  • Good find Luis but seemingly that timer would be 16mHz/80000 = 12.5us timer periods.

    Had made similar mistake for very long time then discovered to calculate timers clock base, this case SYSCLK period (62.5ns*n) as the timer load value. So SYSCLK period times the timers load value and work backwards from 1ms to find (n) value.

    80000 = 5ms @62.5ns timer (16mHz) SYSCLK periods. So 80000/4 = 20000 * 62.5ns = 1.25ms and 1/x=800.

  • BP101 said:
    Good find Luis but seemingly that timer would be 16mHz/80000 = 12.5us timer periods.



    I don't quite get what you mean.

    What I am basing my math on is:
    The timer clock is the same as the system clock - so considering 80Mhz system clock (am I mistaken? Is it not the same as the CPU clock?), meaning each timer increment means 12.5ns have passed.

    So each count is 12.5ns. You want a 1ms period. So 0.001 / 0.0000000125 (1ms/12.5ns) = 80000. Since this using periods (interrupt period / system clock period), using frequency is: 80Mhz/1Khz (system clock frequency / interrupt frequency).



    Can you please explain why you divide 80000 by 4 to get 1.25ms (80000 is 5ms in 16Mhz timer so wouldn't make sense to divide it by 5 to get 1ms?)

    BP101 said:
    80000 = 5ms @62.5ns timer (16mHz) SYSCLK periods. So 80000/4 = 20000 * 62.5ns = 1.25ms and 1/x=800.

  • Hi Luis,

    Thought you might believe SYSCLK was perhaps set 120mHz and not 80Mhz. 

    Yet the posters code shows: #define F_CPU 16000000  // 16MHz

    So it appeared posters GPTM base clock was 16Mhz same as CPU clock speed. Point was dividing GPTM base frequency MHZ value versus by 1/x period is mistake made some time ago. 

    Actually your second answer is much closer checking it again 80000/5=16000*62.5ns=1ms exactly. 

    Windows 7 calculator have to check answer twice, at times produces strange answers. Checked again it just gave an answer (80000/5=5000) and I know dang well I entered 80000 divide by 5.

  • Hey,
    All of this still sounds a little confusing codewhise.
    Might seem like a stupid question but what would i have to change on the existing Code to properly measure in ms after all of the above?

    kindest Regards,
    Ben
  • First and most important if a button is being pressed you must debounce the switch closure in software even when polling. There are some programming examples on how to debounce. The best thing if just beginner is make a flow chart on paper with boxes and input/output lines on each box to indicate your intended pragmatic flow with yes/no directives at each critical point.

    Experience programmers do that (see code) in thought process and even that gets dicey at times when timers and interrupts are in play.
    Sounds like some work (pencil paper) but will help to debug your code later when or if it fails. The GPTM can indicate the number of milliseconds that pass from a single button press up to a preset time asserting LED ON based on (initial load count) and the time out interrupt that follows while in down count mode.