In this discussion we will go through ARM Cortex-M3 LPC1343 Timer Tutorial. Previously we saw a blinky example using GPIO and hardcoded delays, now its time to improvise and use precise delay using timers. LPC1343 has two 16-bit Timers and two 32-bit Timers. Both of them are similar in operation except for the bit-size. We will be using 32-bit timers in this tutorial and is also applicable to similar MCUs like LPC1347.
Timer Module in LPC134x
Each Timer module in ARM Cortex-M3 LPC134x microcontroller has its own Timer Counter(TC) and Prescale Register(PR) associated with it. When a Timer is Reset and Enabled, the TC is set to 0 and incremented by 1 every ‘PR+1’ clock cycles – where PR is the value stored in Prescale Register. When it reaches its maximum value it gets reset to 0 and hence restarts counting. Prescale Register is used to define the resolution of the timer. If PR is 0 then TC is incremented every 1 clock cycle of the peripheral clock. If PR=1 then TC is incremented every 2 clock cycles of peripheral clock and so on. By setting an appropriate value in PR we can make timer increment or count: every peripheral clock cycle or 1 microsecond or 1 millisecond or 1 second and so on.
Match Register
A Match Register is a Register which contains a specific value set by the user. When the Timer starts – every time after TC is incremented the value in TC is compared with match register. If it matches then it can Reset the Timer or can generate an interrupt as defined by the user. We are only concerned with match registers in this tutorial.
Match Registers can be used to:
- Stop Timer on Match(i.e when the value in count register is same as than in Match register) and trigger an optional interrupt.
- Reset Timer on Match and trigger an optional interrupt.
- To count continuously and trigger an interrupt on match.
External Match Output
When a corresponding Match register(MRx) equals the Timer Counter(TC) the match output can be controlled using External Match Register(EMR) to: either toggle, go HIGH, go LOW or do nothing. This Match output is diverted to a physical pin on the MCU by selecting CT32Bx_MATn alternate function for the pin which supports it.
Capture Register
As the name suggests it is used to Capture Input signal. When a transition event occurs on a Capture pin , it can be used to copy the value of TC into any of the 4 Capture Register or to genreate an Interrupt. Hence these can be also used to demodulated PWM signals. We are not going to use them in this tutorial since we are only concerned with using Timer block as a ‘Timer’. We’ll see them in a later tutorial.
LPC1343 which is found on LPCXpresso Board has four Match Outputs and one Capture Input.
LPC134x Timer Registers
We will be using CMSIS based lpc13xx.h (ARM Cortex M3) header file for programming. In CMSIS, all the Registers used to program and use 32-bit timers are defined as members of structure(pointer) LPC_TMR32Bx where x is the 32-bit Timer module 0 or 1. So for Timer0 we will use LPC_TMR32B0 and so on. Registers can be accessed by de-referencing the pointer using “->” operator. For, example we can access TCR of Timer0 block as LPC_TMR32B0->TCR. Similary for 16-bit Timer block, the structure is defined as LPC_TMR16Bx where x is the 16-bit Timer module 0 or 1.
1) PR (LPC_TMR32Bx->PR): Prescale Register – Stores Prescale Value.
2) PC (LPC_TMR32Bx->PC): Prescale Counter Register – This register increments on every PCLK(CCLK). This register controls the resolution of the timer. When PC reaches the value in PR , PC is reset back to 0 and Timer Counter is incremented by 1. Hence if PR=0 then Timer Counter Increments on every 1 PCLK. E.g. If PR=9 then Timer Counter Increments on every 10th cycle of PCLK. Hence by selecting an appropriate prescale value we can control the resolution of the timer.
3) TC (LPC_TMR32Bx->TC): Timer Counter Register – This stores current Timer Counter Value. Timer Counter increments when PC reaches its maximum value as specified by PR. If timer is not reset explicitly(directly) or by using an interrupt then it will act as a free running counter which resets back to zero when it reaches its maximum value which is 0xFFFFFFFF.
4) TCR (LPC_TMR32Bx->TCR): Timer Control Register – This register is used to enable , disable and reset TC. When bit0 is 1 timer is enabled and when 0 it is disabled. When bit1 is set to 1 TC and PC are set to zero together in sync on the next positive edge of PCLK. Rest of the bits of TCR are reserved.
5) CTCR (LPC_TMR32Bx->CTCR): Count Control register – It is used to select Timer/Counter Mode. When the value of the CTCR is set to 0x0 Timer Mode is selected.
6) MCR (LPC_TMR32Bx->MCR): Match Control register – This register is used to control what operations can be done when the value in MR matches the value in TC. Bits 0,1,2 are for MR0 , Bits 3,4,5 for MR1 and so on.. The bit Mapping is as given below:
For MR0:
- Bit 0 : Interrupt on MR0 i.e. trigger an interrupt when MR0 matches TC. Interrupts are enabled when set to 1 and disabled when set to 0.
- Bit 1 : Reset on MR0. When set to 1 , TC will be reset when it matched MR0. Disabled when set to 0.
- Bit 2 : Stop on MR0. When set to 1 , TC & PC will stop when MR0 matches TC.
Similarly bits 3-5 , 6-8 , 9-11 are for MR1 , MR2 , MR3 respectively.
7) IR (LPC_TMR32Bx->IR): Interrupt Register – It contains the interrupt flags for 4 match and 2 capture interrupts. Bit0 to bit3 are for MR0 to MR3 interrupts respectively. And similarly the next 2 for CR0 & CR1 interrupts. when an interrupt is raised the corresponding bit in IR will be set to 1 and 0 otherwise. Writing a 1 to the corresponding bit location will reset the interrupt – which is used to acknowledge the completion of the corresponding ISR execution.
8) EMR (LPC_TMR32Bx->EMR): External Match Register – It provides both status and control of External Match Output Pins. First four bits are for EM0 to EM3. Next 8 bits are for EMC0 to EMC3 in pairs of 2.
- Bit 0 – EM0: External Match 0. When a match occurs between TC and MR0, depending on bits[5:4] i.e. EMC0 of this register, this bit can either toggle, go LOW, go HIGH, or do nothing. This bit is driven to MATx.0 where x=Timer number.
- Similarly for Bits 1 (EM1), 2 (EM2) & 3 (EM3).
- Bits[5:4] – EMC0: External Match 0. The values in these bits select the functionality of EM0 as follows:
- 0x0 – Do nothing
- 0x1 – Clear the corresponding External Match output to 0 (MATx.m pin is LOW).
- 0x2 – Set the corresponding External Match output to 1 (MATx.m pin is HIGH).
- 0x3 – Toggle the corresponding External Match output.
- Similarly for Bits[7:6] – EMC1, Bits[9,8] – EMC2, Bits[11:10] – EMC3.
Setting up & configuring Timers in LPC1343
To use timers we need to first configure them. We need to set appropriate values in CTCR, IR, PR registers and reset PC, TC registers. Finally we assign TCR = 0x01 which enables the timer.
- Enable Clock Input for the Timer Block using LPC_SYSCON->SYSAHBCLKCTRL register
- Set appropriate value in LPC_TMR32Bx->CTCR
- Define the Prescale value in LPC_TMR32Bx->PR
- Set Value(s) in Match Register(s) if required
- Set appropriate value in LPC_TMR32Bx->MCR if using Match registers / Interrupts
- Reset Timer using LPC_TMR32Bx->TCR – Which resets PR and TC
- Set LPC_TMR32Bx->TCR to 0x01 to Enable the Timer when required
- Reset LPC_TMR32Bx->TCR to 0x00 to Disable the Timer when required
Selecting Match Outputs: Match outputs for Timer0(CT32B0) and Timer1(CT32B1) is available as an alternate function on pins given below. Match output function must be selected using IOCON registers for the following pins:
- Timer0 MAT 0 (CT32B0_MAT0) – PIO1_6
- Timer0 MAT 1 (CT32B0_MAT1) – PIO1_7
- Timer0 MAT 2 (CT32B0_MAT2) – PIO0_1
- Timer0 MAT 3 (CT32B0_MAT3) – PIO0_11 (R_PIO0_11)
- Timer1 MAT 0 (CT32B1_MAT0) – PIO1_1 (R_PIO1_1)
- Timer1 MAT 1 (CT32B1_MAT1) – PIO1_2 (R_PIO1_1)
- Timer1 MAT 2 (CT32B1_MAT2) – PIO1_3 (SWDIO_PIO1_3)
- Timer1 MAT 3 (CT32B1_MAT3) – PIO1_4
The name inside brackets above represent actual member(IOCON register) names of LPC_IOCON structure, if brackets are present. You can go through my previous tutorial on IOCON register regarding its usage.
Enabling System AHB Clock for Timer: The input clock for timers is from System AHB clock or simply the System Clock. The System Clock can be derived from the Main Clock using System AHB Clock Divider Register SYSAHBLKDIV. System Clock for Peripherals like Timers needs to be enabled, before using them, by setting appropriate bits (1=enable, 0=disable) in System AHB Clock Control Register SYSAHBCLKCTRL as given below:
- Bit 7 For 16-Bit Timer0 (CT16B0)
- Bit 8 For 16-Bit Timer1 (CT16B1)
- Bit 9 For 32-Bit Timer0 (CT32B0)
- Bit 10 For 32-Bit Timer1 (CT32B1)
LPC1343 Timer Prescaler Calculations:
The delay or time required for 1 clock cycle when PCLK/CCLK(System Clock) = ‘X’ Mhz is given by:
=
Seconds
It is also the maximum resolution Timer block can provide at a given PCLK(CCLK) frequency of X Mhz. The general formula for Timer resolution at X Mhz PCLK(CCLK) and a given value for prescale (PR) is as given below:
=
Seconds
Hence, we get the Formula for Prescaler (PR) for required Timer resolution (TRES in Secs) at given PCLK(in Hz) frequency as:
Note that here, the resolution is also the time delay required to increment TC by 1.
Hence, Prescaler value for 1 micro-second resolution/ 1us time delay at 72 Mhz PCLK(CCLK) is,
Prescale for 1 mS (milli-second) resolution at 72Mhz PCLK(CCLK) is,
LPC1343 Timer Examples with sample code
Example 1) – LPC134x Blinky Example using Timer & GPIO
Now lets write a C/C++ blinky program which flashes an LED every half a second. Since 0.5 second = 500 millisecond we will invoke timer delay function ‘delayMS’ as delayMS(500). An LED is connected to Pin PIO0_7 which is present on LPCXpresso 1343 board.
/*(C) Umang Gajera - www.ocfreaks.com 2011-17.
More Embedded tutorials @ www.ocfreaks.com/cat/embedded/
LPC1343 Basic Timer example.*/
#include <lpc13xx.h>
#define PRESCALE (72000-1) //72000 PCLK clock cycles to increment TC by 1
void delayMS(unsigned int milliseconds);
void initTimer0(void);
int main(void)
{
//SystemInit(); //called by Startup Code before main(), hence no need to call again.
initTimer0(); //Initialize Timer0
LPC_GPIO0->DIR = (1<<7); //Configure PIO0_7 as output
while(1)
{
LPC_GPIO0->DATA = (1<<7); //Turn LED ON
delayMS(500); //0.5 Second(s) Delay
LPC_GPIO0->DATA = ~(1<<7); //Turn OFF LED
delayMS(500);
}
//return 0; //normally this wont execute ever
}
void initTimer0(void)
{
/*Assuming CCLK (System Clock) = 72Mhz (set by startup code)*/
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<9); //Enable 32Bit Timer0 Clock
LPC_TMR32B0->CTCR = 0x0;
LPC_TMR32B0->PR = PRESCALE; //Increment LPC_TMR32B0->TC at every 71999+1 clock cycles
//72000 clock cycles @72Mhz = 1 mS
LPC_TMR32B0->TCR = 0x02; //Reset Timer
}
void delayMS(unsigned int milliseconds) //Using Timer0
{
LPC_TMR32B0->TCR = 0x02; //Reset Timer
LPC_TMR32B0->TCR = 0x01; //Enable timer
while(LPC_TMR32B0->TC < milliseconds); //wait until timer counter reaches the desired delay
LPC_TMR32B0->TCR = 0x00; //Disable timer
}
Example 2) – LPC134x example code using Timer & Match Outputs
In this C/C++ Example we will use Match outputs 0 and 1 of 32-bit Timer 0 i.e. CT32B0_MAT0 and CT32B0_MAT1. CT32B0_MAT0 is pinned to PIO1_6(P1.6) and CT32B0_MAT1 pinned to PIO1_7(P1.7). You can connect LED to any of the Match ouput pin (PIO1_6 or PIO1_7) and see the code in action. Note that, on LPCXpresso 1114 Board PIO1_6 is marked as RXD and PIO1_7 is marked as TXD since these pin have UART alternate functions.
/*(C) Umang Gajera - https://www.ocfreaks.com 2011-17.
More Embedded tutorials @ https://www.ocfreaks.com/cat/embedded/
LPC1343 Timer example 2.*/
#include <lpc13xx.h>
#define PRESCALE (72000-1) //72000 PCLK clock cycles to increment TC by 1
void initTimer0(void);
int main (void)
{
//SystemInit(); //called by Startup Code before main(), hence no need to call again.
LPC_IOCON->PIO1_6 |= 0x2; //Select CT32B0_MAT0 function - Marked as TXD on LPCXpresso Board
LPC_IOCON->PIO1_7 |= 0x2; //Select CT32B0_MAT1 function - Marked as RXD on LPCXpresso Board
initTimer0(); //Initialize Timer0
while(1)
{
//Idle loop
}
//return 0; //normally this won't execute
}
void initTimer0(void)
{
/*Assuming CCLK (System Clock) = 72Mhz (set by startup code)*/
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<9); //Enable 32Bit Timer0 Clock
LPC_TMR32B0->CTCR = 0x0;
LPC_TMR32B0->PR = PRESCALE; //Increment LPC_TMR32B0->TC at every 71999+1 clock cycles
//72000 clock cycles @72Mhz = 1 mS
LPC_TMR32B0->MR0 = 500; //toggle time in mS
LPC_TMR32B0->MCR = (1<<1); //Reset on MR0 Match
LPC_TMR32B0->EMR |= (1<<7) | (1<<6) | (1<<5) | (1<<4); //Toggle Match output for MAT0.0(P2.5), MAT0.1(P2.6)
LPC_TMR32B0->TCR = 0x02; //Reset Timer
LPC_TMR32B0->TCR = 0x01; //Enable timer
}