Go Down

Topic: Ch-9 Timer/Counter Module of ATmega328P MCU (Read 1 time) previous topic - next topic


Jun 25, 2020, 06:04 pm Last Edit: Jul 01, 2020, 09:11 am by GolamMostafa
Timer/Counter (TC) Module is a "Programmable Electronic Circuit" with ATmega328P MCU, which can be used as Timer to create some fixed amount of time like a Stop Watch. The same TC Module can also be used as Counter to count pulses coming from external sources. It can be used to generate PWM signals, square wave signals etc. There are three TC Modules (TC0, TC1, and TC2) within ATmega328P MCU. In this Chapter, we will study the architecture and programming of the TC1 Module.

9.1  Introduction
(1)  Within ATmega328P MCU of the Arduino UNO Board, there are three "Timer/Counter Modules/Registers" (Fig-9.1). These are:
(a)  8-bit TC0 (Timer/Counter 0) Module/Register. It is also Known as TCNT0 (Timer/Counter 0).
(b)  16-bit TC1 (Timer/Counter 1) Module/Register. It is also Known as TCNT1 (Timer/Counter 0).
(c)  8-bit TC2 (Timer/Counter 2) Module/Register. It is also Known as TCNT2 (Timer/Counter 2).

Figure-9.1: Timer/Counter Modules/Registers of ATmega328P MCU

(2)  TCNT1 is a 16-bit Register/Module. It is composed of two parts: TCNT1H (high byte of TCNT1) and TCNT1L (low byte of TCNT1). In "Normal Mode" operation, the TCNT1 always counts in the upward direction; this means that TCNT1 is an "up counter" register.    

(3)  TCNT1 can receive the counting/driving pulses (clkTC1) from the following two sources:
(a)  From internal "16 MHz Oscillator" which can be further divided by "TC1 Clock Prescaler".
(b)  From external source via DPin-5; there is no divider in this case.

(4)  When TCNT1 receives its driving clkTC1 from internal oscillator, it is said that TCNT1 is working as Timer-1.

(5)  When TCNT1 receives its driving clkTC1 from external source, it is said that TCNT1 is working as Counter-1.

(6)  In Fig-9.2, we observe that TCNT1 begins the counting of clkTC1 pulses from 0x0000 (inital count or BOTTOM) and goes upto 0xFFFF (final or MAXimum count) and then again to 0x0000 after counting one more pulse. That is:

Figure-9.2: Counting sequence of TCNT1

Initial = BOTTOM Count            =    0000, ..., 0000 (16-bit) = 0 in decimal
next count                               =    0000, ..., 0001 (16-bit) = 1 in decimal
next = Final = MAXimum Count =    1111, ..., 1111 (16-bit) = 65535 in decimal
next = Total Count                    = 1 0000, ..., 0000 (17-bit) = 65536 in decimal

It means that the initial count contains all 0s and the final (MAXimum) count contains all 1s. Total counting sequence will be complete when the counter will count one more pulse; as a result, the 16-bit content of the TCNT1 timer/counter will be back to 0000, ..., 0000.

Total count is 1 0000, ..., 0000 (17-bit); but, the size of TC1/TCNT1 is 16-bit; hence, there is an over-flow bit which is the left-most bit (the 17th bit in decimal). This bit is saved into the TOV1 bit/flag of TIFR1 Register (Fig-9.3) of the MCU. Looking at the TOV1 bit for HIGH state, it could be sure that the TCNT1 has made the Total Count.

Figure-9.3: Bit layout of TIFR1 Register

The TOV1 bit/flag assumes HIGH state when the 16-bit content of TCNT1 turns form all 1s (0xFFFF) to all 0s (0x0000). This event of transition from all 1s to all 0s is called over-flow or roll-over event.

The "time" required for the 16-bit TCNT1 is the "time" that is needed to count "MAX + 1 = 65536" pulses. Ley us designate this "time' by the term "timeDelay".  The timeDelay will be chnage if the frequency of the clkTC1 signal changes.

