Computational Robotics
Engineering
Microcontrollers
Programming U3
Exam U3
Timers and Interrupts
Student
Esquivar Genesta Efrain Enrique
Carlos Jose Balam Poot
March 11th - 2021
Index
Introduction ............................................................................................................................ 1
Global variables .................................................................................................................. 1
List of materials ...................................................................................................................... 2
Development ........................................................................................................................... 3
Results .................................................................................................................................... 5
Conclusion .............................................................................................................................. 5
References .............................................................................................................................. 6
Table of images
Fig. 1 Time scaled example ............................................................................................................... 1
Fig. 2 Built circuit .............................................................................................................................. 3
Fig. 3 Motor and LED dimming ...................................................................................................... 5
Introduction
This document shows the
realization of the exam of
Microcontroller unit 3, which
consists of generating 2 PWM
through the internal timers of
the ESP32 (their frequencies).
We will see what timers are
and how to use them. The
ESP32 has 4 64-bit timers,
with a 16-bit prescaler. The
timer can count up or down
(incrementing or Fig. 1 Time scaled example
decrementing). They have an
auto reloaded function and also can be triggered on an edge or in a level interrupt. But it only
makes senses if you also combined time or with an GPIO pin where you have an edge or
falling or rising edge or both or have a level with the ADC.[1]
The timers are organized in two groups. Timer group 0 for time are 0 and 1, and Timer group
1 for timer 2 and timer 3. The prescaler is used to divide the frequency of the base signal
(usually 80 MHz), which is then used to increment / decrement the timer counter. Since the
prescaler has 16 bits, it can divide the clock signal frequency by a factor from 2 to 65536,
giving a lot of configuration freedom.
Some of the important distinct timer modes are:
• The timer is disabled. The hardware is not ticking at all.
• The timer is enabled, but the alarm is disabled. The timer hardware is ticking, it is
optionally incrementing or decrementing the internal counter, but nothing else is
happening.
• The timer is enabled, and its alarm is also enabled. Like before, but this time some
action is performed when the timer counter reaches a particular, configured value:
The counter is reset and/or an interrupt is generated.
Global variables
As usual, since this counter variable will be shared amongst the main loop and the ISR, then
it needs to be declared with the volatile keyword, which avoids it being removed due to
compiler optimizations [2].
1 volatile int interruptCounter;
We will have an additional counter to track how many interrupts have already occurred since
the beginning of the program. This one will only be used by the main loop and thus it doesn’t
need to be declared as volatile.
1
2 int totalInterruptCounter;
In order to configure the timer, we will need a pointer to a variable of type hw_timer_t, which
we will later use in the Arduino setup function.
3 hw_timer_t * timer = NULL;
Finally, we will need to declare a variable of type portMUX_TYPE, which we will use to
take care of the synchronization between the main loop and the ISR, when modifying a shared
variable.
4 portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
Timers’ counters can be read by arbitrary code, but in most cases, we are interested in doing
something periodically, and this means we will configure the timer hardware to generate an
interrupt, and we will write code to handle it.
An interrupt handler function must finish before the next interrupt is generated, which gives
us a hard upper limit on how complex the function can get. Generally, an interrupt handler
should do the least amount of work it can.
To achieve anything remotely complex, it should instead set a flag which is checked by non-
interrupt code. Any kind of I/O more complex than reading or setting a single pin to a single
value is often better offloaded to a separate handler [3].
List of materials
• Protoboard of 6,4 x 17,2 cm with 830 perforation.
• Computer.
• ESP32.
• 1 330 Ohm Resistances.
• 1 2n2222 transistor
• 1 5v supply (we use Arduino 5V, GND pins)
• 1 DC motor 5v
• 1 Diode rectifier
• Du-pont wire.
• 1 LED.
2
Development
We see below the circuit made for
this practice. POT 1 and POT 2
potentiometers go on pins 34 and
35, respectively. The signal
output for the led is pin 2, and for
the motor is pin 5. We also see the
necessary connection to create a
separate circuit for the power
supply of the circuit, this is mainly
the use of the rectifier diode that
only allows the passage of current
on one side, blocking that the 5v
from the source reaches the signal
output of pin 2 of the ESP32.
Alligators were used to facilitate
the connection of the circuit. Fig. 2 Built circuit
Although not shown, the motor is
at the bottom of the image (not shown). The positive of the motor goes directly to the positive
of the 5V, and the negative of the motor is connected to the emitter of the 2n2222.
Code
hw_timer_t*timer=NULL; //Here we define the timer
//Timer 1
int Resolution = 100;//PWM resolution regarding the duty cycle
int Duty_Cycle = 50;//duty cycle
int Counter1 = 0;
//Timer 2
int Resolution2 = 20;//PWM resolution regarding the duty cycle
int Duty_Cycle2 = 10;//duty cycle
int Counter2 = 0;
void IRAM_ATTR onTimer()
{
if(Counter1 == Resolution)
Counter1 = 0;//Restart the step once it got 100
if(Duty_Cycle >= Counter1)//If Step is greater than Duty Cycle, equal to 1, else equal
to 0
{
digitalWrite(5, 0);
}
else
3
{
digitalWrite(5, 1);
}
Counter1++;
if(Counter2 == Resolution2)
Counter2 = 0;//Restart the step once it got 100
if(Duty_Cycle2 >= Counter2)//If Step is greater than Duty Cycle, equal to 1, else equal
to 0
{
digitalWrite(22, 0);
}
else
{
digitalWrite(22, 1);
}
Counter2++;
}
void setup()
{
Serial.begin(115200);
pinMode(22,OUTPUT);
pinMode(5,OUTPUT);
timer = timerBegin(0,80,true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 10, true);//Frequency = (timer)*(resolution) // 10us * 100 =
1ms = 1kHz // 10us * 20 = 0.2ms = 5kHz
timerAlarmEnable(timer);
}
void loop()
{
int pot1 = analogRead(34);
int pot2 = analogRead(35);
pot2 = pot2*100/4095;
pot1 = pot1*100/4095;
Duty_Cycle = 100-pot1;
Duty_Cycle2 = 20*(100-pot2)/100;
}
We start our code by declaring some global variables. As it was mentioned in Introduction,
the first one will be a counter that will be used by the interrupt service routine to signal the
main loop that an interrupt has occurred. Also, Resolution and Duty Cycle were necessary
4
for the PWM and a pointer to a variable of type hw_timer_t, which we will later use in the
Arduino setup function.
Next, the interrupt handling routine should have the void IRAM_ATTR onTimer() attribute,
which uses ISR based routines to run various taskings. Instead of functions calls, where the
timer has to go to those functions and follow those functions through, the functions are just
triggered to run as CPU cycles allow.
On the setup, as usual, we start by opening a serial connection; in case we want, we can later
output the results of our program to be available in the Arduino IDE serial monitor. Also, we
needed to set all the functions regarding the timer. On the other hand, we declared the motor
and led pins as Output.
Finally, for the Void loop, we just configured the potentiometers and their functions of
varying brightness and speed.
Results
The project had the desired
result, of increasing and
decreasing the brightness of the
led (fade), and the speed of the
motor. It will not be possible to
see much in the image x, but the
motor is rotating at a desired
speed, as well as the led at a
desired brightness. Both
controlled by a potentiometer
for each one. Remember that
potentiometers emit an analog
signal pwm, which the Fig. 3 Motor and LED dimming
microcontroller converts into
ADC to be able to work with that information in bits.
Conclusion
In this practice we learned to generate a PWM signal from the generation of an internal timer
of the ESP32. The use of timers is an alternative, necessary in some cases, where we want to
work with multiple ADC signals in our circuits, or even where we simply need 2 different
timers, each one for a different function. Both timers used the assignment or rather calling of
the ADCs, and these ADCs, in turn, to control the pulse width of different components. It
should be said that for the ADC of the engine it was a bit more complicated with what was
the connection of the same in the breadboard.
Compared to practice 3 of this unit, we did not know how to quote the digitalwrite to be able
to do the attenuation inside the timer to be able to make the interruption. Well, it was basically
5
that, creating a conditional to know if the duty cycle was greater than the counter that was
generated. Which will be adding one by one each interruption. This happens very fast because
it is controlled with the potentiometer, being prioritized by the same interrupt. So this is
where the very fast LED switching happens, due to that conditional. And as we also saw in
the code, in the void loop it is only necessary to keep cycling the pwm reading of the
potentiometers, which must also be converted to ADC.
References
[1] Alessandro Matera. (2015). How timer overflow interrupt works. February 19th, 2021,
from KeyChanino Web site: https://www.keychainino.com/how-timer-overflow-interrupt-
works/ . Recovered on March 11, 2021.
[2] Ivan Voras. (2018). Working with ESP32 Audio Sampling. February 19th, 2021, from
Toptal Web site: https://www.toptal.com/embedded/esp32-audio-sampling. Recovered on
March 11, 2021.
[3]Techtutorialsx, (2018). “ESP32 Arduino: Timer interrupts”. Taken from
https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/. Recovered on March
11, 2021.
[4] Random Nerd Tutorial, (Unavailable year). “ESP32 Interrupts and Timers”. Taken from
https://randomnerdtutorials.com/esp32-pir-motion-sensor-interrupts-timers/. . Recovered on
March 11, 2021.