Wednesday, November 17, 2010

Configuring and playing with Timer of LPC1768

After saying Hello to LPC1768 and blinking an LED using delay through GPIO, it is time to use the timer for blinking the LED. First let us just get the timer running and then with the help of interrupts we shall blink the LED. For all the register description we require LPC17xx manual.



For using any of the LPC1768 peripherals, the general steps to be followed are
1. Power Up the peripheral to be used.
2. Set the Clock Rate for the peripheral
3. Connect necessary pins using Pin Connect Block.
4. Initialize the registers of the peripheral.

Go to page 490 in the manual and follow the links provided there
1. Powering the Timer0 (Table 46, page 63)

LPC_SC->PCONP |= 1 << 1; //Power up Timer 0

2. After enabling it you need to give the clock for Timer0 (Table 40, page 56. For Timer2/3 refer Table 41, page 57) Select clock as per your requirements.

LPC_SC->PCLKSEL0 |= 1 << 3; // Clock for timer = CCLK/2

3. Configuring the interrupt
LPC1768 contains 4 match registers for each timer. These match registers can be used to reset the timer, generate interrupt, stop the timer, to generate timing signal on an external pin. Now we shall use Timer0 Match0 register to generate the interrupt.

Give a suitable value to Match Register 0

LPC_TIM0->MR0 = 1 << 20; // Give a value suitable for the LED blinking frequency based on the clock frequency

Configure it as to interrupt when the timer count matches the Match0 (Table 429, page 496)

LPC_TIM0->MCR |= 1 << 0; // Interrupt on Match0 compare

Reset the timer (Table 427, page 494)

LPC_TIM0->TCR |= 1 << 1; // Reset Timer0

Enable Timer interrupts

NVIC_EnableIRQ(TIMER0_IRQn); // Enable timer interrupt

And finally start the timer (Table 427, page 494)

LPC_TIM0->TCR |= 1 << 0; // Start timer

4. Now configure the pin to which LED is connected on the GPIO port to output mode

    LPC_SC->PCONP |= ( 1 << 15 ); // power up GPIO
    LPC_GPIO1->FIODIR |= 1 << 29; // puts P1.29 into output mode

5. Write the interrupt routine
Give the interrupt vector as TIMER0_IRQHandler and it is very important to check the source of the interrupt inside an interrupt routine. It can be done by checking the IR register of the TIMER0. Here the source of the interrupt can be identified by looking for a bit that is high in IR. The next thing that we should do is to clear this flag. Otherwise another interrupt will be generated as soon as this interrupt is serviced as the interrupt flag will be high. (Table 426, page 493)

void TIMER0_IRQHandler (void)
{
    if((LPC_TIM0->IR & 0x01) == 0x01) // if MR0 interrupt
    {
        LPC_TIM0->IR |= 1 << 0; // Clear MR0 interrupt flag
        LPC_GPIO1->FIOPIN ^= 1 << 29; // Toggle the LED
    }
}

The compiled Eclipse code of the LED blinking with the help of Timer is Here.

33 comments:

Anonymous said...

Great explanation man! Keep it up!

degama said...

the line
LPC_TIM0->TCR |= 1 << 1;
must be followed by
LPC_TIM0->TCR &= 0 << 1;
because how it is written in manual
"The counters remain reset until TCR[1] is returned to zero."

venkatesh said...

hi

this is the uart initialization code. should i do anything more than this for initialization?

void uart_init()
{
PINCON->PINSEL0 |= 0x00000050;
UART0->LCR = 0x00000083;
UART0->DLL = 0x000000075;
UART0->LCR = 0x00000003;
}

-venkat

Thejasvi said...

Venkatesh,

For every peripherial on LPC17xx you will need to follow the below steps

1. Power up the required peripheral (look at PCONP)

2. Give clock to the peripheral (look at PCLKSEL)

3. Set peripheral specific registers (In this case the baud rate, interrupts etc.)

4. Select the appropriate functionality for the output pins (see PINSEL and PINMODE registers)

Currently you have just selected the pin and setup the UART registers, but you have not given clock to it nor have you powered it up.

venkatesh said...

power reset value is 1. and clock is 18. cclk/4 by default. thats wat i did.

but still no luck.

- venkat.

Thejasvi said...

What do you mean by saying that it is not working? Is there no output on the TX pins of LPC17xx?