However, TCNT1 can be configured to begin counting from a "preset value/quantity (N)". For example: TCNT1 may begin counting from 0x1000 and not from 0x0000 (Fig-9.2). In this case, the timeDelay can be changed by changing the value of N.

(7)  The occurrence of the over-flow event can be known in two ways:
(a)  Polling process: This process involves the continuous monitoring of the value of TOV1 flag for HIGH state (Fig-9.3). The codes are:
Code: [Select]
while(bitRead(TIFR1, TOV1) != HIGH)
    ;     //wait and keep checking that TOV1 has become HIGH
bitSet(TIFR1, TOV1);    //claear TOV1 bot/flag by putting HIGH (1) at this bit position

(b)  Interrupt Process:  In this process, the MCU will be automatically interrupted when over-flow event occurs due to HIGH value of the TOV1 flag. To implement this scheme, the "interrupt logic" must be enabled. When interrupy happens, the MCU will suspend the MLP and then will enter into an ISR routine named as ISRTOV1 (ISR Routine due to TC1 over-flow). Before going to ISRTOV1 routine, the MCU will disable only the "global part" of the "interrupt logic" (Fig-9.1); the "local part" of the "interrupt logic" will remain closed as it was before interruption. When the MCU makes a jump to the ISRTOV1 routine, the TOV1 flag is automatically cleared. The ISRTOV1 routine has to be declared by the following codes:
Code: [Select]
//ISRTOV1 Routine
ISR(TIMER1_OVF_vect)   //four pre-defined words: ISR, TIMER1, OVF, vect; we can't change them
    //insert minimum codes as needed

(8)  Data write/storage sequence in TCNT1 Register.
(a)  First, execute code to move 8-bit data into TCNT1H Register. The data is not actually placed into TCNT1H; it is placed into a temporary register/latch. When write operation is performed with TCNT1L Register, the content of 8-bit of temporary register/latch automatically moves into TCNT1H Register. For Example: storing 0x2356 into TCNT1 Register.
Code: [Select]
TCNT1H = 0x23;
TCNT1L = 0x56;

To test the validity of the above codes, we may execute the following codes in UNO:
Code: [Select]
TCCR1A = 0x0000; //do it for read/write test routine; otherwise there might be wrong results
TCNT1H = 0x23;
TCNT1H = 0x45;
Serial.print(TCNT1, HEX);   //shows: 0x2345

(b)  The following single line code can also be performed to store 0x2356 into TCNT1 Register; where the above sequence of operation automatically takes place.
Code: [Select]
TCNT1 = 0x2356; /TCNT1H = 0x23; TCNT1L = 0x56
(9)  Data read sequence from TCNT1 Register.
(a)  Read lower byte first (TCNT1L) and then the higer byte (TCNT1H). This operation brings the content of higher byte register (TCNT1H) into a temporary register/latch. When read operation is performed from higher byte, the data automatically comes from the temporary register. Example:
Code: [Select]
byte x = TCNT1L;
byte y = TCNT1H;

(b)  The following single line code could be executed to read 16-bit data from TCNT1 Register; where, the above sequence of atomic operations are automatically carried out.
Code: [Select]
int z = TCNT1;
(10)  The frequency of clkTC1 signal of TCNT1 Register is set to the following values depending on the bit values of CS12 - CS10 of the TCRR1B Register (Fig-9.4):
(a)  No clock   : S1I (tc1 Switch to connect Internal pulse): Open : TCNT1 is STOP: CS12 - CS10 = 000.
(b)  16 MHz    : S1I is closed with division factor 1       : TCNT1 is running : CS12 - CS10 = 001
(c)  2 MHz      : S1I is closed with division factor 8       : TCNT1 is running : CS12 - C10 = 010
(d)  250 kHz   : S1I is closed with division factor 64     : TCNT1 is running : CS12 - C10 = 011
(e)  62500 Hz : S1I is closed with division factor 256   : TCNT1 is running : CS12 - C10 = 100
(f)  15625 Hz  : S1I is closed with division factor 1024 : TCNT1 is running : CS12 - C10 = 101

Figure-9.4: Bit layout of TCCR1B Register

