Generating a Regular Pulse Using Timer 2

In previous posts you may have seen an example program where we generate a 20Hz signal using the overflow interrupt on Timer 2. Here we will translate the post to use direct register access rather than use the STD Peripheral Library.

So the project definition is simple, output a regular signal (20Hz with a 50% duty cycle) on Port D, Pin 4 (i.e. pin 2 on the STM8S103F3P3).

Algorithm

To make this project a low on processor power we will use interrupts to generate the pulse. To do this we will make use of one of the STM8S timers, namely Timer 2 (T2). The algorithm becomes:

Turn off the timer

Setup the timer to generate an interrupt every 1 / 40th of a second

Set up the output port to generate the signal.

Wait for interrupts indefinitely

The Interrupt Service Routine (ISR) then has one very simple task, toggle the output port and wait for the next interrupt.

The Registers

This application is simple and really only uses a fraction of the power of the STM8S timers. In fact we can set up the chip using relatively few registers. With the exception of resetting the timer to a known state we will be using only six registers in this exercise:

TIM2_PSCR

TIM2_ARRH and TIM2_ARRL

TIM2_IER

TIM2_CR1

TIM2_SR1

TIM2_PSCR – Timer 2 Prescalar

The 16-bit counter in Timer 2 receives a clock signal from the prescalar. This in turn receives a clock from the internal clock of the STM8S (i.e. fmaster). The prescalar divides the fmaster clock by the prescalar set in the TIM2_PSCR register. This allows the timer to receive a slower clock signal than that running the STM8S. The prescalar is a power of 2 and the effective frequency of the clock running Timer 2 is given by the following formula:

fcounter = fmaster / 2TIM2_PSCR

where fcounter is the frequency of the signal being used as a clock source for Timer 2.

TIM2_PSCR is a 4 bit number and this restricts the value of the prescalar to 1 to 32,768.

We will come back to this formula when we write the software in order to calculate the prescalar we will need to generate the 20Hz clock signal.

TIM2_ARRH and TIM2_ARRL – Counter Auto-Reload Registers

We will be using the counter as a simple up/down counter. We will be loading this register with a counter value which the timer will count up to / down from. An interrupt will be generated when the counter value has been reached (for up) or zero is reached (for down). The counter will then be reset using the values in these two registers.

The only important thing to note about these two registers is that TIM2_ARRH must be loaded with a value before TIM2_ARRL.

TIM2_IER – Interrupt Enable Register

This register determines which interrupts Timer2 can generate. In our case we only need one, namely the update interrupt. This is generated when the counter value has been reached.

The interrupt is enabled by setting TIM2_IER_UIE to 1.

TIM2_CR1 – Timer 2 Control Register 1

The only bit we will be interested here is the Counter ENable bit (CEN). This will be used to start the counter.

TIM2_SR1 – Timer 2 Status Register 1

This register gives us status information about the timer. There is only one bit we are interested in for this exercise and that is the Update Interrupt Flag (UIF). This bit determines if an update interrupt is pending. The bit is set by hardware but crucially it must be reset by software.

When we enter the ISR, this bit will have been set by the hardware controlling the timer. On existing the ISR the hardware will check the status of the bit. If it is set then the interrupt will be generated once more. This means that if we are not careful then we can end up in a cycle of generating an interrupt, processing the interrupt in the ISR and then generating the interrupt again ad infinitum. It is therefore crucial that this bit is cleared before the ISR is exited.

Software

One of the first things to note is that as with all of the examples we will discuss in this series, we will assume a clock running using the internal oscillator and set to 16MHz.

The code which will deal with the interrupt has a very simple job to do, namely toggle the pin we are using to generate the output pulse. One thing to note it that as we are toggling the pin in this method we will effectively be halving the output frequency of the signal which has been generated. Lets look at what is happening.

ISR 1 – output is low we will make the output high.

ISR 2 – output is high we will make the signal low

ISR 3 – output is low we will make the signal high

etc.

The frequency of the output for a regular signal is determined by the amount of time between the two rising edges of the output. So in our case, the time is double the frequency of the calls to the ISR as we toggle the output in the ISR. This is important and will be used in the calculations we make regarding the timer settings later.

If you have been following the series, the next piece of code should also be familiar (see the Simple GPIO example). We will be setting up Port D, pin 4 to be an output port. This is the pin which will output the signal we will be generating.

The next thing we need is a method which sets the Timer 2 to generate the interrupt. This is where we need to start doing some calculations.

So let’s start with the frequency of the clock going into the counter for Timer 2. As we have seen earlier, this is given by the following:

fcounter = fmaster / 2TIM2_PSCR

Now we also know that the interrupts will be generated every time the counter value is reached. So the frequency of the interrupt is given by the following:

finterrupt = fcounter / counter

Putting the two together we get the following:

finterrupt = fmaster / (2TIM2_PSCR * counter)

A little rearranging gives:

(2TIM2_PSCR * counter) = fmaster / finterrupt

If we plug in the numbers we know, fmaster = 16MHz and finterrupt = 40 (remember that the frequency of the signal we are generating is half the frequency of the interrupts) then we find:

(2TIM2_PSCR * counter) = 400,000

So, if we take 400,000 and divide by 50,000 (for simplicity) then we have a factor of 8. So, given that the counter is a 16-bit counter then the counter should be 50,000 and the prescalar should be 3 (23 = 8).

Running this application results in the following trace on the oscilloscope:

20 Hz Square Wave Output on an Oscilloscope

A quick look at the measurements shows that this application is generating a 20Hz signal. If you don’t have a scope then you can hook a LED (use the LED circuit from the previous article on external interrupts) through a transistor. You should be able to see the LED flicker as it is turned on and off. You could also slow down the rate of the pulses by looking at changing the prescalar or adding a counter.