Did you do a loopback or echo test by connecting the TX pin of LPC17xx to RX pin of itself? If you did, what did you observe?

venkatesh said...

hi thejasvi,

I tried with the example image of uart given by the board manufacturer. now, i am getting garbage for every character. how to rectify this? this is baud rate issue right?

- venkat.

Thejasvi said...

Yes, that is a baud rate mismatch.

How are you displaying the data coming from UART? Are you connecting the UART to a PC? If so, are you using a USB2UART bridge or are you connecting it through COM port?

If you are using a USB2UART, then the USB will be configured as a virtual COM port and this will not have baud rate mismatch issues.

If you have connected it through COM port of your PC, then just set the correct baud rate in your terminal.

venkatesh said...

hi,

It is displaying same garbage value for the USB to Serial also. I tried by changing the system clock of micro controller also. still the same result.

- venkat

venkatesh said...

hi @thejasvi,

finally, i got some thing positive response from my controller.
The problem is that, the baud rate for the example they given is not exactly 115200.

i configured FDR and fine tuned the value (decreased) till i get the right characters in the terminal. now, i am getting all the alphabets except h,p,x and all the numbers except 0,8. Is there any other way to rectify this issue ??

Thanks & regards,
venkat.

Thejasvi said...

UART cannot always set the baud rate exactly to your required value. It is like PLL, you cannot always get the exact frequency you want.

Using a clock frequency of an integer multiple of 11.0592 MHz for the UART module will set any of the standard UART baud rates exactly. So use a system clock that is a multiple of this.

Anonymous said...

Hi i am trying with software uart in lpc1768 here i have to create the baud rate of 9600 ,as per my knowledge 9600 baud rate Means 1000/9600=0.10416 ms delay i have to generate for sending the one bit. how should i implement this delay using timers in LPC1768

Thejasvi said...

You are correct in calculating the delay between sending each bit for a 9600 baud rate UART.

If you need very accurate baud rate, then you will need to use an integer multiple clock frequency of 11.0592 MHz. Use 11.0592 MHz as the clock for a 32-bit timer. This way each count in the timer corresponds to 90ns. So to get 0.104166666mS the timer needs to count 1152. So set a match register to around (1152 - the expected interrupt latency, which I guess is around 11 cycles when using Thumb-2) and setup a match compare interrupt and send the next bit in the ISR.

If you get some garbage value on the other device, try increasing or decreasing the match register value a little bit.

Anonymous said...

Hi thejasvi,

Thank u for the reply since i am using the below timer code to generate delay of 0.104166666mS but no output
void INIT_Timer()
{
TIM_TIMERCFG_Type TMR0_Cfg;
TIM_MATCHCFG_Type TMR0_Match;
TMR0_Cfg.PrescaleOption = TIM_PRESCALE_USVAL; // Initialize timer 0, prescale count time of 100uS
TMR0_Cfg.PrescaleValue = 2;
TMR0_Match.MatchChannel = 0; // Use channel 0, MR0
TMR0_Match.IntOnMatch = ENABLE; // Enable interrupt when MR0 matches the value in TC register
TMR0_Match.ResetOnMatch = TRUE; // Enable reset on MR0: TIMER will reset if MR0 matches it
TMR0_Match.StopOnMatch = FALSE; // Don't stop on MR0 if MR0 matches it
TMR0_Match.ExtMatchOutputType = TIM_EXTMATCH_NOTHING; /* Do nothing for external output pin if match (see cmsis help, there are another options) */
TMR0_Match.MatchValue = 100; /* Set Match value, count value of 100 (100* 1uS = 100us = 0.1ms --> 1 Hz) */
TIM_Init(LPC_TIM0, TIM_TIMER_MODE, &TMR0_Cfg); /* Set configuration for Tim_config and Tim_MatchConfig */
TIM_ConfigMatch(LPC_TIM0, &TMR0_Match);
TIM_Cmd(LPC_TIM0, ENABLE); /* Start timer 0 */
// NVIC_SetPriority(TIMER0_IRQn, ((0x01<<3)|0x01)); /* Preemption = 1, sub-priority = 1 */
NVIC_EnableIRQ(TIMER0_IRQn); /* Enable interrupt for timer 0 */

}

Thejasvi said...

It looks like you are doing everything correctly. When you say that there is no output, do you mean to say that your ISR (Interrupt Service Routine) is not being called?