(11)  Expanded view of TCNT1 Register (Fig-9.5)

Figure-9.5: Expanded view of TC1 Register

...to be continued


Jun 25, 2020, 06:05 pm Last Edit: Jul 01, 2020, 09:12 am by GolamMostafa
9.2  Questions and Answers
1.  Define timeDelay.
This is the "delay time" that the TCNT1 spends to begin counting from 0 (or from a preset value) and then come back to 0.

2.  Calculate maximum timeDelay that can be achieved using TC1/TCNT1 of Fig-9.1.
Ans: Maximum timeDelay will occur when the TCNT1 is running at minimum frequency and with initial count of 0 (preset value is 0).

In the light of Fig-9.2, we can say that:
timeDelay (max) = "total clock Pulse Count of clkTC1" * "maximum period of 1 clock pulse of clkTC1"
==> timeDelay (max) = (0xFFFFF + 1) * 1/(minimum frequency of  clkTC1"
==> timeDelay(max) = 65536 * 1/(16000000/1024)   //1024 is the division factor of TC1 Clock Prescaler
==> timeDelay (max) = 65536 * 0.000064
==> timeDelay (max) = 4.194304 sec = 4 194 304 us.

3.  Calculate suitable values for clkTC1 and preset quantity for TCNT1 of Fig-9.1 so that the timeDelay is 4 sec.
Hints:  Take one frequency (say: 16 MHz/1024) for the clkTC1 signal. Now, calculate the value of "preset quantity". Consult Fig-9.2.
Frequency of clkTC1 = 16000000/1024 = 15625 Hz.
Period of clkTC1 = 1/frequency of clkTC1 = 1024/16000000 = 0.00000064 = 64 us.
==> presetCount = totalCount - actualCount
==> presetCount = 65536 - (number of  pulse to be counted for 4 sec)
==> presetCount = 65536 - (15625*4)
==> presetCount = 65536 - 62500
==> presetCount = 3036 in decimal = 0x0BDC in hex

4.  Calculate suitable values for clkTC1 and preset quantity for TCNT1 of Fig-9.1 so that the timeDelay is 10 ms.
(1)   totalCount = presetCount + actualCount. (Fig-9.2)
(2)   Choose a division factor 8 for "TC1 Clock Prescaler" to get clkTC1 = 16 MHz/1024 = 2 MHz.
(3)   timeDelay = 10 ms = 10000 ┬Ás. (time to count actualCount)
==> timeDelay = actualCount*(period of clkTC1) //timeDelay = time required to begin counting from preset value and then come back to 0.

==> actualCount = timeDelay/(period of clkTC1) = 10000/(1/clkTC1) = 10000/0.5 = 20000 = 4E20h.
(4)  presetCount = totalCount - actualCount
==> 0x10000h - 0x4E20h = 0xB1E0h = 45536 in decimal.  

5.  What is over-flow/roll-over event?
After arriving at the full/final/MAX count, the TCNTX (X = 0, 1, 2) turns from all 1s to all 0s. This transition from all 1s to all 0s is known as overflow/roll-over event. When over-flow event occurs, the TOVX (X = 0, 1, 2) flag assumes HIGH state. TOVX is the first bit (Bit-0) of the TIFRX (X = 0, 1, 2) Register (Fig-9.3).

5.  (a)  What is the source of interrupt signal in Step-7(b)?
(b)  Is the above interrupt externally or internally generated?
(c)  How can we disable (also called mask) the TOV1 interrupt?
(d)  Write register-level code to put LOW at the TOIE1 bit by consulting the bit layout diagram of the TIMSK1 Register (Fig-9.6).

Figure-9.6: Bit layout of TIMSK1 Register

Ans: (a)  Over-flow event of TCNT1 Register is the source of interrupt signal.
(b)  The interrupt signal has been generated internally.
(c)  By putting LOW at the TOIE1 bit (TCNT1 Over-flow Interrupt Enable Bit).
(d)  ?

6.  Write register level code to close S1E (Switch of TC1 to connect External pulse) of Fig-9.1 so that the TCNT1 will now work as a counter and will count the rising edges of the external pulses coming at DPin-5.
Ans:  Consult Section-9.1(10).

7.  Write a sketch to blink L (built-in LED of UNO) at 1-sec interval. The 1-sec timeDelay should be generated using TCNT1 of Fig-9.1; where, end of 1-sec period would be known by continuous monitoring (known as polling) of the TOV1 flag.
Code: [Select]
void setup()
    Serial.begin(9600);     //PC/IDE is connected with UNO using UART port
    pinMode(13, OUTPUT);    //set direction of DPin-13 to drive L
    //-1. write code to operate TCNT1 as up counter in Normal Mode of operation -- (TCCR1A = 0x00)
    //-2. write code to keep TCNT1 in STOP condition--- (TCCR1B = 0x00)
    //-3. assume clkTC1 = 16 MHz/1024 = 15625 Hz-----
    //-4.  Hand calculate the preset value (0xmmnn) for 1-sec timeDelay at clckTC1 = 15625 Hz
    //-5. Write code to store preset value in TCNT1 (TCNT1=0xmmnn) or TCNT1H = 0xmm; TCNT1L = 0xnn
    //-6. START TCNT1 with clckTC1 at division factor of 1024 (TCCR1B = 0x05; see Fig-9.4

void loop()
     digitalWrite(13, HIGH);   // L is ON
     timeDelay();                   //insert 1-sec timeDelay to be generated by TCNT1
     digitalWrite(13, LOw);     //L is OFF

void timeDelay()
   //check that TOVe flag has assumed HIGH state; if not wait
   while(bitRead(TIFR1, TOV1) != HIGH)
        ;  //wait
   bitSet(TIFR1, TOV1);      //clear TOV1 flag by putting HIGH at this bit position
   TCNT1 = 0xmmnn;          //re-load preset value for 1-sec timeDelay

8.  Repeat Q7 with the condition that the end of 1-sec timeDelay would be known through interrupt process.

In Q7, during 1-sec timeDelay, the MCU was checking and checking the TOV1 flag for HIGH state. This is to say that the MCU was in "blocked condition" -- it had no ability do anything else until the 1-sec timeDelay was elapsed. This is the polling (a blocking case) process.

It would be good if we could leave the MCU free (do something else like checking if someone wants to enter in the Hall Room and the door should be opened) and let the TOV1 flag interrupt the MCU when it (the TOV1 flag) assumes HIGH state after the elapse of 1-sec time. This is the interrupt (an unblocking case) process.

The Sketch: (tested On UNO)
Code: [Select]
volatile bool flag = false;

void setup()
  pinMode(13, OUTPUT);    //DPin direction is output
  TCCR1A = 0x0000;        //up counter mode
  TCCR1B = 0x0000;        //TC1 is STOP
  TCNT1 = 0xC2F7;         //preset value for 1 sec timeDelay
  TCCR1B = 0x05;          //Start TC1 with division factor 1024
  bitSet(TIMSK1, TOIE1);    //local part of interrupu logic is enable; Fig-9.1
  bitSet(SREG, 7);           //global part (I) of interrupt logic is enabled; Fig-9.1
  digitalWrite(13, HIGH);  //initially L is ON

void loop()
  //do something else rather than waiting

//ISRTOV1 Rooutine
ISR(TIMER1_OVF_vect)   //ISR Routine for TOV1 interrupt
  //bitSet(TIFR1, TOV1); this code is not needed; the TOV1 is auto cleared
  TCNT1 = 0xC2F7;  //re-load preset value
  if (flag == false)    //1-sec has gone; OFF L
    digitalWrite(13, LOW);   //L is OFF from ON condition
    flag = true;
  else    //toggle L from OFF to ON state
    digitalWrite(13, HIGH);  //L is ON from OFF
    flag = false;

...to be continued.


Jun 25, 2020, 06:06 pm Last Edit: Jun 29, 2020, 09:37 pm by GolamMostafa
... this is reserved.


Jun 25, 2020, 06:06 pm Last Edit: Jun 27, 2020, 09:11 am by GolamMostafa
...this is also reserved.

Go Up