Tut 2 - PWM and Timers
01. Understanding the PWM Module
Question

Solution
SW approach to generate PWM
The pseudo-code (or step) is shown as follows:
Configure Pin as output
Set as ‘1’
Delay for ‘T-on’
Set as ‘0’
Delay for ‘T-off’
Loop to Step 2
With this approach, the microcontroller is continuously executing the loop to generate the required PWM. As such, it can't do anything else more productive. Furthermore, if there are interrupts in the system, the timing characteristics for the PWM will also be affected.
When the peripheral block is used to generate the PWM, only the initial setup code needs to be executed. Subsequently, it is driven by the HW with minimal processing time in the Interrupts.
Decrease the PWM frequency / Increase the PWM Period
Use the ISR to keep track of the number of Interrupts and then toggle the output pin accordingly. In this approach, we cannot allow the Timter/Counter Module to control the pin directly. The ISR needs to handle it.
Takeaway
The PWM we have learned in Studio 4 - PWM Programming is actually achieved using Hardware. Briefly speaking, PWM is achieved by the Timer/Counter Module on ATmega328p.
02. Timer Interrups
Question

Solution
Concurrent Trigger
Interrupt Priority
Remember the Interrupt Vector Table? Each ISR has an address, and
The lower the address the higher is the priority level.

So, we can see from above that Timer 2's interrupt has higher priority than Timer 1's interrupt. Thus, the executing flow will be as follows:

Explanation:
Main Loop Running: The system (or loop()) is executing normally.
Timer2 Interrupt Triggers: Timer2’s interrupt has higher priority. Thus it occurs first, so the controller immediately jumps to execute Timer2’s ISR.
Timer0 Interrupt Flag Set: While Timer2’s ISR is running, if Timer0’s interrupt occurs, it cannot preempt Timer0. Instead, the Interrupt Flag is set for Timer0's interrupt.
ISR Completion & Context Switch: Once Timer2’s ISR completes, the processor returns to the main loop.
Timer0 ISR Execution: The pending Timer0 flag then triggers the Timer0 ISR, which is executed next.
Sequential Trigger but in reverse priority level
Nested Interrupts are disabled

By default, Nested Interrupts are disabled. When Timer 0 triggers the interrupt first, the controller will jump to Timer 0 ISR and start executing. When Timer 2 triggers, the event is captured by the Interrupt Flag, but the current ISR will complete execution and perform a context switch to the loop(). At this time, the flag will cause the jump to the Timer 2 ISR.
Nested Interrupts enabled

If nested interrupts are enabled. Then, the execution flow will flow normally as shown above.
Very good explanation from ATmega328p datasheet (P32)
There are basically two types of interrupts:
The first type is triggered by an event that sets the Interrupt Flag. For these interrupts, the Program Counter is vectored to the actual Interrupt Vector in order to execute the interrupt handling routine, and hardware clears the corresponding Interrupt Flag. Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s) to be cleared. If an interrupt condition occurs while the corresponding interrupt enable bit is cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the flag is cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt Enable bit is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the Global Interrupt Enable bit is set, and will then be executed by order of priority.
The second type of interrupts will trigger as long as the interrupt condition is present. These interrupts do not necessarily have Interrupt Flags. If the interrupt condition disappears before the interrupt is enabled, the interrupt will not be triggered. When the AVR exits from an interrupt, it will always return to the main program and execute one more instruction before any pending interrupt is served.
Takeaway
The idea of Context Switch when dealing with the execution of ISR is very important and should be remembered and practiced in the future thinking!
03. Timers Basics
Question

Solution
Real-world application of Timers
Configure to trigger once per second then write a soft real-time clock. E.g. at https://bitbucket.org/ctank/smarttimer/src/master/
Used in operating systems to switch between tasks in a multitasking environment, to simulate multiple processes running on a single CPU.
Explanation for the second application - multitasking on a single CPU
This is mainly done thanks to the interrupts triggered by the Timer/Counter Module.
The timer triggers interrupts at regular intervals (typically milliseconds), forcing the CPU to temporarily stop executing the current process, save its state, and transfer control to the operating system's scheduler. The scheduler then selects the next process to run, loads its saved context, and gives it control of the CPU until the next timer interrupt occurs.
This predictable, hardware-driven context switching ensures that no single process can monopolize the CPU, regardless of what it's doing. The timer interrupts effectively slice CPU time into small chunks, creating the illusion that multiple processes are running simultaneously on a single CPU core.
Timer 0 and Timer 2 on ATmega328p
The main counter
TCNT0/TCNT2only counts from 0 to 255.Based on table 19-10 in the datasheet, the largest timer frequency is
On the Arduino is equal to the system clock which is 16MHz, and thus the largest timer frequency is .
This works out to between each increment of Timer 0 and Timer 2.
The largest interval for Timer 0 and Timer 2 is therefore 0.000064 x 255 = 0.01632 seconds. (The largest half-period of of the waveform generated by Timer 0 and Timer 2)
Timer 1 on ATmega328p
Advantage:
Timer 1 counter TCNT1 is 16 bits long, having a maximum value of 65535.
The largest resolution is again 0.000064 seconds (Table 20-7), giving us a maximum interval of 65535 x 0.000064 = 4.1924 seconds.
It is thus possible to set intervals of over a second. (We can have longer period for our waveform)
Disadvantage:
The Timer 1 registers TCNT1, OCR1A and OCR1B are all twice as large as those in Timers 0 and 2 (16-bit), requiring more programming to set them up (since the 328P can only set the registers up 8 bits at a time), and occupying more space on the chip.
Takeaway
From the real-world application of Timers, we've seen that the importance of triggering Interrupts. It can achieve multitasking on one CPU.
From the contrast between Timer2/0 and Timer 1 on ATmega328p, we've seen the importance of deriving the maximum period for the waveform generated by these Timers.
04. Timers Setup
Question

Solution
Interval Calculation
Interval refers to the time period between consecutive events or triggers.
In this context, the interval means the time period between consecutive triggerings of this interrupt. (TIMER1_COMPA_vect)
The prescalar is
0b100which is 256.At 16MHz, the timer resolution is .
The period therefore is
Remember to +1 on the OCRnA value when calculating either period or frequency under the CTC Mode.
Sketch the Waveform
There is a match approx. once per 4ms, and the COM1A0 and COM1A1 bits are 0b01, which is a “toggle on match”.
Hence we get a square wave of period of about 8ms.

Takeaway
The concept of interval, which means "the time period between consecutive events or triggers" is important!
The way to deal with
OCRnAvalue under CTC Mode also needs to pay attention to.When you know
OCRnAvalue and want to use it to calculate period/frequency of the waveform you want to generate, +1 and then times the timer resolution.When you know the period/frequency of the waveform you want to generate and want to use it to calculate the
OCRnAvalue, -1 and then times the timer resolution.
Know how to read the information given the setup of the registers and vice versa, this will be the classic quiz quesitions for Quiz 1.
05. Timers Variant
Question

Solution
Filling in the table, we get
N/A (Bigger than 255)
N/A
N/A
N/A (Bigger than 255)
N/A
N/A
204
51
13
Prescalar of 64 and 256 give the same accuracy while prescalar of 1024 gives very poor accuracy.
In general the smaller a prescalar is, the more accurate the timing would be (because of the higher timer resolution). Of course this will also depend on the rounding error.
Thus, the prescaler of 64 is the best choice.
Takeaway
When rounding the V value (which we will use it minus 1 as our
OCRnAvalue), we always round up.
Last updated