PS: Remember your ISR should look something like this

void TIMER0_IRQHandler (void){}

Anonymous said...

Hi Thejasvi below is my isr program in this isr i am writing my logic to send each bit at 0.14ms

here
p=p+0x100; //creating the dataframe adding 1(stop bit)
p=p<<0; //creating start bit in data frame i.e 0
void TIMER0_IRQHandler (void)
{
TIM_ClearIntPending(LPC_TIM0,TIM_MR0_INT);
for(i=0;i<10;i++)
{
s=(p>>i)&0x01;
if(s==0x01)
LPC_GPIO0->FIOSET = (1<<23); //make P0.23 high
else
LPC_GPIO0->FIOCLR = (1<<23); //Mkae p0.23 low
INIT_Timer();
}

}

here every time i have to call timer_init function to creat delay
Here it is not possible to run the timer every time once we initilised the timer at start?????
Here i am getting garbage value please go through it

Thejasvi said...

I am quite confused here. In the comments of your code, you have written that the timer prescale is set at 100uS. But you have set the MR0 to 100. Shouldnt this give you interrupts once in 1mS? But in calculations you have used 1uS prescale factor.

Also I did not get what you are doing with the "p" and "s" inside the ISR. Is this how you are sending data from the software UART?

Also why are you calling the timer_init again? It is not required.

Anonymous said...


Hi Thejasvi

In ISR i am writing the logic to send the each bit for the software uart..

void TIMER0_IRQHandler(void)
{
if(s!=0)
{
str1=str1>>1;
if(str1 & 0x01)
LPC_GPIO0->FIOSET = (1<<23);
else
LPC_GPIO0->FIOCLR = (1<<23);
s--;
LPC_TIM0 ->IR =1;
}
else
{
LPC_TIM0->TCR &= 0<<0; //Disable timer
//TM_Cmd(LPC_TIM0, DISABLE); //Disable timer
s=0;
}

}

since i am getting the correct character in terminal along with some garbage value
is it correct...
LPC_TIM0->TCR &= 0<<0; to stop timer 0...in order to not get any garbage value along with real character in else part of the code..

Thejasvi said...

If you are doing an 8-bit UART, then stop the timer once you send out the stop bit. This should take care of the garbage values.

The logic seems fine in the ISR, but dont you need to send a start and a stop bit?

Vignesh Nagarajan said...

Hi Team.

How to calculate the MR0 Value for 1msec delay in timer0 in LPc1768.

Please give the formula for calculation.

Regards,
Viky

Thejasvi said...

It is quite simple to calculate the value of MR0 for a required time duration.

First step is to calculate the time period of the clock of the timer. This will give us the time duration per tick of the timer. For example if the input clock to the timer is 1MHz, then the timer will tick once for each 1uS.

Second step is to calculate the MR0 value for a required time period. Here MR0 = (Required time period / timer tick period). If the value you get is not an integer, then either ceil or floor it to the nearest integer.

In your case, if the i/p clock for the timer is 1MHz and you want 1mS match using MR0, then MR0 should be 1mS / 1uS = 1000.

Anonymous said...

Thanks for reply.

Dear Team,

Could you please tell me the step by step procedure for I2C protocol with EEPROM.

Regards,
Viky

Anonymous said...

Sorry can be seem a stupid question but I'm completly newby in LPC17xx.
Where should I specify the time between each timer trigger?

Thejasvi said...

You can either use the timer mode or the counter mode. When in timer mode the timer ticks for every input clock cycle. When in counter mode, the counter ticks for every positive edge or negative edge or both of a given input pin, as per your settings.

Anonymous said...

Hi..sorry i'm a newbie on LPC1768 I have type the following program, and i set the crystal clock to 2MHz and my MR0 is 2000 to generate 1ms with duty cycle 30% and 50% at pin 27 & 28. But my program cannot be enter to the timer interrupt. I checked few times and seems everything is correct. I would be happy if can check my errors. Thank you.

#include

