Timer2

Timer2 is another timer/counter of  8051 architecture. Timer2 has four modes of operation.

1. Normal Timer mode
2. Capture mode
3. Auto-Reload mode
4. Baud Rate Generator mode

Timer2 has a T2CON register which controls the basic operating parameters of it. T2MOD is another register which controls counting direction and a I/O port alternate function for Timer2. Now we are going to dig into Timer2 architecture.

[Modes Selection Table] 
Following table shows bit status for each operating mode.


 RCLK + TCLK
 CP / RL2
 TR2
 EXEN2
 Mode
0
1
1
0
16 bit normal
0
0
1
X
16 bit auto-reload
0
1
1
1
16 bit capture
1
X
1
X baud rate generator
X
X
0
X
off

[T2CON Register]
T2CON register is used to control Timer2 and for selecting operating modes. It also reflects various interrupt events. Details are shown in the following table.



[T2MOD Register]
T2MOD register controls clock input or output from Timer2. In auto-reload mode counting direction can also be changed by using following register. 

[Interrupt vector addresses]
Both Timer2 overflow (TF2) and Timer2 External (EXF2) vector at the same address at 002BH. We can distinguish them by checking bits in the T2CON register.

Now I will show 4 block diagrams for Timer2 operating modes. Before that I will discuss some symbolic text used to describe block diagrams.

T2 = External clock source input pin / Clock output pin form Timer2
T2EX = External pin for controlling Timer2 module. These pins actually used for general purpose interrupt C/T2 = Counter / Timer operation control bit
TR2 = Timer run control bit
TH2 = Timer register high byte
TL2 = Timer register low byte
TF2 = Timer overflow event detection bit
EXF2 =  Timer external event detection bit
[Normal Mode Block Diagram]
[Capture Mode Block Diagram]

[Auto-Reload Mode Block Diagram]

[BaudRate Generator Mode Block Diagram]


Now I am going to describe you how to write a driver routine to so that firmware layer can use it.
Its very simple to organize whole concept with minimal set of functions.

[Here is the detailed code for Timer2 library]

[timer2.h]

#ifndef __TIMER_2_H__
#define __TIMER_2_H__

#include <ioat89c55wd.h>

#define TIMER2_REG_LOW  TL2
#define TIMER2_REG_HIGH TH2
#define Timer2_SetRegister(val) \
  { \
  TL2 = (unsigned char) val; \
  TH2 = (unsigned char) (val >> 8); \
  }

#define TIMER2_CAPREG_LOW  RCAP2L
#define TIMER2_CAPREG_HIGH RCAP2H
#define Timer2_SetRelod(val) \
  { \
  RCAP2L = (unsigned char) val; \
  RCAP2H = (unsigned char) (val >> 8); \
  }

#define Timer2_Run()   T2CON_bit.TR2 = timer2_on
#define Timer2_Stop()  T2CON_bit.TR2 = timer2_off
#define Timer2_SetState(timer2_states)  T2CON_bit.TR2 = timer2_states

#define Timer2_SetExtClock(timer2_clktype) T2MOD_bit.T2OE = timer2_clktype

typedef union {
  unsigned int value;
  struct {
    unsigned char low;
    unsigned char high;
  };
} t_timer2_register;

typedef enum {
  timer2_dir_up = 0,
  timer2_dir_dn = 1
} timer2_dir;

typedef enum {
  timer2_clktype_input  = 0,
  timer2_clktype_output = 1
} timer2_clktype;

enum timer2_clk_src {
  timer2_clk_internal = 0,
  timer2_clk_external = 1
};

typedef enum {
  timer2_off = 0,
  timer2_on  = 1
} timer2_states;

typedef enum {
  timer2_mode_normal  = 0, // Normal mode
  timer2_mode_capture = 1, // Capture mode
  timer2_mode_reload  = 2, // Auto Reload mode
  timer2_mode_baudgen = 3  // Baud Rate Generator mode
} timer2_mode;

struct t_timer2_callbacks {
  void (*pfnOverflow) (t_timer2_register *);
  void (*pfnExternal) (t_timer2_register *);
};

void Timer2_Init(timer2_mode,enum timer2_clk_src);
void Timer2_RegCallbacks(struct t_timer2_callbacks *);
void Timer2_UnregCallbacks();

#endif

[Timer2.c]

#include "timer2.h"

static struct t_timer2_callbacks *p_timer2_callbacks;
static t_timer2_register timer2_counter;