int main()
{
LPC_SC->PCONP |= ( 1 << 15 ); // power up GPIO
LPC_GPIO1->FIODIR |= 1 << 28; // puts P1.28 into output mode.
LPC_GPIO1->FIODIR |= 1 << 29; // puts P1.29 into output mode.
LPC_GPIO1->FIOPIN = 1 << 28; // assign pin to high
LPC_GPIO1->FIOPIN = 1 << 29; //assign pin to high


LPC_SC->PCONP |= 1 << 1; //Power up Timer 0
LPC_SC->PCLKSEL0 |= 1 << 3; // Clock for timer = CCLK/2
LPC_TIM0->MR0 = 1000 << 20; // Give a value suitable for the LED blinking frequency based on the clock frequency

LPC_TIM0->MCR |= 1 << 0; // Interrupt on Match0 compare
LPC_TIM0->TCR |= 1 << 1; // Reset Timer0
LPC_TIM0->TCR &= 0 << 1;

NVIC_EnableIRQ(TIMER0_IRQn); // Enable timer interrupt
LPC_TIM0->TCR |= 1 << 0; // Start timer

while(1);
}


void TIMER0_IRQHandler (void)
{
static unsigned char ms=0;

if((LPC_TIM0->IR & 0x01) == 0x01) // if MR0 interrupt
{
ms++;
LPC_TIM0->IR |= 1 << 0; // Clear MR0 interrupt flag

if (ms==3)
LPC_GPIO1->FIOPIN ^= 1 << 28; // Toggle the LED

else if (ms==5)
LPC_GPIO1->FIOPIN ^= 1 << 29; // Toggle the LED

else if (ms==10)
{
LPC_GPIO1->FIOPIN = 1 << 28;
LPC_GPIO1->FIOPIN = 1 << 29;
ms=0;
}

}
}

Thejasvi said...

Make sure that the startup code that you are using for LPC1768 has mapped TIMER0_IRQn interrupt to the TIMER0_IRQHandler handler. If this mapping is not done by your startup code, then you can manually do it by NVIC_SetVector(TIMER0_IRQn, TIMER0_IRQHandler);

Anonymous said...

Thejasvi, thank you for the explanation. May I know where should I put in the line NVIC_SetVector(TIMER0_IRQn, TIMER0_IRQHandler); May I know how to confirm that startup code that for LPC1768 has mapped TIMER0_IRQn interrupt?
Following are the startup code. THANK YOU.

Thejasvi said...

You can place the NVIC_SetVector right next to NVIC_EnableIRQ.

Just check other files in your project. There should be something like startup_lpc17xx.c or .h. See if TIMER0_IRQn is mapped to TIMER0_IRQHandler using some method. If Timer0_IRQn is mapped to an IRQ handler that is named differently, then use that as the name of your ISR routine. Else use NVIC_SetVector to point the TIMER0 interrupt to the corresponding ISR routine.

Anonymous said...

Thank you Thejasvi. I have tried both but I still not able to enter to timer0 isr during debugging. When I put in the NVIC_SetVector(TIMER0_IRQn, TIM0_IRQHandler); the following errors shown.
warning: #223-D: function "NVIC_SetVector" declared implicitly
error: #20: identifier "TIM0_IRQHandler" is undefined

If i removed this line, the compilation is success, when i perform a single step debug
When TC=MR0 (in debug mode) it jump into startup_MPS_CMO.s and hang at the position as shown (->>>>). I'm using Keil uvsion with startup_MPS_CM0.s. Once again thank you.


Default_Handler PROC

EXPORT WDT_IRQHandler [WEAK]
EXPORT RTC_IRQHandler [WEAK]
EXPORT TIM0_IRQHandler [WEAK]
EXPORT TIM2_IRQHandler [WEAK]
EXPORT MCIA_IRQHandler [WEAK]
EXPORT MCIB_IRQHandler [WEAK]
EXPORT UART0_IRQHandler [WEAK]
EXPORT UART1_IRQHandler [WEAK]
EXPORT UART2_IRQHandler [WEAK]
EXPORT UART3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT AACI_IRQHandler [WEAK]
EXPORT CLCD_IRQHandler [WEAK]
EXPORT ENET_IRQHandler [WEAK]
EXPORT USBDC_IRQHandler [WEAK]
EXPORT USBHC_IRQHandler [WEAK]
EXPORT CHLCD_IRQHandler [WEAK]
EXPORT FLEXRAY_IRQHandler [WEAK]
EXPORT CAN_IRQHandler [WEAK]
EXPORT LIN_IRQHandler [WEAK]
EXPORT I2C_IRQHandler [WEAK]
EXPORT CPU_CLCD_IRQHandler [WEAK]
EXPORT SPI_IRQHandler [WEAK]

WDT_IRQHandler
RTC_IRQHandler
TIM0_IRQHandler
TIM2_IRQHandler
MCIA_IRQHandler
MCIB_IRQHandler
UART0_IRQHandler
UART1_IRQHandler
UART2_IRQHandler
UART3_IRQHandler
UART4_IRQHandler
AACI_IRQHandler
CLCD_IRQHandler
ENET_IRQHandler
USBDC_IRQHandler
USBHC_IRQHandler
CHLCD_IRQHandler
FLEXRAY_IRQHandler
CAN_IRQHandler
LIN_IRQHandler
I2C_IRQHandler
CPU_CLCD_IRQHandler
SPI_IRQHandler
->>>>> B .

ENDP


ALIGN

Thejasvi said...

I have never used Keil. So, I do not know what that debugger is doing.

The good news is that your startup code is mapping the timer0 interrupt to TIM0_IRQHandler(). So you can go ahead and remove the NVIC_SetVector(). However, in your code the ISR routine is named TIMER0_IRQHandler. So, just go ahead and change its name to TIM0_IRQHandler and it should work.

The Innovative said...

hi,
i was trying to interface hc sr04 ultrasonic module with lpc 1768 ,
I'm using the following code, i tried to develop it ..
i'm not gtting propr o/p. the distace is 0 always or changing improperly..can u pls look into my code..thank you


FIOCLR
#define US_PORTSET LPC_GPIO0->FIOSET
#define US_DDR LPC_GPIO0->FIODIR
#define US_PIN LPC_GPIO0->FIOPIN
#define US_ECHO 5 // pot 0 5th pin for echo
#define US_TRIG 6 // p0.6 for trigger
#define US_ERROR 0xffff
#define US_NO_OBSTACLE 0xfffe



uint32_t d;



uint16_t getPulseWidth()
{

uint32_t i,result;

//Wait for the rising edge
for(i=0;i<5800;i++) //5800=> 5800*6.6us=38.2ms
{
if(!(US_PIN & (1<if(0).
} //here condetion is true when echo pin is low(or 0) and continue looping; else false when echo pin is high.

if(i==5800) //for hc sr04, If no object is detected, the Echo pin will stay high for 38ms and then go low.
return 0xffff; //Indicates time out

//High Edge Found(if the IF condetion is false, it'll not execute condetional block,and jumps to next line of instruction .)

//Setup Timer1
LPC_SC->PCONP |= 1 << 1; //Power up Timer 0
LPC_SC->PCLKSEL0 |= ( 1 << 2)|(1<<3); // Clock for timer = CCLK /8 -->12000000/8 = 150000hz -->6.6us to make one count
LPC_TIM0->TC=0x00000000; // init counter

LPC_TIM0->TCR |= 1 << 1; // reset timer
LPC_TIM0->TCR &= ~(1 << 1); // stop resetting the timer.
delay_ms(10);
LPC_TIM0->TCR |= 1 << 0; // Start timer

//Now wait for the falling edge
for(i=0;i<5800;i++)
{
if(US_PIN & (1<TC) > 5800) break; else continue;
}
else
break;
}

if(i==5800)
return 0xffff; //Indicates time out

//Falling edge found

result=(LPC_TIM0->TC); //STORE COUNT IN RESULT


LPC_TIM0->TCR &= ~(1 << 0); //Stop Timer


if(result > 5800)
return 0xfffe; //No obstacle
else
return (result>>1);
}

int main(void)
{

uint16_t r;
LPC_PINCON->PINSEL0=0x00000000;// MAKING P0.5,6 AS GPIO
SystemInit();

lcd_init(); //initialization of LCD
delay(500);

lcd_gotoxy(0,0); //function to move the cursor position to (0th row & 5th column )


lcd_string("Hc sr04 test"); //function to display a string
delay(500);
while(1)
{
//Set Ultra Sonic Port as out
US_DDR|=(1<

kiranvarma-npeducations said...

I am trying to write the same program without using LPC header files. I defined addresses of the SFR's like PCONP, etc as #define. But unfortunately My code was not working. can any body provide the code to blink the LED without using Header files.

Abhinav Dubey said...

Hello Guys, Can anyone tell me how to generate 60hz PWM signal on lpc1768???, and how to vary "ON TIME". I want to vary "ON TIME" to attain 100% duty cycle after 5 or 6 sec. pls help me on this!!!