#pragma vector=0x2B
__interrupt void timer2_interrupt_handler(void) {
  if(T2CON_bit.TF2 == 1) {
    timer2_counter.high = TIMER2_REG_HIGH;
    timer2_counter.low  = TIMER2_REG_LOW;
    p_timer2_callbacks->pfnOverflow(&timer2_counter);
  }
  if(T2CON_bit.EXF2 == 1) {
    timer2_counter.high = TIMER2_CAPREG_HIGH;
    timer2_counter.low  = TIMER2_CAPREG_LOW;
    p_timer2_callbacks->pfnExternal(&timer2_counter);
    T2CON_bit.EXF2 = 0;
  }
}

void Timer2_Init(timer2_mode mode,enum timer2_clk_src clk_src) {
  switch(mode) {
  case timer2_mode_normal:
    T2CON = 0x00 << 4;
    T2CON_bit.EXEN2 = 0;
    T2CON_bit.CP_RL2 = 1;
    break;
  case timer2_mode_capture:
    T2CON = 0x00 << 4;
    T2CON_bit.EXEN2 = 1;
    T2CON_bit.CP_RL2 = 1;
    break;
  case timer2_mode_reload:
    T2CON = 0x00 << 4;
    T2CON_bit.EXEN2 = 1;
    T2CON_bit.CP_RL2 = 0;
    break;
  case timer2_mode_baudgen:
    T2CON = 0x03 << 4;
    break;
  }
  T2CON_bit.C_T2 = clk_src;
  T2MOD_bit.DCEN = 1;
}

void Timer2_RegCallbacks(struct t_timer2_callbacks *pCallbacks) {
  IE_bit.ET2 = 1;
  p_timer2_callbacks = pCallbacks;
}

void Timer2_UnregCallbacks() {
  IE_bit.ET2 = 0;
}

[Timer2 mode: Normal]

int main( void )
{
  Timer2_Init(timer2_mode_normal,timer2_clk_internal);
  Timer2_SetRegister(0x0000);
  Timer2_RegCallbacks(&timer2_callbacks);
              
  IE_bit.EA = 1; // Enable global interrupt
 
  Timer2_Run();
 
  while(1) { /* User codes will go here */ }
   
  //return 0;
}

[Timer2 mode: Capture]

int main( void )
{
  Timer2_Init(timer2_mode_capture,timer2_clk_internal);
  Timer2_SetRegister(0x0000);
  Timer2_RegCallbacks(&timer2_callbacks);
              
  IE_bit.EA = 1; // Enable global interrupt
 
  Timer2_Run();
 
  while(1) { /* User codes will go here */ }
   
  //return 0;


[Timer2 mode: Auto-Reload]

int main( void )
{
  Timer2_Init(timer2_mode_reload,timer2_clk_internal);
  Timer2_SetRegister(0xFF00);
  Timer2_SetRelod(0xFF00);
  Timer2_RegCallbacks(&timer2_callbacks);
              
  IE_bit.EA = 1; // Enable global interrupt
 
  Timer2_Run();
 
  while(1) { /* User codes will go here */ }
   
  //return 0;


[Timer2 mode: BaudRate Genetrator]

int main( void )
{
  Timer2_SetExtClock(timer2_clktype_output);
  Timer2_Init(timer2_mode_baudgen,timer2_clk_internal);
  Timer2_SetRelod(0xFF00);
  Timer2_RegCallbacks(&timer2_callbacks);
              
  IE_bit.EA = 1; // Enable global interrupt
 
  Timer2_Run();
 
  while(1) { /* User codes will go here */ }
   
  //return 0;
}

Now I will show a complete main.c file which should look like

#include <timer_0_1.h>
#include <timer2.h>
#include <ioat89c55wd.h>


unsigned int capval;

void Timer2Ovrflow(t_timer2_register *);
void Timer2External(t_timer2_register *);

static struct t_timer2_callbacks timer2_callbacks = {
                                                        .pfnOverflow = Timer2Ovrflow,
                                                        .pfnExternal = Timer2External
                                                      };

 int main( void )
{
  Timer2_Init(timer2_mode_capture,timer2_clk_internal);
  Timer2_SetRegister(0x0000);
  Timer2_RegCallbacks(&timer2_callbacks);
              
  IE_bit.EA = 1; // Enable global interrupt
 
  Timer2_Run();
 
  while(1) { /* User codes will go here */ }
   
  //return 0;
}

void Timer2Ovrflow(t_timer2_register *p_timer2_register) {
  Timer2_SetRegister(0x0000);
  P0 = P0 ^ 0x01; // Toggle to show action on P0.0
}

void Timer2External(t_timer2_register *p_timer2_register) {
  capval = p_timer2_register->value;
  P0 = P0 ^ 0x02; // Toggle to show action on P0.1
}

N.B: Thanks for reading my article. I will update more this article latter. Requesting for your suggestions. Serial port is coming soon.

No comments:

Post a Comment